diff --git a/.gitignore b/.gitignore index a7cc8803..c551f7a2 100644 --- a/.gitignore +++ b/.gitignore @@ -18,8 +18,10 @@ !client/hardnested/tables/*.z usb_cmd.lua version.c +armsrc/fpga_version_info.c client/ui/ui_overlays.h *.Td +.DS_Store *.exe hardnested_stats.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 8beb31a0..8b610d21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] ### Changed +- Adjusted `lf cmdread` to respond to client when complete and the client will then automatically call `data samples` - Improved backdoor detection missbehaving magic s50/1k tag (Fl0-0) - Deleted wipe functionality from `hf mf csetuid` (Merlok) - Changed `hf mf nested` logic (Merlok) @@ -20,8 +21,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ### Fixed - Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok) +- Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi) ### Added +- Added a bitbang mode to `lf cmdread` if delay is 0 the cmd bits turn off and on the antenna with 0 and 1 respectively (marshmellow) - Added PAC/Stanley detection to lf search (marshmellow) - Added lf pac demod and lf pac read - extracts the raw blocks from a PAC/Stanley tag (marshmellow) - Added hf mf c* commands compatibity for 4k and gen1b backdoor (Fl0-0) @@ -47,6 +50,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added to `hf emv exec` MSD path for VISA and Mastercard and some other compatible EMV cards (Merlok) - Added to `hf emv exec` SDA, DDA, fast DDA, CDA calculations for VISA and Mastercard and some other compatible EMV cards (Merlok) - Added `hf emv test` - crypto tests for DES, AES, SHA, RSA, SDA, DDA, CDA and some other crypto functions (Merlok) +- Added `hf list mf` - deciphers crypto1 stream and works with first authentication and weak nested authentications (Merlok) ## [3.0.1][2017-06-08] @@ -62,7 +66,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added lf hitag write 24, the command writes a block to hitag2 tags in crypto mode (henjo) ### Added -- Added hf mf hardnested, an attack working for hardened Mifare cards (EV1, Mifare Plus SL1) where hf mf nested fails +- Added hf mf hardnested, an attack working for hardened Mifare cards (EV1, Mifare Plus SL1) where hf mf nested fails (piwi) - Added experimental testmode write option for t55xx (danger) (marshmellow) - Added t55xx p1detect to `lf search` chip detections (marshmellow) - Added lf t55xx p1detect, detect page 1 of a t55xx tag based on E015 mfg code (marshmellow) diff --git a/CI/.travis.yml b/CI/.travis.yml new file mode 100644 index 00000000..8e9289b1 --- /dev/null +++ b/CI/.travis.yml @@ -0,0 +1,55 @@ +# Travis-CI config +# variable REPOSITORY_EP must be filled with repository name. as sample: "merlokk/proxmark3" +language: c + +compiler: gcc + +# Test on Linux and MacOS +matrix: + include: + - os: osx + osx_image: xcode7.3 # OS X 10.11 + - os: osx + osx_image: xcode8.3 # OS X 10.12 + - os: osx + osx_image: xcode9 # OS X 10.12 + - os: osx + osx_image: xcode9.2 # OS X 10.12 + - os: linux + dist: trusty + sudo: required + +before_install: +## Install ARM toolchain on Linux. +## add our homebrew tap for MacOS +## Note: all dependencies on MacOS should be resolved by the brew install command + echo $REPOSITORY_EP; + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + sudo apt-get update -qq; + sudo apt-get install -y gcc-arm-none-eabi; + elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + brew update; + if [[ "$REPOSITORY_EP" == "" ]]; then + brew tap proxmark/proxmark3; + else + brew tap "$REPOSITORY_EP" --env=std; + fi + fi + +install: + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + brew info proxmark3; + brew install -v --HEAD proxmark3; + elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + make all; + fi + +before_script: + +script: +## for the time being we are satisfied if it can be build and then successfully started + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + proxmark3 /dev/notexists travis_test_commands.scr ; + elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + ./client/proxmark3 /dev/notexists travis_test_commands.scr ; + fi diff --git a/appveyor.yml b/CI/appveyor.yml similarity index 100% rename from appveyor.yml rename to CI/appveyor.yml diff --git a/CI/readme.md b/CI/readme.md new file mode 100644 index 00000000..d4159290 --- /dev/null +++ b/CI/readme.md @@ -0,0 +1,20 @@ +# How to configure continuous integration + +Here 2 CI configuration files: + +1. for [travis](travis-ci.org) +2. for [appveyor](appveyor.com) + +It needs to put files from this directory to repository root and then configure CI from appropriate WEB portal. + +## travis + +- Copy .travis.yml and travis_test_commands.scr files to repository root +- Configure CI from http://travis-ci.org +- It needs to fork https://github.com/Proxmark/homebrew-proxmark3 from your proxmark repository home +- Put to file `proxmark3.rb` in line `head "https://github.com/proxmark/proxmark3.git"` your repository link. As sample: `head "https://github.com/merlokk/proxmark3.git"` + + +## appveyor + +- Just copy appveyor.yml file to root and configure it from http://appveyor.com diff --git a/CI/travis_test_commands.scr b/CI/travis_test_commands.scr new file mode 100644 index 00000000..4f5b025c --- /dev/null +++ b/CI/travis_test_commands.scr @@ -0,0 +1,3 @@ +hf mf hardnested t 1 000000000000 +hf emv test +exit diff --git a/README.md b/README.md index 7258f918..09f23a6b 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ The Proxmark3 is available for purchase (assembled and tested) from the following locations: * [RyscCorp](https://proxmark3.com/) (US) +* [Hackerwarehouse](https://hackerwarehouse.com/) (US) * [Elechouse](http://www.elechouse.com/) (HK) * [Lab401](https://lab401.com/) (FR) * [RFxSecure](http://www.rfxsecure.com/) (SG) diff --git a/armsrc/Makefile b/armsrc/Makefile index dea5d06c..f0a0c0ff 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -10,10 +10,16 @@ APP_INCLUDES = apps.h #remove one of the following defines and comment out the relevant line #in the next section to remove that particular feature from compilation -APP_CFLAGS = -DWITH_ISO14443a_StandAlone -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG -DWITH_CRC -DON_DEVICE -DWITH_HFSNOOP \ - -fno-strict-aliasing -ffunction-sections -fdata-sections -#-DWITH_LCD +APP_CFLAGS = -DON_DEVICE \ + -fno-strict-aliasing -ffunction-sections -fdata-sections +include ../common/Makefile_Enabled_Options.common + +ifneq (,$(findstring LCD,$(APP_CFLAGS))) + SRC_LCD = fonts.c LCD.c +else + SRC_LCD = +endif #SRC_LCD = fonts.c LCD.c SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c protocols.c SRC_ISO15693 = iso15693.c iso15693tools.c @@ -21,7 +27,6 @@ SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c mifares SRC_ISO14443b = iso14443b.c SRC_CRAPTO1 = crypto1.c des.c SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c parity.c - #the FPGA bitstream files. Note: order matters! FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit @@ -59,6 +64,9 @@ ARMSRC = fpgaloader.c \ optimized_cipher.c \ hfsnoop.c +VERSIONSRC = version.c \ + fpga_version_info.c + # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC include ../common/Makefile.common @@ -69,6 +77,14 @@ all: $(OBJS) .DELETE_ON_ERROR: +# version.c should be remade on every compilation +.PHONY: version.c +version.c: default_version.c + perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@ + +fpga_version_info.c: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR) + $(FPGA_COMPRESSOR) -v $(filter %.bit,$^) $@ + $(OBJDIR)/fpga_all.o: $(OBJDIR)/fpga_all.bit.z $(OBJCOPY) -O elf32-littlearm -I binary -B arm --prefix-sections=fpga_all_bit $^ $@ diff --git a/armsrc/appmain.c b/armsrc/appmain.c index e292483b..27f43b3f 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -16,6 +16,7 @@ #include "cmd.h" #include "proxmark3.h" #include "apps.h" +#include "fpga.h" #include "util.h" #include "printf.h" #include "string.h" @@ -31,7 +32,7 @@ #endif // Craig Young - 14a stand-alone code -#ifdef WITH_ISO14443a_StandAlone +#ifdef WITH_ISO14443a #include "iso14443a.h" #endif @@ -135,35 +136,28 @@ void Dbhexdump(int len, uint8_t *d, bool bAsci) { // return that. //----------------------------------------------------------------------------- static int ReadAdc(int ch) -{ - uint32_t d; - - AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST; - AT91C_BASE_ADC->ADC_MR = - ADC_MODE_PRESCALE(63 /* was 32 */) | // ADC_CLK = MCK / ((63+1) * 2) = 48MHz / 128 = 375kHz - ADC_MODE_STARTUP_TIME(1 /* was 16 */) | // Startup Time = (1+1) * 8 / ADC_CLK = 16 / 375kHz = 42,7us Note: must be > 20us - ADC_MODE_SAMPLE_HOLD_TIME(15 /* was 8 */); // Sample & Hold Time SHTIM = 15 / ADC_CLK = 15 / 375kHz = 40us - +{ // Note: ADC_MODE_PRESCALE and ADC_MODE_SAMPLE_HOLD_TIME are set to the maximum allowed value. - // Both AMPL_LO and AMPL_HI are very high impedance (10MOhm) outputs, the input capacitance of the ADC is 12pF (typical). This results in a time constant - // of RC = 10MOhm * 12pF = 120us. Even after the maximum configurable sample&hold time of 40us the input capacitor will not be fully charged. + // AMPL_HI is are high impedance (10MOhm || 1MOhm) output, the input capacitance of the ADC is 12pF (typical). This results in a time constant + // of RC = (0.91MOhm) * 12pF = 10.9us. Even after the maximum configurable sample&hold time of 40us the input capacitor will not be fully charged. // // The maths are: // If there is a voltage v_in at the input, the voltage v_cap at the capacitor (this is what we are measuring) will be // - // v_cap = v_in * (1 - exp(-RC/SHTIM)) = v_in * (1 - exp(-3)) = v_in * 0,95 (i.e. an error of 5%) - // - // Note: with the "historic" values in the comments above, the error was 34% !!! - - AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ch); + // v_cap = v_in * (1 - exp(-SHTIM/RC)) = v_in * (1 - exp(-40us/10.9us)) = v_in * 0,97 (i.e. an error of 3%) + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST; + AT91C_BASE_ADC->ADC_MR = + ADC_MODE_PRESCALE(63) | // ADC_CLK = MCK / ((63+1) * 2) = 48MHz / 128 = 375kHz + ADC_MODE_STARTUP_TIME(1) | // Startup Time = (1+1) * 8 / ADC_CLK = 16 / 375kHz = 42,7us Note: must be > 20us + ADC_MODE_SAMPLE_HOLD_TIME(15); // Sample & Hold Time SHTIM = 15 / ADC_CLK = 15 / 375kHz = 40us + + AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ch); AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; - while(!(AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ch))) - ; - d = AT91C_BASE_ADC->ADC_CDR[ch]; - - return d; + while(!(AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ch))) {}; + + return AT91C_BASE_ADC->ADC_CDR[ch]; } int AvgAdc(int ch) // was static - merlok @@ -193,6 +187,8 @@ void MeasureAntennaTuningLfOnly(int *vLf125, int *vLf134, int *peakf, int *peakv FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + SpinDelay(50); + for (i=255; i>=19; i--) { WDT_HIT(); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i); @@ -201,7 +197,7 @@ void MeasureAntennaTuningLfOnly(int *vLf125, int *vLf134, int *peakf, int *peakv if (i==95) *vLf125 = adcval; // voltage at 125Khz if (i==89) *vLf134 = adcval; // voltage at 134Khz - LF_Results[i] = adcval>>8; // scale int to fit in byte for graphing purposes + LF_Results[i] = adcval >> 9; // scale int to fit in byte for graphing purposes if(LF_Results[i] > peak) { *peakv = adcval; peak = LF_Results[i]; @@ -249,7 +245,7 @@ void MeasureAntennaTuning(int mode) } } - cmd_send(CMD_MEASURED_ANTENNA_TUNING, vLf125 | (vLf134<<16), vHf, peakf | (peakv<<16), LF_Results, 256); + cmd_send(CMD_MEASURED_ANTENNA_TUNING, vLf125>>1 | (vLf134>>1<<16), vHf, peakf | (peakv>>1<<16), LF_Results, 256); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_B_OFF(); return; @@ -291,6 +287,7 @@ void ReadMem(int addr) extern struct version_information version_information; /* bootrom version information is pointed to from _bootphase1_version_pointer */ extern char *_bootphase1_version_pointer, _flash_start, _flash_end, _bootrom_start, _bootrom_end, __data_src_start__; + void SendVersion(void) { char temp[USB_CMD_DATA_SIZE]; /* Limited data payload in USB packets */ @@ -311,10 +308,12 @@ void SendVersion(void) FormatVersionInformation(temp, sizeof(temp), "os: ", &version_information); strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1); - FpgaGatherVersion(FPGA_BITSTREAM_LF, temp, sizeof(temp)); - strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1); - FpgaGatherVersion(FPGA_BITSTREAM_HF, temp, sizeof(temp)); - strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1); + for (int i = 0; i < fpga_bitstream_num; i++) { + strncat(VersionString, fpga_version_information[i], sizeof(VersionString) - strlen(VersionString) - 1); + if (i < fpga_bitstream_num - 1) { + strncat(VersionString, "\n", sizeof(VersionString) - strlen(VersionString) - 1); + } + } // Send Chip ID and used flash memory uint32_t text_and_rodata_section_size = (uint32_t)&__data_src_start__ - (uint32_t)&_flash_start; @@ -368,7 +367,7 @@ void SendStatus(void) cmd_send(CMD_ACK,1,0,0,0,0); } -#if defined(WITH_ISO14443a_StandAlone) || defined(WITH_LF) +#if defined(WITH_ISO14443a_StandAlone) || defined(WITH_LF_StandAlone) #define OPTS 2 @@ -399,8 +398,8 @@ void StandAloneMode14a() FpgaDownloadAndGo(FPGA_BITSTREAM_HF); int selected = 0; - int playing = 0, iGotoRecord = 0, iGotoClone = 0; - int cardRead[OPTS] = {0}; + bool playing = false, GotoRecord = false, GotoClone = false; + bool cardRead[OPTS] = {false}; uint8_t readUID[10] = {0}; uint32_t uid_1st[OPTS]={0}; uint32_t uid_2nd[OPTS]={0}; @@ -416,9 +415,9 @@ void StandAloneMode14a() WDT_HIT(); SpinDelay(300); - if (iGotoRecord == 1 || cardRead[selected] == 0) + if (GotoRecord || !cardRead[selected]) { - iGotoRecord = 0; + GotoRecord = false; LEDsoff(); LED(selected + 1, 0); LED(LED_RED2, 0); @@ -443,7 +442,7 @@ void StandAloneMode14a() else if (cardRead[(selected+1)%OPTS]) { Dbprintf("Button press detected but no card in bank[%d] so playing from bank[%d]", selected, (selected+1)%OPTS); selected = (selected+1)%OPTS; - break; // playing = 1; + break; } else { Dbprintf("Button press detected but no stored tag to play. (Ignoring button)"); @@ -493,14 +492,14 @@ void StandAloneMode14a() LED(selected + 1, 0); // Next state is replay: - playing = 1; + playing = true; - cardRead[selected] = 1; + cardRead[selected] = true; } /* MF Classic UID clone */ - else if (iGotoClone==1) + else if (GotoClone) { - iGotoClone=0; + GotoClone=false; LEDsoff(); LED(selected + 1, 0); LED(LED_ORANGE, 250); @@ -551,7 +550,7 @@ void StandAloneMode14a() MifareCGetBlock(0x3F, 1, 0, oldBlock0); if (oldBlock0[0] == 0 && oldBlock0[0] == oldBlock0[1] && oldBlock0[1] == oldBlock0[2] && oldBlock0[2] == oldBlock0[3]) { Dbprintf("No changeable tag detected. Returning to replay mode for bank[%d]", selected); - playing = 1; + playing = true; } else { Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0],oldBlock0[1],oldBlock0[2],oldBlock0[3]); @@ -569,14 +568,14 @@ void StandAloneMode14a() if (memcmp(testBlock0,newBlock0,16)==0) { DbpString("Cloned successfull!"); - cardRead[selected] = 0; // Only if the card was cloned successfully should we clear it - playing = 0; - iGotoRecord = 1; + cardRead[selected] = false; // Only if the card was cloned successfully should we clear it + playing = false; + GotoRecord = true; selected = (selected+1) % OPTS; } else { Dbprintf("Clone failed. Back to replay mode on bank[%d]", selected); - playing = 1; + playing = true; } } LEDsoff(); @@ -584,65 +583,59 @@ void StandAloneMode14a() } // Change where to record (or begin playing) - else if (playing==1) // button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected]) + else if (playing) // button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected]) { LEDsoff(); LED(selected + 1, 0); // Begin transmitting - if (playing) - { - LED(LED_GREEN, 0); - DbpString("Playing"); - for ( ; ; ) { - WDT_HIT(); - int button_action = BUTTON_HELD(1000); - if (button_action == 0) { // No button action, proceed with sim - uint8_t data[512] = {0}; // in case there is a read command received we shouldn't break - Dbprintf("Simulating ISO14443a tag with uid[0]: %08x, uid[1]: %08x [Bank: %u]", uid_1st[selected],uid_2nd[selected],selected); - if (hi14a_card[selected].sak == 8 && hi14a_card[selected].atqa[0] == 4 && hi14a_card[selected].atqa[1] == 0) { - DbpString("Mifare Classic"); - SimulateIso14443aTag(1,uid_1st[selected], uid_2nd[selected], data); // Mifare Classic - } - else if (hi14a_card[selected].sak == 0 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 0) { - DbpString("Mifare Ultralight"); - SimulateIso14443aTag(2,uid_1st[selected],uid_2nd[selected],data); // Mifare Ultralight - } - else if (hi14a_card[selected].sak == 20 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 3) { - DbpString("Mifare DESFire"); - SimulateIso14443aTag(3,uid_1st[selected],uid_2nd[selected],data); // Mifare DESFire - } - else { - Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation"); - SimulateIso14443aTag(1,uid_1st[selected], uid_2nd[selected], data); - } + LED(LED_GREEN, 0); + DbpString("Playing"); + for ( ; ; ) { + WDT_HIT(); + int button_action = BUTTON_HELD(1000); + if (button_action == 0) { // No button action, proceed with sim + uint8_t data[512] = {0}; // in case there is a read command received we shouldn't break + Dbprintf("Simulating ISO14443a tag with uid[0]: %08x, uid[1]: %08x [Bank: %u]", uid_1st[selected],uid_2nd[selected],selected); + if (hi14a_card[selected].sak == 8 && hi14a_card[selected].atqa[0] == 4 && hi14a_card[selected].atqa[1] == 0) { + DbpString("Mifare Classic"); + SimulateIso14443aTag(1,uid_1st[selected], uid_2nd[selected], data); // Mifare Classic } - else if (button_action == BUTTON_SINGLE_CLICK) { - selected = (selected + 1) % OPTS; - Dbprintf("Done playing. Switching to record mode on bank %d",selected); - iGotoRecord = 1; - break; + else if (hi14a_card[selected].sak == 0 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 0) { + DbpString("Mifare Ultralight"); + SimulateIso14443aTag(2,uid_1st[selected],uid_2nd[selected],data); // Mifare Ultralight } - else if (button_action == BUTTON_HOLD) { - Dbprintf("Playtime over. Begin cloning..."); - iGotoClone = 1; - break; + else if (hi14a_card[selected].sak == 20 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 3) { + DbpString("Mifare DESFire"); + SimulateIso14443aTag(3,uid_1st[selected],uid_2nd[selected],data); // Mifare DESFire + } + else { + Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation"); + SimulateIso14443aTag(1,uid_1st[selected], uid_2nd[selected], data); } - WDT_HIT(); } - - /* We pressed a button so ignore it here with a delay */ - SpinDelay(300); - LEDsoff(); - LED(selected + 1, 0); + else if (button_action == BUTTON_SINGLE_CLICK) { + selected = (selected + 1) % OPTS; + Dbprintf("Done playing. Switching to record mode on bank %d",selected); + GotoRecord = true; + break; + } + else if (button_action == BUTTON_HOLD) { + Dbprintf("Playtime over. Begin cloning..."); + GotoClone = true; + break; + } + WDT_HIT(); } - else - while(BUTTON_PRESS()) - WDT_HIT(); + + /* We pressed a button so ignore it here with a delay */ + SpinDelay(300); + LEDsoff(); + LED(selected + 1, 0); } } } -#elif WITH_LF +#elif WITH_LF_StandAlone // samy's sniff and repeat routine void SamyRun() { @@ -1435,7 +1428,7 @@ void __attribute__((noreturn)) AppMain(void) } WDT_HIT(); -#ifdef WITH_LF +#ifdef WITH_LF_StandAlone #ifndef WITH_ISO14443a_StandAlone if (BUTTON_HELD(1000) > 0) SamyRun(); diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index c0b04f3c..77223bd0 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -10,20 +10,21 @@ // mode once it is configured. //----------------------------------------------------------------------------- +#include "fpgaloader.h" + #include #include #include -#include "fpgaloader.h" +#include "apps.h" +#include "fpga.h" #include "proxmark3.h" #include "util.h" #include "string.h" #include "BigBuf.h" #include "zlib.h" -extern void Dbprintf(const char *fmt, ...); - // remember which version of the bitstream we have already downloaded to the FPGA -static int downloaded_bitstream = FPGA_BITSTREAM_ERR; +static int downloaded_bitstream = 0; // this is where the bitstreams are located in memory: extern uint8_t _binary_obj_fpga_all_bit_z_start, _binary_obj_fpga_all_bit_z_end; @@ -31,10 +32,7 @@ extern uint8_t _binary_obj_fpga_all_bit_z_start, _binary_obj_fpga_all_bit_z_end; static uint8_t *fpga_image_ptr = NULL; static uint32_t uncompressed_bytes_cnt; -static const uint8_t _bitparse_fixed_header[] = {0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01}; -#define FPGA_BITSTREAM_FIXED_HEADER_SIZE sizeof(_bitparse_fixed_header) #define OUTPUT_BUFFER_LEN 80 -#define FPGA_INTERLEAVE_SIZE 288 //----------------------------------------------------------------------------- // Set up the Serial Peripheral Interface as master @@ -201,7 +199,7 @@ static int get_from_fpga_combined_stream(z_streamp compressed_fpga_stream, uint8 //---------------------------------------------------------------------------- static int get_from_fpga_stream(int bitstream_version, z_streamp compressed_fpga_stream, uint8_t *output_buffer) { - while((uncompressed_bytes_cnt / FPGA_INTERLEAVE_SIZE) % FPGA_BITSTREAM_MAX != (bitstream_version - 1)) { + while((uncompressed_bytes_cnt / FPGA_INTERLEAVE_SIZE) % fpga_bitstream_num != (bitstream_version - 1)) { // skip undesired data belonging to other bitstream_versions get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer); } @@ -234,7 +232,7 @@ static bool reset_fpga_stream(int bitstream_version, z_streamp compressed_fpga_s // initialize z_stream structure for inflate: compressed_fpga_stream->next_in = &_binary_obj_fpga_all_bit_z_start; - compressed_fpga_stream->avail_in = &_binary_obj_fpga_all_bit_z_start - &_binary_obj_fpga_all_bit_z_end; + compressed_fpga_stream->avail_in = &_binary_obj_fpga_all_bit_z_end - &_binary_obj_fpga_all_bit_z_start; compressed_fpga_stream->next_out = output_buffer; compressed_fpga_stream->avail_out = OUTPUT_BUFFER_LEN; compressed_fpga_stream->zalloc = &fpga_inflate_malloc; @@ -248,8 +246,8 @@ static bool reset_fpga_stream(int bitstream_version, z_streamp compressed_fpga_s header[i] = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer); } - // Check for a valid .bit file (starts with _bitparse_fixed_header) - if(memcmp(_bitparse_fixed_header, header, FPGA_BITSTREAM_FIXED_HEADER_SIZE) == 0) { + // Check for a valid .bit file (starts with bitparse_fixed_header) + if(memcmp(bitparse_fixed_header, header, FPGA_BITSTREAM_FIXED_HEADER_SIZE) == 0) { return true; } else { return false; @@ -427,7 +425,7 @@ void FpgaDownloadAndGo(int bitstream_version) } unsigned int bitstream_length; - if(bitparse_find_section(bitstream_version, 'e', &bitstream_length, &compressed_fpga_stream, output_buffer)) { + if (bitparse_find_section(bitstream_version, 'e', &bitstream_length, &compressed_fpga_stream, output_buffer)) { DownloadFPGA(bitstream_version, bitstream_length, &compressed_fpga_stream, output_buffer); downloaded_bitstream = bitstream_version; } @@ -442,77 +440,6 @@ void FpgaDownloadAndGo(int bitstream_version) } -//----------------------------------------------------------------------------- -// Gather version information from FPGA image. Needs to decompress the begin -// of the respective (HF or LF) image. -// Note: decompression makes use of (i.e. overwrites) BigBuf[]. It is therefore -// advisable to call this only once and store the results for later use. -//----------------------------------------------------------------------------- -void FpgaGatherVersion(int bitstream_version, char *dst, int len) -{ - unsigned int fpga_info_len; - char tempstr[40] = {0x00}; - z_stream compressed_fpga_stream; - uint8_t output_buffer[OUTPUT_BUFFER_LEN] = {0x00}; - - dst[0] = '\0'; - - // ensure that we can allocate enough memory for decompression: - BigBuf_free(); BigBuf_Clear_ext(false); - - if (!reset_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer)) - return; - - if(bitparse_find_section(bitstream_version, 'a', &fpga_info_len, &compressed_fpga_stream, output_buffer)) { - for (uint16_t i = 0; i < fpga_info_len; i++) { - char c = (char)get_from_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer); - if (i < sizeof(tempstr)) { - tempstr[i] = c; - } - } - if (!memcmp("fpga_lf", tempstr, 7)) - strncat(dst, "LF ", len-1); - else if (!memcmp("fpga_hf", tempstr, 7)) - strncat(dst, "HF ", len-1); - } - strncat(dst, "FPGA image built", len-1); - if(bitparse_find_section(bitstream_version, 'b', &fpga_info_len, &compressed_fpga_stream, output_buffer)) { - strncat(dst, " for ", len-1); - for (uint16_t i = 0; i < fpga_info_len; i++) { - char c = (char)get_from_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer); - if (i < sizeof(tempstr)) { - tempstr[i] = c; - } - } - strncat(dst, tempstr, len-1); - } - if(bitparse_find_section(bitstream_version, 'c', &fpga_info_len, &compressed_fpga_stream, output_buffer)) { - strncat(dst, " on ", len-1); - for (uint16_t i = 0; i < fpga_info_len; i++) { - char c = (char)get_from_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer); - if (i < sizeof(tempstr)) { - tempstr[i] = c; - } - } - strncat(dst, tempstr, len-1); - } - if(bitparse_find_section(bitstream_version, 'd', &fpga_info_len, &compressed_fpga_stream, output_buffer)) { - strncat(dst, " at ", len-1); - for (uint16_t i = 0; i < fpga_info_len; i++) { - char c = (char)get_from_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer); - if (i < sizeof(tempstr)) { - tempstr[i] = c; - } - } - strncat(dst, tempstr, len-1); - } - - strncat(dst, "\n", len-1); - - inflateEnd(&compressed_fpga_stream); -} - - //----------------------------------------------------------------------------- // Send a 16 bit command/data pair to the FPGA. // The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 @@ -562,12 +489,8 @@ void SetAdcMuxFor(uint32_t whichGpio) } void Fpga_print_status(void) { - Dbprintf("Fgpa"); - switch(downloaded_bitstream) { - case FPGA_BITSTREAM_HF: Dbprintf(" mode....................HF"); break; - case FPGA_BITSTREAM_LF: Dbprintf(" mode....................LF"); break; - default: Dbprintf(" mode....................%d", downloaded_bitstream); break; - } + Dbprintf("Currently loaded FPGA image:"); + Dbprintf(" %s", fpga_version_information[downloaded_bitstream-1]); } int FpgaGetCurrent() { diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 7dfc5c12..fa16771d 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -10,10 +10,15 @@ // mode once it is configured. //----------------------------------------------------------------------------- +#ifndef __FPGALOADER_H +#define __FPGALOADER_H + +#include +#include + void FpgaSendCommand(uint16_t cmd, uint16_t v); void FpgaWriteConfWord(uint8_t v); void FpgaDownloadAndGo(int bitstream_version); -void FpgaGatherVersion(int bitstream_version, char *dst, int len); void FpgaSetupSsc(void); void SetupSpi(int mode); bool FpgaSetupSscDma(uint8_t *buf, int len); @@ -24,12 +29,9 @@ int FpgaGetCurrent(); void SetAdcMuxFor(uint32_t whichGpio); // definitions for multiple FPGA config files support -#define FPGA_BITSTREAM_MAX 2 // the total number of FPGA bitstreams (configs) -#define FPGA_BITSTREAM_ERR 0 #define FPGA_BITSTREAM_LF 1 #define FPGA_BITSTREAM_HF 2 - // Definitions for the FPGA commands. #define FPGA_CMD_SET_CONFREG (1<<12) #define FPGA_CMD_SET_DIVISOR (2<<12) @@ -72,3 +74,5 @@ void SetAdcMuxFor(uint32_t whichGpio); #define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0) #define FPGA_HF_ISO14443A_READER_LISTEN (3<<0) #define FPGA_HF_ISO14443A_READER_MOD (4<<0) + +#endif diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index aec01860..8e690a7b 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -813,13 +813,13 @@ void SnoopHitag(uint32_t type) { int lastbit; bool bSkip; int tag_sof; - byte_t rx[HITAG_FRAME_LEN]; + byte_t rx[HITAG_FRAME_LEN] = {0}; size_t rxlen=0; FpgaDownloadAndGo(FPGA_BITSTREAM_LF); // Clean up trace and prepare it for storing frames - set_tracing(TRUE); + set_tracing(true); clear_trace(); auth_table_len = 0; @@ -1032,7 +1032,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { FpgaDownloadAndGo(FPGA_BITSTREAM_LF); // Clean up trace and prepare it for storing frames - set_tracing(TRUE); + set_tracing(true); clear_trace(); auth_table_len = 0; @@ -1225,7 +1225,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { bSuccessful = false; // Clean up trace and prepare it for storing frames - set_tracing(TRUE); + set_tracing(true); clear_trace(); //DbpString("Starting Hitag reader family"); @@ -1548,7 +1548,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { bSuccessful = false; // Clean up trace and prepare it for storing frames - set_tracing(TRUE); + set_tracing(true); clear_trace(); //DbpString("Starting Hitag reader family"); diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index dc2281b9..f6ba0c6b 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -210,7 +210,7 @@ static void hitag_send_bit(int bit) { ; LOW(GPIO_SSC_DOUT); while (AT91C_BASE_TC0->TC_CV < T0 * 32) - ;; + ; } LED_A_OFF(); break; @@ -945,7 +945,6 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { int i, j; byte_t rx[HITAG_FRAME_LEN]; size_t rxlen = 0; -//bool bQuitTraceFull = false; bQuiet = false; byte_t txbuf[HITAG_FRAME_LEN]; byte_t* tx = txbuf; @@ -953,7 +952,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { BigBuf_free(); // Clean up trace and prepare it for storing frames - set_tracing(TRUE); + set_tracing(true); clear_trace(); DbpString("Starting HitagS simulation"); @@ -985,39 +984,39 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { tag.max_page=0; //con1 tag.auth=0; - if((tag.pages[1][2]&0x80)==1) + if (tag.pages[1][2]&0x80) tag.auth=1; tag.LCON=0; - if((tag.pages[1][2]&0x2)==1) + if (tag.pages[1][2]&0x2) tag.LCON=1; tag.LKP=0; - if((tag.pages[1][2]&0x1)==1) + if (tag.pages[1][2]&0x1) tag.LKP=1; //con2 //0=read write 1=read only tag.LCK7=0; - if((tag.pages[1][1]&0x80)==1) + if (tag.pages[1][1]&0x80) tag.LCK7=1; tag.LCK6=0; - if((tag.pages[1][1]&0x40)==1) + if (tag.pages[1][1]&0x40) tag.LCK6=1; tag.LCK5=0; - if((tag.pages[1][1]&0x20)==1) + if (tag.pages[1][1]&0x20) tag.LCK5=1; tag.LCK4=0; - if((tag.pages[1][1]&0x10)==1) + if (tag.pages[1][1]&0x10) tag.LCK4=1; tag.LCK3=0; - if((tag.pages[1][1]&0x8)==1) + if (tag.pages[1][1]&0x8) tag.LCK3=1; tag.LCK2=0; - if((tag.pages[1][1]&0x4)==1) + if (tag.pages[1][1]&0x4) tag.LCK2=1; tag.LCK1=0; - if((tag.pages[1][1]&0x2)==1) + if (tag.pages[1][1]&0x2) tag.LCK1=1; tag.LCK0=0; - if((tag.pages[1][1]&0x1)==1) + if (tag.pages[1][1]&0x1) tag.LCK0=1; // Set up simulator mode, frequency divisor which will drive the FPGA @@ -1216,7 +1215,7 @@ void ReadHitagS(hitag_function htf, hitag_data* htd) { bSuccessful = false; // Clean up trace and prepare it for storing frames - set_tracing(TRUE); + set_tracing(true); clear_trace(); bQuiet = false; @@ -1560,7 +1559,7 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { tag.tstate = NO_OP; // Clean up trace and prepare it for storing frames - set_tracing(TRUE); + set_tracing(true); clear_trace(); bQuiet = false; @@ -1847,7 +1846,7 @@ void check_challenges(bool file_given, byte_t* data) { bSuccessful = false; // Clean up trace and prepare it for storing frames - set_tracing(TRUE); + set_tracing(true); clear_trace(); bQuiet = false; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index f9aedc95..c587f8ea 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -91,7 +91,7 @@ static RAMFUNC int OutOfNDecoding(int bit) if(!Uart.bitBuffer) { Uart.bitBuffer = bit ^ 0xFF0; - return FALSE; + return false; } else { Uart.bitBuffer <<= 4; @@ -102,7 +102,7 @@ static RAMFUNC int OutOfNDecoding(int bit) Uart.output[Uart.byteCnt] = Uart.bitBuffer & 0xFF; Uart.byteCnt++; Uart.swapper = 0; - if(Uart.byteCnt > 15) { return TRUE; } + if(Uart.byteCnt > 15) { return true; } } else { Uart.swapper = 1; @@ -139,12 +139,12 @@ static RAMFUNC int OutOfNDecoding(int bit) Uart.highCnt = 0; if(Uart.byteCnt == 0) { // Its not straightforward to show single EOFs - // So just leave it and do not return TRUE + // So just leave it and do not return true Uart.output[0] = 0xf0; Uart.byteCnt++; } else { - return TRUE; + return true; } } else if(Uart.state != STATE_START_OF_COMMUNICATION) { @@ -263,7 +263,7 @@ static RAMFUNC int OutOfNDecoding(int bit) Uart.byteCnt++; Uart.output[Uart.byteCnt] = 0xAA; Uart.byteCnt++; - return TRUE; + return true; }*/ } @@ -318,7 +318,7 @@ static RAMFUNC int OutOfNDecoding(int bit) } } - return FALSE; + return false; } //============================================================================= @@ -371,7 +371,7 @@ static RAMFUNC int ManchesterDecoding(int v) if(Demod.buff < 3) { Demod.buff++; - return FALSE; + return false; } if(Demod.state==DEMOD_UNSYNCD) { @@ -473,7 +473,7 @@ static RAMFUNC int ManchesterDecoding(int v) Demod.len++; Demod.state = DEMOD_UNSYNCD; // error = 0x0f; - return TRUE; + return true; } else { Demod.state = DEMOD_ERROR_WAIT; @@ -557,7 +557,7 @@ static RAMFUNC int ManchesterDecoding(int v) } Demod.state = DEMOD_UNSYNCD; - return TRUE; + return true; } else { Demod.output[Demod.len] = 0xad; @@ -612,14 +612,14 @@ static RAMFUNC int ManchesterDecoding(int v) Demod.len++; Demod.output[Demod.len] = 0xBB; Demod.len++; - return TRUE; + return true; } } } // end (state != UNSYNCED) - return FALSE; + return false; } //============================================================================= @@ -639,7 +639,7 @@ void RAMFUNC SnoopIClass(void) // We won't start recording the frames that we acquire until we trigger; // a good trigger condition to get started is probably when we see a // response from the tag. - //int triggered = FALSE; // FALSE to wait first for card + //int triggered = false; // false to wait first for card // The command (reader -> tag) that we're receiving. // The length of a received command will in most cases be no more than 18 bytes. @@ -656,9 +656,9 @@ void RAMFUNC SnoopIClass(void) // The DMA buffer, used to stream samples from the FPGA uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); - set_tracing(TRUE); + set_tracing(true); clear_trace(); - iso14a_set_trigger(FALSE); + iso14a_set_trigger(false); int lastRxCounter; uint8_t *upTo; @@ -749,12 +749,12 @@ void RAMFUNC SnoopIClass(void) time_stop = (GetCountSspClk()-time_0) << 4; LED_C_ON(); - //if(!LogTrace(Uart.output,Uart.byteCnt, rsamples, Uart.parityBits,TRUE)) break; - //if(!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, TRUE)) break; + //if(!LogTrace(Uart.output,Uart.byteCnt, rsamples, Uart.parityBits,true)) break; + //if(!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, true)) break; if(tracing) { uint8_t parity[MAX_PARITY_SIZE]; GetParity(Uart.output, Uart.byteCnt, parity); - LogTrace(Uart.output,Uart.byteCnt, time_start, time_stop, parity, TRUE); + LogTrace(Uart.output,Uart.byteCnt, time_start, time_stop, parity, true); } @@ -782,7 +782,7 @@ void RAMFUNC SnoopIClass(void) if(tracing) { uint8_t parity[MAX_PARITY_SIZE]; GetParity(Demod.output, Demod.len, parity); - LogTrace(Demod.output, Demod.len, time_start, time_stop, parity, FALSE); + LogTrace(Demod.output, Demod.len, time_start, time_stop, parity, false); } // And ready to receive another response. @@ -830,7 +830,7 @@ void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) { //----------------------------------------------------------------------------- // Wait for commands from reader // Stop when button is pressed -// Or return TRUE when command is captured +// Or return true when command is captured //----------------------------------------------------------------------------- static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen) { @@ -848,7 +848,7 @@ static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen) for(;;) { WDT_HIT(); - if(BUTTON_PRESS()) return FALSE; + if(BUTTON_PRESS()) return false; if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = 0x00; @@ -858,7 +858,7 @@ static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen) if(OutOfNDecoding(b & 0x0f)) { *len = Uart.byteCnt; - return TRUE; + return true; } } } @@ -993,7 +993,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Enable and clear the trace - set_tracing(TRUE); + set_tracing(true); clear_trace(); //Use the emulator memory for SIM uint8_t *emulator = BigBuf_get_EM_addr(); @@ -1325,11 +1325,11 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) if (tracing) { uint8_t parity[MAX_PARITY_SIZE]; GetParity(receivedCmd, len, parity); - LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, (r2t_time-time_0) << 4, parity, TRUE); + LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, (r2t_time-time_0) << 4, parity, true); if (trace_data != NULL) { GetParity(trace_data, trace_data_size, parity); - LogTrace(trace_data, trace_data_size, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, FALSE); + LogTrace(trace_data, trace_data_size, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, false); } if(!tracing) { DbpString("Trace full"); @@ -1420,7 +1420,7 @@ static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int uint8_t sendbyte; - bool firstpart = TRUE; + bool firstpart = true; c = 0; for(;;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { @@ -1512,14 +1512,14 @@ void ReaderTransmitIClass(uint8_t* frame, int len) if (tracing) { uint8_t par[MAX_PARITY_SIZE]; GetParity(frame, len, par); - LogTrace(frame, len, rsamples, rsamples, par, TRUE); + LogTrace(frame, len, rsamples, rsamples, par, true); } } //----------------------------------------------------------------------------- // Wait a certain time for tag response -// If a response is captured return TRUE -// If it takes too long return FALSE +// If a response is captured return true +// If it takes too long return false //----------------------------------------------------------------------------- static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) //uint8_t *buffer { @@ -1538,27 +1538,27 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, uint8_t b; if (elapsed) *elapsed = 0; - bool skip = FALSE; + bool skip = false; c = 0; for(;;) { WDT_HIT(); - if(BUTTON_PRESS()) return FALSE; + if(BUTTON_PRESS()) return false; if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = 0x00; // To make use of exact timing of next command from reader!! if (elapsed) (*elapsed)++; } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - if(c < timeout) { c++; } else { return FALSE; } + if(c < timeout) { c++; } else { return false; } b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; skip = !skip; if(skip) continue; if(ManchesterDecoding(b & 0x0f)) { *samples = c << 3; - return TRUE; + return true; } } } @@ -1567,14 +1567,14 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, int ReaderReceiveIClass(uint8_t* receivedAnswer) { int samples = 0; - if (!GetIClassAnswer(receivedAnswer,160,&samples,0)) return FALSE; + if (!GetIClassAnswer(receivedAnswer,160,&samples,0)) return false; rsamples += samples; if (tracing) { uint8_t parity[MAX_PARITY_SIZE]; GetParity(receivedAnswer, Demod.len, parity); - LogTrace(receivedAnswer,Demod.len,rsamples,rsamples,parity,FALSE); + LogTrace(receivedAnswer,Demod.len,rsamples,rsamples,parity,false); } - if(samples == 0) return FALSE; + if(samples == 0) return false; return Demod.len; } @@ -1582,7 +1582,7 @@ void setupIclassReader() { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Reset trace buffer - set_tracing(TRUE); + set_tracing(true); clear_trace(); // Setup SSC @@ -1822,7 +1822,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { uint8_t resp[ICLASS_BUFFER_SIZE]; setupIclassReader(); - set_tracing(TRUE); + set_tracing(true); while(!BUTTON_PRESS()) { diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 94ca52f5..a8273e5e 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2151,9 +2151,7 @@ void ReaderMifare(bool first_try) uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - if (first_try) { - iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - } + iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); // free eventually allocated BigBuf memory. We want all for tracing. BigBuf_free(); @@ -2161,9 +2159,9 @@ void ReaderMifare(bool first_try) clear_trace(); set_tracing(true); - byte_t nt_diff = 0; + uint8_t nt_diff = 0; uint8_t par[1] = {0}; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough - static byte_t par_low = 0; + static uint8_t par_low = 0; bool led_on = true; uint8_t uid[10] ={0}; uint32_t cuid; @@ -2171,11 +2169,11 @@ void ReaderMifare(bool first_try) uint32_t nt = 0; uint32_t previous_nt = 0; static uint32_t nt_attacked = 0; - byte_t par_list[8] = {0x00}; - byte_t ks_list[8] = {0x00}; + uint8_t par_list[8] = {0x00}; + uint8_t ks_list[8] = {0x00}; #define PRNG_SEQUENCE_LENGTH (1 << 16); - static uint32_t sync_time; + uint32_t sync_time = GetCountSspClk() & 0xfffffff8; static int32_t sync_cycles; int catch_up_cycles = 0; int last_catch_up = 0; @@ -2185,10 +2183,9 @@ void ReaderMifare(bool first_try) if (first_try) { mf_nr_ar3 = 0; - sync_time = GetCountSspClk() & 0xfffffff8; + par[0] = par_low = 0; sync_cycles = PRNG_SEQUENCE_LENGTH; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the tag nonces). nt_attacked = 0; - par[0] = 0; } else { // we were unsuccessful on a previous call. Try another READER nonce (first 3 parity bits remain the same) @@ -2204,6 +2201,7 @@ void ReaderMifare(bool first_try) #define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up. #define MAX_SYNC_TRIES 32 + #define SYNC_TIME_BUFFER 16 // if there is only SYNC_TIME_BUFFER left before next planned sync, wait for next PRNG cycle #define NUM_DEBUG_INFOS 8 // per strategy #define MAX_STRATEGY 3 uint16_t unexpected_random = 0; @@ -2253,8 +2251,8 @@ void ReaderMifare(bool first_try) sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles; catch_up_cycles = 0; - // if we missed the sync time already, advance to the next nonce repeat - while(GetCountSspClk() > sync_time) { + // if we missed the sync time already or are about to miss it, advance to the next nonce repeat + while(sync_time < GetCountSspClk() + SYNC_TIME_BUFFER) { elapsed_prng_sequences++; sync_time = (sync_time & 0xfffffff8) + sync_cycles; } @@ -2410,14 +2408,14 @@ void ReaderMifare(bool first_try) } } - byte_t buf[28]; + uint8_t buf[32]; memcpy(buf + 0, uid, 4); num_to_bytes(nt, 4, buf + 4); memcpy(buf + 8, par_list, 8); memcpy(buf + 16, ks_list, 8); - memcpy(buf + 24, mf_nr_ar, 4); + memcpy(buf + 24, mf_nr_ar, 8); - cmd_send(CMD_ACK, isOK, 0, 0, buf, 28); + cmd_send(CMD_ACK, isOK, 0, 0, buf, 32); // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -2482,7 +2480,7 @@ void RAMFUNC SniffMifare(uint8_t param) { for(uint32_t sniffCounter = 0; true; ) { if(BUTTON_PRESS()) { - DbpString("cancelled by button"); + DbpString("Canceled by button."); break; } @@ -2539,7 +2537,9 @@ void RAMFUNC SniffMifare(uint8_t param) { if(!TagIsActive) { // no need to try decoding tag data if the reader is sending uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4); if(MillerDecoding(readerdata, (sniffCounter-1)*4)) { - LED_C_INV(); + LED_B_ON(); + LED_C_OFF(); + if (MfSniffLogic(receivedCmd, Uart.len, Uart.parity, Uart.bitCount, true)) break; /* And ready to receive another command. */ @@ -2554,7 +2554,8 @@ void RAMFUNC SniffMifare(uint8_t param) { if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending uint8_t tagdata = (previous_data << 4) | (*data & 0x0F); if(ManchesterDecoding(tagdata, 0, (sniffCounter-1)*4)) { - LED_C_INV(); + LED_B_OFF(); + LED_C_ON(); if (MfSniffLogic(receivedResponse, Demod.len, Demod.parity, Demod.bitCount, false)) break; @@ -2576,7 +2577,7 @@ void RAMFUNC SniffMifare(uint8_t param) { } // main cycle - DbpString("COMMAND FINISHED"); + DbpString("COMMAND FINISHED."); FpgaDisableSscDma(); MfSniffEnd(); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 22227e74..75769859 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -243,7 +243,7 @@ static RAMFUNC int Handle14443bUartBit(uint8_t bit) LED_A_OFF(); // Finished receiving Uart.state = STATE_UNSYNCD; if (Uart.byteCnt != 0) { - return TRUE; + return true; } } else { // this is an error @@ -259,7 +259,7 @@ static RAMFUNC int Handle14443bUartBit(uint8_t bit) break; } - return FALSE; + return false; } @@ -283,7 +283,7 @@ static void UartInit(uint8_t *data) // Receive a command (from the reader to us, where we are the simulated tag), // and store it in the given buffer, up to the given maximum length. Keeps // spinning, waiting for a well-framed command, until either we get one -// (returns TRUE) or someone presses the pushbutton on the board (FALSE). +// (returns true) or someone presses the pushbutton on the board (false). // // Assume that we're called with the SSC (to the FPGA) and ADC path set // correctly. @@ -302,20 +302,20 @@ static int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len) for(;;) { WDT_HIT(); - if(BUTTON_PRESS()) return FALSE; + if(BUTTON_PRESS()) return false; if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; for(uint8_t mask = 0x80; mask != 0x00; mask >>= 1) { if(Handle14443bUartBit(b & mask)) { *len = Uart.byteCnt; - return TRUE; + return true; } } } } - return FALSE; + return false; } //----------------------------------------------------------------------------- @@ -347,7 +347,7 @@ void SimulateIso14443bTag(void) FpgaDownloadAndGo(FPGA_BITSTREAM_HF); clear_trace(); - set_tracing(TRUE); + set_tracing(true); const uint8_t *resp; uint8_t *respCode; @@ -387,7 +387,7 @@ void SimulateIso14443bTag(void) if (tracing) { uint8_t parity[MAX_PARITY_SIZE]; - LogTrace(receivedCmd, len, 0, 0, parity, TRUE); + LogTrace(receivedCmd, len, 0, 0, parity, true); } // Good, look at the command now. @@ -464,7 +464,7 @@ void SimulateIso14443bTag(void) // trace the response: if (tracing) { uint8_t parity[MAX_PARITY_SIZE]; - LogTrace(resp, respLen, 0, 0, parity, FALSE); + LogTrace(resp, respLen, 0, 0, parity, false); } } @@ -702,7 +702,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) LED_C_OFF(); if(s == 0x000) { // This is EOF (start, stop and all data bits == '0' - return TRUE; + return true; } } } @@ -716,7 +716,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) break; } - return FALSE; + return false; } @@ -739,12 +739,12 @@ static void DemodInit(uint8_t *data) /* * Demodulate the samples we received from the tag, also log to tracebuffer - * quiet: set to 'TRUE' to disable debug output + * quiet: set to 'true' to disable debug output */ static void GetSamplesFor14443bDemod(int n, bool quiet) { int max = 0; - bool gotFrame = FALSE; + bool gotFrame = false; int lastRxCounter, ci, cq, samples = 0; // Allocate memory from BigBuf for some buffers @@ -792,7 +792,7 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) samples += 2; if(Handle14443bSamplesDemod(ci, cq)) { - gotFrame = TRUE; + gotFrame = true; break; } } @@ -808,7 +808,7 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) //Tracing if (tracing && Demod.len > 0) { uint8_t parity[MAX_PARITY_SIZE]; - LogTrace(Demod.output, Demod.len, 0, 0, parity, FALSE); + LogTrace(Demod.output, Demod.len, 0, 0, parity, false); } } @@ -929,7 +929,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) TransmitFor14443b(); if (tracing) { uint8_t parity[MAX_PARITY_SIZE]; - LogTrace(cmd,len, 0, 0, parity, TRUE); + LogTrace(cmd,len, 0, 0, parity, true); } } @@ -951,7 +951,7 @@ int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *respo // send CodeAndTransmit14443bAsReader(message_frame, message_length + 4); // get response - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT*100, TRUE); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT*100, true); if(Demod.len < 3) { return 0; @@ -981,7 +981,7 @@ int iso14443b_select_card() // first, wake up the tag CodeAndTransmit14443bAsReader(wupb, sizeof(wupb)); - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); // ATQB too short? if (Demod.len < 14) { @@ -996,7 +996,7 @@ int iso14443b_select_card() attrib[7] = Demod.output[10] & 0x0F; ComputeCrc14443(CRC_14443_B, attrib, 9, attrib + 9, attrib + 10); CodeAndTransmit14443bAsReader(attrib, sizeof(attrib)); - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); // Answer to ATTRIB too short? if(Demod.len < 3) { @@ -1056,12 +1056,12 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) SpinDelay(200); clear_trace(); - set_tracing(TRUE); + set_tracing(true); // First command: wake up the tag using the INITIATE command uint8_t cmd1[] = {0x06, 0x00, 0x97, 0x5b}; CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); if (Demod.len == 0) { DbpString("No response from tag"); @@ -1077,7 +1077,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) cmd1[1] = Demod.output[0]; ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); if (Demod.len != 3) { Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); return; @@ -1099,7 +1099,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) cmd1[0] = 0x0B; ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]); CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); if (Demod.len != 10) { Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); return; @@ -1128,7 +1128,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) cmd1[1] = i; ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); if (Demod.len != 6) { // Check if we got an answer from the tag DbpString("Expected 6 bytes from tag, got less..."); return; @@ -1174,13 +1174,13 @@ void RAMFUNC SnoopIso14443b(void) // We won't start recording the frames that we acquire until we trigger; // a good trigger condition to get started is probably when we see a // response from the tag. - int triggered = TRUE; // TODO: set and evaluate trigger condition + int triggered = true; // TODO: set and evaluate trigger condition FpgaDownloadAndGo(FPGA_BITSTREAM_HF); BigBuf_free(); clear_trace(); - set_tracing(TRUE); + set_tracing(true); // The DMA buffer, used to stream samples from the FPGA int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); @@ -1217,8 +1217,8 @@ void RAMFUNC SnoopIso14443b(void) FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); uint8_t parity[MAX_PARITY_SIZE]; - bool TagIsActive = FALSE; - bool ReaderIsActive = FALSE; + bool TagIsActive = false; + bool ReaderIsActive = false; // And now we loop, receiving samples. for(;;) { @@ -1259,7 +1259,7 @@ void RAMFUNC SnoopIso14443b(void) if (!TagIsActive) { // no need to try decoding reader data if the tag is sending if(Handle14443bUartBit(ci & 0x01)) { if(triggered && tracing) { - LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE); + LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true); } /* And ready to receive another command. */ UartReset(); @@ -1269,7 +1269,7 @@ void RAMFUNC SnoopIso14443b(void) } if(Handle14443bUartBit(cq & 0x01)) { if(triggered && tracing) { - LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE); + LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true); } /* And ready to receive another command. */ UartReset(); @@ -1287,9 +1287,9 @@ void RAMFUNC SnoopIso14443b(void) if(tracing) { uint8_t parity[MAX_PARITY_SIZE]; - LogTrace(Demod.output, Demod.len, samples, samples, parity, FALSE); + LogTrace(Demod.output, Demod.len, samples, samples, parity, false); } - triggered = TRUE; + triggered = true; // And ready to receive another response. DemodReset(); @@ -1330,12 +1330,12 @@ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, u FpgaSetupSsc(); if (datalen){ - set_tracing(TRUE); + set_tracing(true); CodeAndTransmit14443bAsReader(data, datalen); if(recv) { - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); uint16_t iLen = MIN(Demod.len, USB_CMD_DATA_SIZE); cmd_send(CMD_ACK, iLen, 0, 0, Demod.output, iLen); } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index e11e5a9c..1f0b8193 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -305,7 +305,7 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads c = 0; - getNext = FALSE; + getNext = false; for(;;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = 0x43; @@ -444,7 +444,7 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads c = 0; - getNext = FALSE; + getNext = false; for(;;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = 0x43; @@ -612,7 +612,7 @@ void AcquireRawAdcSamplesIso15693(void) FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); c = 0; - getNext = FALSE; + getNext = false; for(;;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = 0x43; @@ -666,7 +666,7 @@ void RecordRawAdcSamplesIso15693(void) FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); c = 0; - getNext = FALSE; + getNext = false; for(;;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = 0x43; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 4344742b..911ba8da 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -4,7 +4,7 @@ // the license. //----------------------------------------------------------------------------- // Miscellaneous routines for low frequency tag operations. -// Tags supported here so far are Texas Instruments (TI), HID +// Tags supported here so far are Texas Instruments (TI), HID, EM4x05, EM410x // Also routines for raw mode reading/simulating of LF waveform //----------------------------------------------------------------------------- @@ -28,51 +28,103 @@ */ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command) { + // start timer + StartTicks(); - int divisor_used = 95; // 125 KHz - // see if 'h' was specified + // use lf config settings + sample_config *sc = getSamplingConfig(); - if (command[strlen((char *) command) - 1] == 'h') - divisor_used = 88; // 134.8 KHz - - sample_config sc = { 0,0,1, divisor_used, 0}; - setSamplingConfig(&sc); - //clear read buffer - BigBuf_Clear_keep_EM(); - - /* Make sure the tag is reset */ + // Make sure the tag is reset FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(2500); + WaitMS(2500); - LFSetupFPGAForADC(sc.divisor, 1); + // clear read buffer (after fpga bitstream loaded...) + BigBuf_Clear_keep_EM(); + + // power on + LFSetupFPGAForADC(sc->divisor, 1); // And a little more time for the tag to fully power up - SpinDelay(2000); - + WaitMS(2000); + // if delay_off = 0 then just bitbang 1 = antenna on 0 = off for respective periods. + bool bitbang = delay_off == 0; // now modulate the reader field - while(*command != '\0' && *command != ' ') { + + if (bitbang) { + // HACK it appears the loop and if statements take up about 7us so adjust waits accordingly... + uint8_t hack_cnt = 7; + if (period_0 < hack_cnt || period_1 < hack_cnt) { + DbpString("Warning periods cannot be less than 7us in bit bang mode"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + return; + } + + // hack2 needed--- it appears to take about 8-16us to turn the antenna back on + // leading to ~ 1 to 2 125khz samples extra in every off period + // so we should test for last 0 before next 1 and reduce period_0 by this extra amount... + // but is this time different for every antenna or other hw builds??? more testing needed + + // prime cmd_len to save time comparing strings while modulating + int cmd_len = 0; + while(command[cmd_len] != '\0' && command[cmd_len] != ' ') + cmd_len++; + + int counter = 0; + bool off = false; + for (counter = 0; counter < cmd_len; counter++) { + // if cmd = 0 then turn field off + if (command[counter] == '0') { + // if field already off leave alone (affects timing otherwise) + if (off == false) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + off = true; + } + // note we appear to take about 7us to switch over (or run the if statements/loop...) + WaitUS(period_0-hack_cnt); + // else if cmd = 1 then turn field on + } else { + // if field already on leave alone (affects timing otherwise) + if (off) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + LED_D_ON(); + off = false; + } + // note we appear to take about 7us to switch over (or run the if statements/loop...) + WaitUS(period_1-hack_cnt); + } + } + } else { // old mode of cmd read using delay as off period + while(*command != '\0' && *command != ' ') { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + WaitUS(delay_off); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + LED_D_ON(); + if(*(command++) == '0') { + WaitUS(period_0); + } else { + WaitUS(period_1); + } + } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); - SpinDelayUs(delay_off); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc.divisor); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - LED_D_ON(); - if(*(command++) == '0') - SpinDelayUs(period_0); - else - SpinDelayUs(period_1); + WaitUS(delay_off); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - SpinDelayUs(delay_off); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc.divisor); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); // now do the read DoAcquisition_config(false, 0); + + // Turn off antenna + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + // tell client we are done + cmd_send(CMD_ACK,0,0,0,0,0); } /* blank r/w tag data stream @@ -516,7 +568,7 @@ static void fcAll(uint8_t fc, int *n, uint8_t clock, uint16_t *modCnt) uint8_t wavesPerClock = clock/fc; uint8_t mod = clock % fc; //modifier uint8_t modAdj = fc/mod; //how often to apply modifier - bool modAdjOk = !(fc % mod); //if (fc % mod==0) modAdjOk=TRUE; + bool modAdjOk = !(fc % mod); //if (fc % mod==0) modAdjOk=true; // loop through clock - step field clock for (uint8_t idx=0; idx < wavesPerClock; idx++){ // put 1/2 FC length 1's and 1/2 0's per field clock wave (to create the wave) @@ -768,9 +820,9 @@ void CmdPSKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream) for (i=0; i= 128 && blockN <= 256) { return ((blockN & 0x0F) == 0x0F); } - return FALSE; + return false; } void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 145e2989..e17fa998 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -16,7 +16,6 @@ #include "proxmark3.h" #include "apps.h" #include "util.h" -#include "string.h" #include "iso14443crc.h" #include "iso14443a.h" diff --git a/armsrc/mifaresniff.c b/armsrc/mifaresniff.c index 7f94b0fe..5391e5f9 100644 --- a/armsrc/mifaresniff.c +++ b/armsrc/mifaresniff.c @@ -1,183 +1,166 @@ -//----------------------------------------------------------------------------- -// Merlok - 2012 -// -// 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. -//----------------------------------------------------------------------------- -// Routines to support mifare classic sniffer. -//----------------------------------------------------------------------------- - -#include "mifaresniff.h" -#include "apps.h" -#include "proxmark3.h" -#include "util.h" -#include "string.h" -#include "iso14443crc.h" -#include "iso14443a.h" -#include "crapto1/crapto1.h" -#include "mifareutil.h" -#include "common.h" - - -static int sniffState = SNF_INIT; -static uint8_t sniffUIDType; -static uint8_t sniffUID[8] = {0x00}; -static uint8_t sniffATQA[2] = {0x00}; -static uint8_t sniffSAK; -static uint8_t sniffBuf[16] = {0x00}; -static uint32_t timerData = 0; - - -bool MfSniffInit(void){ - memset(sniffUID, 0x00, 8); - memset(sniffATQA, 0x00, 2); - sniffSAK = 0; - sniffUIDType = SNF_UID_4; - - return FALSE; -} - -bool MfSniffEnd(void){ - LED_B_ON(); - cmd_send(CMD_ACK,0,0,0,0,0); - LED_B_OFF(); - - return FALSE; -} - -bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader) { - - if (reader && (len == 1) && (bitCnt == 7)) { // reset on 7-Bit commands from reader - sniffState = SNF_INIT; - } - - switch (sniffState) { - case SNF_INIT:{ - if ((len == 1) && (reader) && (bitCnt == 7) ) { // REQA or WUPA from reader - sniffUIDType = SNF_UID_4; - memset(sniffUID, 0x00, 8); - memset(sniffATQA, 0x00, 2); - sniffSAK = 0; - sniffState = SNF_WUPREQ; - } - break; - } - case SNF_WUPREQ:{ - if ((!reader) && (len == 2)) { // ATQA from tag - memcpy(sniffATQA, data, 2); - sniffState = SNF_ATQA; - } - break; - } - case SNF_ATQA:{ - if ((reader) && (len == 2) && (data[0] == 0x93) && (data[1] == 0x20)) { // Select ALL from reader - sniffState = SNF_ANTICOL1; - } - break; - } - case SNF_ANTICOL1:{ - if ((!reader) && (len == 5) && ((data[0] ^ data[1] ^ data[2] ^ data[3]) == data[4])) { // UID from tag (CL1) - memcpy(sniffUID + 3, data, 4); - sniffState = SNF_UID1; - } - break; - } +//----------------------------------------------------------------------------- +// Merlok - 2012 +// +// 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. +//----------------------------------------------------------------------------- +// Routines to support mifare classic sniffer. +//----------------------------------------------------------------------------- + +#include "mifaresniff.h" +#include "apps.h" +#include "proxmark3.h" +#include "util.h" +#include "string.h" +#include "iso14443crc.h" +#include "iso14443a.h" +#include "crapto1/crapto1.h" +#include "mifareutil.h" +#include "common.h" + + +static int sniffState = SNF_INIT; +static uint8_t sniffUIDType; +static uint8_t sniffUID[8] = {0x00}; +static uint8_t sniffATQA[2] = {0x00}; +static uint8_t sniffSAK; +static uint8_t sniffBuf[16] = {0x00}; +static uint32_t timerData = 0; + + +bool MfSniffInit(void){ + memset(sniffUID, 0x00, 8); + memset(sniffATQA, 0x00, 2); + sniffSAK = 0; + sniffUIDType = SNF_UID_4; + + return false; +} + +bool MfSniffEnd(void){ + LED_B_ON(); + cmd_send(CMD_ACK,0,0,0,0,0); + LED_B_OFF(); + + return false; +} + +bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader) { + + if (reader && (len == 1) && (bitCnt == 7)) { // reset on 7-Bit commands from reader + sniffState = SNF_INIT; + } + + switch (sniffState) { + case SNF_INIT:{ + if ((len == 1) && (reader) && (bitCnt == 7) ) { // REQA or WUPA from reader + sniffUIDType = SNF_UID_4; + memset(sniffUID, 0x00, 8); + memset(sniffATQA, 0x00, 2); + sniffSAK = 0; + sniffState = SNF_ATQA; + if (data[0] == 0x40) + sniffState = SNF_MAGIC_WUPC2; + } + break; + } + case SNF_MAGIC_WUPC2: + if ((len == 1) && (reader) && (data[0] == 0x43) ) { + sniffState = SNF_CARD_IDLE; + } + break; + case SNF_ATQA:{ + if ((!reader) && (len == 2)) { // ATQA from tag + memcpy(sniffATQA, data, 2); + sniffState = SNF_UID1; + } + break; + } case SNF_UID1:{ if ((reader) && (len == 9) && (data[0] == 0x93) && (data[1] == 0x70) && (CheckCrc14443(CRC_14443_A, data, 9))) { // Select 4 Byte UID from reader + memcpy(sniffUID + 3, &data[2], 4); sniffState = SNF_SAK; } - break; - } - case SNF_SAK:{ - if ((!reader) && (len == 3) && (CheckCrc14443(CRC_14443_A, data, 3))) { // SAK from card? - sniffSAK = data[0]; - if (sniffUID[3] == 0x88) { // CL2 UID part to be expected - sniffState = SNF_ANTICOL2; - } else { // select completed - sniffState = SNF_CARD_IDLE; - } - } - break; - } - case SNF_ANTICOL2:{ - if ((!reader) && (len == 5) && ((data[0] ^ data[1] ^ data[2] ^ data[3]) == data[4])) { // CL2 UID - memcpy(sniffUID, sniffUID+4, 3); - memcpy(sniffUID+3, data, 4); - sniffUIDType = SNF_UID_7; - sniffState = SNF_UID2; - } - break; + break; } + case SNF_SAK:{ + if ((!reader) && (len == 3) && (CheckCrc14443(CRC_14443_A, data, 3))) { // SAK from card? + sniffSAK = data[0]; + if ((sniffUID[3] == 0x88) && (sniffUIDType == SNF_UID_4)) { // CL2 UID part to be expected + sniffUIDType = SNF_UID_7; + memcpy(sniffUID, sniffUID + 4, 3); + sniffState = SNF_UID2; + } else { // select completed + sniffState = SNF_CARD_IDLE; + } + } + break; + } case SNF_UID2:{ - if ((reader) && (len == 9) && (data[0] == 0x95) && (data[1] == 0x70) && (CheckCrc14443(CRC_14443_A, data, 9))) { // Select 2nd part of 7 Byte UID + if ((reader) && (len == 9) && (data[0] == 0x95) && (data[1] == 0x70) && (CheckCrc14443(CRC_14443_A, data, 9))) { + memcpy(sniffUID + 3, &data[2], 4); sniffState = SNF_SAK; } break; } - case SNF_CARD_IDLE:{ // trace the card select sequence - sniffBuf[0] = 0xFF; - sniffBuf[1] = 0xFF; - memcpy(sniffBuf + 2, sniffUID, 7); - memcpy(sniffBuf + 9, sniffATQA, 2); - sniffBuf[11] = sniffSAK; - sniffBuf[12] = 0xFF; - sniffBuf[13] = 0xFF; - LogTrace(sniffBuf, 14, 0, 0, NULL, TRUE); - } // intentionally no break; - case SNF_CARD_CMD:{ - LogTrace(data, len, 0, 0, NULL, TRUE); - sniffState = SNF_CARD_RESP; - timerData = GetTickCount(); - break; - } - case SNF_CARD_RESP:{ - LogTrace(data, len, 0, 0, NULL, FALSE); - sniffState = SNF_CARD_CMD; - timerData = GetTickCount(); - break; - } - - default: - sniffState = SNF_INIT; - break; - } - - - return FALSE; -} - -bool RAMFUNC MfSniffSend(uint16_t maxTimeoutMs) { - if (BigBuf_get_traceLen() && (GetTickCount() > timerData + maxTimeoutMs)) { - return intMfSniffSend(); - } - return FALSE; -} - -// internal sending function. not a RAMFUNC. -bool intMfSniffSend() { - - int pckSize = 0; - int pckLen = BigBuf_get_traceLen(); - int pckNum = 0; - uint8_t *trace = BigBuf_get_addr(); - - FpgaDisableSscDma(); - while (pckLen > 0) { - pckSize = MIN(USB_CMD_DATA_SIZE, pckLen); - LED_B_ON(); - cmd_send(CMD_ACK, 1, BigBuf_get_traceLen(), pckSize, trace + BigBuf_get_traceLen() - pckLen, pckSize); - LED_B_OFF(); - - pckLen -= pckSize; - pckNum++; - } - - LED_B_ON(); - cmd_send(CMD_ACK,2,0,0,0,0); - LED_B_OFF(); - - clear_trace(); - - return TRUE; -} + case SNF_CARD_IDLE:{ // trace the card select sequence + sniffBuf[0] = 0xFF; + sniffBuf[1] = 0xFF; + memcpy(sniffBuf + 2, sniffUID, 7); + memcpy(sniffBuf + 9, sniffATQA, 2); + sniffBuf[11] = sniffSAK; + sniffBuf[12] = 0xFF; + sniffBuf[13] = 0xFF; + LogTrace(sniffBuf, 14, 0, 0, NULL, true); + sniffState = SNF_CARD_CMD; + } // intentionally no break; + case SNF_CARD_CMD:{ + LogTrace(data, len, 0, 0, parity, reader); + timerData = GetTickCount(); + break; + } + + default: + sniffState = SNF_INIT; + break; + } + + + return false; +} + +bool RAMFUNC MfSniffSend(uint16_t maxTimeoutMs) { + if (BigBuf_get_traceLen() && (GetTickCount() > timerData + maxTimeoutMs)) { + return intMfSniffSend(); + } + return false; +} + +// internal sending function. not a RAMFUNC. +bool intMfSniffSend() { + + int pckSize = 0; + int pckLen = BigBuf_get_traceLen(); + int pckNum = 0; + uint8_t *trace = BigBuf_get_addr(); + + FpgaDisableSscDma(); + while (pckLen > 0) { + pckSize = MIN(USB_CMD_DATA_SIZE, pckLen); + LED_B_ON(); + cmd_send(CMD_ACK, 1, BigBuf_get_traceLen(), pckSize, trace + BigBuf_get_traceLen() - pckLen, pckSize); + LED_B_OFF(); + + pckLen -= pckSize; + pckNum++; + } + + LED_B_ON(); + cmd_send(CMD_ACK,2,0,0,0,0); + LED_B_OFF(); + + clear_trace(); + + return true; +} diff --git a/armsrc/mifaresniff.h b/armsrc/mifaresniff.h index 8a8e31a9..b181f982 100644 --- a/armsrc/mifaresniff.h +++ b/armsrc/mifaresniff.h @@ -27,6 +27,7 @@ #define SNF_CARD_IDLE 9 #define SNF_CARD_CMD 10 #define SNF_CARD_RESP 11 +#define SNF_MAGIC_WUPC2 12 #define SNF_UID_4 0 #define SNF_UID_7 0 diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 38ca934a..684b5e36 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -405,31 +405,48 @@ int mifare_ultra_auth(uint8_t *keybytes){ return 1; } + +#define MFU_MAX_RETRIES 5 int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) { uint16_t len; uint8_t bt[2]; uint8_t receivedAnswer[MAX_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; - + uint8_t retries; + int result = 0; - len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL); - if (len == 1) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - return 1; + for (retries = 0; retries < MFU_MAX_RETRIES; retries++) { + len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL); + if (len == 1) { + if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + result = 1; + continue; + } + if (len != 18) { + if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: card timeout. len: %x", len); + result = 2; + continue; + } + + memcpy(bt, receivedAnswer + 16, 2); + AppendCrc14443a(receivedAnswer, 16); + if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { + if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd CRC response error."); + result = 3; + continue; + } + + // No errors encountered; don't retry + result = 0; + break; } - if (len != 18) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: card timeout. len: %x", len); - return 2; + + if (result != 0) { + Dbprintf("Cmd Error: too many retries; read failed"); + return result; } - - memcpy(bt, receivedAnswer + 16, 2); - AppendCrc14443a(receivedAnswer, 16); - if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd CRC response error."); - return 3; - } - + memcpy(blockData, receivedAnswer, 14); return 0; } diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index c34dc8f4..b2912895 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -24,8 +24,6 @@ #define CRYPT_REQUEST 2 #define AUTH_FIRST 0 #define AUTH_NESTED 2 -#define AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) -#define PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication // mifare 4bit card answers #define CARD_ACK 0x0A // 1010 - ACK diff --git a/armsrc/optimized_cipher.c b/armsrc/optimized_cipher.c index 005f473b..b1f33737 100644 --- a/armsrc/optimized_cipher.c +++ b/armsrc/optimized_cipher.c @@ -22,7 +22,7 @@ * * This is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. + * by the Free Software Foundation, or, at your option, any later version. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/armsrc/optimized_cipher.h b/armsrc/optimized_cipher.h index c10aea28..6a4e2641 100644 --- a/armsrc/optimized_cipher.h +++ b/armsrc/optimized_cipher.h @@ -1,4 +1,41 @@ -#ifndef OPTIMIZED_CIPHER_H +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or, at your option, any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + ****************************************************************************/ + + #ifndef OPTIMIZED_CIPHER_H #define OPTIMIZED_CIPHER_H #include diff --git a/armsrc/printf.c b/armsrc/printf.c index 94ed809d..79c123df 100644 --- a/armsrc/printf.c +++ b/armsrc/printf.c @@ -175,6 +175,7 @@ reswitch: switch (ch = (u_char)*fmt++) { padc = '0'; goto reswitch; } + // intentionally fall through to next case case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': for (n = 0;; ++fmt) { diff --git a/armsrc/util.c b/armsrc/util.c index e25c6e0b..8a8d6657 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -448,31 +448,52 @@ uint32_t RAMFUNC GetCountSspClk(){ // ------------------------------------------------------------------------- -// Timer for bitbanging, or LF stuff when you need a very precis timer +// Timer for bitbanging, or LF stuff when you need a very precis timer // 1us = 1.5ticks // ------------------------------------------------------------------------- void StartTicks(void){ - //initialization of the timer - // tc1 is higher 0xFFFF0000 - // tc0 is lower 0x0000FFFF + // initialization of the timer AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32 - AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR | - AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET; - AT91C_BASE_TC0->TC_RA = 1; - AT91C_BASE_TC0->TC_RC = 0; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from TC0 - - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TCB->TCB_BCR = 1; - - // wait until timer becomes zero. - while (AT91C_BASE_TC1->TC_CV > 0); + // disable TC0 and TC1 for re-configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + + // first configure TC1 (higher, 0xFFFF0000) 16 bit counter + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // just connect to TIOA0 from TC0 + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0 + + // second configure TC0 (lower, 0x0000FFFF) 16 bit counter + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32 + AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | + AT91C_TC_ACPA_CLEAR | // RA comperator clears TIOA (carry bit) + AT91C_TC_ACPC_SET | // RC comperator sets TIOA (carry bit) + AT91C_TC_ASWTRG_SET; // SWTriger sets TIOA (carry bit) + AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero + AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer + + // synchronized startup procedure + while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero + while (AT91C_BASE_TC0->TC_CV < 2); // and has started (TC_CV > TC_RA, now TC1 is cleared) + + // return to zero + AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV > 0); +} + + +uint32_t GetTicks(void) { + uint32_t hi, lo; + + do { + hi = AT91C_BASE_TC1->TC_CV; + lo = AT91C_BASE_TC0->TC_CV; + } while(hi != AT91C_BASE_TC1->TC_CV); + + return (hi << 16) | lo; } @@ -480,30 +501,28 @@ void StartTicks(void){ // if called with a high number, this will trigger the WDT... void WaitTicks(uint32_t ticks){ if ( ticks == 0 ) return; - ticks += GET_TICKS; - while (GET_TICKS < ticks); + ticks += GetTicks(); + while (GetTicks() < ticks); } // Wait / Spindelay in us (microseconds) // 1us = 1.5ticks. void WaitUS(uint16_t us){ - if ( us == 0 ) return; - WaitTicks( (uint32_t)(us * 1.5) ); + WaitTicks( (uint32_t)us * 3 / 2 ) ; } void WaitMS(uint16_t ms){ - if (ms == 0) return; - WaitTicks( (uint32_t)(ms * 1500) ); + WaitTicks( (uint32_t)ms * 1500 ); } // Starts Clock and waits until its reset void ResetTicks(void){ - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - while (AT91C_BASE_TC1->TC_CV > 0); + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV > 0); } diff --git a/armsrc/util.h b/armsrc/util.h index 0148e1dd..58dcdd52 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -44,7 +44,7 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers //iceman's ticks.h #ifndef GET_TICKS -# define GET_TICKS (uint32_t)((AT91C_BASE_TC1->TC_CV << 16) | AT91C_BASE_TC0->TC_CV) +# define GET_TICKS GetTicks() #endif void SpinDelay(int ms); @@ -62,6 +62,7 @@ void ResetSspClk(void); uint32_t RAMFUNC GetCountSspClk(); extern void StartTicks(void); +extern uint32_t GetTicks(void); extern void WaitTicks(uint32_t ticks); extern void WaitUS(uint16_t us); extern void WaitMS(uint16_t ms); diff --git a/bootrom/Makefile b/bootrom/Makefile index 92373995..dd1e7e08 100644 --- a/bootrom/Makefile +++ b/bootrom/Makefile @@ -10,6 +10,7 @@ ARMSRC = THUMBSRC = cmd.c usb_cdc.c bootrom.c ASMSRC = ram-reset.s flash-reset.s +VERSIONSRC = version.c ## There is a strange bug with the linker: Sometimes it will not emit the glue to call ## BootROM from ARM mode. The symbol is emitted, but the section will be filled with @@ -21,6 +22,11 @@ ASMSRC = ram-reset.s flash-reset.s # stdint.h provided locally until GCC 4.5 becomes C99 compliant APP_CFLAGS = -I. +# version.c should be remade on every compilation +.PHONY: version.c +version.c: default_version.c + perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@ + # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC include ../common/Makefile.common diff --git a/client/Makefile b/client/Makefile index 2f7b6f24..57c1629e 100644 --- a/client/Makefile +++ b/client/Makefile @@ -23,6 +23,10 @@ LDFLAGS = $(ENV_LDFLAGS) CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../common/polarssl -I../zlib -I../uart -I/opt/local/include -I../liblua -Wall -g -O3 CXXFLAGS = -I../include -Wall -O3 +APP_CFLAGS = +include ../common/Makefile_Enabled_Options.common +CFLAGS += $(APP_CFLAGS) + LUAPLATFORM = generic platform = $(shell uname) ifneq (,$(findstring MINGW,$(platform))) @@ -37,32 +41,34 @@ else endif endif -# Check for correctly configured Qt5 -QTINCLUDES = $(shell pkg-config --cflags Qt5Core Qt5Widgets 2>/dev/null) -QTLDLIBS = $(shell pkg-config --libs Qt5Core Qt5Widgets 2>/dev/null) -MOC = $(shell pkg-config --variable=host_bins Qt5Core)/moc -UIC = $(shell pkg-config --variable=host_bins Qt5Core)/uic -ifeq ($(QTINCLUDES), ) -# if Qt5 not found check for correctly configured Qt4 - QTINCLUDES = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) - QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null) - MOC = $(shell pkg-config --variable=moc_location QtCore) - UIC = $(shell pkg-config --variable=uic_location QtCore) -else - CXXFLAGS += -std=c++11 -fPIC -endif -ifeq ($(QTINCLUDES), ) -# if both pkg-config commands failed, search in common places - ifneq ($(QTDIR), ) - QTINCLUDES = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui - QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4 - ifneq ($(wildcard $(QTDIR)/include/QtWidgets),) - QTINCLUDES += -I$(QTDIR)/include/QtWidgets - QTLDLIBS = -L$(QTDIR)/lib -lQt5Widgets -lQt5Gui -lQt5Core - CXXFLAGS += -std=c++11 -fPIC +ifneq (,$(findstring WITH_GUI,$(APP_CFLAGS))) + # Check for correctly configured Qt5 + QTINCLUDES = $(shell pkg-config --cflags Qt5Core Qt5Widgets 2>/dev/null) + QTLDLIBS = $(shell pkg-config --libs Qt5Core Qt5Widgets 2>/dev/null) + MOC = $(shell pkg-config --variable=host_bins Qt5Core)/moc + UIC = $(shell pkg-config --variable=host_bins Qt5Core)/uic + ifeq ($(QTINCLUDES), ) + # if Qt5 not found check for correctly configured Qt4 + QTINCLUDES = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) + QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null) + MOC = $(shell pkg-config --variable=moc_location QtCore) + UIC = $(shell pkg-config --variable=uic_location QtCore) + else + CXXFLAGS += -std=c++11 -fPIC + endif + ifeq ($(QTINCLUDES), ) + # if both pkg-config commands failed, search in common places + ifneq ($(QTDIR), ) + QTINCLUDES = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui + QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4 + ifneq ($(wildcard $(QTDIR)/include/QtWidgets),) + QTINCLUDES += -I$(QTDIR)/include/QtWidgets + QTLDLIBS = -L$(QTDIR)/lib -lQt5Widgets -lQt5Gui -lQt5Core + CXXFLAGS += -std=c++11 -fPIC + endif + MOC = $(QTDIR)/bin/moc + UIC = $(QTDIR)/bin/uic endif - MOC = $(QTDIR)/bin/moc - UIC = $(QTDIR)/bin/uic endif endif @@ -79,10 +85,13 @@ DEPFLAGS = -MT $@ -MMD -MP -MF $(OBJDIR)/$*.Td # make temporary to final dependeny files after successful compilation POSTCOMPILE = $(MV) -f $(OBJDIR)/$*.Td $(OBJDIR)/$*.d + CORESRCS = uart_posix.c \ uart_win32.c \ util.c \ - util_posix.c + util_posix.c \ + ui.c \ + comms.c CMDSRCS = crapto1/crapto1.c\ crapto1/crypto1.c\ @@ -107,9 +116,7 @@ CMDSRCS = crapto1/crapto1.c\ crc64.c \ iso14443crc.c \ iso15693tools.c \ - data.c \ graph.c \ - ui.c \ cmddata.c \ lfdemod.c \ emv/crypto_polarssl.c\ @@ -130,6 +137,7 @@ CMDSRCS = crapto1/crapto1.c\ emv/test/cda_test.c\ emv/cmdemv.c\ cmdhf.c \ + cmdhflist.c \ cmdhf14a.c \ cmdhf14b.c \ cmdhf15.c \ @@ -171,14 +179,7 @@ CMDSRCS = crapto1/crapto1.c\ cmdscript.c\ pm3_binlib.c\ pm3_bitlib.c\ - protocols.c\ - cmdcrc.c\ - reveng/reveng.c\ - reveng/cli.c\ - reveng/bmpbit.c\ - reveng/model.c\ - reveng/poly.c\ - #reveng/getopt.c\ + protocols.c cpu_arch = $(shell uname -m) ifneq ($(findstring 86, $(cpu_arch)), ) @@ -311,6 +312,7 @@ DEPENDENCY_FILES = $(patsubst %.c, $(OBJDIR)/%.d, $(CORESRCS) $(CMDSRCS) $(ZLIBS $(patsubst %.cpp, $(OBJDIR)/%.d, $(QTGUISRCS)) \ $(OBJDIR)/proxmark3.d $(OBJDIR)/flash.d $(OBJDIR)/flasher.d $(OBJDIR)/fpga_compress.d + $(DEPENDENCY_FILES): ; .PRECIOUS: $(DEPENDENCY_FILES) diff --git a/client/cmdcrc.c b/client/cmdcrc.c deleted file mode 100644 index 0ca2b8b1..00000000 --- a/client/cmdcrc.c +++ /dev/null @@ -1,547 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2015 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. -//----------------------------------------------------------------------------- -// CRC Calculations from the software reveng commands -//----------------------------------------------------------------------------- - -#ifdef _WIN32 -# include -# include -# ifndef STDIN_FILENO -# define STDIN_FILENO 0 -# endif /* STDIN_FILENO */ -#endif /* _WIN32 */ - -#include -#include -#include -#include -#include "cmdmain.h" -#include "cmdcrc.h" -#include "reveng/reveng.h" -#include "ui.h" -#include "util.h" - -#define MAX_ARGS 20 - -int uerr(char *msg){ - PrintAndLog("%s",msg); - return 0; -} - -int split(char *str, char *arr[MAX_ARGS]){ - int beginIndex = 0; - int endIndex; - int maxWords = MAX_ARGS; - int wordCnt = 0; - - while(1){ - while(isspace((unsigned char)str[beginIndex])){ - ++beginIndex; - } - if(str[beginIndex] == '\0') { - break; - } - endIndex = beginIndex; - while (str[endIndex] && !isspace((unsigned char)str[endIndex])){ - ++endIndex; - } - int len = endIndex - beginIndex; - char *tmp = calloc(len + 1, sizeof(char)); - memcpy(tmp, &str[beginIndex], len); - arr[wordCnt++] = tmp; - //PrintAndLog("DEBUG cnt: %d, %s",wordCnt-1, arr[wordCnt-1]); - beginIndex = endIndex; - if (wordCnt == maxWords) - break; - } - return wordCnt; -} - -int CmdCrc(const char *Cmd) -{ - char name[] = {"reveng "}; - char Cmd2[50 + 7]; - memcpy(Cmd2, name, 7); - memcpy(Cmd2 + 7, Cmd, 50); - char *argv[MAX_ARGS]; - int argc = split(Cmd2, argv); - - if (argc == 3 && memcmp(argv[1],"-g",2)==0) { - CmdrevengSearch(argv[2]); - } else { - reveng_main(argc, argv); - } - //PrintAndLog("DEBUG argc: %d, %s %s Cmd: %s",argc, argv[0], Cmd2, Cmd); - for(int i = 0; i < argc; ++i){ - free(argv[i]); - } - - return 0; -} - -//returns array of model names and the count of models returning -// as well as a width array for the width of each model -int GetModels(char *Models[], int *count, uint8_t *width){ - /* default values */ - static model_t model = { - PZERO, /* no CRC polynomial, user must specify */ - PZERO, /* Init = 0 */ - P_BE, /* RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h */ - PZERO, /* XorOut = 0 */ - PZERO, /* check value unused */ - NULL /* no model name */ - }; - - int ibperhx = 8;//, obperhx = 8; - int rflags = 0, uflags = 0; /* search and UI flags */ - poly_t apoly, crc, qpoly = PZERO, *apolys = NULL, *pptr = NULL, *qptr = NULL; - model_t pset = model, *candmods, *mptr; - - /* stdin must be binary */ - #ifdef _WIN32 - _setmode(STDIN_FILENO, _O_BINARY); - #endif /* _WIN32 */ - - SETBMP(); - - int args = 0, psets, pass; - int Cnt = 0; - if (width[0] == 0) { //reveng -D - *count = mcount(); - if(!*count) - return uerr("no preset models available"); - - for(int mode = 0; mode < *count; ++mode) { - mbynum(&model, mode); - mcanon(&model); - size_t size = (model.name && *model.name) ? strlen(model.name) : 6; - char *tmp = calloc(size+1, sizeof(char)); - if (tmp==NULL) - return uerr("out of memory?"); - - memcpy(tmp, model.name, size); - Models[mode] = tmp; - width[mode] = plen(model.spoly); - } - mfree(&model); - } else { //reveng -s - - if(~model.flags & P_MULXN) - return uerr("cannot search for non-Williams compliant models"); - - praloc(&model.spoly, (unsigned long)width[0]); - praloc(&model.init, (unsigned long)width[0]); - praloc(&model.xorout, (unsigned long)width[0]); - if(!plen(model.spoly)) - palloc(&model.spoly, (unsigned long)width[0]); - else - width[0] = (uint8_t)plen(model.spoly); - - /* special case if qpoly is zero, search to end of range */ - if(!ptst(qpoly)) - rflags &= ~R_HAVEQ; - - - /* not going to be sending additional args at this time (maybe future?) - - // allocate argument array - args = argc - optind; - if(!(apolys = malloc(args * sizeof(poly_t)))) - return uerr("cannot allocate memory for argument list"); - - for(pptr = apolys; optind < argc; ++optind) { - if(uflags & C_INFILE) - *pptr++ = rdpoly(argv[optind], model.flags, ibperhx); - else - *pptr++ = strtop(argv[optind], model.flags, ibperhx); - } - // exit value of pptr is used hereafter! - - */ - - /* if endianness not specified, try - * little-endian then big-endian. - * NB: crossed-endian algorithms will not be - * searched. - */ - /* scan against preset models */ - if(~uflags & C_FORCE) { - pass = 0; - Cnt = 0; - do { - psets = mcount(); - //PrintAndLog("psets: %d",psets); - while(psets) { - mbynum(&pset, --psets); - - /* skip if different width, or refin or refout don't match */ - if(plen(pset.spoly) != width[0] || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT)) - continue; - /* skip if the preset doesn't match specified parameters */ - if(rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly)) - continue; - if(rflags & R_HAVEI && psncmp(&model.init, &pset.init)) - continue; - if(rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout)) - continue; - - //for additional args (not used yet, maybe future?) - apoly = pclone(pset.xorout); - if(pset.flags & P_REFOUT) - prev(&apoly); - - for(qptr = apolys; qptr < pptr; ++qptr) { - crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0); - if(ptst(crc)) { - pfree(&crc); - break; - } else - pfree(&crc); - } - pfree(&apoly); - if(qptr == pptr) { - - /* the selected model solved all arguments */ - - mcanon(&pset); - - size_t size = (pset.name && *pset.name) ? strlen(pset.name) : 6; - //PrintAndLog("Size: %d, %s, count: %d",size,pset.name, Cnt); - char *tmp = calloc(size+1, sizeof(char)); - if (tmp==NULL){ - PrintAndLog("out of memory?"); - return 0; - } - width[Cnt] = width[0]; - memcpy(tmp, pset.name, size); - Models[Cnt++] = tmp; - *count = Cnt; - uflags |= C_RESULT; - } - } - mfree(&pset); - - /* toggle refIn/refOut and reflect arguments */ - if(~rflags & R_HAVERI) { - model.flags ^= P_REFIN | P_REFOUT; - for(qptr = apolys; qptr < pptr; ++qptr) - prevch(qptr, ibperhx); - } - } while(~rflags & R_HAVERI && ++pass < 2); - } - //got everything now free the memory... - - if(uflags & C_RESULT) { - for(qptr = apolys; qptr < pptr; ++qptr) - pfree(qptr); - } - if(!(model.flags & P_REFIN) != !(model.flags & P_REFOUT)) - return uerr("cannot search for crossed-endian models"); - - pass = 0; - do { - mptr = candmods = reveng(&model, qpoly, rflags, args, apolys); - if(mptr && plen(mptr->spoly)) - uflags |= C_RESULT; - while(mptr && plen(mptr->spoly)) { - mfree(mptr++); - } - free(candmods); - if(~rflags & R_HAVERI) { - model.flags ^= P_REFIN | P_REFOUT; - for(qptr = apolys; qptr < pptr; ++qptr) - prevch(qptr, ibperhx); - } - } while(~rflags & R_HAVERI && ++pass < 2); - for(qptr = apolys; qptr < pptr; ++qptr) - pfree(qptr); - free(apolys); - if(~uflags & C_RESULT) - return uerr("no models found"); - mfree(&model); - } - return 1; -} - -//test call to GetModels -int CmdrevengTest(const char *Cmd){ - char *Models[80]; - int count = 0; - uint8_t widtharr[80] = {0}; - uint8_t width = 0; - width = param_get8(Cmd, 0); - //PrintAndLog("width: %d",width); - if (width > 89) - return uerr("Width cannot exceed 89"); - - widtharr[0] = width; - int ans = GetModels(Models, &count, widtharr); - if (!ans) return 0; - - PrintAndLog("Count: %d",count); - for (int i = 0; i < count; i++){ - PrintAndLog("Model %d: %s, width: %d",i,Models[i], widtharr[i]); - free(Models[i]); - } - return 1; -} - -//-c || -v -//inModel = valid model name string - CRC-8 -//inHexStr = input hex string to calculate crc on -//reverse = reverse calc option if true -//endian = {0 = calc default endian input and output, b = big endian input and output, B = big endian output, r = right justified -// l = little endian input and output, L = little endian output only, t = left justified} -//result = calculated crc hex string -int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result){ - /* default values */ - static model_t model = { - PZERO, // no CRC polynomial, user must specify - PZERO, // Init = 0 - P_BE, // RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h - PZERO, // XorOut = 0 - PZERO, // check value unused - NULL // no model name - }; - int ibperhx = 8, obperhx = 8; - int rflags = 0; // search flags - int c; - //unsigned long width; - poly_t apoly, crc; - - char *string; - - // stdin must be binary - #ifdef _WIN32 - _setmode(STDIN_FILENO, _O_BINARY); - #endif /* _WIN32 */ - - SETBMP(); - //set model - if(!(c = mbynam(&model, inModel))) { - fprintf(stderr,"error: preset model '%s' not found. Use reveng -D to list presets.\n", inModel); - return 0; - } - if(c < 0) - return uerr("no preset models available"); - - // must set width so that parameter to -ipx is not zeroed - //width = plen(model.spoly); - rflags |= R_HAVEP | R_HAVEI | R_HAVERI | R_HAVERO | R_HAVEX; - - //set flags - switch (endian) { - case 'b': /* b big-endian (RefIn = false, RefOut = false ) */ - model.flags &= ~P_REFIN; - rflags |= R_HAVERI; - /* fall through: */ - case 'B': /* B big-endian output (RefOut = false) */ - model.flags &= ~P_REFOUT; - rflags |= R_HAVERO; - mnovel(&model); - /* fall through: */ - case 'r': /* r right-justified */ - model.flags |= P_RTJUST; - break; - case 'l': /* l little-endian input and output */ - model.flags |= P_REFIN; - rflags |= R_HAVERI; - /* fall through: */ - case 'L': /* L little-endian output */ - model.flags |= P_REFOUT; - rflags |= R_HAVERO; - mnovel(&model); - /* fall through: */ - case 't': /* t left-justified */ - model.flags &= ~P_RTJUST; - break; - } - - mcanon(&model); - - if (reverse) { - // v calculate reversed CRC - /* Distinct from the -V switch as this causes - * the arguments and output to be reversed as well. - */ - // reciprocate Poly - prcp(&model.spoly); - - /* mrev() does: - * if(refout) prev(init); else prev(xorout); - * but here the entire argument polynomial is - * reflected, not just the characters, so RefIn - * and RefOut are not inverted as with -V. - * Consequently Init is the mirror image of the - * one resulting from -V, and so we have: - */ - if(~model.flags & P_REFOUT) { - prev(&model.init); - prev(&model.xorout); - } - - // swap init and xorout - apoly = model.init; - model.init = model.xorout; - model.xorout = apoly; - } - // c calculate CRC - - // validate inputs - /* if(plen(model.spoly) == 0) { - * fprintf(stderr,"%s: no polynomial specified for -%c (add -w WIDTH -p POLY)\n", myname, mode); - * exit(EXIT_FAILURE); - * } - */ - - /* in the Williams model, xorout is applied after the refout stage. - * as refout is part of ptostr(), we reverse xorout here. - */ - if(model.flags & P_REFOUT) - prev(&model.xorout); - - apoly = strtop(inHexStr, model.flags, ibperhx); - - if(reverse) - prev(&apoly); - - crc = pcrc(apoly, model.spoly, model.init, model.xorout, model.flags); - - if(reverse) - prev(&crc); - - string = ptostr(crc, model.flags, obperhx); - for (int i = 0; i < 50; i++){ - result[i] = string[i]; - if (result[i]==0) break; - } - free(string); - pfree(&crc); - pfree(&apoly); - return 1; -} - -//test call to RunModel -int CmdrevengTestC(const char *Cmd){ - int cmdp = 0; - char inModel[30] = {0x00}; - char inHexStr[30] = {0x00}; - char result[30]; - int dataLen; - char endian = 0; - dataLen = param_getstr(Cmd, cmdp++, inModel, sizeof(inModel)); - if (dataLen < 4) return 0; - dataLen = param_getstr(Cmd, cmdp++, inHexStr, sizeof(inHexStr)); - if (dataLen < 4) return 0; - bool reverse = (param_get8(Cmd, cmdp++)) ? true : false; - endian = param_getchar(Cmd, cmdp++); - - //PrintAndLog("mod: %s, hex: %s, rev %d", inModel, inHexStr, reverse); - int ans = RunModel(inModel, inHexStr, reverse, endian, result); - if (!ans) return 0; - - PrintAndLog("Result: %s",result); - return 1; -} - -//returns a calloced string (needs to be freed) -char *SwapEndianStr(const char *inStr, const size_t len, const uint8_t blockSize){ - char *tmp = calloc(len+1, sizeof(char)); - for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){ - for (size_t i = 0; i < blockSize; i+=2){ - tmp[i+(blockSize*block)] = inStr[(blockSize-1-i-1)+(blockSize*block)]; - tmp[i+(blockSize*block)+1] = inStr[(blockSize-1-i)+(blockSize*block)]; - } - } - return tmp; -} - -// takes hex string in and searches for a matching result (hex string must include checksum) -int CmdrevengSearch(const char *Cmd){ - char inHexStr[50] = {0x00}; - int dataLen = param_getstr(Cmd, 0, inHexStr, sizeof(inHexStr)); - if (dataLen < 4) return 0; - - char *Models[80]; - int count = 0; - uint8_t width[80]; - width[0] = 0; - uint8_t crcChars = 0; - char result[30]; - char revResult[30]; - int ans = GetModels(Models, &count, width); - bool found = false; - if (!ans) return 0; - - // try each model and get result - for (int i = 0; i < count; i++){ - /*if (found) { - free(Models[i]); - continue; - }*/ - // round up to # of characters in this model's crc - crcChars = ((width[i]+7)/8)*2; - // can't test a model that has more crc digits than our data - if (crcChars >= dataLen) - continue; - memset(result, 0, 30); - char *inCRC = calloc(crcChars+1, sizeof(char)); - memcpy(inCRC, inHexStr+(dataLen-crcChars), crcChars); - - char *outHex = calloc(dataLen-crcChars+1, sizeof(char)); - memcpy(outHex, inHexStr, dataLen-crcChars); - - //PrintAndLog("DEBUG: dataLen: %d, crcChars: %d, Model: %s, CRC: %s, width: %d, outHex: %s",dataLen, crcChars, Models[i], inCRC, width[i], outHex); - ans = RunModel(Models[i], outHex, false, 0, result); - if (ans) { - //test for match - if (memcmp(result, inCRC, crcChars)==0){ - PrintAndLog("\nFound a possible match!\nModel: %s\nValue: %s\n",Models[i], result); - //optional - stop searching if found... - found = true; - } else { - if (crcChars > 2){ - char *swapEndian = SwapEndianStr(result, crcChars, crcChars); - if (memcmp(swapEndian, inCRC, crcChars)==0){ - PrintAndLog("\nFound a possible match!\nModel: %s\nValue EndianSwapped: %s\n",Models[i], swapEndian); - //optional - stop searching if found... - found = true; - } - free(swapEndian); - } - } - } - - //if (!found){ - ans = RunModel(Models[i], outHex, true, 0, revResult); - if (ans) { - //test for match - if (memcmp(revResult, inCRC, crcChars)==0){ - PrintAndLog("\nFound a possible match!\nModel Reversed: %s\nValue: %s\n",Models[i], revResult); - //optional - stop searching if found... - found = true; - } else { - if (crcChars > 2){ - char *swapEndian = SwapEndianStr(revResult, crcChars, crcChars); - if (memcmp(swapEndian, inCRC, crcChars)==0){ - PrintAndLog("\nFound a possible match!\nModel Reversed: %s\nValue EndianSwapped: %s\n",Models[i], swapEndian); - //optional - stop searching if found... - found = true; - } - free(swapEndian); - } - } - } - //} - free(inCRC); - free(outHex); - free(Models[i]); - } - if (!found) PrintAndLog("\nNo matches found\n"); - return 1; -} diff --git a/client/cmdcrc.h b/client/cmdcrc.h deleted file mode 100644 index 5041554d..00000000 --- a/client/cmdcrc.h +++ /dev/null @@ -1,20 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2015 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. -//----------------------------------------------------------------------------- -// CRC Calculations from the software reveng commands -//----------------------------------------------------------------------------- - -#ifndef CMDCRC_H__ -#define CMDCRC_H__ - -int CmdCrc(const char *Cmd); -int CmdrevengTest(const char *Cmd); -int CmdrevengTestC(const char *Cmd); -int CmdrevengSearch(const char *Cmd); -int GetModels(char *Models[], int *count, uint8_t *width); -int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result); -#endif diff --git a/client/cmddata.c b/client/cmddata.c index 1f548284..c4f0e8a3 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -8,15 +8,15 @@ // Data and Graph commands //----------------------------------------------------------------------------- +#include "cmddata.h" + #include // also included in util.h #include // also included in util.h #include #include // for CmdNorm INT_MIN && INT_MAX -#include "data.h" // also included in util.h -#include "cmddata.h" #include "util.h" #include "cmdmain.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" // for show graph controls #include "graph.h" // for graph data #include "cmdparser.h"// already included in cmdmain.h @@ -591,8 +591,7 @@ int CmdBitsamples(const char *Cmd) int cnt = 0; uint8_t got[12288]; - GetFromBigBuf(got,sizeof(got),0); - WaitForResponse(CMD_ACK,NULL); + GetFromBigBuf(got, sizeof(got), 0 , NULL, -1, false); for (int j = 0; j < sizeof(got); j++) { for (int k = 0; k < 8; k++) { @@ -1131,8 +1130,7 @@ int CmdHexsamples(const char *Cmd) return 0; } - GetFromBigBuf(got,requested,offset); - WaitForResponse(CMD_ACK,NULL); + GetFromBigBuf(got, requested, offset, NULL, -1, false); i = 0; for (j = 0; j < requested; j++) { @@ -1200,10 +1198,9 @@ int getSamples(int n, bool silent) n = sizeof(got); if (!silent) PrintAndLog("Reading %d bytes from device memory\n", n); - GetFromBigBuf(got,n,0); - if (!silent) PrintAndLog("Data fetched"); UsbCommand response; - WaitForResponse(CMD_ACK, &response); + GetFromBigBuf(got, n, 0, &response, -1, false); + if (!silent) PrintAndLog("Data fetched"); uint8_t bits_per_sample = 8; //Old devices without this feature would send 0 at arg[0] @@ -1281,26 +1278,36 @@ int CmdTuneSamples(const char *Cmd) peakf = resp.arg[2] & 0xffff; peakv = resp.arg[2] >> 16; PrintAndLog(""); - PrintAndLog("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/1000.0); - PrintAndLog("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/1000.0); - PrintAndLog("# LF optimal: %5.2f V @%9.2f kHz", peakv/1000.0, 12000.0/(peakf+1)); - PrintAndLog("# HF antenna: %5.2f V @ 13.56 MHz", vHf/1000.0); + if (arg & FLAG_TUNE_LF) + { + PrintAndLog("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/500.0); + PrintAndLog("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/500.0); + PrintAndLog("# LF optimal: %5.2f V @%9.2f kHz", peakv/500.0, 12000.0/(peakf+1)); + } + if (arg & FLAG_TUNE_HF) + PrintAndLog("# HF antenna: %5.2f V @ 13.56 MHz", vHf/1000.0); - #define LF_UNUSABLE_V 2948 // was 2000. Changed due to bugfix in voltage measurements. LF results are now 47% higher. - #define LF_MARGINAL_V 14739 // was 10000. Changed due to bugfix bug in voltage measurements. LF results are now 47% higher. - #define HF_UNUSABLE_V 3167 // was 2000. Changed due to bugfix in voltage measurements. HF results are now 58% higher. - #define HF_MARGINAL_V 7917 // was 5000. Changed due to bugfix in voltage measurements. HF results are now 58% higher. + #define LF_UNUSABLE_V 3000 + #define LF_MARGINAL_V 15000 + #define HF_UNUSABLE_V 3200 + #define HF_MARGINAL_V 8000 - if (peakv < LF_UNUSABLE_V) - PrintAndLog("# Your LF antenna is unusable."); - else if (peakv < LF_MARGINAL_V) - PrintAndLog("# Your LF antenna is marginal."); - if (vHf < HF_UNUSABLE_V) - PrintAndLog("# Your HF antenna is unusable."); - else if (vHf < HF_MARGINAL_V) - PrintAndLog("# Your HF antenna is marginal."); + if (arg & FLAG_TUNE_LF) + { + if (peakv<<1 < LF_UNUSABLE_V) + PrintAndLog("# Your LF antenna is unusable."); + else if (peakv<<1 < LF_MARGINAL_V) + PrintAndLog("# Your LF antenna is marginal."); + } + if (arg & FLAG_TUNE_HF) + { + if (vHf < HF_UNUSABLE_V) + PrintAndLog("# Your HF antenna is unusable."); + else if (vHf < HF_MARGINAL_V) + PrintAndLog("# Your HF antenna is marginal."); + } - if (peakv >= LF_UNUSABLE_V) { + if (peakv<<1 >= LF_UNUSABLE_V) { for (int i = 0; i < 256; i++) { GraphBuffer[i] = resp.d.asBytes[i] - 128; } diff --git a/client/cmdhf.c b/client/cmdhf.c index 7a2f3252..93906a7d 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -1,5 +1,6 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh +// Merlok - 2017 // // 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 @@ -8,18 +9,18 @@ // High frequency commands //----------------------------------------------------------------------------- +#include "cmdhf.h" + #include #include #include -#include "proxmark3.h" +#include "comms.h" #include "util.h" -#include "data.h" #include "ui.h" #include "iso14443crc.h" #include "parity.h" #include "cmdmain.h" #include "cmdparser.h" -#include "cmdhf.h" #include "cmdhf14a.h" #include "cmdhf14b.h" #include "cmdhf15.h" @@ -31,6 +32,7 @@ #include "cmdhftopaz.h" #include "protocols.h" #include "emv/cmdemv.h" +#include "cmdhflist.h" static int CmdHelp(const char *Cmd); @@ -41,236 +43,6 @@ int CmdHFTune(const char *Cmd) return 0; } - -void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) -{ - switch(cmd[0]) - { - case ISO14443A_CMD_WUPA: snprintf(exp,size,"WUPA"); break; - case ISO14443A_CMD_ANTICOLL_OR_SELECT:{ - // 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor) - // 93 70 = Select (usage: 9370+5bytes 9320 answer - answer: 1byte SAK) - if(cmd[1] == 0x70) - { - snprintf(exp,size,"SELECT_UID"); break; - }else - { - snprintf(exp,size,"ANTICOLL"); break; - } - } - case ISO14443A_CMD_ANTICOLL_OR_SELECT_2:{ - //95 20 = Anticollision of cascade level2 - //95 70 = Select of cascade level2 - if(cmd[2] == 0x70) - { - snprintf(exp,size,"SELECT_UID-2"); break; - }else - { - snprintf(exp,size,"ANTICOLL-2"); break; - } - } - case ISO14443A_CMD_REQA: snprintf(exp,size,"REQA"); break; - case ISO14443A_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; - case ISO14443A_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; - case ISO14443A_CMD_HALT: snprintf(exp,size,"HALT"); break; - case ISO14443A_CMD_RATS: snprintf(exp,size,"RATS"); break; - case MIFARE_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break; - case MIFARE_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break; - case MIFARE_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break; - case MIFARE_CMD_TRANSFER: snprintf(exp,size,"TRANSFER(%d)",cmd[1]); break; - case MIFARE_AUTH_KEYA:{ - if ( cmdsize > 3) - snprintf(exp,size,"AUTH-A(%d)",cmd[1]); - else - // case MIFARE_ULEV1_VERSION : both 0x60. - snprintf(exp,size,"EV1 VERSION"); - break; - } - case MIFARE_AUTH_KEYB: snprintf(exp,size,"AUTH-B(%d)",cmd[1]); break; - case MIFARE_MAGICWUPC1: snprintf(exp,size,"MAGIC WUPC1"); break; - case MIFARE_MAGICWUPC2: snprintf(exp,size,"MAGIC WUPC2"); break; - case MIFARE_MAGICWIPEC: snprintf(exp,size,"MAGIC WIPEC"); break; - case MIFARE_ULC_AUTH_1: snprintf(exp,size,"AUTH "); break; - case MIFARE_ULC_AUTH_2: snprintf(exp,size,"AUTH_ANSW"); break; - case MIFARE_ULEV1_AUTH: - if ( cmdsize == 7 ) - snprintf(exp,size,"PWD-AUTH KEY: 0x%02x%02x%02x%02x", cmd[1], cmd[2], cmd[3], cmd[4] ); - else - snprintf(exp,size,"PWD-AUTH"); - break; - case MIFARE_ULEV1_FASTREAD:{ - if ( cmdsize >=3 && cmd[2] <= 0xE6) - snprintf(exp,size,"READ RANGE (%d-%d)",cmd[1],cmd[2]); - else - snprintf(exp,size,"?"); - break; - } - case MIFARE_ULC_WRITE:{ - if ( cmd[1] < 0x21 ) - snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); - else - snprintf(exp,size,"?"); - break; - } - case MIFARE_ULEV1_READ_CNT:{ - if ( cmd[1] < 5 ) - snprintf(exp,size,"READ CNT(%d)",cmd[1]); - else - snprintf(exp,size,"?"); - break; - } - case MIFARE_ULEV1_INCR_CNT:{ - if ( cmd[1] < 5 ) - snprintf(exp,size,"INCR(%d)",cmd[1]); - else - snprintf(exp,size,"?"); - break; - } - case MIFARE_ULEV1_READSIG: snprintf(exp,size,"READ_SIG"); break; - case MIFARE_ULEV1_CHECKTEAR: snprintf(exp,size,"CHK_TEARING(%d)",cmd[1]); break; - case MIFARE_ULEV1_VCSL: snprintf(exp,size,"VCSL"); break; - default: snprintf(exp,size,"?"); break; - } - return; -} - -void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) -{ - switch(cmd[0]) - { - case ICLASS_CMD_ACTALL: snprintf(exp,size,"ACTALL"); break; - case ICLASS_CMD_READ_OR_IDENTIFY:{ - if(cmdsize > 1){ - snprintf(exp,size,"READ(%d)",cmd[1]); - }else{ - snprintf(exp,size,"IDENTIFY"); - } - break; - } - case ICLASS_CMD_SELECT: snprintf(exp,size,"SELECT"); break; - case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL(%d)", cmd[1]); break; - case ICLASS_CMD_READCHECK_KC:snprintf(exp,size,"READCHECK[Kc](%d)", cmd[1]); break; - case ICLASS_CMD_READCHECK_KD:snprintf(exp,size,"READCHECK[Kd](%d)", cmd[1]); break; - case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break; - case ICLASS_CMD_DETECT: snprintf(exp,size,"DETECT"); break; - case ICLASS_CMD_HALT: snprintf(exp,size,"HALT"); break; - case ICLASS_CMD_UPDATE: snprintf(exp,size,"UPDATE(%d)",cmd[1]); break; - case ICLASS_CMD_ACT: snprintf(exp,size,"ACT"); break; - case ICLASS_CMD_READ4: snprintf(exp,size,"READ4(%d)",cmd[1]); break; - default: snprintf(exp,size,"?"); break; - } - return; -} - -void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) -{ - - if(cmd[0] == 0x26) - { - switch(cmd[1]){ - case ISO15693_INVENTORY :snprintf(exp, size, "INVENTORY");break; - case ISO15693_STAYQUIET :snprintf(exp, size, "STAY_QUIET");break; - default: snprintf(exp,size,"?"); break; - - } - }else if(cmd[0] == 0x02) - { - switch(cmd[1]) - { - case ISO15693_READBLOCK :snprintf(exp, size, "READBLOCK");break; - case ISO15693_WRITEBLOCK :snprintf(exp, size, "WRITEBLOCK");break; - case ISO15693_LOCKBLOCK :snprintf(exp, size, "LOCKBLOCK");break; - case ISO15693_READ_MULTI_BLOCK :snprintf(exp, size, "READ_MULTI_BLOCK");break; - case ISO15693_SELECT :snprintf(exp, size, "SELECT");break; - case ISO15693_RESET_TO_READY :snprintf(exp, size, "RESET_TO_READY");break; - case ISO15693_WRITE_AFI :snprintf(exp, size, "WRITE_AFI");break; - case ISO15693_LOCK_AFI :snprintf(exp, size, "LOCK_AFI");break; - case ISO15693_WRITE_DSFID :snprintf(exp, size, "WRITE_DSFID");break; - case ISO15693_LOCK_DSFID :snprintf(exp, size, "LOCK_DSFID");break; - case ISO15693_GET_SYSTEM_INFO :snprintf(exp, size, "GET_SYSTEM_INFO");break; - case ISO15693_READ_MULTI_SECSTATUS :snprintf(exp, size, "READ_MULTI_SECSTATUS");break; - default: snprintf(exp,size,"?"); break; - } - } -} - - -void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) -{ - switch(cmd[0]) { - case TOPAZ_REQA :snprintf(exp, size, "REQA");break; - case TOPAZ_WUPA :snprintf(exp, size, "WUPA");break; - case TOPAZ_RID :snprintf(exp, size, "RID");break; - case TOPAZ_RALL :snprintf(exp, size, "RALL");break; - case TOPAZ_READ :snprintf(exp, size, "READ");break; - case TOPAZ_WRITE_E :snprintf(exp, size, "WRITE-E");break; - case TOPAZ_WRITE_NE :snprintf(exp, size, "WRITE-NE");break; - case TOPAZ_RSEG :snprintf(exp, size, "RSEG");break; - case TOPAZ_READ8 :snprintf(exp, size, "READ8");break; - case TOPAZ_WRITE_E8 :snprintf(exp, size, "WRITE-E8");break; - case TOPAZ_WRITE_NE8 :snprintf(exp, size, "WRITE-NE8");break; - default: snprintf(exp,size,"?"); break; - } -} - - -/** -06 00 = INITIATE -0E xx = SELECT ID (xx = Chip-ID) -0B = Get UID -08 yy = Read Block (yy = block number) -09 yy dd dd dd dd = Write Block (yy = block number; dd dd dd dd = data to be written) -0C = Reset to Inventory -0F = Completion -0A 11 22 33 44 55 66 = Authenticate (11 22 33 44 55 66 = data to authenticate) -**/ - -void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) -{ - switch(cmd[0]){ - case ISO14443B_REQB : snprintf(exp,size,"REQB");break; - case ISO14443B_ATTRIB : snprintf(exp,size,"ATTRIB");break; - case ISO14443B_HALT : snprintf(exp,size,"HALT");break; - case ISO14443B_INITIATE : snprintf(exp,size,"INITIATE");break; - case ISO14443B_SELECT : snprintf(exp,size,"SELECT(%d)",cmd[1]);break; - case ISO14443B_GET_UID : snprintf(exp,size,"GET UID");break; - case ISO14443B_READ_BLK : snprintf(exp,size,"READ_BLK(%d)", cmd[1]);break; - case ISO14443B_WRITE_BLK : snprintf(exp,size,"WRITE_BLK(%d)",cmd[1]);break; - case ISO14443B_RESET : snprintf(exp,size,"RESET");break; - case ISO14443B_COMPLETION : snprintf(exp,size,"COMPLETION");break; - case ISO14443B_AUTHENTICATE : snprintf(exp,size,"AUTHENTICATE");break; - default : snprintf(exp,size ,"?");break; - } - -} - -/** - * @brief iso14443A_CRC_check Checks CRC in command or response - * @param isResponse - * @param data - * @param len - * @return 0 : CRC-command, CRC not ok - * 1 : CRC-command, CRC ok - * 2 : Not crc-command - */ - -uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len) -{ - uint8_t b1,b2; - - if(len <= 2) return 2; - - if(isResponse & (len < 6)) return 2; - - ComputeCrc14443(CRC_14443_A, data, len-2, &b1, &b2); - if (b1 != data[len-2] || b2 != data[len-1]) { - return 0; - } else { - return 1; - } -} - - /** * @brief iso14443B_CRC_check Checks CRC in command or response * @param isResponse @@ -418,6 +190,8 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui uint8_t topaz_reader_command[9]; uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp; char explanation[30] = {0}; + uint8_t mfData[32] = {0}; + size_t mfDataLen = 0; if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen) return traceLen; @@ -466,6 +240,9 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui case TOPAZ: crcStatus = iso14443B_CRC_check(isResponse, frame, data_len); break; + case PROTO_MIFARE: + crcStatus = mifare_CRC_check(isResponse, frame, data_len); + break; case ISO_14443A: crcStatus = iso14443A_CRC_check(isResponse, frame, data_len); break; @@ -514,6 +291,9 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui EndOfTransmissionTimestamp = timestamp + duration; + if (protocol == PROTO_MIFARE) + annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, parity_len, isResponse); + if(!isResponse) { switch(protocol) { @@ -542,6 +322,19 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui (j == num_lines-1) ? explanation : ""); } } + + if (DecodeMifareData(frame, data_len, parityBytes, isResponse, mfData, &mfDataLen)) { + memset(explanation, 0x00, sizeof(explanation)); + if (!isResponse) { + explanation[0] = '>'; + annotateIso14443a(&explanation[1], sizeof(explanation) - 1, mfData, mfDataLen); + } + uint8_t crcc = iso14443A_CRC_check(isResponse, mfData, mfDataLen); + PrintAndLog(" | * | dec |%-64s | %-4s| %s", + sprint_hex(mfData, mfDataLen), + (crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")), + (true) ? explanation : ""); + }; if (is_last_record(tracepos, trace, traceLen)) return traceLen; @@ -562,99 +355,186 @@ int CmdHFList(const char *Cmd) { bool showWaitCycles = false; bool markCRCBytes = false; + bool loadFromFile = false; + bool saveToFile = false; + char param1 = '\0'; + char param2 = '\0'; + char param3 = '\0'; char type[40] = {0}; - int tlen = param_getstr(Cmd,0,type, sizeof(type)); - char param1 = param_getchar(Cmd, 1); - char param2 = param_getchar(Cmd, 2); - bool errors = false; + char filename[FILE_PATH_SIZE] = {0}; uint8_t protocol = 0; - //Validate params + + // parse command line + int tlen = param_getstr(Cmd, 0, type, sizeof(type)); + if (param_getlength(Cmd, 1) == 1) { + param1 = param_getchar(Cmd, 1); + } else { + param_getstr(Cmd, 1, filename, sizeof(filename)); + } + if (param_getlength(Cmd, 2) == 1) { + param2 = param_getchar(Cmd, 2); + } else if (strlen(filename) == 0) { + param_getstr(Cmd, 2, filename, sizeof(filename)); + } + if (param_getlength(Cmd, 3) == 1) { + param3 = param_getchar(Cmd, 3); + } else if (strlen(filename) == 0) { + param_getstr(Cmd, 3, filename, sizeof(filename)); + } + + // Validate param1 + bool errors = false; if(tlen == 0) { errors = true; } if(param1 == 'h' - || (param1 != 0 && param1 != 'f' && param1 != 'c') - || (param2 != 0 && param2 != 'f' && param2 != 'c')) { + || (param1 != 0 && param1 != 'f' && param1 != 'c' && param1 != 'l') + || (param2 != 0 && param2 != 'f' && param2 != 'c' && param2 != 'l') + || (param3 != 0 && param3 != 'f' && param3 != 'c' && param3 != 'l')) { errors = true; } if(!errors) { if(strcmp(type, "iclass") == 0) { protocol = ICLASS; + } else if(strcmp(type, "mf") == 0) { + protocol = PROTO_MIFARE; } else if(strcmp(type, "14a") == 0) { protocol = ISO_14443A; } else if(strcmp(type, "14b") == 0) { protocol = ISO_14443B; - } else if(strcmp(type,"topaz")== 0) { + } else if(strcmp(type,"topaz") == 0) { protocol = TOPAZ; - } else if(strcmp(type,"raw")== 0) { - protocol = -1;//No crc, no annotations + } else if(strcmp(type,"raw") == 0) { + protocol = -1; //No crc, no annotations + } else if (strcmp(type, "save") == 0) { + saveToFile = true; } else { errors = true; } } + + if (param1 == 'f' || param2 == 'f' || param3 == 'f') { + showWaitCycles = true; + } + if (param1 == 'c' || param2 == 'c' || param3 == 'c') { + markCRCBytes = true; + } + + if (param1 == 'l' || param2 == 'l' || param3 == 'l') { + loadFromFile = true; + } + + if ((loadFromFile || saveToFile) && strlen(filename) == 0) { + errors = true; + } + + if (loadFromFile && saveToFile) { + errors = true; + } + if (errors) { - PrintAndLog("List protocol data in trace buffer."); - PrintAndLog("Usage: hf list [f][c]"); + PrintAndLog("List or save protocol data."); + PrintAndLog("Usage: hf list [f] [c] [l ]"); + PrintAndLog(" hf list save "); PrintAndLog(" f - show frame delay times as well"); PrintAndLog(" c - mark CRC bytes"); + PrintAndLog(" l - load data from file instead of trace buffer"); + PrintAndLog(" save - save data to file"); PrintAndLog("Supported values:"); PrintAndLog(" raw - just show raw data without annotations"); PrintAndLog(" 14a - interpret data as iso14443a communications"); + PrintAndLog(" mf - interpret data as iso14443a communications and decrypt crypto1 stream"); PrintAndLog(" 14b - interpret data as iso14443b communications"); PrintAndLog(" iclass - interpret data as iclass communications"); PrintAndLog(" topaz - interpret data as topaz communications"); PrintAndLog(""); PrintAndLog("example: hf list 14a f"); PrintAndLog("example: hf list iclass"); + PrintAndLog("example: hf list save myCardTrace.trc"); + PrintAndLog("example: hf list 14a l myCardTrace.trc"); return 0; } - if (param1 == 'f' || param2 == 'f') { - showWaitCycles = true; - } - - if (param1 == 'c' || param2 == 'c') { - markCRCBytes = true; - } - uint8_t *trace; - uint16_t tracepos = 0; - trace = malloc(USB_CMD_DATA_SIZE); - - // Query for the size of the trace - UsbCommand response; - GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0); - WaitForResponse(CMD_ACK, &response); - uint16_t traceLen = response.arg[2]; - if (traceLen > USB_CMD_DATA_SIZE) { - uint8_t *p = realloc(trace, traceLen); - if (p == NULL) { + uint32_t tracepos = 0; + uint32_t traceLen = 0; + + if (loadFromFile) { + #define TRACE_CHUNK_SIZE (1<<16) // 64K to start with. Will be enough for BigBuf and some room for future extensions + FILE *tracefile = NULL; + size_t bytes_read; + trace = malloc(TRACE_CHUNK_SIZE); + if (trace == NULL) { PrintAndLog("Cannot allocate memory for trace"); - free(trace); return 2; } - trace = p; - GetFromBigBuf(trace, traceLen, 0); - WaitForResponse(CMD_ACK, NULL); + if ((tracefile = fopen(filename,"rb")) == NULL) { + PrintAndLog("Could not open file %s", filename); + free(trace); + return 0; + } + while (!feof(tracefile)) { + bytes_read = fread(trace+traceLen, 1, TRACE_CHUNK_SIZE, tracefile); + traceLen += bytes_read; + if (!feof(tracefile)) { + uint8_t *p = realloc(trace, traceLen + TRACE_CHUNK_SIZE); + if (p == NULL) { + PrintAndLog("Cannot allocate memory for trace"); + free(trace); + fclose(tracefile); + return 2; + } + trace = p; + } + } + fclose(tracefile); + } else { + trace = malloc(USB_CMD_DATA_SIZE); + // Query for the size of the trace + UsbCommand response; + GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0, &response, -1, false); + traceLen = response.arg[2]; + if (traceLen > USB_CMD_DATA_SIZE) { + uint8_t *p = realloc(trace, traceLen); + if (p == NULL) { + PrintAndLog("Cannot allocate memory for trace"); + free(trace); + return 2; + } + trace = p; + GetFromBigBuf(trace, traceLen, 0, NULL, -1, false); + } } - - PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen); - PrintAndLog(""); - PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); - PrintAndLog("iso14443a - All times are in carrier periods (1/13.56Mhz)"); - PrintAndLog("iClass - Timings are not as accurate"); - PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |"); - PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|"); - while(tracepos < traceLen) - { - tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes); + if (saveToFile) { + FILE *tracefile = NULL; + if ((tracefile = fopen(filename,"wb")) == NULL) { + PrintAndLog("Could not create file %s", filename); + return 1; + } + fwrite(trace, 1, traceLen, tracefile); + PrintAndLog("Recorded Activity (TraceLen = %d bytes) written to file %s", traceLen, filename); + fclose(tracefile); + } else { + PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen); + PrintAndLog(""); + PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); + PrintAndLog("iso14443a - All times are in carrier periods (1/13.56Mhz)"); + PrintAndLog("iClass - Timings are not as accurate"); + PrintAndLog(""); + PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |"); + PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|"); + + ClearAuthData(); + while(tracepos < traceLen) + { + tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes); + } } free(trace); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 82d31ff5..2d76f109 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -20,8 +20,7 @@ #include "util.h" #include "util_posix.h" #include "iso14443crc.h" -#include "data.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "cmdparser.h" #include "common.h" @@ -36,8 +35,13 @@ static int CmdHelp(const char *Cmd); static int waitCmd(uint8_t iLen); +// structure and database for uid -> tagtype lookups +typedef struct { + uint8_t uid; + char* desc; +} manufactureName; -const manufactureName manufactureMapping[] = { +static const manufactureName manufactureMapping[] = { // ID, "Vendor Country" { 0x01, "Motorola UK" }, { 0x02, "ST Microelectronics SA France" }, @@ -187,7 +191,7 @@ int CmdHF14AReader(const char *Cmd) { PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]); + PrintAndLog(" SAK : %02x [%" PRIu64 "]", card.sak, resp.arg[0]); if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes PrintAndLog(" ATS : %s", sprint_hex(card.ats, card.ats_len)); } @@ -239,7 +243,7 @@ int CmdHF14AInfo(const char *Cmd) PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]); + PrintAndLog(" SAK : %02x [%" PRIu64 "]", card.sak, resp.arg[0]); bool isMifareClassic = true; switch (card.sak) { @@ -477,12 +481,12 @@ int CmdHF14AInfo(const char *Cmd) // try to see if card responses to "chinese magic backdoor" commands. - mfCIdentify(); + (void)mfCIdentify(); if (isMifareClassic) { switch(DetectClassicPrng()) { case 0: - PrintAndLog("Prng detection: HARDEND (hardnested)"); + PrintAndLog("Prng detection: HARDENED (hardnested)"); break; case 1: PrintAndLog("Prng detection: WEAK"); @@ -949,12 +953,9 @@ static command_t CommandTable[] = }; int CmdHF14A(const char *Cmd) { - // flush - WaitForResponseTimeout(CMD_ACK,NULL,100); - - // parse - CmdsParse(CommandTable, Cmd); - return 0; + (void)WaitForResponseTimeout(CMD_ACK,NULL,100); + CmdsParse(CommandTable, Cmd); + return 0; } int CmdHelp(const char *Cmd) diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index 401cead0..71007f95 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -15,12 +15,6 @@ #include #include -// structure and database for uid -> tagtype lookups -typedef struct { - uint8_t uid; - char* desc; -} manufactureName; - int CmdHF14A(const char *Cmd); int CmdHF14AList(const char *Cmd); int CmdHF14AMifare(const char *Cmd); diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index 36932cbd..ff0bf7c9 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -8,19 +8,19 @@ // High frequency ISO14443B commands //----------------------------------------------------------------------------- +#include "cmdhf14b.h" + #include #include #include #include #include #include "iso14443crc.h" -#include "proxmark3.h" -#include "data.h" +#include "comms.h" #include "graph.h" #include "util.h" #include "ui.h" #include "cmdparser.h" -#include "cmdhf14b.h" #include "cmdmain.h" #include "cmdhf14a.h" diff --git a/client/cmdhf14b.h b/client/cmdhf14b.h index a45b7434..4fcae927 100644 --- a/client/cmdhf14b.h +++ b/client/cmdhf14b.h @@ -11,6 +11,8 @@ #ifndef CMDHF14B_H__ #define CMDHF14B_H__ +#include + int CmdHF14B(const char *Cmd); int CmdHF14BList(const char *Cmd); int CmdHF14BInfo(const char *Cmd); diff --git a/client/cmdhf15.c b/client/cmdhf15.c index 8ddbea89..08cc3b15 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -22,18 +22,18 @@ // the client. Signal Processing & decoding is done on the pc. This is the slowest // variant, but offers the possibility to analyze the waveforms directly. +#include "cmdhf15.h" + #include #include #include #include -#include "proxmark3.h" -#include "data.h" +#include "comms.h" #include "graph.h" #include "ui.h" #include "util.h" #include "cmdparser.h" -#include "cmdhf15.h" #include "iso15693tools.h" #include "cmdmain.h" diff --git a/client/cmdhf15.h b/client/cmdhf15.h index c6264604..d0517fe5 100644 --- a/client/cmdhf15.h +++ b/client/cmdhf15.h @@ -11,6 +11,8 @@ #ifndef CMDHF15_H__ #define CMDHF15_H__ +#include + int CmdHF15(const char *Cmd); int CmdHF15Demod(const char *Cmd); diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index f3456afb..76664bf5 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -17,7 +17,7 @@ #include #include "util.h" #include "util_posix.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "cmdparser.h" #include "common.h" @@ -202,10 +202,7 @@ int CmdHelp(const char *Cmd) int CmdHFEPA(const char *Cmd) { - // flush - WaitForResponseTimeout(CMD_ACK,NULL,100); - - // parse - CmdsParse(CommandTable, Cmd); - return 0; + (void)WaitForResponseTimeout(CMD_ACK,NULL,100); + CmdsParse(CommandTable, Cmd); + return 0; } diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index d42f7eef..499f7aae 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -16,8 +16,7 @@ #include #include #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type -#include "data.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "cmdparser.h" #include "cmdhficlass.h" @@ -750,8 +749,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) { blocksRead = (sizeof(tag_data)/8) - blockno; } // response ok - now get bigbuf content of the dump - GetFromBigBuf(tag_data+(blockno*8), blocksRead*8, startindex); - WaitForResponse(CMD_ACK,NULL); + GetFromBigBuf(tag_data+(blockno*8), blocksRead*8, startindex, NULL, -1, false); size_t gotBytes = blocksRead*8 + blockno*8; // try AA2 @@ -793,8 +791,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) { blocksRead = (sizeof(tag_data) - gotBytes)/8; } // get dumped data from bigbuf - GetFromBigBuf(tag_data+gotBytes, blocksRead*8, startindex); - WaitForResponse(CMD_ACK,NULL); + GetFromBigBuf(tag_data+gotBytes, blocksRead*8, startindex, NULL, -1, false); gotBytes += blocksRead*8; } else { //field is still on - turn it off... diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index c9f3485e..691e1978 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -8,16 +8,17 @@ // High frequency Legic commands //----------------------------------------------------------------------------- +#include "cmdhflegic.h" + #include #include #include -#include "proxmark3.h" -#include "data.h" +#include "comms.h" #include "ui.h" #include "cmdparser.h" -#include "cmdhflegic.h" #include "cmdmain.h" #include "util.h" + static int CmdHelp(const char *Cmd); static command_t CommandTable[] = @@ -64,8 +65,7 @@ int CmdLegicDecode(const char *Cmd) char token_type[4]; // copy data from proxmark into buffer - GetFromBigBuf(data_buf,sizeof(data_buf),0); - WaitForResponse(CMD_ACK,NULL); + GetFromBigBuf(data_buf, sizeof(data_buf), 0, NULL, -1, false); // Output CDF System area (9 bytes) plus remaining header area (12 bytes) @@ -294,8 +294,7 @@ int CmdLegicSave(const char *Cmd) return -1; } - GetFromBigBuf(got,requested,offset); - WaitForResponse(CMD_ACK,NULL); + GetFromBigBuf(got, requested, offset, NULL, -1, false); for (int j = 0; j < requested; j += 8) { fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n", diff --git a/client/cmdhflist.c b/client/cmdhflist.c new file mode 100644 index 00000000..5538b6fb --- /dev/null +++ b/client/cmdhflist.c @@ -0,0 +1,606 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Merlok - 2017 +// +// 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. +//----------------------------------------------------------------------------- +// Command: hf mf list. It shows data from arm buffer. +//----------------------------------------------------------------------------- + +#include "cmdhflist.h" + +#include +#include +#include +#include +#include +#include "util.h" +#include "ui.h" +#include "iso14443crc.h" +#include "parity.h" +#include "protocols.h" +#include "crapto1/crapto1.h" +#include "mifarehost.h" +#include "mifaredefault.h" + + +enum MifareAuthSeq { + masNone, + masNt, + masNrAr, + masAt, + masAuthComplete, + masFirstData, + masData, + masError, +}; +static enum MifareAuthSeq MifareAuthState; +static TAuthData AuthData; + +void ClearAuthData() { + AuthData.uid = 0; + AuthData.nt = 0; + AuthData.first_auth = true; + AuthData.ks2 = 0; + AuthData.ks3 = 0; +} + +/** + * @brief iso14443A_CRC_check Checks CRC in command or response + * @param isResponse + * @param data + * @param len + * @return 0 : CRC-command, CRC not ok + * 1 : CRC-command, CRC ok + * 2 : Not crc-command + */ +uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len) +{ + uint8_t b1,b2; + + if(len <= 2) return 2; + + if(isResponse & (len < 6)) return 2; + + ComputeCrc14443(CRC_14443_A, data, len-2, &b1, &b2); + if (b1 != data[len-2] || b2 != data[len-1]) { + return 0; + } else { + return 1; + } +} + +uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len) +{ + switch(MifareAuthState) { + case masNone: + case masError: + return iso14443A_CRC_check(isResponse, data, len); + default: + return 2; + } +} + +void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + switch(cmd[0]) + { + case ICLASS_CMD_ACTALL: snprintf(exp,size,"ACTALL"); break; + case ICLASS_CMD_READ_OR_IDENTIFY:{ + if(cmdsize > 1){ + snprintf(exp,size,"READ(%d)",cmd[1]); + }else{ + snprintf(exp,size,"IDENTIFY"); + } + break; + } + case ICLASS_CMD_SELECT: snprintf(exp,size,"SELECT"); break; + case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL(%d)", cmd[1]); break; + case ICLASS_CMD_READCHECK_KC:snprintf(exp,size,"READCHECK[Kc](%d)", cmd[1]); break; + case ICLASS_CMD_READCHECK_KD:snprintf(exp,size,"READCHECK[Kd](%d)", cmd[1]); break; + case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break; + case ICLASS_CMD_DETECT: snprintf(exp,size,"DETECT"); break; + case ICLASS_CMD_HALT: snprintf(exp,size,"HALT"); break; + case ICLASS_CMD_UPDATE: snprintf(exp,size,"UPDATE(%d)",cmd[1]); break; + case ICLASS_CMD_ACT: snprintf(exp,size,"ACT"); break; + case ICLASS_CMD_READ4: snprintf(exp,size,"READ4(%d)",cmd[1]); break; + default: snprintf(exp,size,"?"); break; + } + return; +} + +void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + + if(cmd[0] == 0x26) + { + switch(cmd[1]){ + case ISO15693_INVENTORY :snprintf(exp, size, "INVENTORY");break; + case ISO15693_STAYQUIET :snprintf(exp, size, "STAY_QUIET");break; + default: snprintf(exp,size,"?"); break; + + } + }else if(cmd[0] == 0x02) + { + switch(cmd[1]) + { + case ISO15693_READBLOCK :snprintf(exp, size, "READBLOCK");break; + case ISO15693_WRITEBLOCK :snprintf(exp, size, "WRITEBLOCK");break; + case ISO15693_LOCKBLOCK :snprintf(exp, size, "LOCKBLOCK");break; + case ISO15693_READ_MULTI_BLOCK :snprintf(exp, size, "READ_MULTI_BLOCK");break; + case ISO15693_SELECT :snprintf(exp, size, "SELECT");break; + case ISO15693_RESET_TO_READY :snprintf(exp, size, "RESET_TO_READY");break; + case ISO15693_WRITE_AFI :snprintf(exp, size, "WRITE_AFI");break; + case ISO15693_LOCK_AFI :snprintf(exp, size, "LOCK_AFI");break; + case ISO15693_WRITE_DSFID :snprintf(exp, size, "WRITE_DSFID");break; + case ISO15693_LOCK_DSFID :snprintf(exp, size, "LOCK_DSFID");break; + case ISO15693_GET_SYSTEM_INFO :snprintf(exp, size, "GET_SYSTEM_INFO");break; + case ISO15693_READ_MULTI_SECSTATUS :snprintf(exp, size, "READ_MULTI_SECSTATUS");break; + default: snprintf(exp,size,"?"); break; + } + } +} + + +void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + switch(cmd[0]) { + case TOPAZ_REQA :snprintf(exp, size, "REQA");break; + case TOPAZ_WUPA :snprintf(exp, size, "WUPA");break; + case TOPAZ_RID :snprintf(exp, size, "RID");break; + case TOPAZ_RALL :snprintf(exp, size, "RALL");break; + case TOPAZ_READ :snprintf(exp, size, "READ");break; + case TOPAZ_WRITE_E :snprintf(exp, size, "WRITE-E");break; + case TOPAZ_WRITE_NE :snprintf(exp, size, "WRITE-NE");break; + case TOPAZ_RSEG :snprintf(exp, size, "RSEG");break; + case TOPAZ_READ8 :snprintf(exp, size, "READ8");break; + case TOPAZ_WRITE_E8 :snprintf(exp, size, "WRITE-E8");break; + case TOPAZ_WRITE_NE8 :snprintf(exp, size, "WRITE-NE8");break; + default: snprintf(exp,size,"?"); break; + } +} + + +/** +06 00 = INITIATE +0E xx = SELECT ID (xx = Chip-ID) +0B = Get UID +08 yy = Read Block (yy = block number) +09 yy dd dd dd dd = Write Block (yy = block number; dd dd dd dd = data to be written) +0C = Reset to Inventory +0F = Completion +0A 11 22 33 44 55 66 = Authenticate (11 22 33 44 55 66 = data to authenticate) +**/ + +void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + switch(cmd[0]){ + case ISO14443B_REQB : snprintf(exp,size,"REQB");break; + case ISO14443B_ATTRIB : snprintf(exp,size,"ATTRIB");break; + case ISO14443B_HALT : snprintf(exp,size,"HALT");break; + case ISO14443B_INITIATE : snprintf(exp,size,"INITIATE");break; + case ISO14443B_SELECT : snprintf(exp,size,"SELECT(%d)",cmd[1]);break; + case ISO14443B_GET_UID : snprintf(exp,size,"GET UID");break; + case ISO14443B_READ_BLK : snprintf(exp,size,"READ_BLK(%d)", cmd[1]);break; + case ISO14443B_WRITE_BLK : snprintf(exp,size,"WRITE_BLK(%d)",cmd[1]);break; + case ISO14443B_RESET : snprintf(exp,size,"RESET");break; + case ISO14443B_COMPLETION : snprintf(exp,size,"COMPLETION");break; + case ISO14443B_AUTHENTICATE : snprintf(exp,size,"AUTHENTICATE");break; + default : snprintf(exp,size ,"?");break; + } + +} + +void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + switch(cmd[0]) + { + case ISO14443A_CMD_WUPA: + snprintf(exp,size,"WUPA"); + break; + case ISO14443A_CMD_ANTICOLL_OR_SELECT:{ + // 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor) + // 93 70 = Select (usage: 9370+5bytes 9320 answer - answer: 1byte SAK) + if(cmd[1] == 0x70) + { + snprintf(exp,size,"SELECT_UID"); break; + }else + { + snprintf(exp,size,"ANTICOLL"); break; + } + } + case ISO14443A_CMD_ANTICOLL_OR_SELECT_2:{ + //95 20 = Anticollision of cascade level2 + //95 70 = Select of cascade level2 + if(cmd[2] == 0x70) + { + snprintf(exp,size,"SELECT_UID-2"); break; + }else + { + snprintf(exp,size,"ANTICOLL-2"); break; + } + } + case ISO14443A_CMD_REQA: + snprintf(exp,size,"REQA"); + break; + case ISO14443A_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; + case ISO14443A_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; + case ISO14443A_CMD_HALT: + snprintf(exp,size,"HALT"); + MifareAuthState = masNone; + break; + case ISO14443A_CMD_RATS: snprintf(exp,size,"RATS"); break; + case MIFARE_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break; + case MIFARE_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break; + case MIFARE_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break; + case MIFARE_CMD_TRANSFER: snprintf(exp,size,"TRANSFER(%d)",cmd[1]); break; + case MIFARE_AUTH_KEYA: + if ( cmdsize > 3) { + snprintf(exp,size,"AUTH-A(%d)",cmd[1]); + MifareAuthState = masNt; + } else { + // case MIFARE_ULEV1_VERSION : both 0x60. + snprintf(exp,size,"EV1 VERSION"); + } + break; + case MIFARE_AUTH_KEYB: + MifareAuthState = masNt; + snprintf(exp,size,"AUTH-B(%d)",cmd[1]); + break; + case MIFARE_MAGICWUPC1: snprintf(exp,size,"MAGIC WUPC1"); break; + case MIFARE_MAGICWUPC2: snprintf(exp,size,"MAGIC WUPC2"); break; + case MIFARE_MAGICWIPEC: snprintf(exp,size,"MAGIC WIPEC"); break; + case MIFARE_ULC_AUTH_1: snprintf(exp,size,"AUTH "); break; + case MIFARE_ULC_AUTH_2: snprintf(exp,size,"AUTH_ANSW"); break; + case MIFARE_ULEV1_AUTH: + if ( cmdsize == 7 ) + snprintf(exp,size,"PWD-AUTH KEY: 0x%02x%02x%02x%02x", cmd[1], cmd[2], cmd[3], cmd[4] ); + else + snprintf(exp,size,"PWD-AUTH"); + break; + case MIFARE_ULEV1_FASTREAD:{ + if ( cmdsize >=3 && cmd[2] <= 0xE6) + snprintf(exp,size,"READ RANGE (%d-%d)",cmd[1],cmd[2]); + else + snprintf(exp,size,"?"); + break; + } + case MIFARE_ULC_WRITE:{ + if ( cmd[1] < 0x21 ) + snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); + else + snprintf(exp,size,"?"); + break; + } + case MIFARE_ULEV1_READ_CNT:{ + if ( cmd[1] < 5 ) + snprintf(exp,size,"READ CNT(%d)",cmd[1]); + else + snprintf(exp,size,"?"); + break; + } + case MIFARE_ULEV1_INCR_CNT:{ + if ( cmd[1] < 5 ) + snprintf(exp,size,"INCR(%d)",cmd[1]); + else + snprintf(exp,size,"?"); + break; + } + case MIFARE_ULEV1_READSIG: snprintf(exp,size,"READ_SIG"); break; + case MIFARE_ULEV1_CHECKTEAR: snprintf(exp,size,"CHK_TEARING(%d)",cmd[1]); break; + case MIFARE_ULEV1_VCSL: snprintf(exp,size,"VCSL"); break; + default: snprintf(exp,size,"?"); break; + } + return; +} + +void annotateMifare(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize, uint8_t* parity, uint8_t paritysize, bool isResponse) { + if (!isResponse && cmdsize == 1) { + switch(cmd[0]) { + case ISO14443A_CMD_WUPA: + case ISO14443A_CMD_REQA: + MifareAuthState = masNone; + break; + default: + break; + } + } + + // get UID + if (MifareAuthState == masNone) { + if (cmdsize == 9 && cmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && cmd[1] == 0x70) { + ClearAuthData(); + AuthData.uid = bytes_to_num(&cmd[2], 4); + } + if (cmdsize == 9 && cmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && cmd[1] == 0x70) { + ClearAuthData(); + AuthData.uid = bytes_to_num(&cmd[2], 4); + } + } + + switch(MifareAuthState) { + case masNt: + if (cmdsize == 4 && isResponse) { + snprintf(exp,size,"AUTH: nt %s", (AuthData.first_auth) ? "" : "(enc)"); + MifareAuthState = masNrAr; + if (AuthData.first_auth) { + AuthData.nt = bytes_to_num(cmd, 4); + } else { + AuthData.nt_enc = bytes_to_num(cmd, 4); + AuthData.nt_enc_par = parity[0]; + } + return; + } else { + MifareAuthState = masError; + } + break; + case masNrAr: + if (cmdsize == 8 && !isResponse) { + snprintf(exp,size,"AUTH: nr ar (enc)"); + MifareAuthState = masAt; + AuthData.nr_enc = bytes_to_num(cmd, 4); + AuthData.ar_enc = bytes_to_num(&cmd[4], 4); + AuthData.ar_enc_par = parity[0] << 4; + return; + } else { + MifareAuthState = masError; + } + break; + case masAt: + if (cmdsize == 4 && isResponse) { + snprintf(exp,size,"AUTH: at (enc)"); + MifareAuthState = masAuthComplete; + AuthData.at_enc = bytes_to_num(cmd, 4); + AuthData.at_enc_par = parity[0]; + return; + } else { + MifareAuthState = masError; + } + break; + default: + break; + } + + if (!isResponse && ((MifareAuthState == masNone) || (MifareAuthState == masError))) + annotateIso14443a(exp, size, cmd, cmdsize); + +} + +bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen) { + static struct Crypto1State *traceCrypto1; + static uint64_t mfLastKey; + + *mfDataLen = 0; + + if (MifareAuthState == masAuthComplete) { + if (traceCrypto1) { + crypto1_destroy(traceCrypto1); + traceCrypto1 = NULL; + } + + MifareAuthState = masFirstData; + return false; + } + + if (cmdsize > 32) + return false; + + if (MifareAuthState == masFirstData) { + if (AuthData.first_auth) { + AuthData.ks2 = AuthData.ar_enc ^ prng_successor(AuthData.nt, 64); + AuthData.ks3 = AuthData.at_enc ^ prng_successor(AuthData.nt, 96); + + mfLastKey = GetCrypto1ProbableKey(&AuthData); + PrintAndLog(" | * | key | probable key:%012"PRIx64" Prng:%s ks2:%08x ks3:%08x | |", + mfLastKey, + validate_prng_nonce(AuthData.nt) ? "WEAK": "HARD", + AuthData.ks2, + AuthData.ks3); + + AuthData.first_auth = false; + + traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3); + } else { + if (traceCrypto1) { + crypto1_destroy(traceCrypto1); + traceCrypto1 = NULL; + } + + // check last used key + if (mfLastKey) { + if (NestedCheckKey(mfLastKey, &AuthData, cmd, cmdsize, parity)) { + PrintAndLog(" | * | key | last used key:%012"PRIx64" ks2:%08x ks3:%08x | |", + mfLastKey, + AuthData.ks2, + AuthData.ks3); + + traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3); + }; + } + + // check default keys + if (!traceCrypto1) { + for (int defaultKeyCounter = 0; defaultKeyCounter < MifareDefaultKeysSize; defaultKeyCounter++){ + if (NestedCheckKey(MifareDefaultKeys[defaultKeyCounter], &AuthData, cmd, cmdsize, parity)) { + PrintAndLog(" | * | key | default key:%012"PRIx64" ks2:%08x ks3:%08x | |", + MifareDefaultKeys[defaultKeyCounter], + AuthData.ks2, + AuthData.ks3); + + mfLastKey = MifareDefaultKeys[defaultKeyCounter]; + traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3); + break; + }; + } + } + + // nested + if (!traceCrypto1 && validate_prng_nonce(AuthData.nt)) { + uint32_t ntx = prng_successor(AuthData.nt, 90); + for (int i = 0; i < 16383; i++) { + ntx = prng_successor(ntx, 1); + if (NTParityChk(&AuthData, ntx)){ + + uint32_t ks2 = AuthData.ar_enc ^ prng_successor(ntx, 64); + uint32_t ks3 = AuthData.at_enc ^ prng_successor(ntx, 96); + struct Crypto1State *pcs = lfsr_recovery64(ks2, ks3); + memcpy(mfData, cmd, cmdsize); + mf_crypto1_decrypt(pcs, mfData, cmdsize, 0); + + crypto1_destroy(pcs); + if (CheckCrypto1Parity(cmd, cmdsize, mfData, parity) && CheckCrc14443(CRC_14443_A, mfData, cmdsize)) { + AuthData.ks2 = ks2; + AuthData.ks3 = ks3; + + AuthData.nt = ntx; + mfLastKey = GetCrypto1ProbableKey(&AuthData); + PrintAndLog(" | * | key | nested probable key:%012"PRIx64" ks2:%08x ks3:%08x | |", + mfLastKey, + AuthData.ks2, + AuthData.ks3); + + traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3); + break; + } + } + } + } + + //hardnested + if (!traceCrypto1) { + printf("hardnested not implemented. uid:%x nt:%x ar_enc:%x at_enc:%x\n", AuthData.uid, AuthData.nt, AuthData.ar_enc, AuthData.at_enc); + MifareAuthState = masError; + + /* TOO SLOW( needs to have more strong filter. with this filter - aprox 4 mln tests + uint32_t t = msclock(); + uint32_t t1 = t; + int n = 0; + for (uint32_t i = 0; i < 0xFFFFFFFF; i++) { + if (NTParityChk(&AuthData, i)){ + + uint32_t ks2 = AuthData.ar_enc ^ prng_successor(i, 64); + uint32_t ks3 = AuthData.at_enc ^ prng_successor(i, 96); + struct Crypto1State *pcs = lfsr_recovery64(ks2, ks3); + + + + + n++; + + if (!(n % 100000)) { + printf("delta=%d n=%d ks2=%x ks3=%x \n", msclock() - t1 , n, ks2, ks3); + t1 = msclock(); + } + + } + } + printf("delta=%d n=%d\n", msclock() - t, n); + */ + } + } + + + + MifareAuthState = masData; + } + + if (MifareAuthState == masData && traceCrypto1) { + memcpy(mfData, cmd, cmdsize); + mf_crypto1_decrypt(traceCrypto1, mfData, cmdsize, 0); + *mfDataLen = cmdsize; + } + + return *mfDataLen > 0; +} + +bool NTParityChk(TAuthData *ad, uint32_t ntx) { + if ( + (oddparity8(ntx >> 8 & 0xff) ^ (ntx & 0x01) ^ ((ad->nt_enc_par >> 5) & 0x01) ^ (ad->nt_enc & 0x01)) || + (oddparity8(ntx >> 16 & 0xff) ^ (ntx >> 8 & 0x01) ^ ((ad->nt_enc_par >> 6) & 0x01) ^ (ad->nt_enc >> 8 & 0x01)) || + (oddparity8(ntx >> 24 & 0xff) ^ (ntx >> 16 & 0x01) ^ ((ad->nt_enc_par >> 7) & 0x01) ^ (ad->nt_enc >> 16 & 0x01)) + ) + return false; + + uint32_t ar = prng_successor(ntx, 64); + if ( + (oddparity8(ar >> 8 & 0xff) ^ (ar & 0x01) ^ ((ad->ar_enc_par >> 5) & 0x01) ^ (ad->ar_enc & 0x01)) || + (oddparity8(ar >> 16 & 0xff) ^ (ar >> 8 & 0x01) ^ ((ad->ar_enc_par >> 6) & 0x01) ^ (ad->ar_enc >> 8 & 0x01)) || + (oddparity8(ar >> 24 & 0xff) ^ (ar >> 16 & 0x01) ^ ((ad->ar_enc_par >> 7) & 0x01) ^ (ad->ar_enc >> 16 & 0x01)) + ) + return false; + + uint32_t at = prng_successor(ntx, 96); + if ( + (oddparity8(ar & 0xff) ^ (at >> 24 & 0x01) ^ ((ad->ar_enc_par >> 4) & 0x01) ^ (ad->at_enc >> 24 & 0x01)) || + (oddparity8(at >> 8 & 0xff) ^ (at & 0x01) ^ ((ad->at_enc_par >> 5) & 0x01) ^ (ad->at_enc & 0x01)) || + (oddparity8(at >> 16 & 0xff) ^ (at >> 8 & 0x01) ^ ((ad->at_enc_par >> 6) & 0x01) ^ (ad->at_enc >> 8 & 0x01)) || + (oddparity8(at >> 24 & 0xff) ^ (at >> 16 & 0x01) ^ ((ad->at_enc_par >> 7) & 0x01) ^ (ad->at_enc >> 16 & 0x01)) + ) + return false; + + return true; +} + +bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity) { + uint8_t buf[32] = {0}; + struct Crypto1State *pcs; + + AuthData.ks2 = 0; + AuthData.ks3 = 0; + + pcs = crypto1_create(key); + uint32_t nt1 = crypto1_word(pcs, ad->nt_enc ^ ad->uid, 1) ^ ad->nt_enc; + uint32_t ar = prng_successor(nt1, 64); + uint32_t at = prng_successor(nt1, 96); + + crypto1_word(pcs, ad->nr_enc, 1); +// uint32_t nr1 = crypto1_word(pcs, ad->nr_enc, 1) ^ ad->nr_enc; // if needs deciphered nr + uint32_t ar1 = crypto1_word(pcs, 0, 0) ^ ad->ar_enc; + uint32_t at1 = crypto1_word(pcs, 0, 0) ^ ad->at_enc; + + if (!(ar == ar1 && at == at1 && NTParityChk(ad, nt1))) { + crypto1_destroy(pcs); + return false; + } + + memcpy(buf, cmd, cmdsize); + mf_crypto1_decrypt(pcs, buf, cmdsize, 0); + + crypto1_destroy(pcs); + + if (!CheckCrypto1Parity(cmd, cmdsize, buf, parity)) + return false; + + if(!CheckCrc14443(CRC_14443_A, buf, cmdsize)) + return false; + + AuthData.nt = nt1; + AuthData.ks2 = AuthData.ar_enc ^ ar; + AuthData.ks3 = AuthData.at_enc ^ at; + + return true; +} + +bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, uint8_t *parity_enc) { + for (int i = 0; i < cmdsize - 1; i++) { + if (oddparity8(cmd[i]) ^ (cmd[i + 1] & 0x01) ^ ((parity_enc[i / 8] >> (7 - i % 8)) & 0x01) ^ (cmd_enc[i + 1] & 0x01)) + return false; + } + + return true; +} + +uint64_t GetCrypto1ProbableKey(TAuthData *ad) { + struct Crypto1State *revstate = lfsr_recovery64(ad->ks2, ad->ks3); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, ad->nr_enc, 1); + lfsr_rollback_word(revstate, ad->uid ^ ad->nt, 0); + + uint64_t lfsr = 0; + crypto1_get_lfsr(revstate, &lfsr); + crypto1_destroy(revstate); + + return lfsr; +} diff --git a/client/cmdhflist.h b/client/cmdhflist.h new file mode 100644 index 00000000..8f289b48 --- /dev/null +++ b/client/cmdhflist.h @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Merlok - 2017 +// +// 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. +//----------------------------------------------------------------------------- +// Command: hf mf list. It shows data from arm buffer. +//----------------------------------------------------------------------------- +#ifndef CMDHFLIST_H +#define CMDHFLIST_H + +#include +#include +#include + +typedef struct { + uint32_t uid; // UID + uint32_t nt; // tag challenge + uint32_t nt_enc; // encrypted tag challenge + uint8_t nt_enc_par; // encrypted tag challenge parity + uint32_t nr_enc; // encrypted reader challenge + uint32_t ar_enc; // encrypted reader response + uint8_t ar_enc_par; // encrypted reader response parity + uint32_t at_enc; // encrypted tag response + uint8_t at_enc_par; // encrypted tag response parity + bool first_auth; // is first authentication + uint32_t ks2; // ar ^ ar_enc + uint32_t ks3; // at ^ at_enc +} TAuthData; +extern void ClearAuthData(); + +extern uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len); +extern uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len); +extern void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize); +extern void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize); +extern void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize); +extern void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize); +extern void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize); +extern void annotateMifare(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize, uint8_t* parity, uint8_t paritysize, bool isResponse); +extern bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen); +extern bool NTParityChk(TAuthData *ad, uint32_t ntx); +extern bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity); +extern bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, uint8_t *parity_enc); +extern uint64_t GetCrypto1ProbableKey(TAuthData *ad); + +#endif // CMDHFLIST diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index c471fdf7..e2a4ba1e 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -15,9 +15,10 @@ #include #include #include -#include "proxmark3.h" +#include "comms.h" #include "cmdmain.h" #include "cmdhfmfhard.h" +#include "parity.h" #include "util.h" #include "util_posix.h" #include "usb_cmd.h" @@ -25,6 +26,7 @@ #include "mifarehost.h" #include "mifare.h" #include "mfkey.h" +#include "hardnested/hardnested_bf_core.h" #define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up @@ -682,9 +684,9 @@ int CmdHF14AMfNested(const char *Cmd) if (transferToEml) { uint8_t sectortrailer; if (trgBlockNo < 32*4) { // 4 block sector - sectortrailer = (trgBlockNo & 0x03) + 3; + sectortrailer = trgBlockNo | 0x03; } else { // 16 block sector - sectortrailer = (trgBlockNo & 0x0f) + 15; + sectortrailer = trgBlockNo | 0x0f; } mfEmlGetMem(keyBlock, sectortrailer, 1); @@ -724,7 +726,6 @@ int CmdHF14AMfNested(const char *Cmd) blockNo = i * 4; keyType = j; num_to_bytes(e_sector[i].Key[j], 6, key); - keyFound = true; break; } @@ -735,6 +736,7 @@ int CmdHF14AMfNested(const char *Cmd) // Can't found a key.... if (!keyFound) { PrintAndLog("Can't found any of the known keys."); + free(e_sector); return 4; } PrintAndLog("--auto key. block no:%3d, key type:%c key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6)); @@ -862,6 +864,13 @@ int CmdHF14AMfNestedHard(const char *Cmd) PrintAndLog(" w: Acquire nonces and write them to binary file nonces.bin"); PrintAndLog(" s: Slower acquisition (required by some non standard cards)"); PrintAndLog(" r: Read nonces.bin and start attack"); + PrintAndLog(" iX: set type of SIMD instructions. Without this flag programs autodetect it."); + PrintAndLog(" i5: AVX512"); + PrintAndLog(" i2: AVX2"); + PrintAndLog(" ia: AVX"); + PrintAndLog(" is: SSE2"); + PrintAndLog(" im: MMX"); + PrintAndLog(" in: none (use CPU regular instruction set)"); PrintAndLog(" "); PrintAndLog(" sample1: hf mf hardnested 0 A FFFFFFFFFFFF 4 A"); PrintAndLog(" sample2: hf mf hardnested 0 A FFFFFFFFFFFF 4 A w"); @@ -880,15 +889,20 @@ int CmdHF14AMfNestedHard(const char *Cmd) int tests = 0; + uint16_t iindx = 0; if (ctmp == 'R' || ctmp == 'r') { nonce_file_read = true; + iindx = 1; if (!param_gethex(Cmd, 1, trgkey, 12)) { know_target_key = true; + iindx = 2; } } else if (ctmp == 'T' || ctmp == 't') { tests = param_get32ex(Cmd, 1, 100, 10); + iindx = 2; if (!param_gethex(Cmd, 2, trgkey, 12)) { know_target_key = true; + iindx = 3; } } else { blockNo = param_get8(Cmd, 0); @@ -922,19 +936,54 @@ int CmdHF14AMfNestedHard(const char *Cmd) know_target_key = true; i++; } + iindx = i; while ((ctmp = param_getchar(Cmd, i))) { if (ctmp == 's' || ctmp == 'S') { slow = true; } else if (ctmp == 'w' || ctmp == 'W') { nonce_file_write = true; + } else if (param_getlength(Cmd, i) == 2 && ctmp == 'i') { + iindx = i; } else { - PrintAndLog("Possible options are w and/or s"); + PrintAndLog("Possible options are w , s and/or iX"); return 1; } i++; } } + + SetSIMDInstr(SIMD_AUTO); + if (iindx > 0) { + while ((ctmp = param_getchar(Cmd, iindx))) { + if (param_getlength(Cmd, iindx) == 2 && ctmp == 'i') { + switch(param_getchar_indx(Cmd, 1, iindx)) { + case '5': + SetSIMDInstr(SIMD_AVX512); + break; + case '2': + SetSIMDInstr(SIMD_AVX2); + break; + case 'a': + SetSIMDInstr(SIMD_AVX); + break; + case 's': + SetSIMDInstr(SIMD_SSE2); + break; + case 'm': + SetSIMDInstr(SIMD_MMX); + break; + case 'n': + SetSIMDInstr(SIMD_NONE); + break; + default: + PrintAndLog("Unknown SIMD type. %c", param_getchar_indx(Cmd, 1, iindx)); + return 1; + } + } + iindx++; + } + } PrintAndLog("--target block no:%3d, target key type:%c, known target key: 0x%02x%02x%02x%02x%02x%02x%s, file action: %s, Slow: %s, Tests: %d ", trgBlockNo, @@ -1138,7 +1187,10 @@ int CmdHF14AMfChk(const char *Cmd) // initialize storage for found keys e_sector = calloc(SectorsCnt, sizeof(sector_t)); - if (e_sector == NULL) return 1; + if (e_sector == NULL) { + free(keyBlock); + return 1; + } for (uint8_t keyAB = 0; keyAB < 2; keyAB++) { for (uint16_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) { e_sector[sectorNo].Key[keyAB] = 0xffffffffffff; @@ -1637,10 +1689,7 @@ int CmdHF14AMfESet(const char *Cmd) } // 1 - blocks count - UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNo, 1, 0}}; - memcpy(c.d.asBytes, memBlock, 16); - SendCommand(&c); - return 0; + return mfEmlSetMem(memBlock, blockNo, 1); } @@ -1859,7 +1908,7 @@ int CmdHF14AMfECFill(const char *Cmd) default: numSectors = 16; } - printf("--params: numSectors: %d, keyType:%d", numSectors, keyType); + printf("--params: numSectors: %d, keyType:%d\n", numSectors, keyType); UsbCommand c = {CMD_MIFARE_EML_CARDLOAD, {numSectors, keyType, 0}}; SendCommand(&c); return 0; @@ -2425,6 +2474,7 @@ int CmdHF14AMfSniff(const char *Cmd){ //var int res = 0; int len = 0; + int parlen = 0; int blockLen = 0; int pckNum = 0; int num = 0; @@ -2436,6 +2486,7 @@ int CmdHF14AMfSniff(const char *Cmd){ uint8_t *buf = NULL; uint16_t bufsize = 0; uint8_t *bufPtr = NULL; + uint8_t parity[16]; char ctmp = param_getchar(Cmd, 0); if ( ctmp == 'h' || ctmp == 'H' ) { @@ -2479,14 +2530,13 @@ int CmdHF14AMfSniff(const char *Cmd){ } UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,2000)) { + if (WaitForResponseTimeoutW(CMD_ACK, &resp, 2000, false)) { res = resp.arg[0] & 0xff; uint16_t traceLen = resp.arg[1]; len = resp.arg[2]; if (res == 0) { // we are done - free(buf); - return 0; + break; } if (res == 1) { // there is (more) data to be transferred @@ -2528,6 +2578,7 @@ int CmdHF14AMfSniff(const char *Cmd){ } else { isTag = false; } + parlen = (len - 1) / 8 + 1; bufPtr += 2; if ((len == 14) && (bufPtr[0] == 0xff) && (bufPtr[1] == 0xff) && (bufPtr[12] == 0xff) && (bufPtr[13] == 0xff)) { memcpy(uid, bufPtr + 2, 7); @@ -2546,15 +2597,22 @@ int CmdHF14AMfSniff(const char *Cmd){ if (wantDecrypt) mfTraceInit(uid, atqa, sak, wantSaveToEmlFile); } else { - PrintAndLog("%s(%d):%s", isTag ? "TAG":"RDR", num, sprint_hex(bufPtr, len)); + oddparitybuf(bufPtr, len, parity); + PrintAndLog("%s(%d):%s [%s] c[%s]%c", + isTag ? "TAG":"RDR", + num, + sprint_hex(bufPtr, len), + printBitsPar(bufPtr + len, len), + printBitsPar(parity, len), + memcmp(bufPtr + len, parity, len / 8 + 1) ? '!' : ' '); if (wantLogToFile) AddLogHex(logHexFileName, isTag ? "TAG: ":"RDR: ", bufPtr, len); if (wantDecrypt) - mfTraceDecode(bufPtr, len, wantSaveToEmlFile); + mfTraceDecode(bufPtr, len, bufPtr[len], wantSaveToEmlFile); num++; } bufPtr += len; - bufPtr += ((len-1)/8+1); // ignore parity + bufPtr += parlen; // ignore parity } pckNum = 0; } @@ -2562,6 +2620,9 @@ int CmdHF14AMfSniff(const char *Cmd){ } // while (true) free(buf); + + msleep(300); // wait for exiting arm side. + PrintAndLog("Done."); return 0; } @@ -2608,11 +2669,9 @@ static command_t CommandTable[] = int CmdHFMF(const char *Cmd) { - // flush - WaitForResponseTimeout(CMD_ACK,NULL,100); - - CmdsParse(CommandTable, Cmd); - return 0; + (void)WaitForResponseTimeout(CMD_ACK,NULL,100); + CmdsParse(CommandTable, Cmd); + return 0; } int CmdHelp(const char *Cmd) diff --git a/client/cmdhfmfhard.c b/client/cmdhfmfhard.c index 0153541e..4a379c71 100644 --- a/client/cmdhfmfhard.c +++ b/client/cmdhfmfhard.c @@ -25,6 +25,7 @@ #include #include #include "proxmark3.h" +#include "comms.h" #include "cmdmain.h" #include "ui.h" #include "util.h" @@ -32,6 +33,7 @@ #include "crapto1/crapto1.h" #include "parity.h" #include "hardnested/hardnested_bruteforce.h" +#include "hardnested/hardnested_bf_core.h" #include "hardnested/hardnested_bitarray_core.h" #include "zlib.h" @@ -71,27 +73,32 @@ static float brute_force_per_second; static void get_SIMD_instruction_set(char* instruction_set) { -#if defined (__i386__) || defined (__x86_64__) - #if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1)) - #if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2) - if (__builtin_cpu_supports("avx512f")) strcpy(instruction_set, "AVX512F"); - else if (__builtin_cpu_supports("avx2")) strcpy(instruction_set, "AVX2"); - #else - if (__builtin_cpu_supports("avx2")) strcpy(instruction_set, "AVX2"); - #endif - else if (__builtin_cpu_supports("avx")) strcpy(instruction_set, "AVX"); - else if (__builtin_cpu_supports("sse2")) strcpy(instruction_set, "SSE2"); - else if (__builtin_cpu_supports("mmx")) strcpy(instruction_set, "MMX"); - else - #endif -#endif - strcpy(instruction_set, "no"); + switch(GetSIMDInstrAuto()) { + case SIMD_AVX512: + strcpy(instruction_set, "AVX512F"); + break; + case SIMD_AVX2: + strcpy(instruction_set, "AVX2"); + break; + case SIMD_AVX: + strcpy(instruction_set, "AVX"); + break; + case SIMD_SSE2: + strcpy(instruction_set, "SSE2"); + break; + case SIMD_MMX: + strcpy(instruction_set, "MMX"); + break; + default: + strcpy(instruction_set, "no"); + break; + } } static void print_progress_header(void) { char progress_text[80]; - char instr_set[12] = ""; + char instr_set[12] = {0}; get_SIMD_instruction_set(instr_set); sprintf(progress_text, "Start using %d threads and %s SIMD core", num_CPUs(), instr_set); PrintAndLog("\n\n"); @@ -144,12 +151,6 @@ static inline void set_bit24(uint32_t *bitarray, uint32_t index) } -static inline void clear_bit24(uint32_t *bitarray, uint32_t index) -{ - bitarray[index>>5] &= ~(0x80000000>>(index&0x0000001f)); -} - - static inline uint32_t test_bit24(uint32_t *bitarray, uint32_t index) { return bitarray[index>>5] & (0x80000000>>(index&0x0000001f)); @@ -190,40 +191,6 @@ static inline uint32_t next_state(uint32_t *bitarray, uint32_t state) } -static inline uint32_t next_not_state(uint32_t *bitarray, uint32_t state) -{ - if (++state == 1<<24) return 1<<24; - uint32_t index = state >> 5; - uint_fast8_t bit = state & 0x1f; - uint32_t line = bitarray[index] << bit; - while (bit <= 0x1f) { - if ((line & 0x80000000) == 0) return state; - state++; - bit++; - line <<= 1; - } - index++; - while (bitarray[index] == 0xffffffff && state < 1<<24) { - index++; - state += 0x20; - } - if (state >= 1<<24) return 1<<24; -#if defined __GNUC__ - return state + __builtin_clz(~bitarray[index]); -#else - bit = 0x00; - line = bitarray[index]; - while (bit <= 0x1f) { - if ((line & 0x80000000) == 0) return state; - state++; - bit++; - line <<= 1; - } - return 1<<24; -#endif -} - - #define BITFLIP_2ND_BYTE 0x0200 @@ -309,7 +276,6 @@ static void init_bitflip_bitarrays(void) if (bytesread != filesize) { printf("File read error with %s. Aborting...\n", state_file_name); fclose(statesfile); - inflateEnd(&compressed_stream); exit(5); } fclose(statesfile); @@ -1192,7 +1158,13 @@ static bool timeout(void) } -static void *check_for_BitFlipProperties_thread(void *args) +static void +#ifdef __has_attribute +#if __has_attribute(force_align_arg_pointer) +__attribute__((force_align_arg_pointer)) +#endif +#endif +*check_for_BitFlipProperties_thread(void *args) { uint8_t first_byte = ((uint8_t *)args)[0]; uint8_t last_byte = ((uint8_t *)args)[1]; @@ -1940,7 +1912,13 @@ static void init_book_of_work(void) } -static void *generate_candidates_worker_thread(void *args) +static void +#ifdef __has_attribute +#if __has_attribute(force_align_arg_pointer) +__attribute__((force_align_arg_pointer)) +#endif +#endif +*generate_candidates_worker_thread(void *args) { uint16_t *sum_args = (uint16_t *)args; uint16_t sum_a0 = sums[sum_args[0]]; @@ -2528,6 +2506,10 @@ static void set_test_state(uint8_t byte) int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *trgkey, bool nonce_file_read, bool nonce_file_write, bool slow, int tests) { char progress_text[80]; + + char instr_set[12] = {0}; + get_SIMD_instruction_set(instr_set); + PrintAndLog("Using %s SIMD core.", instr_set); srand((unsigned) time(NULL)); brute_force_per_second = brute_force_benchmark(); diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index 63c41728..1077ec99 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -12,7 +12,7 @@ #include #include -#include "proxmark3.h" +#include "comms.h" #include "usb_cmd.h" #include "cmdmain.h" #include "ui.h" @@ -22,7 +22,6 @@ #include "mifare.h" #include "util.h" #include "protocols.h" -#include "data.h" #define MAX_UL_BLOCKS 0x0f #define MAX_ULC_BLOCKS 0x2b @@ -1325,8 +1324,7 @@ int CmdHF14AMfUDump(const char *Cmd){ PrintAndLog("Data exceeded Buffer size!"); bufferSize = sizeof(data); } - GetFromBigBuf(data, bufferSize, startindex); - WaitForResponse(CMD_ACK,NULL); + GetFromBigBuf(data, bufferSize, startindex, NULL, -1, false); Pages = bufferSize/4; // Load lock bytes. @@ -1836,7 +1834,7 @@ static command_t CommandTable[] = }; int CmdHFMFUltra(const char *Cmd){ - WaitForResponseTimeout(CMD_ACK,NULL,100); + (void)WaitForResponseTimeout(CMD_ACK,NULL,100); CmdsParse(CommandTable, Cmd); return 0; } diff --git a/client/cmdhftopaz.c b/client/cmdhftopaz.c index 39ff1804..6058cabe 100644 --- a/client/cmdhftopaz.c +++ b/client/cmdhftopaz.c @@ -8,17 +8,18 @@ // High frequency Topaz (NFC Type 1) commands //----------------------------------------------------------------------------- +#include "cmdhftopaz.h" + #include #include #include #include #include "cmdmain.h" #include "cmdparser.h" -#include "cmdhftopaz.h" #include "cmdhf14a.h" #include "ui.h" #include "mifare.h" -#include "proxmark3.h" +#include "comms.h" #include "iso14443crc.h" #include "protocols.h" @@ -454,7 +455,7 @@ int CmdHFTopazReader(const char *Cmd) PrintAndLog("HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)", rid_response[0], (rid_response[0] & 0xF0) == 0x10 ? "" : "not ", (rid_response[0] & 0xF0) == 0x10 ? "" : "not ", - (rid_response[0] & 0x0F) == 0x10 ? "static" : "dynamic"); + (rid_response[0] & 0x0F) == 0x01 ? "static" : "dynamic"); PrintAndLog("HR1 : %02x", rid_response[1]); status = topaz_rall(uid_echo, rall_response); @@ -553,10 +554,7 @@ static command_t CommandTable[] = int CmdHFTopaz(const char *Cmd) { - // flush - WaitForResponseTimeout(CMD_ACK,NULL,100); - - // parse + (void)WaitForResponseTimeout(CMD_ACK,NULL,100); CmdsParse(CommandTable, Cmd); return 0; } diff --git a/client/cmdhw.c b/client/cmdhw.c index 8f7243ad..f994e938 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -8,17 +8,17 @@ // Hardware commands //----------------------------------------------------------------------------- +#include "cmdhw.h" + #include #include #include #include #include "ui.h" -#include "proxmark3.h" +#include "comms.h" #include "cmdparser.h" -#include "cmdhw.h" #include "cmdmain.h" #include "cmddata.h" -#include "data.h" /* low-level hardware control */ @@ -408,34 +408,23 @@ int CmdVersion(const char *Cmd) clearCommandBuffer(); UsbCommand c = {CMD_VERSION}; - static UsbCommand resp = {0, {0, 0, 0}}; + UsbCommand resp = {0, {0, 0, 0}}; - if (resp.arg[0] == 0 && resp.arg[1] == 0) { // no cached information available - SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { - PrintAndLog("Prox/RFID mark3 RFID instrument"); - PrintAndLog((char*)resp.d.asBytes); - lookupChipID(resp.arg[0], resp.arg[1]); - } - } else { - PrintAndLog("[[[ Cached information ]]]\n"); + SendCommand(&c); + if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { PrintAndLog("Prox/RFID mark3 RFID instrument"); PrintAndLog((char*)resp.d.asBytes); lookupChipID(resp.arg[0], resp.arg[1]); - PrintAndLog(""); } return 0; } int CmdStatus(const char *Cmd) { - uint8_t speed_test_buffer[USB_CMD_DATA_SIZE]; - sample_buf = speed_test_buffer; - clearCommandBuffer(); UsbCommand c = {CMD_STATUS}; SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK,&c,1900)) { + if (!WaitForResponseTimeout(CMD_ACK, &c, 1900)) { PrintAndLog("Status command failed. USB Speed Test timed out"); } return 0; diff --git a/client/cmdlf.c b/client/cmdlf.c index ef9c3cbb..c09a299c 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -8,21 +8,21 @@ // Low frequency commands //----------------------------------------------------------------------------- +#include "cmdlf.h" + #include #include #include #include #include #include -#include "proxmark3.h" -#include "cmdlf.h" +#include "comms.h" #include "lfdemod.h" // for psk2TOpsk1 #include "util.h" // for parsing cli command utils #include "ui.h" // for show graph controls #include "graph.h" // for graph data #include "cmdparser.h" // for getting cli commands included in cmdmain.h #include "cmdmain.h" // for sending cmds to device -#include "data.h" // for GetFromBigBuf #include "cmddata.h" // for `lf search` #include "cmdlfawid.h" // for awid menu #include "cmdlfem4x.h" // for em4x menu @@ -54,26 +54,24 @@ static int CmdHelp(const char *Cmd); int usage_lf_cmdread(void) { - PrintAndLog("Usage: lf cmdread d z o c [H] "); + PrintAndLog("Usage: lf cmdread d z o c "); PrintAndLog("Options: "); PrintAndLog(" h This help"); - PrintAndLog(" L Low frequency (125 KHz)"); - PrintAndLog(" H High frequency (134 KHz)"); - PrintAndLog(" d delay OFF period"); - PrintAndLog(" z time period ZERO"); - PrintAndLog(" o time period ONE"); + PrintAndLog(" d delay OFF period between bits (0 for bitbang mode)"); + PrintAndLog(" z time period ZERO (antenna off in bitbang mode)"); + PrintAndLog(" o time period ONE (antenna on in bitbang mode)"); PrintAndLog(" c Command bytes"); PrintAndLog(" ************* All periods in microseconds"); + PrintAndLog(" ************* Use lf config to configure options."); PrintAndLog("Examples:"); PrintAndLog(" lf cmdread d 80 z 100 o 200 c 11000"); - PrintAndLog(" lf cmdread d 80 z 100 o 100 c 11000 H"); + PrintAndLog(" lf cmdread d 80 z 100 o 100 c 11000"); return 0; } /* send a command before reading */ int CmdLFCommandRead(const char *Cmd) { - static char dummy[3] = {0x20,0x00,0x00}; UsbCommand c = {CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K}; bool errors = false; //uint8_t divisor = 95; //125khz @@ -84,14 +82,6 @@ int CmdLFCommandRead(const char *Cmd) { case 'h': return usage_lf_cmdread(); - case 'H': - //divisor = 88; - dummy[1]='h'; - cmdp++; - break; - case 'L': - cmdp++; - break; case 'c': param_getstr(Cmd, cmdp+1, (char *)&c.d.asBytes, sizeof(c.d.asBytes)); cmdp+=2; @@ -121,11 +111,13 @@ int CmdLFCommandRead(const char *Cmd) //Validations if(errors) return usage_lf_cmdread(); - // in case they specified 'H' - strcpy((char *)&c.d.asBytes + strlen((char *)c.d.asBytes), dummy); - clearCommandBuffer(); SendCommand(&c); + + WaitForResponse(CMD_ACK,NULL); + getSamples(0, true); + + return 0; } @@ -335,7 +327,7 @@ int CmdLFSetConfig(const char *Cmd) } bool lf_read(bool silent, uint32_t samples) { - if (offline) return false; + if (IsOffline()) return false; UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K, {silent,samples,0}}; clearCommandBuffer(); //And ship it to device @@ -878,7 +870,7 @@ int CmdVchDemod(const char *Cmd) int CheckChipType(char cmdp) { uint32_t wordData = 0; - if (offline || cmdp == '1') return 0; + if (IsOffline() || cmdp == '1') return 0; save_restoreGB(GRAPH_SAVE); save_restoreDB(GRAPH_SAVE); @@ -923,7 +915,7 @@ int CmdLFfind(const char *Cmd) return 0; } - if (!offline && (cmdp != '1')) { + if (!IsOffline() && (cmdp != '1')) { lf_read(true, 30000); } else if (GraphTraceLen < minLength) { PrintAndLog("Data in Graphbuffer was too small."); @@ -939,7 +931,7 @@ int CmdLFfind(const char *Cmd) // only run if graphbuffer is just noise as it should be for hitag/cotag if (graphJustNoise(GraphBuffer, testLen)) { // only run these tests if we are in online mode - if (!offline && (cmdp != '1')) { + if (!IsOffline() && (cmdp != '1')) { // test for em4x05 in reader talk first mode. if (EM4x05Block0Test(&wordData)) { PrintAndLog("\nValid EM4x05/EM4x69 Chip Found\nUse lf em 4x05readword/dump commands to read\n"); @@ -955,6 +947,7 @@ int CmdLFfind(const char *Cmd) return 1; } } + PrintAndLog("\nNo Data Found! - maybe not an LF tag?\n"); return 0; } diff --git a/client/cmdlfawid.c b/client/cmdlfawid.c index 141ba172..cde94555 100644 --- a/client/cmdlfawid.c +++ b/client/cmdlfawid.c @@ -11,10 +11,11 @@ // FSK2a, RF/50, 96 bits (complete) //----------------------------------------------------------------------------- +#include "cmdlfawid.h" + #include #include // sscanf -#include "proxmark3.h" // Definitions, USB controls, etc -#include "cmdlfawid.h" +#include "comms.h" // Definitions, USB controls, etc #include "ui.h" // PrintAndLog #include "cmdparser.h" // CmdsParse, CmdsHelp #include "lfdemod.h" // parityTest + diff --git a/client/cmdlfcotag.c b/client/cmdlfcotag.c index 6d035e8c..d1808c9a 100644 --- a/client/cmdlfcotag.c +++ b/client/cmdlfcotag.c @@ -7,14 +7,15 @@ //----------------------------------------------------------------------------- // Low frequency COTAG commands //----------------------------------------------------------------------------- + +#include "cmdlfcotag.h" + #include #include #include -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "cmddata.h" -#include "data.h" -#include "cmdlfcotag.h" #include "lfdemod.h" #include "usb_cmd.h" #include "cmdmain.h" @@ -99,10 +100,9 @@ int CmdCOTAGRead(const char *Cmd) { getSamples(0, true); break; } case 1: { - GetFromBigBuf(DemodBuffer, COTAG_BITS, 0); - DemodBufferLen = COTAG_BITS; UsbCommand response; - if ( !WaitForResponseTimeout(CMD_ACK, &response, 1000) ) { + DemodBufferLen = COTAG_BITS; + if (!GetFromBigBuf(DemodBuffer, COTAG_BITS, 0, &response, 1000, true)) { PrintAndLog("timeout while waiting for reply."); return -1; } diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 6d562be0..cdaeb5ed 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -8,14 +8,14 @@ // Low frequency EM4x commands //----------------------------------------------------------------------------- +#include "cmdlfem4x.h" + #include #include #include -#include "cmdlfem4x.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "util.h" -#include "data.h" #include "graph.h" #include "cmdparser.h" #include "cmddata.h" @@ -804,8 +804,7 @@ int usage_lf_em_read(void) { bool downloadSamplesEM() { // 8 bit preamble + 32 bit word response (max clock (128) * 40bits = 5120 samples) uint8_t got[6000]; - GetFromBigBuf(got, sizeof(got), 0); - if ( !WaitForResponseTimeout(CMD_ACK, NULL, 4000) ) { + if (!GetFromBigBuf(got, sizeof(got), 0, NULL, 4000, true)) { PrintAndLog("command execution time out"); return false; } diff --git a/client/cmdlffdx.c b/client/cmdlffdx.c index 2e2ee9fd..20f834ce 100644 --- a/client/cmdlffdx.c +++ b/client/cmdlffdx.c @@ -13,7 +13,7 @@ #include #include #include -#include "proxmark3.h" +#include "comms.h" #include "ui.h" // for PrintAndLog #include "util.h" #include "cmdparser.h" diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index 19b5a142..433a093d 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -6,20 +6,193 @@ // the license. //----------------------------------------------------------------------------- // 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" + #include #include -#include "cmdlfhid.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "graph.h" #include "cmdparser.h" #include "cmddata.h" //for g_debugMode, demodbuff cmds #include "lfdemod.h" // for HIDdemodFSK +#include "parity.h" // for parity +#include "util.h" // for param_get8,32 static int CmdHelp(const char *Cmd); + +/** + * Packs a "short" (<38-bit) HID ID from component parts. + * + * This only works with 26, 34, 35 and 37 bit card IDs. + * + * NOTE: Parity calculation is only supported on 26-bit tags. Other card lengths + * may have invalid parity. + * + * Returns false on invalid inputs. + */ +bool pack_short_hid(/* out */ uint32_t *hi, /* out */ uint32_t *lo, /* in */ const short_hid_info *info) { + uint32_t high = 0, low = 0; + + switch (info->fmtLen) { + case 26: // HID H10301 + low |= (info->cardnum & 0xffff) << 1; + low |= (info->fc & 0xff) << 17; + + if (info->parityValid) { + // Calculate parity + low |= oddparity32((low >> 1) & 0xfff) & 1; + low |= (evenparity32((low >> 13) & 0xfff) & 1) << 25; + } + break; + + case 34: + low |= (info->cardnum & 0xffff) << 1; + low |= (info->fc & 0x7fff) << 17; + high |= (info->fc & 0x8000) >> 15; + // TODO: Calculate parity + break; + + case 35: + low |= (info->cardnum & 0xfffff) << 1; + low |= (info->fc & 0x7ff) << 21; + high |= (info->fc & 0x800) >> 11; + // TODO: Calculate parity + break; + + case 37: + low |= (info->cardnum & 0x7ffff) << 1; + low |= (info->fc & 0xfff) << 20; + high |= (info->fc & 0xf000) >> 12; + // TODO: Calculate parity + break; + + default: + // Invalid / unsupported length + return false; + } + + // Set the highest bit + if (info->fmtLen != 37) { + // Bit 37 is always set + high |= 0x20; + + // Set the bit corresponding to the length. + if (info->fmtLen < 32) { + low |= 1 << info->fmtLen; + } else { + high |= 1 << (info->fmtLen - 32); + } + } + + // Return result only if successful. + *hi = high; + *lo = low; + return true; +} + + +/** + * Unpacks a "short" (<38-bit) HID ID into its component parts. + * + * This only works with 26, 34, 35 and 37 bit card IDs. + * + * NOTE: Parity checking is only supported on 26-bit tags. + * + * Returns false on invalid inputs. + */ +bool unpack_short_hid(short_hid_info *out, uint32_t hi, uint32_t lo) { + memset(out, 0, sizeof(short_hid_info)); + + if (((hi >> 5) & 1) == 1) { + // if bit 38 is set then < 37 bit format is used + uint32_t lo2 = 0; + // get bits 21-37 to check for format len bit + lo2 = (((hi & 31) << 12) | (lo >> 20)); + uint8_t idx3 = 1; + // find last bit set to 1 (format len bit) + while (lo2 > 1) { + lo2 = lo2 >> 1; + idx3++; + } + + out->fmtLen = idx3 + 19; + + switch (out->fmtLen) { + case 26: // HID H10301 + out->cardnum = (lo >> 1) & 0xFFFF; + out->fc = (lo >> 17) & 0xFF; + + if (g_debugMode) { + PrintAndLog("oddparity : input=%x, calculated=%d, provided=%d", + (lo >> 1) & 0xFFF, oddparity32((lo >> 1) & 0xFFF), lo & 1); + PrintAndLog("evenparity: input=%x, calculated=%d, provided=%d", + (lo >> 13) & 0xFFF, evenparity32((lo >> 13) & 0xFFF) & 1, (lo >> 25) & 1); + } + + out->parityValid = + (oddparity32((lo >> 1) & 0xFFF) == (lo & 1)) && + ((evenparity32((lo >> 13) & 0xFFF) & 1) == ((lo >> 25) & 1)); + break; + + case 34: + out->cardnum = (lo >> 1) & 0xFFFF; + out->fc = ((hi & 1) << 15) | (lo >> 17); + // TODO: Calculate parity + break; + + case 35: + out->cardnum = (lo >> 1) & 0xFFFFF; + out->fc = ((hi & 1) << 11) | (lo >> 21); + // TODO: Calculate parity + break; + + default: + return false; + } + } else { + // If bit 38 is not set, then 37 bit format is used + out->fmtLen = 37; + out->cardnum = (lo >> 1) & 0x7FFFF; + out->fc = ((hi & 0xF) << 12) | (lo >> 20); + // TODO: Calculate parity + } + return true; +} + + +/** + * Converts a hex string to component "hi" and "lo" 32-bit integers, one nibble + * at a time. + * + * Returns the number of nibbles (4 bits) entered. + */ +int hexstring_to_int64(/* out */ uint32_t* hi, /* out */ uint32_t* lo, const char* str) { + // TODO: Replace this with param_gethex when it supports arbitrary length + // inputs. + int n = 0, i = 0; + + while (sscanf(&str[i++], "%1x", &n ) == 1) { + *hi = (*hi << 4) | (*lo >> 28); + *lo = (*lo << 4) | (n & 0xf); + } + + return i - 1; +} + //by marshmellow (based on existing demod + holiman's refactor) //HID Prox demod - FSK RF/50 with preamble of 00011101 (then manchester encoded) //print full HID Prox ID and some bit format details if found @@ -59,45 +232,19 @@ int CmdFSKdemodHID(const char *Cmd) (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); } else { //standard HID tags <38 bits - uint8_t fmtLen = 0; - uint32_t fc = 0; - uint32_t cardnum = 0; - if (((hi>>5)&1)==1){//if bit 38 is set then < 37 bit format is used - uint32_t lo2=0; - lo2=(((hi & 31) << 12) | (lo>>20)); //get bits 21-37 to check for format len bit - uint8_t idx3 = 1; - while(lo2>1){ //find last bit set to 1 (format len bit) - lo2=lo2>>1; - idx3++; - } - fmtLen =idx3+19; - fc =0; - cardnum=0; - if(fmtLen==26){ - cardnum = (lo>>1)&0xFFFF; - fc = (lo>>17)&0xFF; - } - if(fmtLen==34){ - cardnum = (lo>>1)&0xFFFF; - fc= ((hi&1)<<15)|(lo>>17); - } - if(fmtLen==35){ - cardnum = (lo>>1)&0xFFFFF; - fc = ((hi&1)<<11)|(lo>>21); - } - } - else { //if bit 38 is not set then 37 bit format is used - fmtLen = 37; - fc = 0; - cardnum = 0; - if(fmtLen == 37){ - cardnum = (lo>>1)&0x7FFFF; - fc = ((hi&0xF)<<12)|(lo>>20); - } - } - PrintAndLog("HID Prox TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", + short_hid_info card_info; + bool ret = unpack_short_hid(&card_info, (uint32_t)hi, (uint32_t)lo); + PrintAndLog("HID Prox TAG ID: %x%08x (%d) - Format Len: %u bits - FC: %u - Card: %u", (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, - (unsigned int) fmtLen, (unsigned int) fc, (unsigned int) cardnum); + card_info.fmtLen, card_info.fc, card_info.cardnum); + + if (card_info.fmtLen == 26) { + PrintAndLog("Parity: %s", card_info.parityValid ? "valid" : "invalid"); + } + + if (!ret) { + PrintAndLog("Invalid or unsupported tag length."); + } } setDemodBuf(BitStream,BitLen,idx); setClockGrid(50, waveIdx + (idx*50)); @@ -111,7 +258,7 @@ int CmdFSKdemodHID(const char *Cmd) int CmdHIDReadFSK(const char *Cmd) { int findone=0; - if(Cmd[0]=='1') findone=1; + if(Cmd[0]=='1') findone=1; UsbCommand c={CMD_HID_DEMOD_FSK}; c.arg[0]=findone; SendCommand(&c); @@ -120,30 +267,30 @@ int CmdHIDReadFSK(const char *Cmd) int CmdHIDSim(const char *Cmd) { - uint32_t hi = 0, lo = 0; - int n = 0, i = 0; + uint32_t hi = 0, lo = 0; + hexstring_to_int64(&hi, &lo, Cmd); + if (hi >= 0x40) { + PrintAndLog("This looks like a long tag ID. Use 'lf simfsk' for long tags. Aborting!"); + return 0; + } - while (sscanf(&Cmd[i++], "%1x", &n ) == 1) { - hi = (hi << 4) | (lo >> 28); - lo = (lo << 4) | (n & 0xf); - } + PrintAndLog("Emulating tag with ID %x%08x", hi, lo); + PrintAndLog("Press pm3-button to abort simulation"); - PrintAndLog("Emulating tag with ID %x%08x", hi, lo); - PrintAndLog("Press pm3-button to abort simulation"); - - UsbCommand c = {CMD_HID_SIM_TAG, {hi, lo, 0}}; - SendCommand(&c); - return 0; + UsbCommand c = {CMD_HID_SIM_TAG, {hi, lo, 0}}; + SendCommand(&c); + return 0; } int CmdHIDClone(const char *Cmd) { unsigned int hi2 = 0, hi = 0, lo = 0; - int n = 0, i = 0; UsbCommand c; if (strchr(Cmd,'l') != 0) { - while (sscanf(&Cmd[i++], "%1x", &n ) == 1) { + int n = 0, i = 0; + + while (sscanf(&Cmd[i++], "%1x", &n ) == 1) { hi2 = (hi2 << 4) | (hi >> 28); hi = (hi << 4) | (lo >> 28); lo = (lo << 4) | (n & 0xf); @@ -154,9 +301,10 @@ int CmdHIDClone(const char *Cmd) c.d.asBytes[0] = 1; } else { - while (sscanf(&Cmd[i++], "%1x", &n ) == 1) { - hi = (hi << 4) | (lo >> 28); - lo = (lo << 4) | (n & 0xf); + hexstring_to_int64(&hi, &lo, Cmd); + if (hi >= 0x40) { + PrintAndLog("This looks like a long tag ID. Aborting!"); + return 0; } PrintAndLog("Cloning tag with ID %x%08x", hi, lo); @@ -174,6 +322,73 @@ int CmdHIDClone(const char *Cmd) return 0; } + +int CmdHIDPack(const char *Cmd) { + uint32_t hi = 0, lo = 0; + short_hid_info card_info; + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: lf hid pack "); + PrintAndLog(" sample: lf hid pack 26 123 4567"); + return 0; + } + + card_info.fmtLen = param_get8(Cmd, 0); + card_info.fc = param_get32ex(Cmd, 1, 0, 10); + card_info.cardnum = param_get32ex(Cmd, 2, 0, 10); + card_info.parityValid = true; + + // TODO + if (card_info.fmtLen != 26) { + PrintAndLog("Warning: Parity bits are only calculated for 26 bit IDs -- this may be invalid!"); + } + + bool ret = pack_short_hid(&hi, &lo, &card_info); + + if (ret) { + PrintAndLog("HID Prox TAG ID: %x%08x (%d) - Format Len: %u bits - FC: %u - Card: %u", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, + card_info.fmtLen, card_info.fc, card_info.cardnum); + } else { + PrintAndLog("Invalid or unsupported tag length."); + } + return 0; +} + + +int CmdHIDUnpack(const char *Cmd) +{ + uint32_t hi = 0, lo = 0; + if (strlen(Cmd)<1) { + PrintAndLog("Usage: lf hid unpack "); + PrintAndLog(" sample: lf hid unpack 2006f623ae"); + return 0; + } + + hexstring_to_int64(&hi, &lo, Cmd); + if (hi >= 0x40) { + PrintAndLog("This looks like a long tag ID. Aborting!"); + return 0; + } + + short_hid_info card_info; + bool ret = unpack_short_hid(&card_info, hi, lo); + + PrintAndLog("HID Prox TAG ID: %x%08x (%d) - Format Len: %u bits - FC: %u - Card: %u", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, + card_info.fmtLen, card_info.fc, card_info.cardnum); + + if (card_info.fmtLen == 26) { + PrintAndLog("Parity: %s", card_info.parityValid ? "valid" : "invalid"); + } + + if (!ret) { + PrintAndLog("Invalid or unsupported tag length."); + } + return 0; +} + + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, @@ -181,6 +396,8 @@ static command_t CommandTable[] = {"read", CmdHIDReadFSK, 0, "['1'] Realtime HID FSK Read from antenna (option '1' for one tag only)"}, {"sim", CmdHIDSim, 0, " -- HID tag simulator"}, {"clone", CmdHIDClone, 0, " ['l'] -- Clone HID to T55x7 (tag must be in antenna)(option 'l' for 84bit ID)"}, + {"pack", CmdHIDPack, 1, " -- packs a <38 bit (short) HID ID from its length, facility code and card number"}, + {"unpack", CmdHIDUnpack, 1, " -- unpacks a <38 bit (short) HID ID to its length, facility code and card number"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlfhid.h b/client/cmdlfhid.h index b03f7041..e53a95c6 100644 --- a/client/cmdlfhid.h +++ b/client/cmdlfhid.h @@ -11,10 +11,39 @@ #ifndef CMDLFHID_H__ #define CMDLFHID_H__ +#include +#include + +// Structure for unpacked "short" (<38 bits) HID Prox tags. +typedef struct { + // Format length, in bits. + uint8_t fmtLen; + + // Facility code. + uint32_t fc; + + // Card number. + uint32_t cardnum; + + // Parity validity. + // + // When used with pack_short_hid, this determines if we should calculate + // parity values for the ID. + // + // When used with unpack_short_hid, this indicates if we got valid parity + // values for the ID. + bool parityValid; +} short_hid_info; + +bool pack_short_hid(/* out */ uint32_t *hi, /* out */ uint32_t *lo, /* in */ const short_hid_info *info); +bool unpack_short_hid(short_hid_info* out, uint32_t hi, uint32_t lo); + int CmdLFHID(const char *Cmd); int CmdFSKdemodHID(const char *Cmd); int CmdHIDReadDemod(const char *Cmd); int CmdHIDSim(const char *Cmd); int CmdHIDClone(const char *Cmd); +int CmdHIDPack(const char *Cmd); +int CmdHIDUnpack(const char *Cmd); #endif diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index 73c02a14..8eef2359 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -8,11 +8,12 @@ // Low frequency Hitag support //----------------------------------------------------------------------------- +#include "cmdlfhitag.h" + #include #include #include -#include "data.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "cmdparser.h" #include "common.h" @@ -34,8 +35,7 @@ int CmdLFHitagList(const char *Cmd) // Query for the actual size of the trace UsbCommand response; - GetFromBigBuf(got, USB_CMD_DATA_SIZE, 0); - WaitForResponse(CMD_ACK, &response); + GetFromBigBuf(got, USB_CMD_DATA_SIZE, 0, &response, -1, false); uint16_t traceLen = response.arg[2]; if (traceLen > USB_CMD_DATA_SIZE) { uint8_t *p = realloc(got, traceLen); @@ -45,8 +45,7 @@ int CmdLFHitagList(const char *Cmd) return 2; } got = p; - GetFromBigBuf(got, traceLen, 0); - WaitForResponse(CMD_ACK,NULL); + GetFromBigBuf(got, traceLen, 0, NULL, -1, false); } PrintAndLog("recorded activity (TraceLen = %d bytes):"); @@ -67,6 +66,7 @@ int CmdLFHitagList(const char *Cmd) if (strlen(filename) > 0) { if ((pf = fopen(filename,"wb")) == NULL) { PrintAndLog("Error: Could not open file [%s]",filename); + free(got); return 1; } } @@ -167,11 +167,11 @@ int CmdLFHitagSim(const char *Cmd) { return 1; } tag_mem_supplied = true; - if (fread(c.d.asBytes,48,1,pf) == 0) { - PrintAndLog("Error: File reading error"); - fclose(pf); + if (fread(c.d.asBytes,1,48,pf) != 48) { + PrintAndLog("Error: File reading error"); + fclose(pf); return 1; - } + } fclose(pf); } else { tag_mem_supplied = false; @@ -290,7 +290,7 @@ int CmdLFHitagSimS(const char *Cmd) { return 1; } tag_mem_supplied = true; - if (fread(c.d.asBytes, 4*64, 1, pf) == 0) { + if (fread(c.d.asBytes, 1, 4*64, pf) != 4*64) { PrintAndLog("Error: File reading error"); fclose(pf); return 1; @@ -322,9 +322,9 @@ int CmdLFHitagCheckChallenges(const char *Cmd) { return 1; } file_given = true; - if (fread(c.d.asBytes,8*60,1,pf) == 0) { - PrintAndLog("Error: File reading error"); - fclose(pf); + if (fread(c.d.asBytes,1,8*60,pf) != 8*60) { + PrintAndLog("Error: File reading error"); + fclose(pf); return 1; } fclose(pf); diff --git a/client/cmdlfindala.c b/client/cmdlfindala.c index 0a4f7834..02c906d0 100644 --- a/client/cmdlfindala.c +++ b/client/cmdlfindala.c @@ -8,10 +8,11 @@ // PSK1, rf/32, 64 or 224 bits (known) //----------------------------------------------------------------------------- +#include "cmdlfindala.h" + #include #include -#include "cmdlfindala.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "graph.h" #include "cmdparser.h" @@ -286,7 +287,7 @@ int CmdIndalaDemod(const char *Cmd) { } int CmdIndalaClone(const char *Cmd) { - UsbCommand c; + UsbCommand c = {0}; unsigned int uid1, uid2, uid3, uid4, uid5, uid6, uid7; uid1 = uid2 = uid3 = uid4 = uid5 = uid6 = uid7 = 0; diff --git a/client/cmdlfio.c b/client/cmdlfio.c index 4ccd5538..feb7d373 100644 --- a/client/cmdlfio.c +++ b/client/cmdlfio.c @@ -8,14 +8,14 @@ // FSK2a, rf/64, 64 bits (complete) //----------------------------------------------------------------------------- +#include "cmdlfio.h" + #include #include #include #include #include -#include "cmdlfio.h" -#include "proxmark3.h" -#include "data.h" +#include "comms.h" #include "graph.h" #include "ui.h" #include "cmdparser.h" diff --git a/client/cmdlfjablotron.c b/client/cmdlfjablotron.c index 9c69099e..4756266c 100644 --- a/client/cmdlfjablotron.c +++ b/client/cmdlfjablotron.c @@ -9,10 +9,11 @@ //----------------------------------------------------------------------------- #include "cmdlfjablotron.h" + #include #include #include -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "util.h" #include "graph.h" diff --git a/client/cmdlfnexwatch.c b/client/cmdlfnexwatch.c index caabe835..d44c2a27 100644 --- a/client/cmdlfnexwatch.c +++ b/client/cmdlfnexwatch.c @@ -7,12 +7,14 @@ // Low frequency Honeywell NexWatch tag commands // PSK1 RF/16, RF/2, 128 bits long (known) //----------------------------------------------------------------------------- + +#include "cmdlfnexwatch.h" + #include #include #include #include -#include "cmdlfnexwatch.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "util.h" #include "graph.h" diff --git a/client/cmdlfnoralsy.c b/client/cmdlfnoralsy.c index 2c90fa14..52c35081 100644 --- a/client/cmdlfnoralsy.c +++ b/client/cmdlfnoralsy.c @@ -7,11 +7,13 @@ // Low frequency Noralsy tag commands // ASK/Manchester, STT, RF/32, 96 bits long (some bits unknown) //----------------------------------------------------------------------------- + #include "cmdlfnoralsy.h" + #include #include #include -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "util.h" #include "graph.h" diff --git a/client/cmdlfpac.c b/client/cmdlfpac.c index ef6b394b..190361ec 100644 --- a/client/cmdlfpac.c +++ b/client/cmdlfpac.c @@ -7,10 +7,12 @@ // Low frequency Stanley/PAC tag commands // NRZ, RF/32, 128 bits long (unknown cs) //----------------------------------------------------------------------------- + #include "cmdlfpac.h" + #include #include -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "util.h" #include "graph.h" diff --git a/client/cmdlfpcf7931.c b/client/cmdlfpcf7931.c index ffaf946f..9c694b8d 100644 --- a/client/cmdlfpcf7931.c +++ b/client/cmdlfpcf7931.c @@ -8,9 +8,12 @@ //----------------------------------------------------------------------------- // Low frequency PCF7931 commands //----------------------------------------------------------------------------- + +#include "cmdlfpcf7931.h" + #include #include -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "util.h" #include "graph.h" @@ -18,7 +21,6 @@ #include "cmddata.h" #include "cmdmain.h" #include "cmdlf.h" -#include "cmdlfpcf7931.h" static int CmdHelp(const char *Cmd); diff --git a/client/cmdlfpcf7931.h b/client/cmdlfpcf7931.h index e093039c..8b24f03a 100644 --- a/client/cmdlfpcf7931.h +++ b/client/cmdlfpcf7931.h @@ -12,6 +12,8 @@ #ifndef CMDLFPCF7931_H__ #define CMDLFPCF7931_H__ +#include + struct pcf7931_config{ uint8_t Pwd[7]; uint16_t InitDelay; diff --git a/client/cmdlfpresco.c b/client/cmdlfpresco.c index 2f4bacfe..865b384b 100644 --- a/client/cmdlfpresco.c +++ b/client/cmdlfpresco.c @@ -7,11 +7,13 @@ // Low frequency Presco tag commands // ASK/Manchester, rf/32, 128 bits (complete) //----------------------------------------------------------------------------- + +#include "cmdlfpresco.h" + #include #include #include -#include "cmdlfpresco.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "util.h" #include "graph.h" diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index 366889f3..82367720 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -7,11 +7,13 @@ // Low frequency Farpoint / Pyramid tag commands // FSK2a, rf/50, 128 bits (complete) //----------------------------------------------------------------------------- + +#include "cmdlfpyramid.h" + #include #include #include -#include "cmdlfpyramid.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "util.h" #include "graph.h" diff --git a/client/cmdlfsecurakey.c b/client/cmdlfsecurakey.c index 8ae81250..44b77060 100644 --- a/client/cmdlfsecurakey.c +++ b/client/cmdlfsecurakey.c @@ -7,11 +7,13 @@ // Low frequency Securakey tag commands // ASK/Manchester, RF/40, 96 bits long (unknown cs) //----------------------------------------------------------------------------- + #include "cmdlfsecurakey.h" + #include #include #include -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "util.h" #include "graph.h" diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index c5a6dd3f..2a096cd0 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -7,21 +7,21 @@ // Low frequency T55xx commands //----------------------------------------------------------------------------- +#include "cmdlft55xx.h" + #include #include #include #include #include -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "graph.h" #include "cmdmain.h" #include "cmdparser.h" #include "cmddata.h" #include "cmdlf.h" -#include "cmdlft55xx.h" #include "util.h" -#include "data.h" #include "lfdemod.h" #include "cmdhf14a.h" //for getTagInfo #include "protocols.h" @@ -207,7 +207,7 @@ void printT5xxHeader(uint8_t page){ int CmdT55xxSetConfig(const char *Cmd) { uint8_t offset = 0; - char modulation[5] = {0x00}; + char modulation[6] = {0x00}; char tmp = 0x00; uint8_t bitRate = 0; uint8_t rates[9] = {8,16,32,40,50,64,100,128,0}; @@ -1355,8 +1355,7 @@ int CmdResetRead(const char *Cmd) { } uint8_t got[BIGBUF_SIZE-1]; - GetFromBigBuf(got,sizeof(got),0); - WaitForResponse(CMD_ACK,NULL); + GetFromBigBuf(got, sizeof(got), 0, NULL, -1 , 0); setGraphBuf(got, sizeof(got)); return 1; } diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index 4f0fd21d..2ae3e69b 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -10,6 +10,9 @@ #ifndef CMDLFT55XX_H__ #define CMDLFT55XX_H__ +#include +#include + typedef struct { uint32_t bl1; uint32_t bl2; diff --git a/client/cmdlfti.c b/client/cmdlfti.c index 5dae9c0e..ff463971 100644 --- a/client/cmdlfti.c +++ b/client/cmdlfti.c @@ -8,16 +8,17 @@ // Low frequency TI commands //----------------------------------------------------------------------------- +#include "cmdlfti.h" + #include #include #include #include "crc16.h" -#include "proxmark3.h" -#include "data.h" +#include "comms.h" #include "ui.h" #include "graph.h" #include "cmdparser.h" -#include "cmdlfti.h" +#include "util.h" static int CmdHelp(const char *Cmd); diff --git a/client/cmdlfviking.c b/client/cmdlfviking.c index 779156c8..73a9126a 100644 --- a/client/cmdlfviking.c +++ b/client/cmdlfviking.c @@ -7,11 +7,13 @@ // Low frequency Viking tag commands (AKA FDI Matalec Transit) // ASK/Manchester, RF/32, 64 bits (complete) //----------------------------------------------------------------------------- + +#include "cmdlfviking.h" + #include #include #include -#include "proxmark3.h" -#include "cmdlfviking.h" +#include "comms.h" #include "ui.h" #include "util.h" #include "graph.h" diff --git a/client/cmdlfvisa2000.c b/client/cmdlfvisa2000.c index 04589ba5..33259794 100644 --- a/client/cmdlfvisa2000.c +++ b/client/cmdlfvisa2000.c @@ -13,7 +13,7 @@ #include #include -#include "proxmark3.h" +#include "comms.h" #include "ui.h" #include "util.h" #include "graph.h" diff --git a/client/cmdmain.c b/client/cmdmain.c index ae059ea2..01d4c9a7 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -17,7 +17,6 @@ #include #include "cmdparser.h" #include "proxmark3.h" -#include "data.h" #include "usb_cmd.h" #include "ui.h" #include "cmdhf.h" @@ -27,24 +26,11 @@ #include "util.h" #include "util_posix.h" #include "cmdscript.h" -#include "cmdcrc.h" -unsigned int current_command = CMD_UNKNOWN; - static int CmdHelp(const char *Cmd); static int CmdQuit(const char *Cmd); -static int CmdRev(const char *Cmd); -//For storing command that are received from the device -#define CMD_BUFFER_SIZE 50 -static UsbCommand cmdBuffer[CMD_BUFFER_SIZE]; -//Points to the next empty position to write to -static int cmd_head;//Starts as 0 -//Points to the position of the last unread command -static int cmd_tail;//Starts as 0 -// to lock cmdBuffer operations from different threads -static pthread_mutex_t cmdBufferMutex = PTHREAD_MUTEX_INITIALIZER; static command_t CommandTable[] = { @@ -53,7 +39,6 @@ static command_t CommandTable[] = {"hf", CmdHF, 1, "{ High Frequency commands... }"}, {"hw", CmdHW, 1, "{ Hardware commands... }"}, {"lf", CmdLF, 1, "{ Low Frequency commands... }"}, - {"reveng",CmdRev, 1, "Crc calculations from the software reveng1-30"}, {"script",CmdScript,1, "{ Scripting commands }"}, {"quit", CmdQuit, 1, "Exit program"}, {"exit", CmdQuit, 1, "Exit program"}, @@ -64,130 +49,18 @@ command_t* getTopLevelCommandTable() { return CommandTable; } -int CmdHelp(const char *Cmd) + +static int CmdHelp(const char *Cmd) { CmdsHelp(CommandTable); return 0; } -int CmdQuit(const char *Cmd) +static int CmdQuit(const char *Cmd) { return 99; } -int CmdRev(const char *Cmd) -{ - CmdCrc(Cmd); - return 0; -} - -/** - * @brief This method should be called when sending a new command to the pm3. In case any old - * responses from previous commands are stored in the buffer, a call to this method should clear them. - * A better method could have been to have explicit command-ACKS, so we can know which ACK goes to which - * operation. Right now we'll just have to live with this. - */ -void clearCommandBuffer() -{ - //This is a very simple operation - pthread_mutex_lock(&cmdBufferMutex); - cmd_tail = cmd_head; - pthread_mutex_unlock(&cmdBufferMutex); -} - -/** - * @brief storeCommand stores a USB command in a circular buffer - * @param UC - */ -void storeCommand(UsbCommand *command) -{ - pthread_mutex_lock(&cmdBufferMutex); - if( ( cmd_head+1) % CMD_BUFFER_SIZE == cmd_tail) - { - //If these two are equal, we're about to overwrite in the - // circular buffer. - PrintAndLog("WARNING: Command buffer about to overwrite command! This needs to be fixed!"); - } - //Store the command at the 'head' location - UsbCommand* destination = &cmdBuffer[cmd_head]; - memcpy(destination, command, sizeof(UsbCommand)); - - cmd_head = (cmd_head +1) % CMD_BUFFER_SIZE; //increment head and wrap - pthread_mutex_unlock(&cmdBufferMutex); -} - - -/** - * @brief getCommand gets a command from an internal circular buffer. - * @param response location to write command - * @return 1 if response was returned, 0 if nothing has been received - */ -int getCommand(UsbCommand* response) -{ - pthread_mutex_lock(&cmdBufferMutex); - //If head == tail, there's nothing to read, or if we just got initialized - if(cmd_head == cmd_tail){ - pthread_mutex_unlock(&cmdBufferMutex); - return 0; - } - //Pick out the next unread command - UsbCommand* last_unread = &cmdBuffer[cmd_tail]; - memcpy(response, last_unread, sizeof(UsbCommand)); - //Increment tail - this is a circular buffer, so modulo buffer size - cmd_tail = (cmd_tail +1 ) % CMD_BUFFER_SIZE; - pthread_mutex_unlock(&cmdBufferMutex); - return 1; -} - - -/** - * Waits for a certain response type. This method waits for a maximum of - * ms_timeout milliseconds for a specified response command. - *@brief WaitForResponseTimeout - * @param cmd command to wait for - * @param response struct to copy received command into. - * @param ms_timeout - * @return true if command was returned, otherwise false - */ -bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeout, bool show_warning) { - - UsbCommand resp; - - if (response == NULL) { - response = &resp; - } - - uint64_t start_time = msclock(); - - // Wait until the command is received - while (true) { - while(getCommand(response)) { - if(response->cmd == cmd){ - return true; - } - } - if (msclock() - start_time > ms_timeout) { - break; - } - if (msclock() - start_time > 2000 && show_warning) { - PrintAndLog("Waiting for a response from the proxmark..."); - PrintAndLog("Don't forget to cancel its operation first by pressing on the button"); - show_warning = false; - } - } - return false; -} - - -bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) { - return WaitForResponseTimeoutW(cmd, response, ms_timeout, true); -} - -bool WaitForResponse(uint32_t cmd, UsbCommand* response) { - return WaitForResponseTimeoutW(cmd, response, -1, true); -} - - //----------------------------------------------------------------------------- // Entry point into our code: called whenever the user types a command and // then presses Enter, which the full command line that they typed. @@ -196,38 +69,3 @@ int CommandReceived(char *Cmd) { return CmdsParse(CommandTable, Cmd); } - -//----------------------------------------------------------------------------- -// Entry point into our code: called whenever we received a packet over USB -// that we weren't necessarily expecting, for example a debug print. -//----------------------------------------------------------------------------- -void UsbCommandReceived(UsbCommand *UC) -{ - switch(UC->cmd) { - // First check if we are handling a debug message - case CMD_DEBUG_PRINT_STRING: { - char s[USB_CMD_DATA_SIZE+1]; - memset(s, 0x00, sizeof(s)); - size_t len = MIN(UC->arg[0],USB_CMD_DATA_SIZE); - memcpy(s,UC->d.asBytes,len); - PrintAndLog("#db# %s", s); - return; - } break; - - case CMD_DEBUG_PRINT_INTEGERS: { - PrintAndLog("#db# %08x, %08x, %08x \r\n", UC->arg[0], UC->arg[1], UC->arg[2]); - return; - } break; - - case CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K: { - memcpy(sample_buf+(UC->arg[0]),UC->d.asBytes,UC->arg[1]); - return; - } break; - - default: - storeCommand(UC); - break; - } - -} - diff --git a/client/cmdmain.h b/client/cmdmain.h index d39bc114..42b49145 100644 --- a/client/cmdmain.h +++ b/client/cmdmain.h @@ -11,17 +11,9 @@ #ifndef CMDMAIN_H__ #define CMDMAIN_H__ -#include -#include -#include "usb_cmd.h" #include "cmdparser.h" -extern void UsbCommandReceived(UsbCommand *UC); extern int CommandReceived(char *Cmd); -extern bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeout, bool show_warning); -extern bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout); -extern bool WaitForResponse(uint32_t cmd, UsbCommand* response); -extern void clearCommandBuffer(); extern command_t* getTopLevelCommandTable(); #endif diff --git a/client/cmdparser.c b/client/cmdparser.c index 32508997..34230d52 100644 --- a/client/cmdparser.c +++ b/client/cmdparser.c @@ -8,12 +8,14 @@ // Command parser //----------------------------------------------------------------------------- +#include "cmdparser.h" + #include #include #include #include "ui.h" -#include "cmdparser.h" #include "proxmark3.h" +#include "comms.h" void CmdsHelp(const command_t Commands[]) @@ -23,7 +25,7 @@ void CmdsHelp(const command_t Commands[]) int i = 0; while (Commands[i].Name) { - if (!offline || Commands[i].Offline) + if (!IsOffline() || Commands[i].Offline) PrintAndLog("%-16s %s", Commands[i].Name, Commands[i].Help); ++i; } diff --git a/client/cmdscript.c b/client/cmdscript.c index 0d19f496..7b0e9000 100644 --- a/client/cmdscript.c +++ b/client/cmdscript.c @@ -17,7 +17,6 @@ #include "proxmark3.h" #include "scripting.h" -#include "data.h" #include "ui.h" #include "graph.h" #include "cmdparser.h" diff --git a/client/comms.c b/client/comms.c new file mode 100644 index 00000000..2030f8f3 --- /dev/null +++ b/client/comms.c @@ -0,0 +1,411 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2009 Michael Gernoth +// Copyright (C) 2010 iZsh +// +// 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. +//----------------------------------------------------------------------------- +// Code for communicating with the proxmark3 hardware. +//----------------------------------------------------------------------------- + +#include "comms.h" + +#include +#if defined(__linux__) && !defined(NO_UNLINK) +#include // for unlink() +#endif +#include "uart.h" +#include "ui.h" +#include "common.h" +#include "util_posix.h" + + +// Serial port that we are communicating with the PM3 on. +static serial_port sp = NULL; +static char *serial_port_name = NULL; + +// If TRUE, then there is no active connection to the PM3, and we will drop commands sent. +static bool offline; + +typedef struct { + bool run; // If TRUE, continue running the uart_communication thread + bool block_after_ACK; // if true, block after receiving an ACK package +} communication_arg_t; + +static communication_arg_t conn; +static pthread_t USB_communication_thread; + +// Transmit buffer. +static UsbCommand txBuffer; +static bool txBuffer_pending = false; +static pthread_mutex_t txBufferMutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t txBufferSig = PTHREAD_COND_INITIALIZER; + +// Used by UsbReceiveCommand as a ring buffer for messages that are yet to be +// processed by a command handler (WaitForResponse{,Timeout}) +static UsbCommand rxBuffer[CMD_BUFFER_SIZE]; + +// Points to the next empty position to write to +static int cmd_head = 0; + +// Points to the position of the last unread command +static int cmd_tail = 0; + +// to lock rxBuffer operations from different threads +static pthread_mutex_t rxBufferMutex = PTHREAD_MUTEX_INITIALIZER; + +// These wrappers are required because it is not possible to access a static +// global variable outside of the context of a single file. + +void SetOffline(bool new_offline) { + offline = new_offline; +} + +bool IsOffline() { + return offline; +} + +void SendCommand(UsbCommand *c) { + #ifdef COMMS_DEBUG + printf("Sending %04x cmd\n", c->cmd); + #endif + + if (offline) { + PrintAndLog("Sending bytes to proxmark failed - offline"); + return; + } + + pthread_mutex_lock(&txBufferMutex); + /** + This causes hangups at times, when the pm3 unit is unresponsive or disconnected. The main console thread is alive, + but comm thread just spins here. Not good.../holiman + **/ + while (txBuffer_pending) { + pthread_cond_wait(&txBufferSig, &txBufferMutex); // wait for communication thread to complete sending a previous commmand + } + + txBuffer = *c; + txBuffer_pending = true; + pthread_cond_signal(&txBufferSig); // tell communication thread that a new command can be send + + pthread_mutex_unlock(&txBufferMutex); + +} + + +/** + * @brief This method should be called when sending a new command to the pm3. In case any old + * responses from previous commands are stored in the buffer, a call to this method should clear them. + * A better method could have been to have explicit command-ACKS, so we can know which ACK goes to which + * operation. Right now we'll just have to live with this. + */ +void clearCommandBuffer() +{ + //This is a very simple operation + pthread_mutex_lock(&rxBufferMutex); + cmd_tail = cmd_head; + pthread_mutex_unlock(&rxBufferMutex); +} + +/** + * @brief storeCommand stores a USB command in a circular buffer + * @param UC + */ +static void storeCommand(UsbCommand *command) +{ + pthread_mutex_lock(&rxBufferMutex); + if( (cmd_head+1) % CMD_BUFFER_SIZE == cmd_tail) + { + // If these two are equal, we're about to overwrite in the + // circular buffer. + PrintAndLog("WARNING: Command buffer about to overwrite command! This needs to be fixed!"); + } + + // Store the command at the 'head' location + UsbCommand* destination = &rxBuffer[cmd_head]; + memcpy(destination, command, sizeof(UsbCommand)); + + cmd_head = (cmd_head +1) % CMD_BUFFER_SIZE; //increment head and wrap + pthread_mutex_unlock(&rxBufferMutex); +} + + +/** + * @brief getCommand gets a command from an internal circular buffer. + * @param response location to write command + * @return 1 if response was returned, 0 if nothing has been received + */ +static int getCommand(UsbCommand* response) +{ + pthread_mutex_lock(&rxBufferMutex); + //If head == tail, there's nothing to read, or if we just got initialized + if (cmd_head == cmd_tail){ + pthread_mutex_unlock(&rxBufferMutex); + return 0; + } + + //Pick out the next unread command + UsbCommand* last_unread = &rxBuffer[cmd_tail]; + memcpy(response, last_unread, sizeof(UsbCommand)); + //Increment tail - this is a circular buffer, so modulo buffer size + cmd_tail = (cmd_tail + 1) % CMD_BUFFER_SIZE; + + pthread_mutex_unlock(&rxBufferMutex); + return 1; +} + + +//---------------------------------------------------------------------------------- +// Entry point into our code: called whenever we received a packet over USB. +// Handle debug commands directly, store all other commands in circular buffer. +//---------------------------------------------------------------------------------- +static void UsbCommandReceived(UsbCommand *UC) +{ + switch(UC->cmd) { + // First check if we are handling a debug message + case CMD_DEBUG_PRINT_STRING: { + char s[USB_CMD_DATA_SIZE+1]; + memset(s, 0x00, sizeof(s)); + size_t len = MIN(UC->arg[0],USB_CMD_DATA_SIZE); + memcpy(s,UC->d.asBytes,len); + PrintAndLog("#db# %s", s); + return; + } break; + + case CMD_DEBUG_PRINT_INTEGERS: { + PrintAndLog("#db# %08x, %08x, %08x \r\n", UC->arg[0], UC->arg[1], UC->arg[2]); + return; + } break; + + default: + storeCommand(UC); + break; + } + +} + + +static void +#ifdef __has_attribute +#if __has_attribute(force_align_arg_pointer) +__attribute__((force_align_arg_pointer)) +#endif +#endif +*uart_communication(void *targ) { + communication_arg_t *conn = (communication_arg_t*)targ; + size_t rxlen; + UsbCommand rx; + UsbCommand *prx = ℞ + + while (conn->run) { + rxlen = 0; + bool ACK_received = false; + if (uart_receive(sp, (uint8_t *)prx, sizeof(UsbCommand) - (prx-&rx), &rxlen) && rxlen) { + prx += rxlen; + if (prx-&rx < sizeof(UsbCommand)) { + continue; + } + UsbCommandReceived(&rx); + if (rx.cmd == CMD_ACK) { + ACK_received = true; + } + } + prx = ℞ + + + pthread_mutex_lock(&txBufferMutex); + + if (conn->block_after_ACK) { + // if we just received an ACK, wait here until a new command is to be transmitted + if (ACK_received) { + while (!txBuffer_pending) { + pthread_cond_wait(&txBufferSig, &txBufferMutex); + } + } + } + + if(txBuffer_pending) { + if (!uart_send(sp, (uint8_t*) &txBuffer, sizeof(UsbCommand))) { + PrintAndLog("Sending bytes to proxmark failed"); + } + txBuffer_pending = false; + pthread_cond_signal(&txBufferSig); // tell main thread that txBuffer is empty + } + + pthread_mutex_unlock(&txBufferMutex); + } + + pthread_exit(NULL); + return NULL; +} + + +/** + * Data transfer from Proxmark to client. This method times out after + * ms_timeout milliseconds. + * @brief GetFromBigBuf + * @param dest Destination address for transfer + * @param bytes number of bytes to be transferred + * @param start_index offset into Proxmark3 BigBuf[] + * @param response struct to copy last command (CMD_ACK) into + * @param ms_timeout timeout in milliseconds + * @param show_warning display message after 2 seconds + * @return true if command was returned, otherwise false + */ +bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning) +{ + UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}}; + SendCommand(&c); + + uint64_t start_time = msclock(); + + UsbCommand resp; + if (response == NULL) { + response = &resp; + } + + int bytes_completed = 0; + while(true) { + if (getCommand(response)) { + if (response->cmd == CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { + int copy_bytes = MIN(bytes - bytes_completed, response->arg[1]); + memcpy(dest + response->arg[0], response->d.asBytes, copy_bytes); + bytes_completed += copy_bytes; + } else if (response->cmd == CMD_ACK) { + return true; + } + } + + if (msclock() - start_time > ms_timeout) { + break; + } + + if (msclock() - start_time > 2000 && show_warning) { + PrintAndLog("Waiting for a response from the proxmark..."); + PrintAndLog("You can cancel this operation by pressing the pm3 button"); + show_warning = false; + } + } + + return false; +} + + +bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode) { + char *portname = (char *)port; + if (!wait_for_port) { + sp = uart_open(portname); + } else { + printf("Waiting for Proxmark to appear on %s ", portname); + fflush(stdout); + int openCount = 0; + do { + sp = uart_open(portname); + msleep(1000); + printf("."); + fflush(stdout); + } while(++openCount < timeout && (sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT)); + printf("\n"); + } + + // check result of uart opening + if (sp == INVALID_SERIAL_PORT) { + printf("ERROR: invalid serial port\n"); + sp = NULL; + serial_port_name = NULL; + return false; + } else if (sp == CLAIMED_SERIAL_PORT) { + printf("ERROR: serial port is claimed by another process\n"); + sp = NULL; + serial_port_name = NULL; + return false; + } else { + // start the USB communication thread + serial_port_name = portname; + conn.run = true; + conn.block_after_ACK = flash_mode; + pthread_create(&USB_communication_thread, NULL, &uart_communication, &conn); + return true; + } +} + + +void CloseProxmark(void) { + conn.run = false; + pthread_join(USB_communication_thread, NULL); + + if (sp) { + uart_close(sp); + } + +#if defined(__linux__) && !defined(NO_UNLINK) + // Fix for linux, it seems that it is extremely slow to release the serial port file descriptor /dev/* + // + // This may be disabled at compile-time with -DNO_UNLINK (used for a JNI-based serial port on Android). + if (serial_port_name) { + unlink(serial_port_name); + } +#endif + + // Clean up our state + sp = NULL; + serial_port_name = NULL; +} + + +/** + * Waits for a certain response type. This method waits for a maximum of + * ms_timeout milliseconds for a specified response command. + *@brief WaitForResponseTimeout + * @param cmd command to wait for, or CMD_UNKNOWN to take any command. + * @param response struct to copy received command into. + * @param ms_timeout + * @param show_warning display message after 2 seconds + * @return true if command was returned, otherwise false + */ +bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeout, bool show_warning) { + + UsbCommand resp; + + #ifdef COMMS_DEBUG + printf("Waiting for %04x cmd\n", cmd); + #endif + + if (response == NULL) { + response = &resp; + } + + uint64_t start_time = msclock(); + + // Wait until the command is received + while (true) { + while(getCommand(response)) { + if (cmd == CMD_UNKNOWN || response->cmd == cmd) { + return true; + } + } + + if (msclock() - start_time > ms_timeout) { + break; + } + + if (msclock() - start_time > 2000 && show_warning) { + // 2 seconds elapsed (but this doesn't mean the timeout was exceeded) + PrintAndLog("Waiting for a response from the proxmark..."); + PrintAndLog("You can cancel this operation by pressing the pm3 button"); + show_warning = false; + } + } + return false; +} + + +bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) { + return WaitForResponseTimeoutW(cmd, response, ms_timeout, true); +} + +bool WaitForResponse(uint32_t cmd, UsbCommand* response) { + return WaitForResponseTimeoutW(cmd, response, -1, true); +} + diff --git a/client/comms.h b/client/comms.h new file mode 100644 index 00000000..68981165 --- /dev/null +++ b/client/comms.h @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2009 Michael Gernoth +// Copyright (C) 2010 iZsh +// +// 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. +//----------------------------------------------------------------------------- +// Code for communicating with the proxmark3 hardware. +//----------------------------------------------------------------------------- + +#ifndef COMMS_H_ +#define COMMS_H_ + +#include +#include + +#include "usb_cmd.h" +#include "uart.h" + +#ifndef CMD_BUFFER_SIZE +#define CMD_BUFFER_SIZE 50 +#endif + +void SetOffline(bool new_offline); +bool IsOffline(); + +bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode); +void CloseProxmark(void); + +void SendCommand(UsbCommand *c); + +void clearCommandBuffer(); +bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeout, bool show_warning); +bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout); +bool WaitForResponse(uint32_t cmd, UsbCommand* response); +bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning); + +#endif // COMMS_H_ diff --git a/client/data.c b/client/data.c deleted file mode 100644 index 4d7d1e41..00000000 --- a/client/data.c +++ /dev/null @@ -1,25 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2010 iZsh -// -// 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. -//----------------------------------------------------------------------------- -// Data utilities -//----------------------------------------------------------------------------- - -#include -#include -#include "data.h" -#include "ui.h" -#include "proxmark3.h" -#include "cmdmain.h" - -uint8_t* sample_buf; - -void GetFromBigBuf(uint8_t *dest, int bytes, int start_index) -{ - sample_buf = dest; - UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}}; - SendCommand(&c); -} diff --git a/client/data.h b/client/data.h deleted file mode 100644 index 7d85e1f1..00000000 --- a/client/data.h +++ /dev/null @@ -1,23 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2010 iZsh -// -// 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. -//----------------------------------------------------------------------------- -// Data utilities -//----------------------------------------------------------------------------- - -#ifndef DATA_H__ -#define DATA_H__ - -#include - -#define FILE_PATH_SIZE 1000 - -extern uint8_t* sample_buf; -#define arraylen(x) (sizeof(x)/sizeof((x)[0])) - -void GetFromBigBuf(uint8_t *dest, int bytes, int start_index); - -#endif diff --git a/client/emv/apduinfo.c b/client/emv/apduinfo.c index ec7a64a1..a631c614 100644 --- a/client/emv/apduinfo.c +++ b/client/emv/apduinfo.c @@ -132,7 +132,7 @@ const APDUCode APDUCodeTable[] = { {"6EXX", APDUCODE_TYPE_ERROR, "Instruction class not supported (procedure byte), (ISO 7816-3)"}, {"6F--", APDUCODE_TYPE_ERROR, "Internal exception"}, {"6F00", APDUCODE_TYPE_ERROR, "Command aborted - more exact diagnosis not possible (e.g., operating system error)."}, - {"6FFF", APDUCODE_TYPE_ERROR, "Card dead (overuse, …)"}, + {"6FFF", APDUCODE_TYPE_ERROR, "Card dead (overuse, ...)"}, {"6FXX", APDUCODE_TYPE_ERROR, "No precise diagnosis (procedure byte), (ISO 7816-3)"}, {"9---", APDUCODE_TYPE_NONE, ""}, {"9000", APDUCODE_TYPE_INFO, "Command successfully executed (OK)."}, diff --git a/client/emv/crypto_polarssl.c b/client/emv/crypto_polarssl.c index 760395c4..5a3db8ea 100644 --- a/client/emv/crypto_polarssl.c +++ b/client/emv/crypto_polarssl.c @@ -105,7 +105,7 @@ static struct crypto_pk *crypto_pk_polarssl_open_rsa(va_list vl) int res = rsa_check_pubkey(&cp->ctx); if(res != 0) { fprintf(stderr, "PolarSSL public key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen); - + free(cp); return NULL; } @@ -150,6 +150,7 @@ static struct crypto_pk *crypto_pk_polarssl_open_priv_rsa(va_list vl) int res = rsa_check_privkey(&cp->ctx); if(res != 0) { fprintf(stderr, "PolarSSL private key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen); + free(cp); return NULL; } @@ -184,6 +185,7 @@ static struct crypto_pk *crypto_pk_polarssl_genkey_rsa(va_list vl) int res = rsa_gen_key(&cp->ctx, &myrand, NULL, nbits, exp); if (res) { fprintf(stderr, "PolarSSL private key generation error res=%x exp=%d nbits=%d.\n", res * -1, exp, nbits); + free(cp); return NULL; } @@ -215,7 +217,8 @@ static unsigned char *crypto_pk_polarssl_encrypt(const struct crypto_pk *_cp, co res = rsa_public(&cp->ctx, buf, result); if(res) { - printf("RSA encrypt failed. Error: %x data len: %d key len: %d\n", res * -1, len, keylen); + printf("RSA encrypt failed. Error: %x data len: %zd key len: %zd\n", res * -1, len, keylen); + free(result); return NULL; } @@ -241,7 +244,8 @@ static unsigned char *crypto_pk_polarssl_decrypt(const struct crypto_pk *_cp, co res = rsa_private(&cp->ctx, buf, result); // CHECK??? if(res) { - printf("RSA decrypt failed. Error: %x data len: %d key len: %d\n", res * -1, len, keylen); + printf("RSA decrypt failed. Error: %x data len: %zd key len: %zd\n", res * -1, len, keylen); + free(result); return NULL; } diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index 7803060e..f79e3045 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -53,7 +53,7 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, } if (cert_tlv->len != enc_pk->mlen) { - printf("ERROR: Certificate length (%d) not equal key length (%d)\n", cert_tlv->len, enc_pk->mlen); + printf("ERROR: Certificate length (%zd) not equal key length (%zd)\n", cert_tlv->len, enc_pk->mlen); return NULL; } kcp = crypto_pk_open(enc_pk->pk_algo, @@ -451,7 +451,7 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t un_tlv, NULL); if (!data || data_len < 3) { - printf("ERROR: can't decode message. len %d\n", data_len); + printf("ERROR: can't decode message. len %zd\n", data_len); return NULL; } diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 08c6e3db..36f6f8eb 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -221,7 +221,7 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) { return tlvdb_fixed(0x02, dCVVlen, dCVV); } -int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { +int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { uint8_t data[APDU_RES_LEN] = {0}; *ResultLen = 0; @@ -237,10 +237,10 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, uint8_t *Re memcpy(&data[5], apdu.data, apdu.Lc); if (APDULogging) - PrintAndLog(">>>> %s", sprint_hex(data, 6 + apdu.Lc)); + PrintAndLog(">>>> %s", sprint_hex(data, (IncludeLe?6:5) + apdu.Lc)); - // 6 byes + data = INS + CLA + P1 + P2 + Lc + + Le - int res = ExchangeAPDU14a(data, 6 + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + // 6 byes + data = INS + CLA + P1 + P2 + Lc + + Le(?IncludeLe) + int res = ExchangeAPDU14a(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); if (res) { return res; @@ -270,11 +270,11 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, uint8_t *Re } int EMVExchange(bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(false, LeaveFieldON, apdu, Result, MaxResultLen, ResultLen, sw, tlv); + return EMVExchangeEx(false, LeaveFieldON, apdu, true, Result, MaxResultLen, ResultLen, sw, tlv); } int EMVSelect(bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, Result, MaxResultLen, ResultLen, sw, tlv); + return EMVExchangeEx(ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, true, Result, MaxResultLen, ResultLen, sw, tlv); } int EMVSelectPSE(bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { @@ -453,7 +453,12 @@ int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, si } int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); + int res = EMVExchange(LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); + if (*sw == 0x6700) { + PrintAndLog(">>> trying to reissue command withouth Le..."); + res = EMVExchangeEx(false, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); + } + return res; } int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { @@ -461,7 +466,12 @@ int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, } int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); + int res = EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); + if (*sw == 0x6700) { + PrintAndLog(">>> trying to reissue command withouth Le..."); + res = EMVExchangeEx(false, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); + } + return res; } int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { diff --git a/client/emv/test/crypto_test.c b/client/emv/test/crypto_test.c index ff18b9da..352f48b4 100644 --- a/client/emv/test/crypto_test.c +++ b/client/emv/test/crypto_test.c @@ -219,7 +219,7 @@ static int test_pk(bool verbose) tmp = crypto_pk_get_parameter(pubk, 0, &tmp_len); if (tmp_len != sizeof(pk_N) || memcmp(tmp, pk_N, tmp_len)) { - fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %d len %d\n", tmp_len, sizeof(pk_N)); + fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %zd len %zd\n", tmp_len, sizeof(pk_N)); free(tmp); goto close_pub; } @@ -256,7 +256,7 @@ static int test_pk(bool verbose) tmp = crypto_pk_get_parameter(privk, 0, &tmp_len); if (tmp_len != sizeof(pk_N) || memcmp(tmp, pk_N, tmp_len)) { - fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %d len %d\n", tmp_len, sizeof(pk_N)); + fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %zd len %zd\n", tmp_len, sizeof(pk_N)); free(tmp); goto close; } diff --git a/client/flash.c b/client/flash.c index 7622e8a5..9a443cb8 100644 --- a/client/flash.c +++ b/client/flash.c @@ -20,14 +20,7 @@ #include "elf.h" #include "proxendian.h" #include "usb_cmd.h" - -void SendCommand(UsbCommand* txcmd); -void ReceiveCommand(UsbCommand* rxcmd); -void CloseProxmark(); -int OpenProxmark(size_t i); - -// FIXME: what the fuckity fuck -unsigned int current_command = CMD_UNKNOWN; +#include "comms.h" #define FLASH_START 0x100000 #define FLASH_SIZE (256*1024) @@ -44,9 +37,10 @@ static const uint8_t elf_ident[] = { EV_CURRENT }; + // Turn PHDRs into flasher segments, checking for PHDR sanity and merging adjacent // unaligned segments if needed -static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs, int num_phdrs) +static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs, uint16_t num_phdrs) { Elf32_Phdr *phdr = phdrs; flash_seg_t *seg; @@ -192,12 +186,12 @@ static int check_segs(flash_file_t *ctx, int can_write_bl) { } // Load an ELF file and prepare it for flashing -int flash_load(flash_file_t *ctx, const char *name, int can_write_bl) +int flash_load(flash_file_t *ctx, const char *name, bool can_write_bl) { FILE *fd = NULL; Elf32_Ehdr ehdr; Elf32_Phdr *phdrs = NULL; - int num_phdrs; + uint16_t num_phdrs; int res; fd = fopen(name, "rb"); @@ -276,11 +270,11 @@ fail: // Get the state of the proxmark, backwards compatible static int get_proxmark_state(uint32_t *state) { - UsbCommand c; + UsbCommand c = {0}; c.cmd = CMD_DEVICE_INFO; - SendCommand(&c); + SendCommand(&c); UsbCommand resp; - ReceiveCommand(&resp); + WaitForResponse(CMD_UNKNOWN, &resp); // wait for any response. No timeout. // Three outcomes: // 1. The old bootrom code will ignore CMD_DEVICE_INFO, but respond with an ACK @@ -338,17 +332,18 @@ static int enter_bootloader(char *serial_port_name) SendCommand(&c); fprintf(stderr,"Press and hold down button NOW if your bootloader requires it.\n"); } - msleep(100); + + msleep(100); CloseProxmark(); - fprintf(stderr,"Waiting for Proxmark to reappear on %s",serial_port_name); - do { - sleep(1); - fprintf(stderr, "."); - } while (!OpenProxmark(0)); - fprintf(stderr," Found.\n"); - - return 0; + bool opened = OpenProxmark(serial_port_name, true, 120, true); // wait for 2 minutes + if (opened) { + fprintf(stderr," Found.\n"); + return 0; + } else { + fprintf(stderr,"Error: Proxmark not found.\n"); + return -1; + } } fprintf(stderr, "Error: Unknown Proxmark mode\n"); @@ -357,8 +352,8 @@ static int enter_bootloader(char *serial_port_name) static int wait_for_ack(void) { - UsbCommand ack; - ReceiveCommand(&ack); + UsbCommand ack; + WaitForResponse(CMD_UNKNOWN, &ack); if (ack.cmd != CMD_ACK) { printf("Error: Unexpected reply 0x%04" PRIx64 " (expected ACK)\n", ack.cmd); return -1; @@ -407,12 +402,12 @@ static int write_block(uint32_t address, uint8_t *data, uint32_t length) memset(block_buf, 0xFF, BLOCK_SIZE); memcpy(block_buf, data, length); - UsbCommand c; + UsbCommand c; c.cmd = CMD_FINISH_WRITE; c.arg[0] = address; memcpy(c.d.asBytes, block_buf, length); - SendCommand(&c); - return wait_for_ack(); + SendCommand(&c); + return wait_for_ack(); } // Write a file's segments to Flash @@ -472,7 +467,7 @@ void flash_free(flash_file_t *ctx) // just reset the unit int flash_stop_flashing(void) { UsbCommand c = {CMD_HARDWARE_RESET}; - SendCommand(&c); - msleep(100); - return 0; + SendCommand(&c); + msleep(100); + return 0; } diff --git a/client/flash.h b/client/flash.h index 3e9f77a7..06c7c96e 100644 --- a/client/flash.h +++ b/client/flash.h @@ -10,7 +10,7 @@ #define __FLASH_H__ #include -#include "elf.h" +#include typedef struct { void *data; @@ -25,11 +25,10 @@ typedef struct { flash_seg_t *segments; } flash_file_t; -int flash_load(flash_file_t *ctx, const char *name, int can_write_bl); -int flash_start_flashing(int enable_bl_writes,char *serial_port_name); +int flash_load(flash_file_t *ctx, const char *name, bool can_write_bl); +int flash_start_flashing(int enable_bl_writes, char *serial_port_name); int flash_write(flash_file_t *ctx); void flash_free(flash_file_t *ctx); int flash_stop_flashing(void); - #endif diff --git a/client/flasher.c b/client/flasher.c index f257d994..a008f7bc 100644 --- a/client/flasher.c +++ b/client/flasher.c @@ -10,21 +10,14 @@ #include #include #include +#include #include "proxmark3.h" #include "util.h" #include "util_posix.h" #include "flash.h" -#include "uart.h" +#include "comms.h" #include "usb_cmd.h" -#ifdef _WIN32 -# define unlink(x) -#else -# include -#endif - -static serial_port sp; -static char* serial_port_name; void cmd_debug(UsbCommand* UC) { // Debug @@ -40,62 +33,24 @@ void cmd_debug(UsbCommand* UC) { printf("...\n"); } -void SendCommand(UsbCommand* txcmd) { -// printf("send: "); -// cmd_debug(txcmd); - if (!uart_send(sp,(byte_t*)txcmd,sizeof(UsbCommand))) { - printf("Sending bytes to proxmark failed\n"); - exit(1); - } -} - -void ReceiveCommand(UsbCommand* rxcmd) { - byte_t* prxcmd = (byte_t*)rxcmd; - byte_t* prx = prxcmd; - size_t rxlen; - while (true) { - if (uart_receive(sp, prx, sizeof(UsbCommand) - (prx-prxcmd), &rxlen)) { - prx += rxlen; - if ((prx-prxcmd) >= sizeof(UsbCommand)) { - return; - } - } - } -} - -void CloseProxmark() { - // Clean up the port - uart_close(sp); - // Fix for linux, it seems that it is extremely slow to release the serial port file descriptor /dev/* - unlink(serial_port_name); -} - -int OpenProxmark(size_t i) { - sp = uart_open(serial_port_name); - if (sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT) { - //poll once a second - return 0; - } - return 1; -} - static void usage(char *argv0) { fprintf(stderr, "Usage: %s [-b] image.elf [image.elf...]\n\n", argv0); fprintf(stderr, "\t-b\tEnable flashing of bootloader area (DANGEROUS)\n\n"); - //Is the example below really true? /Martin - fprintf(stderr, "Example:\n\n\t %s path/to/osimage.elf path/to/fpgaimage.elf\n", argv0); - fprintf(stderr, "\nExample (Linux):\n\n\t %s /dev/ttyACM0 armsrc/obj/fullimage.elf\n", argv0); - fprintf(stderr, "\nNote (Linux): if the flasher gets stuck in 'Waiting for Proxmark to reappear on ',\n"); - fprintf(stderr, " you need to blacklist proxmark for modem-manager - see wiki for more details:\n"); - fprintf(stderr, " http://code.google.com/p/proxmark3/wiki/Linux\n\n"); + fprintf(stderr, "\nExample:\n\n\t %s "SERIAL_PORT_H" armsrc/obj/fullimage.elf\n", argv0); +#ifdef __linux__ + fprintf(stderr, "\nNote (Linux): if the flasher gets stuck at 'Waiting for Proxmark to reappear',\n"); + fprintf(stderr, " you may need to blacklist proxmark for modem-manager. v1.4.14 and later\n"); + fprintf(stderr, " include this configuration patch already. The change can be found at:\n"); + fprintf(stderr, " https://cgit.freedesktop.org/ModemManager/ModemManager/commit/?id=6e7ff47\n\n"); +#endif } #define MAX_FILES 4 int main(int argc, char **argv) { - int can_write_bl = 0; + int can_write_bl = false; int num_files = 0; int res; flash_file_t files[MAX_FILES]; @@ -110,7 +65,7 @@ int main(int argc, char **argv) for (int i = 2; i < argc; i++) { if (argv[i][0] == '-') { if (!strcmp(argv[i], "-b")) { - can_write_bl = 1; + can_write_bl = true; } else { usage(argv[0]); return -1; @@ -126,16 +81,16 @@ int main(int argc, char **argv) } } - serial_port_name = argv[1]; - - fprintf(stderr,"Waiting for Proxmark to appear on %s",serial_port_name); - do { - msleep(1000); - fprintf(stderr, "."); - } while (!OpenProxmark(0)); - fprintf(stderr," Found.\n"); + char* serial_port_name = argv[1]; - res = flash_start_flashing(can_write_bl,serial_port_name); + if (!OpenProxmark(serial_port_name, true, 120, true)) { // wait for 2 minutes + fprintf(stderr, "Could not find Proxmark on %s.\n\n", serial_port_name); + return -1; + } else { + fprintf(stderr," Found.\n"); + } + + res = flash_start_flashing(can_write_bl, serial_port_name); if (res < 0) return -1; @@ -155,6 +110,7 @@ int main(int argc, char **argv) if (res < 0) return -1; + // Stop the command thread. CloseProxmark(); fprintf(stderr, "All done.\n\n"); diff --git a/client/fpga_compress.c b/client/fpga_compress.c index a672ab58..418a02b8 100644 --- a/client/fpga_compress.c +++ b/client/fpga_compress.c @@ -1,4 +1,6 @@ //----------------------------------------------------------------------------- +// piwi, 2017, 2018 +// // 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. @@ -11,9 +13,11 @@ #include #include +#include #include #include #include +#include "fpga.h" #include "zlib.h" #define MAX(a,b) ((a)>(b)?(a):(b)) @@ -37,18 +41,18 @@ #define COMPRESS_MAX_NICE_LENGTH 258 #define COMPRESS_MAX_CHAIN 8192 -#define FPGA_INTERLEAVE_SIZE 288 // (the FPGA's internal config frame size is 288 bits. Interleaving with 288 bytes should give best compression) -#define FPGA_CONFIG_SIZE 42336L // our current fpga_[lh]f.bit files are 42175 bytes. Rounded up to next multiple of FPGA_INTERLEAVE_SIZE #define HARDNESTED_TABLE_SIZE (sizeof(uint32_t) * ((1L<<19)+1)) static void usage(void) { fprintf(stdout, "Usage: fpga_compress ... \n"); fprintf(stdout, " Combine n FPGA bitstream files and compress them into one.\n\n"); - fprintf(stdout, " fpga_compress -d "); - fprintf(stdout, " Decompress . Write result to "); - fprintf(stdout, " fpga_compress -t "); - fprintf(stdout, " Compress hardnested table . Write result to "); + fprintf(stdout, " fpga_compress -v ... \n"); + fprintf(stdout, " Extract Version Information from FPGA bitstream files and write it to \n\n"); + fprintf(stdout, " fpga_compress -d \n"); + fprintf(stdout, " Decompress . Write result to \n\n"); + fprintf(stdout, " fpga_compress -t \n"); + fprintf(stdout, " Compress hardnested table . Write result to \n\n"); } @@ -60,7 +64,7 @@ static voidpf fpga_deflate_malloc(voidpf opaque, uInt items, uInt size) static void fpga_deflate_free(voidpf opaque, voidpf address) { - return free(address); + free(address); } @@ -108,7 +112,7 @@ int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile, bool hardn for(uint16_t j = 0; j < num_infiles; j++) { for(uint16_t k = 0; k < FPGA_INTERLEAVE_SIZE; k++) { - c = fgetc(infile[j]); + c = (uint8_t)fgetc(infile[j]); if (!feof(infile[j])) { fpga_config[i++] = c; } else if (num_infiles > 1) { @@ -252,9 +256,162 @@ int zlib_decompress(FILE *infile, FILE *outfile) } +/* Simple Xilinx .bit parser. The file starts with the fixed opaque byte sequence + * 00 09 0f f0 0f f0 0f f0 0f f0 00 00 01 + * After that the format is 1 byte section type (ASCII character), 2 byte length + * (big endian), bytes content. Except for section 'e' which has 4 bytes + * length. + */ +static int bitparse_find_section(FILE *infile, char section_name, unsigned int *section_length) +{ + int result = 0; + #define MAX_FPGA_BIT_STREAM_HEADER_SEARCH 100 // maximum number of bytes to search for the requested section + uint16_t numbytes = 0; + while(numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH) { + char current_name = (char)fgetc(infile); + numbytes++; + if(current_name < 'a' || current_name > 'e') { + /* Strange section name, abort */ + break; + } + unsigned int current_length = 0; + switch(current_name) { + case 'e': + /* Four byte length field */ + current_length += fgetc(infile) << 24; + current_length += fgetc(infile) << 16; + numbytes += 2; + default: /* Fall through, two byte length field */ + current_length += fgetc(infile) << 8; + current_length += fgetc(infile) << 0; + numbytes += 2; + } + + if(current_name != 'e' && current_length > 255) { + /* Maybe a parse error */ + break; + } + + if(current_name == section_name) { + /* Found it */ + *section_length = current_length; + result = 1; + break; + } + + for (uint16_t i = 0; i < current_length && numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH; i++) { + (void)fgetc(infile); + numbytes++; + } + } + + return result; +} + + +static int FpgaGatherVersion(FILE *infile, char* infile_name, char *dst, int len) +{ + unsigned int fpga_info_len; + char tempstr[40] = {0x00}; + + dst[0] = '\0'; + + for (uint16_t i = 0; i < FPGA_BITSTREAM_FIXED_HEADER_SIZE; i++) { + if (fgetc(infile) != bitparse_fixed_header[i]) { + fprintf(stderr, "Invalid FPGA file. Aborting...\n\n"); + return(EXIT_FAILURE); + } + } + + strncat(dst, basename(infile_name), len-1); + // if (bitparse_find_section(infile, 'a', &fpga_info_len)) { + // for (uint16_t i = 0; i < fpga_info_len; i++) { + // char c = (char)fgetc(infile); + // if (i < sizeof(tempstr)) { + // tempstr[i] = c; + // } + // } + // strncat(dst, tempstr, len-1); + // } + strncat(dst, " built", len-1); + if (bitparse_find_section(infile, 'b', &fpga_info_len)) { + strncat(dst, " for ", len-1); + for (uint16_t i = 0; i < fpga_info_len; i++) { + char c = (char)fgetc(infile); + if (i < sizeof(tempstr)) { + tempstr[i] = c; + } + } + strncat(dst, tempstr, len-1); + } + if (bitparse_find_section(infile, 'c', &fpga_info_len)) { + strncat(dst, " on ", len-1); + for (uint16_t i = 0; i < fpga_info_len; i++) { + char c = (char)fgetc(infile); + if (i < sizeof(tempstr)) { + tempstr[i] = c; + } + } + strncat(dst, tempstr, len-1); + } + if (bitparse_find_section(infile, 'd', &fpga_info_len)) { + strncat(dst, " at ", len-1); + for (uint16_t i = 0; i < fpga_info_len; i++) { + char c = (char)fgetc(infile); + if (i < sizeof(tempstr)) { + tempstr[i] = c; + } + } + strncat(dst, tempstr, len-1); + } + return 0; +} + + +static void print_version_info_preamble(FILE *outfile, int num_infiles) { + fprintf(outfile, "//-----------------------------------------------------------------------------\n"); + fprintf(outfile, "// piwi, 2018\n"); + fprintf(outfile, "//\n"); + fprintf(outfile, "// This code is licensed to you under the terms of the GNU GPL, version 2 or,\n"); + fprintf(outfile, "// at your option, any later version. See the LICENSE.txt file for the text of\n"); + fprintf(outfile, "// the license.\n"); + fprintf(outfile, "//-----------------------------------------------------------------------------\n"); + fprintf(outfile, "// Version information on fpga images\n"); + fprintf(outfile, "//\n"); + fprintf(outfile, "// This file is generated by fpga_compress. Don't edit!\n"); + fprintf(outfile, "//-----------------------------------------------------------------------------\n"); + fprintf(outfile, "\n"); + fprintf(outfile, "\n"); + fprintf(outfile, "const int fpga_bitstream_num = %d;\n", num_infiles); + fprintf(outfile, "const char* const fpga_version_information[%d] = {\n", num_infiles); +} + + +static int generate_fpga_version_info(FILE *infile[], char *infile_names[], int num_infiles, FILE *outfile) { + + char version_string[80] = ""; + + print_version_info_preamble(outfile, num_infiles); + + for (int i = 0; i < num_infiles; i++) { + FpgaGatherVersion(infile[i], infile_names[i], version_string, sizeof(version_string)); + fprintf(outfile, "\t\"%s\"", version_string); + if (i != num_infiles-1) { + fprintf(outfile, ","); + } + fprintf(outfile,"\n"); + } + + fprintf(outfile, "};\n"); + + return 0; +} + + int main(int argc, char **argv) { FILE **infiles; + char **infile_names; FILE *outfile; if (argc == 1 || argc == 2) { @@ -271,43 +428,56 @@ int main(int argc, char **argv) } infiles[0] = fopen(argv[2], "rb"); if (infiles[0] == NULL) { - fprintf(stderr, "Error. Cannot open input file %s", argv[2]); + fprintf(stderr, "Error. Cannot open input file %s\n\n", argv[2]); return(EXIT_FAILURE); } outfile = fopen(argv[3], "wb"); if (outfile == NULL) { - fprintf(stderr, "Error. Cannot open output file %s", argv[3]); + fprintf(stderr, "Error. Cannot open output file %s\n\n", argv[3]); return(EXIT_FAILURE); } return zlib_decompress(infiles[0], outfile); - } else { // Compress + } else { // Compress or gemerate version info bool hardnested_mode = false; + bool generate_version_file = false; int num_input_files = 0; - if (!strcmp(argv[1], "-t")) { // hardnested table + if (!strcmp(argv[1], "-t")) { // compress one hardnested table if (argc != 4) { usage(); return(EXIT_FAILURE); } hardnested_mode = true; num_input_files = 1; - } else { + } else if (!strcmp(argv[1], "-v")) { // generate version info + generate_version_file = true; + num_input_files = argc-3; + } else { // compress 1..n fpga files num_input_files = argc-2; } + infiles = calloc(num_input_files, sizeof(FILE*)); - for (uint16_t i = 0; i < num_input_files; i++) { - infiles[i] = fopen(argv[i+hardnested_mode?2:1], "rb"); + infile_names = calloc(num_input_files, sizeof(char*)); + for (uint16_t i = 0; i < num_input_files; i++) { + infile_names[i] = argv[i+((hardnested_mode || generate_version_file)?2:1)]; + infiles[i] = fopen(infile_names[i], "rb"); if (infiles[i] == NULL) { - fprintf(stderr, "Error. Cannot open input file %s", argv[i+hardnested_mode?2:1]); + fprintf(stderr, "Error. Cannot open input file %s\n\n", infile_names[i]); return(EXIT_FAILURE); } } outfile = fopen(argv[argc-1], "wb"); if (outfile == NULL) { - fprintf(stderr, "Error. Cannot open output file %s", argv[argc-1]); + fprintf(stderr, "Error. Cannot open output file %s\n\n", argv[argc-1]); return(EXIT_FAILURE); } - return zlib_compress(infiles, num_input_files, outfile, hardnested_mode); + if (generate_version_file) { + if (generate_fpga_version_info(infiles, infile_names, num_input_files, outfile)) { + return(EXIT_FAILURE); + } + } else { + return zlib_compress(infiles, num_input_files, outfile, hardnested_mode); + } } } diff --git a/client/hardnested/hardnested_bf_core.c b/client/hardnested/hardnested_bf_core.c index 3c0c044f..d02209e9 100644 --- a/client/hardnested/hardnested_bf_core.c +++ b/client/hardnested/hardnested_bf_core.c @@ -548,44 +548,105 @@ out: crack_states_bitsliced_t *crack_states_bitsliced_function_p = &crack_states_bitsliced_dispatch; bitslice_test_nonces_t *bitslice_test_nonces_function_p = &bitslice_test_nonces_dispatch; -// determine the available instruction set at runtime and call the correct function -const uint64_t crack_states_bitsliced_dispatch(uint32_t cuid, uint8_t *best_first_bytes, statelist_t *p, uint32_t *keys_found, uint64_t *num_keys_tested, uint32_t nonces_to_bruteforce, uint8_t *bf_test_nonce_2nd_byte, noncelist_t *nonces) { +static SIMDExecInstr intSIMDInstr = SIMD_AUTO; + +void SetSIMDInstr(SIMDExecInstr instr) { + intSIMDInstr = instr; + + crack_states_bitsliced_function_p = &crack_states_bitsliced_dispatch; + bitslice_test_nonces_function_p = &bitslice_test_nonces_dispatch; +} + +SIMDExecInstr GetSIMDInstr() { + SIMDExecInstr instr = SIMD_NONE; + #if defined (__i386__) || defined (__x86_64__) #if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1)) #if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2) - if (__builtin_cpu_supports("avx512f")) crack_states_bitsliced_function_p = &crack_states_bitsliced_AVX512; - else if (__builtin_cpu_supports("avx2")) crack_states_bitsliced_function_p = &crack_states_bitsliced_AVX2; + if (__builtin_cpu_supports("avx512f")) instr = SIMD_AVX512; + else if (__builtin_cpu_supports("avx2")) instr = SIMD_AVX2; #else - if (__builtin_cpu_supports("avx2")) crack_states_bitsliced_function_p = &crack_states_bitsliced_AVX2; + if (__builtin_cpu_supports("avx2")) instr = SIMD_AVX2; #endif - else if (__builtin_cpu_supports("avx")) crack_states_bitsliced_function_p = &crack_states_bitsliced_AVX; - else if (__builtin_cpu_supports("sse2")) crack_states_bitsliced_function_p = &crack_states_bitsliced_SSE2; - else if (__builtin_cpu_supports("mmx")) crack_states_bitsliced_function_p = &crack_states_bitsliced_MMX; + else if (__builtin_cpu_supports("avx")) instr = SIMD_AVX; + else if (__builtin_cpu_supports("sse2")) instr = SIMD_SSE2; + else if (__builtin_cpu_supports("mmx")) instr = SIMD_MMX; else #endif #endif - crack_states_bitsliced_function_p = &crack_states_bitsliced_NOSIMD; + instr = SIMD_NONE; + + return instr; +} + +SIMDExecInstr GetSIMDInstrAuto() { + SIMDExecInstr instr = intSIMDInstr; + if (instr == SIMD_AUTO) + return GetSIMDInstr(); + + return instr; +} + +// determine the available instruction set at runtime and call the correct function +const uint64_t crack_states_bitsliced_dispatch(uint32_t cuid, uint8_t *best_first_bytes, statelist_t *p, uint32_t *keys_found, uint64_t *num_keys_tested, uint32_t nonces_to_bruteforce, uint8_t *bf_test_nonce_2nd_byte, noncelist_t *nonces) { + switch(GetSIMDInstrAuto()) { +#if defined (__i386__) || defined (__x86_64__) +#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1)) +#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2) + case SIMD_AVX512: + crack_states_bitsliced_function_p = &crack_states_bitsliced_AVX512; + break; +#endif + case SIMD_AVX2: + crack_states_bitsliced_function_p = &crack_states_bitsliced_AVX2; + break; + case SIMD_AVX: + crack_states_bitsliced_function_p = &crack_states_bitsliced_AVX; + break; + case SIMD_SSE2: + crack_states_bitsliced_function_p = &crack_states_bitsliced_SSE2; + break; + case SIMD_MMX: + crack_states_bitsliced_function_p = &crack_states_bitsliced_MMX; + break; +#endif +#endif + default: + crack_states_bitsliced_function_p = &crack_states_bitsliced_NOSIMD; + break; + } // call the most optimized function for this CPU return (*crack_states_bitsliced_function_p)(cuid, best_first_bytes, p, keys_found, num_keys_tested, nonces_to_bruteforce, bf_test_nonce_2nd_byte, nonces); } void bitslice_test_nonces_dispatch(uint32_t nonces_to_bruteforce, uint32_t *bf_test_nonce, uint8_t *bf_test_nonce_par) { -#if defined (__i386__) || defined (__x86_64__) - #if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1)) - #if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2) - if (__builtin_cpu_supports("avx512f")) bitslice_test_nonces_function_p = &bitslice_test_nonces_AVX512; - else if (__builtin_cpu_supports("avx2")) bitslice_test_nonces_function_p = &bitslice_test_nonces_AVX2; - #else - if (__builtin_cpu_supports("avx2")) bitslice_test_nonces_function_p = &bitslice_test_nonces_AVX2; - #endif - else if (__builtin_cpu_supports("avx")) bitslice_test_nonces_function_p = &bitslice_test_nonces_AVX; - else if (__builtin_cpu_supports("sse2")) bitslice_test_nonces_function_p = &bitslice_test_nonces_SSE2; - else if (__builtin_cpu_supports("mmx")) bitslice_test_nonces_function_p = &bitslice_test_nonces_MMX; - else - #endif + switch(GetSIMDInstrAuto()) { +#if defined (__i386__) || defined (__x86_64__) +#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1)) +#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2) + case SIMD_AVX512: + bitslice_test_nonces_function_p = &bitslice_test_nonces_AVX512; + break; #endif - bitslice_test_nonces_function_p = &bitslice_test_nonces_NOSIMD; + case SIMD_AVX2: + bitslice_test_nonces_function_p = &bitslice_test_nonces_AVX2; + break; + case SIMD_AVX: + bitslice_test_nonces_function_p = &bitslice_test_nonces_AVX; + break; + case SIMD_SSE2: + bitslice_test_nonces_function_p = &bitslice_test_nonces_SSE2; + break; + case SIMD_MMX: + bitslice_test_nonces_function_p = &bitslice_test_nonces_MMX; + break; +#endif +#endif + default: + bitslice_test_nonces_function_p = &bitslice_test_nonces_NOSIMD; + break; + } // call the most optimized function for this CPU (*bitslice_test_nonces_function_p)(nonces_to_bruteforce, bf_test_nonce, bf_test_nonce_par); diff --git a/client/hardnested/hardnested_bf_core.h b/client/hardnested/hardnested_bf_core.h index 7a445993..b3df0547 100644 --- a/client/hardnested/hardnested_bf_core.h +++ b/client/hardnested/hardnested_bf_core.h @@ -52,6 +52,18 @@ THE SOFTWARE. #include "hardnested_bruteforce.h" // statelist_t +typedef enum { + SIMD_AUTO, + SIMD_AVX512, + SIMD_AVX2, + SIMD_AVX, + SIMD_SSE2, + SIMD_MMX, + SIMD_NONE, +} SIMDExecInstr; +extern void SetSIMDInstr(SIMDExecInstr instr); +extern SIMDExecInstr GetSIMDInstrAuto(); + extern const uint64_t crack_states_bitsliced(uint32_t cuid, uint8_t *best_first_bytes, statelist_t *p, uint32_t *keys_found, uint64_t *num_keys_tested, uint32_t nonces_to_bruteforce, uint8_t *bf_test_nonces_2nd_byte, noncelist_t *nonces); extern void bitslice_test_nonces(uint32_t nonces_to_bruteforce, uint32_t *bf_test_nonces, uint8_t *bf_test_nonce_par); diff --git a/client/hardnested/hardnested_bruteforce.c b/client/hardnested/hardnested_bruteforce.c index 718b7c5d..deea69d8 100644 --- a/client/hardnested/hardnested_bruteforce.c +++ b/client/hardnested/hardnested_bruteforce.c @@ -139,8 +139,13 @@ bool verify_key(uint32_t cuid, noncelist_t *nonces, uint8_t *best_first_bytes, u return true; } - -static void* crack_states_thread(void* x){ +static void* +#ifdef __has_attribute +#if __has_attribute(force_align_arg_pointer) +__attribute__((force_align_arg_pointer)) +#endif +#endif +crack_states_thread(void* x){ struct arg { bool silent; diff --git a/client/hid-flasher/proxusb.c b/client/hid-flasher/proxusb.c index 04dbb784..364b21a3 100644 --- a/client/hid-flasher/proxusb.c +++ b/client/hid-flasher/proxusb.c @@ -31,7 +31,6 @@ usb_dev_handle *devh = NULL; static unsigned int claimed_iface = 0; unsigned char return_on_error = 0; unsigned char error_occured = 0; -extern unsigned int current_command; void SendCommand(UsbCommand *c) { @@ -40,7 +39,6 @@ void SendCommand(UsbCommand *c) #if 0 printf("Sending %d bytes\n", sizeof(UsbCommand)); #endif - current_command = c->cmd; ret = usb_bulk_write(devh, 0x01, (char*)c, sizeof(UsbCommand), 1000); if (ret<0) { error_occured = 1; diff --git a/client/lualibs/read14a.lua b/client/lualibs/read14a.lua index ec227b17..60fc0e68 100644 --- a/client/lualibs/read14a.lua +++ b/client/lualibs/read14a.lua @@ -2,7 +2,7 @@ This is a library to read 14443a tags. It can be used something like this local reader = require('read14a') - result, err = reader.read1443a() + result, err = reader.read14443a() if not result then print(err) return @@ -26,7 +26,7 @@ local ISO14A_COMMAND = { ISO14A_NO_RATS = 0x200 } -local ISO14443a_TYPES = {} +local ISO14443a_TYPES = {} ISO14443a_TYPES[0x00] = "NXP MIFARE Ultralight | Ultralight C" ISO14443a_TYPES[0x01] = "NXP MIFARE TNP3xxx Activision Game Appliance" ISO14443a_TYPES[0x04] = "NXP MIFARE (various !DESFire !DESFire EV1)" @@ -43,14 +43,14 @@ ISO14443a_TYPES[0x88] = "Infineon MIFARE CLASSIC 1K" ISO14443a_TYPES[0x98] = "Gemplus MPCOS" -local function tostring_1443a(sak) +local function tostring_14443a(sak) return ISO14443a_TYPES[sak] or ("Unknown (SAK=%x)"):format(sak) end -local function parse1443a(data) +local function parse14443a(data) --[[ - Based on this struct : + Based on this struct : typedef struct { byte_t uid[10]; @@ -66,14 +66,14 @@ local function parse1443a(data) local count,uid,uidlen, atqa, sak, ats_len, ats= bin.unpack('H10CH2CC',data) uid = uid:sub(1,2*uidlen) --print("uid, atqa, sak: ",uid, atqa, sak) - --print("TYPE: ", tostring_1443a(sak)) - return { uid = uid, atqa = atqa, sak = sak, name = tostring_1443a(sak)} + --print("TYPE: ", tostring_14443a(sak)) + return { uid = uid, atqa = atqa, sak = sak, name = tostring_14443a(sak)} end --- Sends a USBpacket to the device -- @param command - the usb packet to send --- @param ignoreresponse - if set to true, we don't read the device answer packet --- which is usually recipe for fail. If not sent, the host will wait 2s for a +-- @param ignoreresponse - if set to true, we don't read the device answer packet +-- which is usually recipe for fail. If not sent, the host will wait 2s for a -- response of type CMD_ACK -- @return packet,nil if successfull -- nil, errormessage if unsuccessfull @@ -99,7 +99,7 @@ end local function read14443a(dont_disconnect, no_rats) local command, result, info, err, data - command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, + command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, arg1 = ISO14A_COMMAND.ISO14A_CONNECT} if dont_disconnect then command.arg1 = command.arg1 + ISO14A_COMMAND.ISO14A_NO_DISCONNECT @@ -110,24 +110,24 @@ local function read14443a(dont_disconnect, no_rats) local result,err = sendToDevice(command) if result then local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL',result) - if arg0 == 0 then + if arg0 == 0 then return nil, "iso14443a card select failed" end data = string.sub(result,count) - info, err = parse1443a(data) + info, err = parse14443a(data) else err ="No response from card" end - if err then - print(err) + if err then + print(err) return nil, err end return info end --- --- Waits for a mifare card to be placed within the vicinity of the reader. +-- Waits for a mifare card to be placed within the vicinity of the reader. -- @return if successfull: an table containing card info -- @return if unsuccessfull : nil, error local function waitFor14443a() @@ -139,14 +139,14 @@ local function waitFor14443a() end return nil, "Aborted by user" end + local library = { - - read1443a = read14443a, - read = read14443a, + read14443a = read14443a, + read = read14443a, waitFor14443a = waitFor14443a, - parse1443a = parse1443a, + parse14443a = parse14443a, sendToDevice = sendToDevice, ISO14A_COMMAND = ISO14A_COMMAND, } -return library \ No newline at end of file +return library diff --git a/client/mifarehost.c b/client/mifarehost.c index 67277b59..9be04b4d 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -16,10 +16,11 @@ #include #include "crapto1/crapto1.h" -#include "proxmark3.h" +#include "comms.h" #include "usb_cmd.h" #include "cmdmain.h" #include "ui.h" +#include "parity.h" #include "util.h" #include "iso14443crc.h" @@ -73,13 +74,12 @@ static uint32_t intersection(uint64_t *list1, uint64_t *list2) // Darkside attack (hf mf mifare) -static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t **keys) { +static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint32_t ar, uint64_t par_info, uint64_t ks_info, uint64_t **keys) { struct Crypto1State *states; - uint32_t i, pos, rr; //nr_diff; + uint32_t i, pos; uint8_t bt, ks3x[8], par[8][8]; uint64_t key_recovered; - static uint64_t *keylist; - rr = 0; + uint64_t *keylist; // Reset the last three significant bits of the reader nonce nr &= 0xffffff1f; @@ -92,7 +92,7 @@ static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_i } } - states = lfsr_common_prefix(nr, rr, ks3x, par, (par_info == 0)); + states = lfsr_common_prefix(nr, ar, ks3x, par, (par_info == 0)); if (states == NULL) { *keys = NULL; @@ -116,7 +116,7 @@ static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_i int mfDarkside(uint64_t *key) { uint32_t uid = 0; - uint32_t nt = 0, nr = 0; + uint32_t nt = 0, nr = 0, ar = 0; uint64_t par_list = 0, ks_list = 0; uint64_t *keylist = NULL, *last_keylist = NULL; uint32_t keycount = 0; @@ -159,18 +159,18 @@ int mfDarkside(uint64_t *key) nt = (uint32_t)bytes_to_num(resp.d.asBytes + 4, 4); par_list = bytes_to_num(resp.d.asBytes + 8, 8); ks_list = bytes_to_num(resp.d.asBytes + 16, 8); - nr = bytes_to_num(resp.d.asBytes + 24, 4); + nr = (uint32_t)bytes_to_num(resp.d.asBytes + 24, 4); + ar = (uint32_t)bytes_to_num(resp.d.asBytes + 28, 4); break; } } if (par_list == 0 && c.arg[0] == true) { PrintAndLog("Parity is all zero. Most likely this card sends NACK on every failed authentication."); - PrintAndLog("Attack will take a few seconds longer because we need two consecutive successful runs."); } c.arg[0] = false; - keycount = nonce2key(uid, nt, nr, par_list, ks_list, &keylist); + keycount = nonce2key(uid, nt, nr, ar, par_list, ks_list, &keylist); if (keycount == 0) { PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt); @@ -178,12 +178,14 @@ int mfDarkside(uint64_t *key) continue; } - qsort(keylist, keycount, sizeof(*keylist), compare_uint64); - keycount = intersection(last_keylist, keylist); - if (keycount == 0) { - free(last_keylist); - last_keylist = keylist; - continue; + if (par_list == 0) { + qsort(keylist, keycount, sizeof(*keylist), compare_uint64); + keycount = intersection(last_keylist, keylist); + if (keycount == 0) { + free(last_keylist); + last_keylist = keylist; + continue; + } } if (keycount > 1) { @@ -198,10 +200,10 @@ int mfDarkside(uint64_t *key) for (int i = 0; i < keycount; i += max_keys) { int size = keycount - i > max_keys ? max_keys : keycount - i; for (int j = 0; j < size; j++) { - if (last_keylist == NULL) { - num_to_bytes(keylist[i*max_keys + j], 6, keyBlock); + if (par_list == 0) { + num_to_bytes(last_keylist[i*max_keys + j], 6, keyBlock+(j*6)); } else { - num_to_bytes(last_keylist[i*max_keys + j], 6, keyBlock); + num_to_bytes(keylist[i*max_keys + j], 6, keyBlock+(j*6)); } } if (!mfCheckKeys(0, 0, false, size, keyBlock, key)) { @@ -295,7 +297,13 @@ typedef // wrapper function for multi-threaded lfsr_recovery32 -void* nested_worker_thread(void *arg) +void +#ifdef __has_attribute +#if __has_attribute(force_align_arg_pointer) +__attribute__((force_align_arg_pointer)) +#endif +#endif +*nested_worker_thread(void *arg) { struct Crypto1State *p1; StateList_t *statelist = arg; @@ -309,6 +317,7 @@ void* nested_worker_thread(void *arg) return statelist->head.slhead; } + int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate) { uint16_t i; @@ -319,7 +328,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, struct Crypto1State *p1, *p2, *p3, *p4; // flush queue - WaitForResponseTimeout(CMD_ACK, NULL, 100); + (void)WaitForResponseTimeout(CMD_ACK,NULL,100); UsbCommand c = {CMD_MIFARE_NESTED, {blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, calibrate}}; memcpy(c.d.asBytes, key, 6); @@ -574,14 +583,19 @@ struct Crypto1State *traceCrypto1 = NULL; struct Crypto1State *revstate; uint64_t lfsr; +uint64_t ui64Key; uint32_t ks2; uint32_t ks3; -uint32_t uid; // serial number -uint32_t nt; // tag challenge -uint32_t nr_enc; // encrypted reader challenge -uint32_t ar_enc; // encrypted reader response -uint32_t at_enc; // encrypted tag response +uint32_t uid; // serial number +uint32_t nt; // tag challenge +uint32_t nt_enc; // encrypted tag challenge +uint8_t nt_enc_par; // encrypted tag challenge parity +uint32_t nr_enc; // encrypted reader challenge +uint32_t ar_enc; // encrypted reader response +uint8_t ar_enc_par; // encrypted reader response parity +uint32_t at_enc; // encrypted tag response +uint8_t at_enc_par; // encrypted tag response parity int isTraceCardEmpty(void) { return ((traceCard[0] == 0) && (traceCard[1] == 0) && (traceCard[2] == 0) && (traceCard[3] == 0)); @@ -609,7 +623,8 @@ int saveTraceCard(void) { for (int i = 0; i < 64; i++) { // blocks for (int j = 0; j < 16; j++) // bytes fprintf(f, "%02x", *(traceCard + i * 16 + j)); - fprintf(f,"\n"); + if (i < 63) + fprintf(f,"\n"); } fclose(f); return 0; @@ -699,8 +714,36 @@ void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool i return; } +bool NTParityCheck(uint32_t ntx) { + if ( + (oddparity8(ntx >> 8 & 0xff) ^ (ntx & 0x01) ^ ((nt_enc_par >> 5) & 0x01) ^ (nt_enc & 0x01)) || + (oddparity8(ntx >> 16 & 0xff) ^ (ntx >> 8 & 0x01) ^ ((nt_enc_par >> 6) & 0x01) ^ (nt_enc >> 8 & 0x01)) || + (oddparity8(ntx >> 24 & 0xff) ^ (ntx >> 16 & 0x01) ^ ((nt_enc_par >> 7) & 0x01) ^ (nt_enc >> 16 & 0x01)) + ) + return false; + + uint32_t ar = prng_successor(ntx, 64); + if ( + (oddparity8(ar >> 8 & 0xff) ^ (ar & 0x01) ^ ((ar_enc_par >> 5) & 0x01) ^ (ar_enc & 0x01)) || + (oddparity8(ar >> 16 & 0xff) ^ (ar >> 8 & 0x01) ^ ((ar_enc_par >> 6) & 0x01) ^ (ar_enc >> 8 & 0x01)) || + (oddparity8(ar >> 24 & 0xff) ^ (ar >> 16 & 0x01) ^ ((ar_enc_par >> 7) & 0x01) ^ (ar_enc >> 16 & 0x01)) + ) + return false; -int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) { + uint32_t at = prng_successor(ntx, 96); + if ( + (oddparity8(ar & 0xff) ^ (at >> 24 & 0x01) ^ ((ar_enc_par >> 4) & 0x01) ^ (at_enc >> 24 & 0x01)) || + (oddparity8(at >> 8 & 0xff) ^ (at & 0x01) ^ ((at_enc_par >> 5) & 0x01) ^ (at_enc & 0x01)) || + (oddparity8(at >> 16 & 0xff) ^ (at >> 8 & 0x01) ^ ((at_enc_par >> 6) & 0x01) ^ (at_enc >> 8 & 0x01)) || + (oddparity8(at >> 24 & 0xff) ^ (at >> 16 & 0x01) ^ ((at_enc_par >> 7) & 0x01) ^ (at_enc >> 16 & 0x01)) + ) + return false; + + return true; +} + + +int mfTraceDecode(uint8_t *data_src, int len, uint8_t parity, bool wantSaveToEmlFile) { uint8_t data[64]; if (traceState == TRACE_ERROR) return 1; @@ -712,7 +755,9 @@ int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) { memcpy(data, data_src, len); if ((traceCrypto1) && ((traceState == TRACE_IDLE) || (traceState > TRACE_AUTH_OK))) { mf_crypto1_decrypt(traceCrypto1, data, len, 0); - PrintAndLog("dec> %s", sprint_hex(data, len)); + uint8_t parity[16]; + oddparitybuf(data, len, parity); + PrintAndLog("dec> %s [%s]", sprint_hex(data, len), printBitsPar(parity, len)); AddLogHex(logHexFileName, "dec> ", data, len); } @@ -801,7 +846,12 @@ int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) { case TRACE_AUTH1: if (len == 4) { traceState = TRACE_AUTH2; - nt = bytes_to_num(data, 4); + if (!traceCrypto1) { + nt = bytes_to_num(data, 4); + } else { + nt_enc = bytes_to_num(data, 4); + nt_enc_par = parity; + } return 0; } else { traceState = TRACE_ERROR; @@ -815,6 +865,7 @@ int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) { nr_enc = bytes_to_num(data, 4); ar_enc = bytes_to_num(data + 4, 4); + ar_enc_par = parity << 4; return 0; } else { traceState = TRACE_ERROR; @@ -827,19 +878,90 @@ int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) { traceState = TRACE_IDLE; at_enc = bytes_to_num(data, 4); + at_enc_par = parity; + if (!traceCrypto1) { - // decode key here) - ks2 = ar_enc ^ prng_successor(nt, 64); - ks3 = at_enc ^ prng_successor(nt, 96); - revstate = lfsr_recovery64(ks2, ks3); - lfsr_rollback_word(revstate, 0, 0); - lfsr_rollback_word(revstate, 0, 0); - lfsr_rollback_word(revstate, nr_enc, 1); - lfsr_rollback_word(revstate, uid ^ nt, 0); + // decode key here) + ks2 = ar_enc ^ prng_successor(nt, 64); + ks3 = at_enc ^ prng_successor(nt, 96); + revstate = lfsr_recovery64(ks2, ks3); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, nr_enc, 1); + lfsr_rollback_word(revstate, uid ^ nt, 0); - crypto1_get_lfsr(revstate, &lfsr); - printf("key> %x%x\n", (unsigned int)((lfsr & 0xFFFFFFFF00000000) >> 32), (unsigned int)(lfsr & 0xFFFFFFFF)); - AddLogUint64(logHexFileName, "key> ", lfsr); + crypto1_get_lfsr(revstate, &lfsr); + crypto1_destroy(revstate); + ui64Key = lfsr; + printf("key> probable key:%x%x Prng:%s ks2:%08x ks3:%08x\n", + (unsigned int)((lfsr & 0xFFFFFFFF00000000) >> 32), (unsigned int)(lfsr & 0xFFFFFFFF), + validate_prng_nonce(nt) ? "WEAK": "HARDEND", + ks2, + ks3); + AddLogUint64(logHexFileName, "key> ", lfsr); + } else { + if (validate_prng_nonce(nt)) { + struct Crypto1State *pcs; + pcs = crypto1_create(ui64Key); + uint32_t nt1 = crypto1_word(pcs, nt_enc ^ uid, 1) ^ nt_enc; + uint32_t ar = prng_successor(nt1, 64); + uint32_t at = prng_successor(nt1, 96); + printf("key> nested auth uid: %08x nt: %08x nt_parity: %s ar: %08x at: %08x\n", uid, nt1, printBitsPar(&nt_enc_par, 4), ar, at); + uint32_t nr1 = crypto1_word(pcs, nr_enc, 1) ^ nr_enc; + uint32_t ar1 = crypto1_word(pcs, 0, 0) ^ ar_enc; + uint32_t at1 = crypto1_word(pcs, 0, 0) ^ at_enc; + crypto1_destroy(pcs); + printf("key> the same key test. nr1: %08x ar1: %08x at1: %08x \n", nr1, ar1, at1); + + if (NTParityCheck(nt1)) + printf("key> the same key test OK. key=%x%x\n", (unsigned int)((ui64Key & 0xFFFFFFFF00000000) >> 32), (unsigned int)(ui64Key & 0xFFFFFFFF)); + else + printf("key> the same key test. check nt parity error.\n"); + + uint32_t ntc = prng_successor(nt, 90); + uint32_t ntx = 0; + int ntcnt = 0; + for (int i = 0; i < 16383; i++) { + ntc = prng_successor(ntc, 1); + if (NTParityCheck(ntc)){ + if (!ntcnt) + ntx = ntc; + ntcnt++; + } + } + if (ntcnt) + printf("key> nt candidate=%08x nonce distance=%d candidates count=%d\n", ntx, nonce_distance(nt, ntx), ntcnt); + else + printf("key> don't have any nt candidate( \n"); + + nt = ntx; + ks2 = ar_enc ^ prng_successor(ntx, 64); + ks3 = at_enc ^ prng_successor(ntx, 96); + + // decode key + revstate = lfsr_recovery64(ks2, ks3); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, nr_enc, 1); + lfsr_rollback_word(revstate, uid ^ nt, 0); + + crypto1_get_lfsr(revstate, &lfsr); + crypto1_destroy(revstate); + ui64Key = lfsr; + printf("key> probable key:%x%x ks2:%08x ks3:%08x\n", + (unsigned int)((lfsr & 0xFFFFFFFF00000000) >> 32), (unsigned int)(lfsr & 0xFFFFFFFF), + ks2, + ks3); + AddLogUint64(logHexFileName, "key> ", lfsr); + } else { + printf("key> hardnested not implemented!\n"); + + crypto1_destroy(traceCrypto1); + + // not implemented + traceState = TRACE_ERROR; + } + } int blockShift = ((traceCurBlock & 0xFC) + 3) * 16; if (isBlockEmpty((traceCurBlock & 0xFC) + 3)) memcpy(traceCard + blockShift + 6, trailerAccessBytes, 4); @@ -857,15 +979,6 @@ int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) { // set cryptosystem state traceCrypto1 = lfsr_recovery64(ks2, ks3); - -// nt = crypto1_word(traceCrypto1, nt ^ uid, 1) ^ nt; - - /* traceCrypto1 = crypto1_create(lfsr); // key in lfsr - crypto1_word(traceCrypto1, nt ^ uid, 0); - crypto1_word(traceCrypto1, ar, 1); - crypto1_word(traceCrypto1, 0, 0); - crypto1_word(traceCrypto1, 0, 0);*/ - return 0; } else { traceState = TRACE_ERROR; diff --git a/client/mifarehost.h b/client/mifarehost.h index 031dac1b..6a37fef1 100644 --- a/client/mifarehost.h +++ b/client/mifarehost.h @@ -13,7 +13,8 @@ #include #include -#include "data.h" +#include "crapto1/crapto1.h" +#include "util.h" // defaults // timeout in units. (ms * 106)/10 or us*0.0106 @@ -50,7 +51,7 @@ extern int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWi extern int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params); extern int mfTraceInit(uint8_t *tuid, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile); -extern int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile); +extern int mfTraceDecode(uint8_t *data_src, int len, uint8_t parity, bool wantSaveToEmlFile); extern int isTraceCardEmpty(void); extern int isBlockEmpty(int blockN); @@ -61,5 +62,7 @@ extern int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t extern int mfCIdentify(); extern int DetectClassicPrng(void); +extern bool validate_prng_nonce(uint32_t nonce); +extern void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted); #endif diff --git a/client/obj/reveng/.dummy b/client/obj/reveng/.dummy deleted file mode 100644 index e69de29b..00000000 diff --git a/client/proxgui.cpp b/client/proxgui.cpp index e899174c..18749158 100644 --- a/client/proxgui.cpp +++ b/client/proxgui.cpp @@ -62,12 +62,9 @@ extern "C" void MainGraphics(void) extern "C" void InitGraphics(int argc, char **argv, char *script_cmds_file, char *script_cmd, bool usb_present) { #ifdef Q_WS_X11 - bool useGUI = getenv("DISPLAY") != 0; -#else - bool useGUI = true; -#endif - if (!useGUI) + if (getenv("DISPLAY") == NULL) return; +#endif main_loop_thread = new WorkerThread(script_cmds_file, script_cmd, usb_present); gui = new ProxGuiQT(argc, argv, main_loop_thread); diff --git a/client/proxgui.h b/client/proxgui.h index 77bcbf01..5cad6e3a 100644 --- a/client/proxgui.h +++ b/client/proxgui.h @@ -30,7 +30,6 @@ extern int s_Buff[MAX_GRAPH_TRACE_LEN]; extern double CursorScaleFactor; extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault, CursorCPos, CursorDPos, GridOffset; extern int CommandFinished; -extern int offline; extern bool GridLocked; //Operations defined in data_operations diff --git a/client/proxguiqt.cpp b/client/proxguiqt.cpp index dc8279b5..ab0976cc 100644 --- a/client/proxguiqt.cpp +++ b/client/proxguiqt.cpp @@ -269,6 +269,7 @@ int Plot::xCoordOf(int i, QRect r ) int Plot::yCoordOf(int v, QRect r, int maxVal) { int z = (r.bottom() - r.top())/2; + if ( maxVal == 0 ) maxVal++; return -(z * v) / maxVal + z; } @@ -579,6 +580,8 @@ Plot::Plot(QWidget *parent) : QWidget(parent), GraphStart(0), GraphPixelsPerPoin CursorBPos = 0; setWindowTitle(tr("Sliders")); + + master = parent; } void Plot::closeEvent(QCloseEvent *event) @@ -688,7 +691,7 @@ void Plot::keyPressEvent(QKeyEvent *event) break; case Qt::Key_Q: - this->hide(); + master->hide(); break; default: diff --git a/client/proxguiqt.h b/client/proxguiqt.h index 45a65b04..5f7199fc 100644 --- a/client/proxguiqt.h +++ b/client/proxguiqt.h @@ -28,6 +28,7 @@ class Plot: public QWidget { private: + QWidget *master; int GraphStart; double GraphPixelsPerPoint; int CursorAPos; @@ -109,7 +110,6 @@ class ProxGuiQT : public QObject ProxWidget *plotwidget; int argc; char **argv; - void (*main_func)(void); WorkerThread *proxmarkThread; public: diff --git a/client/proxmark3.c b/client/proxmark3.c index 99ba9fba..6fb066e8 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -9,6 +9,8 @@ // Main binary //----------------------------------------------------------------------------- +#include "proxmark3.h" + #include #include #include @@ -17,96 +19,33 @@ #include #include -#include "proxmark3.h" #include "util_posix.h" #include "proxgui.h" #include "cmdmain.h" -#include "uart.h" #include "ui.h" #include "util.h" #include "cmdparser.h" #include "cmdhw.h" #include "whereami.h" +#include "comms.h" -#ifdef _WIN32 -#define SERIAL_PORT_H "com3" -#else -#define SERIAL_PORT_H "/dev/ttyACM0" +void +#ifdef __has_attribute +#if __has_attribute(force_align_arg_pointer) +__attribute__((force_align_arg_pointer)) #endif - -// a global mutex to prevent interlaced printing from different threads -pthread_mutex_t print_lock; - -static serial_port sp; -static UsbCommand txcmd; -volatile static bool txcmd_pending = false; - -void SendCommand(UsbCommand *c) { - #if 0 - printf("Sending %d bytes\n", sizeof(UsbCommand)); - #endif - - if (offline) { - PrintAndLog("Sending bytes to proxmark failed - offline"); - return; - } - /** - The while-loop below causes hangups at times, when the pm3 unit is unresponsive - or disconnected. The main console thread is alive, but comm thread just spins here. - Not good.../holiman - **/ - while(txcmd_pending); - txcmd = *c; - txcmd_pending = true; -} - -struct receiver_arg { - int run; -}; - -byte_t rx[sizeof(UsbCommand)]; -byte_t* prx = rx; - -static void *uart_receiver(void *targ) { - struct receiver_arg *arg = (struct receiver_arg*)targ; - size_t rxlen; - - while (arg->run) { - rxlen = 0; - if (uart_receive(sp, prx, sizeof(UsbCommand) - (prx-rx), &rxlen) && rxlen) { - prx += rxlen; - if (prx-rx < sizeof(UsbCommand)) { - continue; - } - UsbCommandReceived((UsbCommand*)rx); - } - prx = rx; - - if(txcmd_pending) { - if (!uart_send(sp, (byte_t*) &txcmd, sizeof(UsbCommand))) { - PrintAndLog("Sending bytes to proxmark failed"); - } - txcmd_pending = false; - } - } - - pthread_exit(NULL); - return NULL; -} - - -void main_loop(char *script_cmds_file, char *script_cmd, bool usb_present) { - struct receiver_arg rarg; +#endif +main_loop(char *script_cmds_file, char *script_cmd, bool usb_present) { char *cmd = NULL; - pthread_t reader_thread; bool execCommand = (script_cmd != NULL); bool stdinOnPipe = !isatty(STDIN_FILENO); - + if (usb_present) { - rarg.run = 1; - pthread_create(&reader_thread, NULL, &uart_receiver, &rarg); + SetOffline(false); // cache Version information now: CmdVersion(NULL); + } else { + SetOffline(true); } // file with script @@ -119,10 +58,10 @@ void main_loop(char *script_cmds_file, char *script_cmd, bool usb_present) { printf("executing commands from file: %s\n", script_cmds_file); } } - + read_history(".history"); - while(1) { + while (1) { // If there is a script file if (script_file) { @@ -192,11 +131,6 @@ void main_loop(char *script_cmds_file, char *script_cmd, bool usb_present) { } write_history(".history"); - - if (usb_present) { - rarg.run = 0; - pthread_join(reader_thread, NULL); - } if (script_file) { fclose(script_file); @@ -244,9 +178,8 @@ static void set_my_executable_path(void) static void show_help(bool showFullHelp, char *command_line){ printf("syntax: %s [-h|-help|-m|-f|-flush|-w|-wait|-c|-command|-l|-lua] [cmd_script_file_name] [command][lua_script_name]\n", command_line); - printf("\tLinux example:'%s /dev/ttyACM0'\n", command_line); - printf("\tWindows example:'%s com3'\n\n", command_line); - + printf("\texample: %s "SERIAL_PORT_H"\n\n", command_line); + if (showFullHelp){ printf("help: <-h|-help> Dump all interactive command's help at once.\n"); printf("\t%s -h\n\n", command_line); @@ -274,7 +207,7 @@ int main(int argc, char* argv[]) { bool addLuaExec = false; char *script_cmds_file = NULL; char *script_cmd = NULL; - + if (argc < 2) { show_help(true, argv[0]); return 1; @@ -294,7 +227,7 @@ int main(int argc, char* argv[]) { if(strcmp(argv[i],"-f") == 0 || strcmp(argv[i],"-flush") == 0){ printf("Output will be flushed after every print.\n"); - flushAfterWrite = 1; + SetFlushAfterWrite(true); } if(strcmp(argv[i],"-w") == 0 || strcmp(argv[i],"-wait") == 0){ @@ -349,39 +282,9 @@ int main(int argc, char* argv[]) { // set global variables set_my_executable_path(); - - // open uart - if (!waitCOMPort) { - sp = uart_open(argv[1]); - } else { - printf("Waiting for Proxmark to appear on %s ", argv[1]); - fflush(stdout); - int openCount = 0; - do { - sp = uart_open(argv[1]); - msleep(1000); - printf("."); - fflush(stdout); - } while(++openCount < 20 && (sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT)); - printf("\n"); - } - // check result of uart opening - if (sp == INVALID_SERIAL_PORT) { - printf("ERROR: invalid serial port\n"); - usb_present = false; - offline = 1; - } else if (sp == CLAIMED_SERIAL_PORT) { - printf("ERROR: serial port is claimed by another process\n"); - usb_present = false; - offline = 1; - } else { - usb_present = true; - offline = 0; - } - - // create a mutex to avoid interlacing print commands from our different threads - pthread_mutex_init(&print_lock, NULL); + // try to open USB connection to Proxmark + usb_present = OpenProxmark(argv[1], waitCOMPort, 20, false); #ifdef HAVE_GUI #ifdef _WIN32 @@ -406,11 +309,8 @@ int main(int argc, char* argv[]) { // Clean up the port if (usb_present) { - uart_close(sp); + CloseProxmark(); } - // clean up mutex - pthread_mutex_destroy(&print_lock); - exit(0); } diff --git a/client/proxmark3.h b/client/proxmark3.h index c6185c43..86d09bc0 100644 --- a/client/proxmark3.h +++ b/client/proxmark3.h @@ -20,7 +20,6 @@ extern "C" { #endif -void SendCommand(UsbCommand *c); const char *get_my_executable_path(void); const char *get_my_executable_directory(void); void main_loop(char *script_cmds_file, char *script_cmd, bool usb_present); diff --git a/client/reveng/bmpbit.c b/client/reveng/bmpbit.c deleted file mode 100644 index 39a29e61..00000000 --- a/client/reveng/bmpbit.c +++ /dev/null @@ -1,86 +0,0 @@ -/* bmpbit.c - * Greg Cook, 9/Apr/2015 - */ - -/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder - * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Gregory Cook - * - * This file is part of CRC RevEng. - * - * CRC RevEng is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * CRC RevEng is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with CRC RevEng. If not, see . - */ - -#ifdef BMPTST -# include -# include -#else -# define FILE void -#endif -#include "reveng.h" - -#if (defined BMPTST) || (BMP_BIT < 32) -/* Size in bits of a bmp_t. Not necessarily a power of two. */ -int bmpbit; - -/* The highest power of two that is strictly less than BMP_BIT. - * Initialises the index of a binary search for set bits in a bmp_t. - * (Computed correctly for BMP_BIT >= 2) - */ -int bmpsub; - -void -setbmp(void) { - /* Initialise BMP_BIT and BMP_SUB for the local architecture. */ - bmp_t bmpmax = ~(bmp_t) 0; - - bmpbit = 0; bmpsub = 1; - - while(bmpmax) { - bmpmax <<= 1; - ++bmpbit; - } - - while((bmpsub | (bmpsub - 1)) < bmpbit - 1) - bmpsub <<= 1; -} -#endif - -#ifdef BMPTST -int -main(int argc, char *argv[]) { - /* check the compile-time bitmap width is correct, otherwise - * searches run forever. */ -# if BMP_BIT > 0 - setbmp(); - if(BMP_BIT != bmpbit || BMP_SUB != bmpsub) { - fprintf(stderr,"reveng: configuration fault. Update " - "config.h with these definitions and " - "recompile:\n" - "\t#define BMP_BIT %d\n" - "\t#define BMP_SUB %d\n", - bmpbit, bmpsub); - exit(EXIT_FAILURE); - } -# endif /* BMP_BIT > 0 */ - /* check the bitmap constant macro */ - if(~(bmp_t) 0 != ~BMP_C(0)) { - fprintf(stderr, "reveng: configuration fault. Edit " - "the definition of BMP_C() in config.h to " - "match BMP_T and recompile.\n"); - exit(EXIT_FAILURE); - } - exit(EXIT_SUCCESS); -} - -#endif /* BMPTST */ diff --git a/client/reveng/cli.c b/client/reveng/cli.c deleted file mode 100644 index aa59e008..00000000 --- a/client/reveng/cli.c +++ /dev/null @@ -1,628 +0,0 @@ -/* cli.c - * Greg Cook, 9/Apr/2015 - */ - -/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder - * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Gregory Cook - * - * This file is part of CRC RevEng. - * - * CRC RevEng is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * CRC RevEng is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with CRC RevEng. If not, see . - */ - -/* 2015-04-03: added -z - * 2013-09-16: do not search with -M - * 2013-06-11: uprog() suppresses first progress report - * 2013-04-22: uprog() prints poly same as mtostr() - * 2013-02-07: added -q, uprog(), removed -W, R_ODDLY - * 2012-05-24: -D dumps parameters of all models - * 2012-03-03: added code to test sort order of model table - * 2012-02-20: set stdin to binary (MinGW). offer -D if preset unknown. - * 2011-09-06: -s reads arguments once. stdin not closed. - * 2011-09-06: fixed bad argument-freeing loops. - * 2011-08-27: validates BMP_C() - * 2011-08-26: validates BMPBIT and BMPSUB - * 2011-08-25: fixed Init/Xorout reflection logic in -V and -v - * 2011-01-17: fixed ANSI C warnings - * 2011-01-15: added NOFORCE - * 2011-01-14: added -k, -P - * 2011-01-10: reorganised switches, added -V, -X - * 2010-12-26: renamed CRC RevEng - * 2010-12-18: implemented -c, -C - * 2010-12-14: added and implemented -d, -D, fixed -ipx entry - * 2010-12-11: implemented -e. first tests - * 2010-12-10: finalised option processing. started input validation - * 2010-12-07: started cli - */ - -#include -#include -#include "getopt.h" -#ifdef _WIN32 -# include -# include -# ifndef STDIN_FILENO -# define STDIN_FILENO 0 -# endif /* STDIN_FILENO */ -#endif /* _WIN32 */ - -#include "reveng.h" - -static FILE *oread(const char *); -static poly_t rdpoly(const char *, int, int); -static void usage(void); - -static const char *myname = "reveng"; /* name of our program */ - -int reveng_main(int argc, char *argv[]) { - /* Command-line interface for CRC RevEng. - * Process options and switches in the argument list and - * run the required function. - */ - - /* default values */ - model_t model = { - PZERO, /* no CRC polynomial, user must specify */ - PZERO, /* Init = 0 */ - P_BE, /* RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h */ - PZERO, /* XorOut = 0 */ - PZERO, /* check value unused */ - NULL /* no model name */ - }; - int ibperhx = 8, obperhx = 8; - int rflags = 0, uflags = 0; /* search and UI flags */ - - unsigned long width = 0UL; - int c, mode = 0, args, psets, pass; - poly_t apoly, crc, qpoly = PZERO, *apolys, *pptr = NULL, *qptr = NULL; - model_t pset = model, *candmods, *mptr; - char *string; - - myname = argv[0]; - - /* stdin must be binary */ -#ifdef _WIN32 - _setmode(STDIN_FILENO, _O_BINARY); -#endif /* _WIN32 */ - - SETBMP(); - - //pos=0; - optind=1; - do { - c=getopt(argc, argv, "?A:BDFLMP:SVXa:bcdefhi:k:lm:p:q:rstuvw:x:yz"); - switch(c) { - case 'A': /* A: bits per output character */ - case 'a': /* a: bits per character */ - if((obperhx = atoi(optarg)) > BMP_BIT) { - fprintf(stderr,"%s: argument to -%c must be between 1 and %d\n", myname, c, BMP_BIT); - return 0; - //exit(EXIT_FAILURE); - } - if(c == 'a') ibperhx = obperhx; - break; - case 'b': /* b big-endian (RefIn = false, RefOut = false ) */ - model.flags &= ~P_REFIN; - rflags |= R_HAVERI; - /* fall through: */ - case 'B': /* B big-endian output (RefOut = false) */ - model.flags &= ~P_REFOUT; - rflags |= R_HAVERO; - mnovel(&model); - /* fall through: */ - case 'r': /* r right-justified */ - model.flags |= P_RTJUST; - break; - case 'c': /* c calculate CRC */ - case 'D': /* D list primary model names */ - case 'd': /* d dump CRC model */ - case 'e': /* e echo arguments */ - case 's': /* s search for algorithm */ - case 'v': /* v calculate reversed CRC */ - if(mode) { - fprintf(stderr,"%s: more than one mode switch specified. Use %s -h for help.\n", myname, myname); - return 0; - //exit(EXIT_FAILURE); - } - mode = c; - break; - case 'F': /* F force search */ -#ifndef NOFORCE - uflags |= C_FORCE; -#endif - break; - case 'f': /* f arguments are filenames */ - uflags |= C_INFILE; - break; - case 'h': /* h get help / usage */ - case 'u': /* u get help / usage */ - case '?': /* ? get help / usage */ - default: - usage(); - return 0; - //exit(EXIT_FAILURE); - break; - case 'i': /* i: Init value */ - pptr = &model.init; - rflags |= R_HAVEI; - goto ippx; - case 'k': /* k: polynomial in Koopman notation */ - pfree(&model.spoly); - model.spoly = strtop(optarg, 0, 4); - pkchop(&model.spoly); - width = plen(model.spoly); - rflags |= R_HAVEP; - mnovel(&model); - break; - case 'l': /* l little-endian input and output */ - model.flags |= P_REFIN; - rflags |= R_HAVERI; - /* fall through: */ - case 'L': /* L little-endian output */ - model.flags |= P_REFOUT; - rflags |= R_HAVERO; - mnovel(&model); - /* fall through: */ - case 't': /* t left-justified */ - model.flags &= ~P_RTJUST; - break; - case 'm': /* m: select preset CRC model */ - if(!(c = mbynam(&model, optarg))) { - fprintf(stderr,"%s: preset model '%s' not found. Use %s -D to list presets.\n", myname, optarg, myname); - return 0; - //exit(EXIT_FAILURE); - } - if(c < 0){ - uerror("no preset models available"); - return 0; - } - /* must set width so that parameter to -ipx is not zeroed */ - width = plen(model.spoly); - rflags |= R_HAVEP | R_HAVEI | R_HAVERI | R_HAVERO | R_HAVEX; - break; - case 'M': /* M non-augmenting algorithm */ - model.flags &= ~P_MULXN; - break; - case 'P': /* P: reversed polynomial */ - case 'p': /* p: polynomial */ - pptr = &model.spoly; - rflags &= ~R_HAVEQ; - rflags |= R_HAVEP; -ippx: - pfree(pptr); - *pptr = strtop(optarg, 0, 4); - pright(pptr, width); - if(c == 'P') - prev(pptr); - mnovel(&model); - break; - case 'q': /* q: range end polynomial */ - pptr = &qpoly; - rflags &= ~R_HAVEP; - rflags |= R_HAVEQ; - goto ippx; - case 'S': /* s space between output characters */ - model.flags |= P_SPACE; - break; - case 'V': /* v reverse algorithm */ - /* Distinct from the -v switch as the - * user will have to reverse his or her - * own arguments. The user cannot dump - * the model generated by -v either. - */ - mrev(&model); - break; - case 'w': /* w: CRC width = order - 1 */ - width = (unsigned long) atol(optarg); - break; - case 'X': /* X print uppercase hex */ - model.flags |= P_UPPER; - break; - case 'x': /* x: XorOut value */ - pptr = &model.xorout; - rflags |= R_HAVEX; - goto ippx; - case 'y': /* y little-endian byte order in files */ - model.flags |= P_LTLBYT; - break; - case 'z': /* z raw binary arguments */ - model.flags |= P_DIRECT; - break; - case -1: /* no more options, continue */ - ; - } - } while(c != -1); - - /* canonicalise the model, so the one we dump is the one we - * calculate with (not with -s, spoly may be blank which will - * normalise to zero and clear init and xorout.) - */ - if(mode != 's') - mcanon(&model); - - switch(mode) { - case 'v': /* v calculate reversed CRC */ - /* Distinct from the -V switch as this causes - * the arguments and output to be reversed as well. - */ - /* reciprocate Poly */ - prcp(&model.spoly); - - /* mrev() does: - * if(refout) prev(init); else prev(xorout); - * but here the entire argument polynomial is - * reflected, not just the characters, so RefIn - * and RefOut are not inverted as with -V. - * Consequently Init is the mirror image of the - * one resulting from -V, and so we have: - */ - if(~model.flags & P_REFOUT) { - prev(&model.init); - prev(&model.xorout); - } - - /* swap init and xorout */ - apoly = model.init; - model.init = model.xorout; - model.xorout = apoly; - - /* fall through: */ - case 'c': /* c calculate CRC */ - - /* validate inputs */ - /* if(plen(model.spoly) == 0) { - * fprintf(stderr,"%s: no polynomial specified for -%c (add -w WIDTH -p POLY)\n", myname, mode); - * exit(EXIT_FAILURE); - * } - */ - - /* in the Williams model, xorout is applied after the refout stage. - * as refout is part of ptostr(), we reverse xorout here. - */ - if(model.flags & P_REFOUT) - prev(&model.xorout); - - for(; optind < argc; ++optind) { - if(uflags & C_INFILE) - apoly = rdpoly(argv[optind], model.flags, ibperhx); - else - apoly = strtop(argv[optind], model.flags, ibperhx); - - if(mode == 'v') - prev(&apoly); - - crc = pcrc(apoly, model.spoly, model.init, model.xorout, model.flags); - - if(mode == 'v') - prev(&crc); - - string = ptostr(crc, model.flags, obperhx); - puts(string); - free(string); - pfree(&crc); - pfree(&apoly); - } - break; - case 'D': /* D dump all models */ - args = mcount(); - if(!args){ - uerror("no preset models available"); - return 0; - } - for(mode = 0; mode < args; ++mode) { - mbynum(&model, mode); - mcanon(&model); - ufound(&model); - } - break; - case 'd': /* d dump CRC model */ - /* maybe we don't want to do this: - * either attaching names to arbitrary models or forcing to a preset - * mmatch(&model, M_OVERWR); - */ - if(~model.flags & P_MULXN){ - uerror("not a Williams model compliant algorithm"); - return 0; - } - string = mtostr(&model); - puts(string); - free(string); - break; - case 'e': /* e echo arguments */ - for(; optind < argc; ++optind) { - if(uflags & C_INFILE) - apoly = rdpoly(argv[optind], model.flags, ibperhx); - else - apoly = strtop(argv[optind], model.flags, ibperhx); - - psum(&apoly, model.init, 0UL); - string = ptostr(apoly, model.flags, obperhx); - puts(string); - free(string); - pfree(&apoly); - } - break; - case 's': /* s search for algorithm */ - if(!width){ - uerror("must specify positive -k or -w before -s"); - return 0; - } - if(~model.flags & P_MULXN){ - uerror("cannot search for non-Williams compliant models"); - return 0; - } - praloc(&model.spoly, width); - praloc(&model.init, width); - praloc(&model.xorout, width); - if(!plen(model.spoly)) - palloc(&model.spoly, width); - else - width = plen(model.spoly); - - /* special case if qpoly is zero, search to end of range */ - if(!ptst(qpoly)) - rflags &= ~R_HAVEQ; - - /* allocate argument array */ - args = argc - optind; - if(!(apolys = malloc(args * sizeof(poly_t)))){ - uerror("cannot allocate memory for argument list"); - return 0; - } - - for(pptr = apolys; optind < argc; ++optind) { - if(uflags & C_INFILE) - *pptr++ = rdpoly(argv[optind], model.flags, ibperhx); - else - *pptr++ = strtop(argv[optind], model.flags, ibperhx); - } - /* exit value of pptr is used hereafter! */ - - /* if endianness not specified, try - * little-endian then big-endian. - * NB: crossed-endian algorithms will not be - * searched. - */ - - /* scan against preset models */ - if(~uflags & C_FORCE) { - pass = 0; - do { - psets = mcount(); - while(psets) { - mbynum(&pset, --psets); - /* skip if different width, or refin or refout don't match */ - if(plen(pset.spoly) != width || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT)) - continue; - /* skip if the preset doesn't match specified parameters */ - if(rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly)) - continue; - if(rflags & R_HAVEI && psncmp(&model.init, &pset.init)) - continue; - if(rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout)) - continue; - apoly = pclone(pset.xorout); - if(pset.flags & P_REFOUT) - prev(&apoly); - for(qptr = apolys; qptr < pptr; ++qptr) { - crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0); - if(ptst(crc)) { - pfree(&crc); - break; - } else - pfree(&crc); - } - pfree(&apoly); - if(qptr == pptr) { - /* the selected model solved all arguments */ - mcanon(&pset); - ufound(&pset); - uflags |= C_RESULT; - } - } - mfree(&pset); - - /* toggle refIn/refOut and reflect arguments */ - if(~rflags & R_HAVERI) { - model.flags ^= P_REFIN | P_REFOUT; - for(qptr = apolys; qptr < pptr; ++qptr) - prevch(qptr, ibperhx); - } - } while(~rflags & R_HAVERI && ++pass < 2); - } - if(uflags & C_RESULT) { - for(qptr = apolys; qptr < pptr; ++qptr) - pfree(qptr); - //return 1; - //exit(EXIT_SUCCESS); - } - if(!(model.flags & P_REFIN) != !(model.flags & P_REFOUT)){ - uerror("cannot search for crossed-endian models"); - return 0; - } - pass = 0; - do { - mptr = candmods = reveng(&model, qpoly, rflags, args, apolys); - if(mptr && plen(mptr->spoly)) - uflags |= C_RESULT; - while(mptr && plen(mptr->spoly)) { - /* results were printed by the callback - * string = mtostr(mptr); - * puts(string); - * free(string); - */ - mfree(mptr++); - } - free(candmods); - if(~rflags & R_HAVERI) { - model.flags ^= P_REFIN | P_REFOUT; - for(qptr = apolys; qptr < pptr; ++qptr) - prevch(qptr, ibperhx); - } - } while(~rflags & R_HAVERI && ++pass < 2); - for(qptr = apolys; qptr < pptr; ++qptr) - pfree(qptr); - free(apolys); - if(~uflags & C_RESULT) - uerror("no models found"); - break; - default: /* no mode specified */ - fprintf(stderr, "%s: no mode switch specified. Use %s -h for help.\n", myname, myname); - //exit(EXIT_FAILURE); - } - - return 1; - //exit(EXIT_SUCCESS); -} - -void -ufound(const model_t *model) { - /* Callback function to report each model found */ - char *string; - - if(!model) return; - /* generated models will be canonical */ - string = mtostr(model); - puts(string); - free(string); -} - -void -uerror(const char *msg) { - /* Callback function to report fatal errors */ - fprintf(stderr, "%s: %s\n", myname, msg); - return; - //exit(EXIT_FAILURE); -} - -void -uprog(const poly_t gpoly, int flags, unsigned long seq) { - /* Callback function to report search progress */ - char *string; - - /* Suppress first report in CLI */ - if(!seq) - return; - string = ptostr(gpoly, P_RTJUST, 4); - fprintf(stderr, "%s: searching: width=%ld poly=0x%s refin=%s refout=%s\n", - myname, plen(gpoly), string, - (flags & P_REFIN ? "true" : "false"), - (flags & P_REFOUT ? "true" : "false") - ); - free(string); -} - -static poly_t -rdpoly(const char *name, int flags, int bperhx) { - /* read poly from file in chunks and report errors */ - - poly_t apoly = PZERO, chunk = PZERO; - FILE *input; - - input = oread(name); - while(!feof(input) && !ferror(input)) { - chunk = filtop(input, BUFFER, flags, bperhx); - psum(&apoly, chunk, plen(apoly)); - pfree(&chunk); - } - if(ferror(input)) { - fprintf(stderr,"%s: error condition on file '%s'\n", myname, name); - exit(EXIT_FAILURE); - } - /* close file unless stdin */ - if(input == stdin) - /* reset EOF condition */ - clearerr(input); - else if(fclose(input)) { - fprintf(stderr,"%s: error closing file '%s'\n", myname, name); - exit(EXIT_FAILURE); - } - return(apoly); -} - -static FILE * -oread(const char *name) { - /* open file for reading and report errors */ - FILE *handle; - - /* recognise special name '-' as standard input */ - if(*name == '-' && name[1] == '\0') - return(stdin); - if(!(handle = fopen(name, "rb"))) { - fprintf(stderr, "%s: cannot open '%s' for reading\n", myname, name); - return 0; - //exit(EXIT_FAILURE); - } - return(handle); -} - -static void -usage(void) { - /* print usage if asked, or if syntax incorrect */ - fprintf(stderr, - "CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder\n" - "Usage:\t"); - fputs(myname, stderr); - fprintf(stderr, - "\t-cdDesvhu? [-bBfFlLMrStVXyz]\n" - "\t\t[-a BITS] [-A OBITS] [-i INIT] [-k KPOLY] [-m MODEL]\n" - "\t\t[-p POLY] [-P RPOLY] [-q QPOLY] [-w WIDTH] [-x XOROUT]\n" - "\t\t[STRING...]\n" - "Options:\n" - "\t-a BITS\t\tbits per character (1 to %d)\n" - "\t-A OBITS\tbits per output character (1 to %d)\n" - "\t-i INIT\t\tinitial register value\n" - "\t-k KPOLY\tgenerator in Koopman notation (implies WIDTH)\n" - "\t-m MODEL\tpreset CRC algorithm\n" - "\t-p POLY\t\tgenerator or search range start polynomial\n" - "\t-P RPOLY\treversed generator polynomial\n", - BMP_BIT, BMP_BIT); - fprintf(stderr, - "\t-q QPOLY\tsearch range end polynomial\n" - "\t-w WIDTH\tregister size, in bits\n" - "\t-x XOROUT\tfinal register XOR value\n" - "Modifier switches:\n" - "\t-b big-endian CRC\t\t-B big-endian CRC output\n" - "\t-f read files named in STRINGs\t-F find presets less quickly\n" - "\t-l little-endian CRC\t\t-L little-endian CRC output\n" - "\t-M non-augmenting algorithm\t-r right-justified output\n" - "\t-S print spaces between chars\t-t left-justified output\n" - "\t-V reverse algorithm only\t-X print uppercase hex\n" - "\t-y low bytes first in files\t-z raw binary STRINGs\n"); - fprintf(stderr, - "Mode switches:\n" - "\t-c calculate CRCs\t\t-d dump algorithm parameters\n" - "\t-D list preset algorithms\t-e echo (and reformat) input\n" - "\t-s search for algorithm\t\t-v calculate reversed CRCs\n" - "\t-g search for alg given hex+crc\t-h | -u | -? show this help\n" - "Common Use Examples:\n" - "\t reveng -g 01020304e3\n" - "\t Searches for a known/common crc preset that computes the crc\n" - "\t on the end of the given hex string\n" - "\t reveng -w 8 -s 01020304e3 010204039d\n" - "\t Searches for any possible 8 bit width crc calc that computes\n" - "\t the crc on the end of the given hex string(s)\n" - "\t reveng -m CRC-8 -c 01020304\n" - "\t Calculates the crc-8 of the given hex string\n" - "\t reveng -D\n" - "\t Outputs a list of all known/common crc models with their\n" - "\t preset values\n" - "\n" - "Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Gregory Cook\n" - "This is free software; see the source for copying conditions. There is NO\n" - "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" - "Version " - VERSION - "\t\t\t\t \n"); -} diff --git a/client/reveng/config.h b/client/reveng/config.h deleted file mode 100644 index 2f5108f0..00000000 --- a/client/reveng/config.h +++ /dev/null @@ -1,96 +0,0 @@ -/* config.h - * Greg Cook, 9/Apr/2015 - */ - -/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder - * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Gregory Cook - * - * This file is part of CRC RevEng. - * - * CRC RevEng is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * CRC RevEng is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with CRC RevEng. If not, see . - */ - -#ifndef CONFIG_H -#define CONFIG_H 1 - -/***************************************** - * * - * Start of user configuration options * - * * - *****************************************/ - -/* A type to contain polynomial coefficient bitmaps. - * Can be changed to 'unsigned long long' for some extended compilers. - * Adjust BMP_C(), BMP_BIT and BMP_SUB below if this is changed. - */ - -#define BMP_T unsigned long - -/* Creates an appropriate numeric constant for bmp_t. - * If the underlying type is 'unsigned long long', change UL to ULL. - */ - -#define BMP_C(n) (n##UL) - -/* Define BMPMACRO to turn the definitions of the size of a bmp_t into - * compile-time constants. This improves efficiency but makes the code - * platform-specific. - */ - -/* #define BMPMACRO 1 */ - -/* Some enterprise users may wish to disable the -F switch to minimise CPU - * usage. To do this, define the macro NOFORCE. - */ - -/* #define NOFORCE 1 */ - -/* Define PRESETS to compile CRC RevEng with the preset models from the - * CRC Catalogue. This implies BMPMACRO and so makes the code platform- - * specific. - */ - - -// PM3 NOTES: -// only PRESETS tested on windows -// PRESETS was commented out of original code -// but to enable preset models it must be enabled -// (marshmellow) -#define PRESETS 1 - - -/* Macros defining the size of a bmp_t. - * Their values only matter if PRESETS and/or BMPMACRO are defined, in - * which case edit the macros below to suit your architecture. - * Otherwise, BMP_BIT and BMP_SUB will be redefined as aliases of bmpbit - * and bmpsub, global objects initialised at run time. - */ - -/* Size in bits of a bmp_t. Not necessarily a power of two. */ - -#define BMP_BIT 32 - -/* The highest power of two that is strictly less than BMP_BIT. - * Initialises the index of a binary search for set bits in a bmp_t. - */ - -#define BMP_SUB 16 - -/***************************************** - * * - * End of user configuration options * - * * - *****************************************/ - -#endif /* CONFIG_H */ diff --git a/client/reveng/getopt.c b/client/reveng/getopt.c deleted file mode 100644 index abe99634..00000000 --- a/client/reveng/getopt.c +++ /dev/null @@ -1,81 +0,0 @@ -/*---------------------------------------------------------------------- - - Replacement for Unix "getopt()", for DOS/Windows/etc. - - getopt.c 1.3 2003/09/17 16:17:59 - - Copyright (C) 1998, 2003 by David A. Hinds -- All Rights Reserved - - This file is part of ASPEX. - - ASPEX is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - ASPEX is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPEX; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -----------------------------------------------------------------------*/ - -#include "string.h" -#include "stdio.h" -#include "getopt.h" - -char *optarg; -int optind = 1, opterr, optopt; -int pos = 0; -int getopt(int argc, char *argv[], const char *optstring) -{ - //static int pos = 0; - char *str; - - if (pos == 0) { - if ((optind >= argc) || (*argv[optind] != '-')) - return EOF; - pos = 1; - if (argv[optind][pos] == '\0') - return EOF; - } - - str = strchr(optstring, argv[optind][pos]); - if (str == NULL) { - optopt = argv[optind][pos]; - if (opterr) - fprintf(stderr, "%s: illegal option -- %c\n", argv[0], - optopt); - return '?'; - } - - if (str[1] == ':') { - if (argv[optind][pos+1] != '\0') { - optarg = &argv[optind][pos+1]; - return *str; - } - optind++; - if (optind >= argc) { - optopt = *str; - if (opterr) - fprintf(stderr, "%s: option requires an argument -- %c\n", - argv[0], optopt); - return '?'; - } - optarg = argv[optind]; - optind++; pos = 0; - return *str; - } - else { - pos++; - if (argv[optind][pos] == '\0') { - optind++; - pos = 0; - } - return *str; - } -} diff --git a/client/reveng/getopt.h b/client/reveng/getopt.h deleted file mode 100644 index bf66d9b1..00000000 --- a/client/reveng/getopt.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - getopt.h 1.2 2003/09/17 16:17:59 - - Copyright (C) 1998, 2003 by David A. Hinds -- All Rights Reserved - - This file is part of ASPEX. - - ASPEX is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - ASPEX is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPEX; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -extern char *optarg; -extern int optind, opterr, optopt, pos; -int getopt(int argc, char *argv[], const char *optstring); diff --git a/client/reveng/model.c b/client/reveng/model.c deleted file mode 100644 index 5a9b6580..00000000 --- a/client/reveng/model.c +++ /dev/null @@ -1,823 +0,0 @@ -/* model.c - * Greg Cook, 9/Apr/2015 - */ - -/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder - * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Gregory Cook - * - * This file is part of CRC RevEng. - * - * CRC RevEng is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * CRC RevEng is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with CRC RevEng. If not, see . - */ - -/* 2014-01-14: added CRC-8/DVB-S2 - * 2014-01-11: corrected CRC-40/GSM, added alias CRC-8/AES - * 2013-10-14: added CRC-13/BBC and six cdma2000 algorithms - * 2013-06-11: ensure BMP_BIT is an integer constant to compile presets - * 2013-01-20: big polynomials autogenerated, corrected CRC-82/DARC - * 2012-07-19: added CRC-8/EBU - * 2012-07-16: added CRC-15/MPT1327 - * 2012-05-25: removed CRC-1/PARITY-EVEN, CRC-1/PARITY-ODD - * 2012-04-12: added model CRC-31/PHILIPS - * 2012-03-03: single-line Williams model string conversion - * 2012-02-20: corrected model CRC-6/DARC - * 2011-09-03: added mrev(), mnovel() - * 2011-08-28: added model CRC-64/XZ - * 2011-04-30: added models CRC-16/TMS37157 and CRC-A, and alias CRC-B - * 2011-02-10: made preset models ANSI C compliant - * 2011-01-17: fixed ANSI C warnings (except preset models) - * 2011-01-01: added mbynum(), mcount() - * 2010-12-26: renamed CRC RevEng - * 2010-12-18: minor change to mtostr() output format - * 2010-12-15: added mcmp(), mmatch() - * 2010-12-14: finished mbynam(), mnames(), mtostr() - * 2010-12-13: restarted with PCONST macros - * 2010-12-12: was having so much fun I didn't think to try compiling. :( - * 2010-12-12: started models.c - */ - -#include -#include -#include -#include -#include "reveng.h" - -/* Private declarations */ - -struct mpreset { - const unsigned long width; /* width of CRC algorithm */ - const bmp_t *const bspoly; /* polynomial with highest-order term removed. length determines CRC width */ - const bmp_t *const binit; /* initial register value. length == poly.length */ - const int flags; /* P_REFIN and P_REFOUT indicate reflected input/output */ - const bmp_t *const bxorout; /* final register XOR mask. length == poly.length */ - const bmp_t *const bcheck; /* optional check value, the CRC of the UTF-8 string "123456789" */ - const char *const name; /* optional canonical name of the model */ -}; - -struct malias { - const char *name; - const struct mpreset *model; - const int isprimry; -}; - -#ifdef PRESETS -# if BMP_BIT < 32 -# error config.h: BMP_BIT must be an integer constant macro to compile presets -# else /* BMP_BIT */ - -/* Big polynomial constants. */ - -/* Directives for relink.pl */ -/* CONSTANT b40 = (40, 0x0004820009) */ -/* CONSTANT b40a = (40, 0xffffffffff) */ -/* CONSTANT b40b = (40, 0xd4164fc646) */ -/* CONSTANT b64 = (64, 0x42f0e1eba9ea3693) */ -/* CONSTANT b64a = (64, 0x6c40df5f0b497347) */ -/* CONSTANT b64b = (64, 0xffffffffffffffff) */ -/* CONSTANT b64c = (64, 0x62ec59e3f1a4f00a) */ -/* CONSTANT b64d = (64, 0x995dc9bbdf1939fa) */ -/* CONSTANT b82 = (82, 0x0308c0111011401440411) */ -/* CONSTANT b82a = (82, 0x09ea83f625023801fd612) */ - -/* The next section was generated by relink.pl from the directives above. */ - -/* DO NOT EDIT the section below, INCLUDING the next comment. */ -/* BEGIN AUTO-GENERATED CONSTANTS */ -# if BMP_BIT >= 40 -static const bmp_t b40[] = { - BMP_C(0x0004820009) << (BMP_BIT - 40), -}; -static const bmp_t b40a[] = { - BMP_C(0xffffffffff) << (BMP_BIT - 40), -}; -static const bmp_t b40b[] = { - BMP_C(0xd4164fc646) << (BMP_BIT - 40), -}; -# else /* BMP_BIT */ -static const bmp_t b40[] = { - BMP_C(0x00048200) << (BMP_BIT - 32) | BMP_C(0x04) >> (39 - BMP_BIT), - BMP_C(0x09) << (BMP_BIT * 2 - 40), -}; -static const bmp_t b40a[] = { - BMP_C(0xffffffff) << (BMP_BIT - 32) | BMP_C(0x7f) >> (39 - BMP_BIT), - BMP_C(0xff) << (BMP_BIT * 2 - 40), -}; -static const bmp_t b40b[] = { - BMP_C(0xd4164fc6) << (BMP_BIT - 32) | BMP_C(0x23) >> (39 - BMP_BIT), - BMP_C(0x46) << (BMP_BIT * 2 - 40), -}; -# endif /* BMP_BIT */ - -# if BMP_BIT >= 64 -static const bmp_t b64[] = { - BMP_C(0x42f0e1eba9ea3693) << (BMP_BIT - 64), -}; -static const bmp_t b64a[] = { - BMP_C(0x6c40df5f0b497347) << (BMP_BIT - 64), -}; -static const bmp_t b64b[] = { - BMP_C(0xffffffffffffffff) << (BMP_BIT - 64), -}; -static const bmp_t b64c[] = { - BMP_C(0x62ec59e3f1a4f00a) << (BMP_BIT - 64), -}; -static const bmp_t b64d[] = { - BMP_C(0x995dc9bbdf1939fa) << (BMP_BIT - 64), -}; -# else /* BMP_BIT */ -static const bmp_t b64[] = { - BMP_C(0x42f0e1eb) << (BMP_BIT - 32) | BMP_C(0x54f51b49) >> (63 - BMP_BIT), - BMP_C(0xa9ea3693) << (BMP_BIT * 2 - 64), -}; -static const bmp_t b64a[] = { - BMP_C(0x6c40df5f) << (BMP_BIT - 32) | BMP_C(0x05a4b9a3) >> (63 - BMP_BIT), - BMP_C(0x0b497347) << (BMP_BIT * 2 - 64), -}; -static const bmp_t b64b[] = { - BMP_C(0xffffffff) << (BMP_BIT - 32) | BMP_C(0x7fffffff) >> (63 - BMP_BIT), - BMP_C(0xffffffff) << (BMP_BIT * 2 - 64), -}; -static const bmp_t b64c[] = { - BMP_C(0x62ec59e3) << (BMP_BIT - 32) | BMP_C(0x78d27805) >> (63 - BMP_BIT), - BMP_C(0xf1a4f00a) << (BMP_BIT * 2 - 64), -}; -static const bmp_t b64d[] = { - BMP_C(0x995dc9bb) << (BMP_BIT - 32) | BMP_C(0x6f8c9cfd) >> (63 - BMP_BIT), - BMP_C(0xdf1939fa) << (BMP_BIT * 2 - 64), -}; -# endif /* BMP_BIT */ - -# if BMP_BIT >= 82 -static const bmp_t b82[] = { - BMP_C(0x0308c0111011401440411) << (BMP_BIT - 82), -}; -static const bmp_t b82a[] = { - BMP_C(0x09ea83f625023801fd612) << (BMP_BIT - 82), -}; -# elif BMP_BIT >= 41 -static const bmp_t b82[] = { - BMP_C(0x01846008880) << (BMP_BIT - 41) | BMP_C(0x08a00a20208) >> (81 - BMP_BIT), - BMP_C(0x11401440411) << (BMP_BIT * 2 - 82), -}; -static const bmp_t b82a[] = { - BMP_C(0x04f541fb128) << (BMP_BIT - 41) | BMP_C(0x011c00feb09) >> (81 - BMP_BIT), - BMP_C(0x023801fd612) << (BMP_BIT * 2 - 82), -}; -# else /* BMP_BIT */ -static const bmp_t b82[] = { - BMP_C(0x0c230044) << (BMP_BIT - 32) | BMP_C(0x040) >> (40 - BMP_BIT), - BMP_C(0x40450051) << (BMP_BIT * 2 - 64) | BMP_C(0x00104) >> (80 - BMP_BIT * 2), - BMP_C(0x00411) << (BMP_BIT * 3 - 82), -}; -static const bmp_t b82a[] = { - BMP_C(0x27aa0fd8) << (BMP_BIT - 32) | BMP_C(0x094) >> (40 - BMP_BIT), - BMP_C(0x9408e007) << (BMP_BIT * 2 - 64) | BMP_C(0x0f584) >> (80 - BMP_BIT * 2), - BMP_C(0x3d612) << (BMP_BIT * 3 - 82), -}; -# endif /* BMP_BIT */ - -/* END AUTO-GENERATED CONSTANTS */ -/* DO NOT EDIT the section above, INCLUDING the previous comment. */ - -/* Array of the polynomial bitmaps used in the model table. */ -static const bmp_t b32[] = { - BMP_C(0x00000000) << (BMP_BIT - 32), /* 0 -- 5, 00 */ - BMP_C(0x000000af) << (BMP_BIT - 32), /* 1 -- 32,000000af */ - BMP_C(0x00010000) << (BMP_BIT - 32), /* 2 -- 16, 0001 */ - BMP_C(0x00020000) << (BMP_BIT - 32), /* 3 -- 15, 0001 */ - BMP_C(0x007e0000) << (BMP_BIT - 32), /* 4 -- 16, 007e */ - BMP_C(0x007f0000) << (BMP_BIT - 32), /* 5 -- 16, 007f */ - BMP_C(0x03400000) << (BMP_BIT - 32), /* 6 -- 11, 01a */ - BMP_C(0x0376e6e7) << (BMP_BIT - 32), /* 7 -- 32,0376e6e7 */ - BMP_C(0x04c11db7) << (BMP_BIT - 32), /* 8 -- 32,04c11db7 */ - BMP_C(0x05890000) << (BMP_BIT - 32), /* 9 -- 16, 0589 */ - BMP_C(0x07000000) << (BMP_BIT - 32), /* 10 -- 8, 07 */ - BMP_C(0x09823b6e) << (BMP_BIT - 32), /* 11 -- 31,04c11db7 */ - BMP_C(0x0b3c0000) << (BMP_BIT - 32), /* 12 -- 15, 059e */ - BMP_C(0x0c000000) << (BMP_BIT - 32), /* 13 -- 6, 03 */ - BMP_C(0x0fb30000) << (BMP_BIT - 32), /* 14 -- 16, 0fb3 */ - BMP_C(0x10210000) << (BMP_BIT - 32), /* 15 -- 16, 1021 */ - BMP_C(0x12000000) << (BMP_BIT - 32), /* 16 -- 7, 09 */ - BMP_C(0x15000000) << (BMP_BIT - 32), /* 17 -- 8, 15 */ - BMP_C(0x18000000) << (BMP_BIT - 32), /* 18 -- 6, 06 */ - BMP_C(0x19d3c8d8) << (BMP_BIT - 32), /* 19 -- 31,0ce9e46c */ - BMP_C(0x1c000000) << (BMP_BIT - 32), /* 20 -- 6, 07 */ - BMP_C(0x1d000000) << (BMP_BIT - 32), /* 21 -- 8, 1d */ - BMP_C(0x1d0f0000) << (BMP_BIT - 32), /* 22 -- 16, 1d0f */ - BMP_C(0x1edc6f41) << (BMP_BIT - 32), /* 23 -- 32,1edc6f41 */ - BMP_C(0x1f23b800) << (BMP_BIT - 32), /* 24 -- 24, 1f23b8 */ - BMP_C(0x20140000) << (BMP_BIT - 32), /* 25 -- 14, 0805 */ - BMP_C(0x20b40000) << (BMP_BIT - 32), /* 26 -- 14, 082d */ - BMP_C(0x21890000) << (BMP_BIT - 32), /* 27 -- 16, 2189 */ - BMP_C(0x21cf0200) << (BMP_BIT - 32), /* 28 -- 24, 21cf02 */ - BMP_C(0x25000000) << (BMP_BIT - 32), /* 29 -- 8, 25 */ - BMP_C(0x26b10000) << (BMP_BIT - 32), /* 30 -- 16, 26b1 */ - BMP_C(0x27d00000) << (BMP_BIT - 32), /* 31 -- 13, 04fa */ - BMP_C(0x28000000) << (BMP_BIT - 32), /* 32 -- 5, 05 */ - BMP_C(0x29b10000) << (BMP_BIT - 32), /* 33 -- 16, 29b1 */ - BMP_C(0x30000000) << (BMP_BIT - 32), /* 34 -- 4, 3 */ - BMP_C(0x3010bf7f) << (BMP_BIT - 32), /* 35 -- 32,3010bf7f */ - BMP_C(0x31000000) << (BMP_BIT - 32), /* 36 -- 8, 31 */ - BMP_C(0x31c30000) << (BMP_BIT - 32), /* 37 -- 16, 31c3 */ - BMP_C(0x34000000) << (BMP_BIT - 32), /* 38 -- 6, 0d */ - BMP_C(0x340bc6d9) << (BMP_BIT - 32), /* 39 -- 32,340bc6d9 */ - BMP_C(0x38000000) << (BMP_BIT - 32), /* 40 -- 5, 07 */ - BMP_C(0x39000000) << (BMP_BIT - 32), /* 41 -- 8, 39 */ - BMP_C(0x3d650000) << (BMP_BIT - 32), /* 42 -- 16, 3d65 */ - BMP_C(0x44c20000) << (BMP_BIT - 32), /* 43 -- 16, 44c2 */ - BMP_C(0x48000000) << (BMP_BIT - 32), /* 44 -- 5, 09 */ - BMP_C(0x4acc0000) << (BMP_BIT - 32), /* 45 -- 15, 2566 */ - BMP_C(0x4b370000) << (BMP_BIT - 32), /* 46 -- 16, 4b37 */ - BMP_C(0x4c060000) << (BMP_BIT - 32), /* 47 -- 16, 4c06 */ - BMP_C(0x55000000) << (BMP_BIT - 32), /* 48 -- 8, 55 */ - BMP_C(0x5d6dcb00) << (BMP_BIT - 32), /* 49 -- 24, 5d6dcb */ - BMP_C(0x60000000) << (BMP_BIT - 32), /* 50 -- 3, 3 */ - BMP_C(0x63d00000) << (BMP_BIT - 32), /* 51 -- 16, 63d0 */ - BMP_C(0x64000000) << (BMP_BIT - 32), /* 52 -- 6, 19 */ - BMP_C(0x66400000) << (BMP_BIT - 32), /* 53 -- 10, 199 */ - BMP_C(0x6f910000) << (BMP_BIT - 32), /* 54 -- 16, 6f91 */ - BMP_C(0x70000000) << (BMP_BIT - 32), /* 55 -- 4, 7 */ - BMP_C(0x70a00000) << (BMP_BIT - 32), /* 56 -- 11, 385 */ - BMP_C(0x765e7680) << (BMP_BIT - 32), /* 57 -- 32,765e7680 */ - BMP_C(0x7979bd00) << (BMP_BIT - 32), /* 58 -- 24, 7979bd */ - BMP_C(0x7e000000) << (BMP_BIT - 32), /* 59 -- 8, 7e */ - BMP_C(0x80050000) << (BMP_BIT - 32), /* 60 -- 16, 8005 */ - BMP_C(0x800d0000) << (BMP_BIT - 32), /* 61 -- 16, 800d */ - BMP_C(0x80f00000) << (BMP_BIT - 32), /* 62 -- 12, 80f */ - BMP_C(0x814141ab) << (BMP_BIT - 32), /* 63 -- 32,814141ab */ - BMP_C(0x864cfb00) << (BMP_BIT - 32), /* 64 -- 24, 864cfb */ - BMP_C(0x87315576) << (BMP_BIT - 32), /* 65 -- 32,87315576 */ - BMP_C(0x89ec0000) << (BMP_BIT - 32), /* 66 -- 16, 89ec */ - BMP_C(0x8b320000) << (BMP_BIT - 32), /* 67 -- 15, 4599 */ - BMP_C(0x8bb70000) << (BMP_BIT - 32), /* 68 -- 16, 8bb7 */ - BMP_C(0x8cc00000) << (BMP_BIT - 32), /* 69 -- 10, 233 */ - BMP_C(0x906e0000) << (BMP_BIT - 32), /* 70 -- 16, 906e */ - BMP_C(0x97000000) << (BMP_BIT - 32), /* 71 -- 8, 97 */ - BMP_C(0x98000000) << (BMP_BIT - 32), /* 72 -- 6, 26 */ - BMP_C(0x9b000000) << (BMP_BIT - 32), /* 73 -- 8, 9b */ - BMP_C(0x9c000000) << (BMP_BIT - 32), /* 74 -- 6, 27 */ - BMP_C(0x9e000000) << (BMP_BIT - 32), /* 75 -- 7, 4f */ - BMP_C(0x9ecf0000) << (BMP_BIT - 32), /* 76 -- 16, 9ecf */ - BMP_C(0xa0970000) << (BMP_BIT - 32), /* 77 -- 16, a097 */ - BMP_C(0xa1000000) << (BMP_BIT - 32), /* 78 -- 8, a1 */ - BMP_C(0xa6000000) << (BMP_BIT - 32), /* 79 -- 7, 53 */ - BMP_C(0xa8000000) << (BMP_BIT - 32), /* 80 -- 5, 15 */ - BMP_C(0xa833982b) << (BMP_BIT - 32), /* 81 -- 32,a833982b */ - BMP_C(0xabcdef00) << (BMP_BIT - 32), /* 82 -- 24, abcdef */ - BMP_C(0xb2aa0000) << (BMP_BIT - 32), /* 83 -- 16, b2aa */ - BMP_C(0xb4600000) << (BMP_BIT - 32), /* 84 -- 11, 5a3 */ - BMP_C(0xb4c80000) << (BMP_BIT - 32), /* 85 -- 16, b4c8 */ - BMP_C(0xb704ce00) << (BMP_BIT - 32), /* 86 -- 24, b704ce */ - BMP_C(0xbb3d0000) << (BMP_BIT - 32), /* 87 -- 16, bb3d */ - BMP_C(0xbc000000) << (BMP_BIT - 32), /* 88 -- 8, bc */ - BMP_C(0xbd0be338) << (BMP_BIT - 32), /* 89 -- 32,bd0be338 */ - BMP_C(0xbf050000) << (BMP_BIT - 32), /* 90 -- 16, bf05 */ - BMP_C(0xc0000000) << (BMP_BIT - 32), /* 91 -- 3, 6 */ - BMP_C(0xc2b70000) << (BMP_BIT - 32), /* 92 -- 16, c2b7 */ - BMP_C(0xc6c60000) << (BMP_BIT - 32), /* 93 -- 16, c6c6 */ - BMP_C(0xc8000000) << (BMP_BIT - 32), /* 94 -- 5, 19 */ - BMP_C(0xc8670000) << (BMP_BIT - 32), /* 95 -- 16, c867 */ - BMP_C(0xcbf43926) << (BMP_BIT - 32), /* 96 -- 32,cbf43926 */ - BMP_C(0xd0000000) << (BMP_BIT - 32), /* 97 -- 8, d0 */ - BMP_C(0xd02a0000) << (BMP_BIT - 32), /* 98 -- 15, 6815 */ - BMP_C(0xd0db0000) << (BMP_BIT - 32), /* 99 -- 16, d0db */ - BMP_C(0xd4d00000) << (BMP_BIT - 32), /* 100 -- 12, d4d */ - BMP_C(0xd5000000) << (BMP_BIT - 32), /* 101 -- 8, d5 */ - BMP_C(0xd64e0000) << (BMP_BIT - 32), /* 102 -- 16, d64e */ - BMP_C(0xda000000) << (BMP_BIT - 32), /* 103 -- 8, da */ - BMP_C(0xdaf00000) << (BMP_BIT - 32), /* 104 -- 12, daf */ - BMP_C(0xe0000000) << (BMP_BIT - 32), /* 105 -- 3, 7 */ - BMP_C(0xe3069283) << (BMP_BIT - 32), /* 106 -- 32,e3069283 */ - BMP_C(0xe5cc0000) << (BMP_BIT - 32), /* 107 -- 16, e5cc */ - BMP_C(0xe7a80000) << (BMP_BIT - 32), /* 108 -- 13, 1cf5 */ - BMP_C(0xea000000) << (BMP_BIT - 32), /* 109 -- 7, 75 */ - BMP_C(0xea820000) << (BMP_BIT - 32), /* 110 -- 16, ea82 */ - BMP_C(0xec000000) << (BMP_BIT - 32), /* 111 -- 6, 3b */ - BMP_C(0xf1300000) << (BMP_BIT - 32), /* 112 -- 12, f13 */ - BMP_C(0xf4000000) << (BMP_BIT - 32), /* 113 -- 8, f4 */ - BMP_C(0xf5b00000) << (BMP_BIT - 32), /* 114 -- 12, f5b */ - BMP_C(0xf6400000) << (BMP_BIT - 32), /* 115 -- 10, 3d9 */ - BMP_C(0xf8000000) << (BMP_BIT - 32), /* 116 -- 5, 1f */ - BMP_C(0xfc000000) << (BMP_BIT - 32), /* 117 -- 6, 3f */ - BMP_C(0xfc891918) << (BMP_BIT - 32), /* 118 -- 32,fc891918 */ - BMP_C(0xfd000000) << (BMP_BIT - 32), /* 119 -- 8, fd */ - BMP_C(0xfe000000) << (BMP_BIT - 32), /* 120 -- 7, 7f */ - BMP_C(0xfedcba00) << (BMP_BIT - 32), /* 121 -- 24, fedcba */ - BMP_C(0xfee80000) << (BMP_BIT - 32), /* 122 -- 16, fee8 */ - BMP_C(0xff000000) << (BMP_BIT - 32), /* 123 -- 8, ff */ - BMP_C(0xffc00000) << (BMP_BIT - 32), /* 124 -- 10, 3ff */ - BMP_C(0xfff00000) << (BMP_BIT - 32), /* 125 -- 12, fff */ - BMP_C(0xffff0000) << (BMP_BIT - 32), /* 126 -- 16, ffff */ - BMP_C(0xfffffffe) << (BMP_BIT - 32), /* 127 -- 31,7fffffff */ - BMP_C(0xffffffff) << (BMP_BIT - 32), /* 128 -- 32,ffffffff */ -}; - -/* Table of preset CRC models. - * Sorted by left-justified polynomial for bsearch(). - */ -static const struct mpreset models[] = { - {32UL, b32+ 1, 0, P_BE, 0, b32+ 89, "XFER" }, /* 0 */ - {40UL, b40, 0, P_BE, b40a, b40b, "CRC-40/GSM" }, /* 1 */ - {32UL, b32+ 8, 0, P_BE, b32+128, b32+ 57, "CRC-32/POSIX" }, /* 2 */ - {32UL, b32+ 8, b32+128, P_BE, 0, b32+ 7, "CRC-32/MPEG-2" }, /* 3 */ - {32UL, b32+ 8, b32+128, P_BE, b32+128, b32+118, "CRC-32/BZIP2" }, /* 4 */ - {32UL, b32+ 8, b32+128, P_LE, 0, b32+ 39, "JAMCRC" }, /* 5 */ - {32UL, b32+ 8, b32+128, P_LE, b32+128, b32+ 96, "CRC-32" }, /* 6 */ - {16UL, b32+ 9, 0, P_BE, 0, b32+ 5, "CRC-16/DECT-X" }, /* 7 */ - {16UL, b32+ 9, 0, P_BE, b32+ 2, b32+ 4, "CRC-16/DECT-R" }, /* 8 */ - { 8UL, b32+ 10, 0, P_BE, 0, b32+113, "CRC-8" }, /* 9 */ - { 8UL, b32+ 10, 0, P_BE, b32+ 48, b32+ 78, "CRC-8/ITU" }, /* 10 */ - { 8UL, b32+ 10, b32+123, P_LE, 0, b32+ 97, "CRC-8/ROHC" }, /* 11 */ - {31UL, b32+ 11, b32+127, P_BE, b32+127, b32+ 19, "CRC-31/PHILIPS" }, /* 12 */ - { 6UL, b32+ 13, 0, P_LE, 0, b32+ 18, "CRC-6/ITU" }, /* 13 */ - {82UL, b82, 0, P_LE, 0, b82a, "CRC-82/DARC" }, /* 14 */ - {16UL, b32+ 15, 0, P_BE, 0, b32+ 37, "XMODEM" }, /* 15 */ - {16UL, b32+ 15, 0, P_LE, 0, b32+ 27, "KERMIT" }, /* 16 */ - {16UL, b32+ 15, b32+ 22, P_BE, 0, b32+107, "CRC-16/AUG-CCITT" }, /* 17 */ - {16UL, b32+ 15, b32+ 66, P_LE, 0, b32+ 30, "CRC-16/TMS37157" }, /* 18 */ - {16UL, b32+ 15, b32+ 83, P_LE, 0, b32+ 51, "CRC-16/RIELLO" }, /* 19 */ - {16UL, b32+ 15, b32+ 93, P_LE, 0, b32+ 90, "CRC-A" }, /* 20 */ - {16UL, b32+ 15, b32+126, P_BE, 0, b32+ 33, "CRC-16/CCITT-FALSE"}, /* 21 */ - {16UL, b32+ 15, b32+126, P_BE, b32+126, b32+102, "CRC-16/GENIBUS" }, /* 22 */ - {16UL, b32+ 15, b32+126, P_LE, 0, b32+ 54, "CRC-16/MCRF4XX" }, /* 23 */ - {16UL, b32+ 15, b32+126, P_LE, b32+126, b32+ 70, "X-25" }, /* 24 */ - { 7UL, b32+ 16, 0, P_BE, 0, b32+109, "CRC-7" }, /* 25 */ - { 6UL, b32+ 20, b32+117, P_BE, 0, b32+111, "CRC-6/CDMA2000-B" }, /* 26 */ - { 8UL, b32+ 21, b32+119, P_BE, 0, b32+ 59, "CRC-8/I-CODE" }, /* 27 */ - { 8UL, b32+ 21, b32+123, P_LE, 0, b32+ 71, "CRC-8/EBU" }, /* 28 */ - {32UL, b32+ 23, b32+128, P_LE, b32+128, b32+106, "CRC-32C" }, /* 29 */ - {14UL, b32+ 25, 0, P_LE, 0, b32+ 26, "CRC-14/DARC" }, /* 30 */ - { 5UL, b32+ 32, b32+116, P_LE, b32+116, b32+ 94, "CRC-5/USB" }, /* 31 */ - { 4UL, b32+ 34, 0, P_LE, 0, b32+ 55, "CRC-4/ITU" }, /* 32 */ - { 8UL, b32+ 36, 0, P_LE, 0, b32+ 78, "CRC-8/MAXIM" }, /* 33 */ - { 8UL, b32+ 41, 0, P_LE, 0, b32+ 17, "CRC-8/DARC" }, /* 34 */ - {16UL, b32+ 42, 0, P_BE, b32+126, b32+ 92, "CRC-16/EN-13757" }, /* 35 */ - {16UL, b32+ 42, 0, P_LE, b32+126, b32+110, "CRC-16/DNP" }, /* 36 */ - {64UL, b64, 0, P_BE, 0, b64a, "CRC-64" }, /* 37 */ - {64UL, b64, b64b, P_BE, b64b, b64c, "CRC-64/WE" }, /* 38 */ - {64UL, b64, b64b, P_LE, b64b, b64d, "CRC-64/XZ" }, /* 39 */ - { 5UL, b32+ 44, b32+ 44, P_BE, 0, b32+ 0, "CRC-5/EPC" }, /* 40 */ - {24UL, b32+ 49, b32+ 82, P_BE, 0, b32+ 24, "CRC-24/FLEXRAY-B" }, /* 41 */ - {24UL, b32+ 49, b32+121, P_BE, 0, b32+ 58, "CRC-24/FLEXRAY-A" }, /* 42 */ - { 3UL, b32+ 50, b32+105, P_LE, 0, b32+ 91, "CRC-3/ROHC" }, /* 43 */ - { 6UL, b32+ 52, 0, P_LE, 0, b32+ 72, "CRC-6/DARC" }, /* 44 */ - {11UL, b32+ 56, b32+ 6, P_BE, 0, b32+ 84, "CRC-11" }, /* 45 */ - {16UL, b32+ 60, 0, P_BE, 0, b32+122, "CRC-16/BUYPASS" }, /* 46 */ - {16UL, b32+ 60, 0, P_LE, 0, b32+ 87, "ARC" }, /* 47 */ - {16UL, b32+ 60, 0, P_LE, b32+126, b32+ 43, "CRC-16/MAXIM" }, /* 48 */ - {16UL, b32+ 60, b32+ 61, P_BE, 0, b32+ 76, "CRC-16/DDS-110" }, /* 49 */ - {16UL, b32+ 60, b32+126, P_LE, 0, b32+ 46, "MODBUS" }, /* 50 */ - {16UL, b32+ 60, b32+126, P_LE, b32+126, b32+ 85, "CRC-16/USB" }, /* 51 */ - {12UL, b32+ 62, 0, P_BE, 0, b32+114, "CRC-12/DECT" }, /* 52 */ - {12UL, b32+ 62, 0, P_BELE, 0, b32+104, "CRC-12/3GPP" }, /* 53 */ - {32UL, b32+ 63, 0, P_BE, 0, b32+ 35, "CRC-32Q" }, /* 54 */ - {24UL, b32+ 64, b32+ 86, P_BE, 0, b32+ 28, "CRC-24" }, /* 55 */ - {15UL, b32+ 67, 0, P_BE, 0, b32+ 12, "CRC-15" }, /* 56 */ - {16UL, b32+ 68, 0, P_BE, 0, b32+ 99, "CRC-16/T10-DIF" }, /* 57 */ - {10UL, b32+ 69, 0, P_BE, 0, b32+ 53, "CRC-10" }, /* 58 */ - { 8UL, b32+ 73, 0, P_LE, 0, b32+ 29, "CRC-8/WCDMA" }, /* 59 */ - { 8UL, b32+ 73, b32+123, P_BE, 0, b32+103, "CRC-8/CDMA2000" }, /* 60 */ - { 6UL, b32+ 74, b32+117, P_BE, 0, b32+ 38, "CRC-6/CDMA2000-A" }, /* 61 */ - { 7UL, b32+ 75, b32+120, P_LE, 0, b32+ 79, "CRC-7/ROHC" }, /* 62 */ - {16UL, b32+ 77, 0, P_BE, 0, b32+ 14, "CRC-16/TELEDISK" }, /* 63 */ - { 5UL, b32+ 80, 0, P_LE, 0, b32+ 40, "CRC-5/ITU" }, /* 64 */ - {32UL, b32+ 81, b32+128, P_LE, b32+128, b32+ 65, "CRC-32D" }, /* 65 */ - {16UL, b32+ 95, b32+126, P_BE, 0, b32+ 47, "CRC-16/CDMA2000" }, /* 66 */ - {15UL, b32+ 98, 0, P_BE, b32+ 3, b32+ 45, "CRC-15/MPT1327" }, /* 67 */ - { 8UL, b32+101, 0, P_BE, 0, b32+ 88, "CRC-8/DVB-S2" }, /* 68 */ - {13UL, b32+108, 0, P_BE, 0, b32+ 31, "CRC-13/BBC" }, /* 69 */ - {12UL, b32+112, b32+125, P_BE, 0, b32+100, "CRC-12/CDMA2000" }, /* 70 */ - {10UL, b32+115, b32+124, P_BE, 0, b32+ 69, "CRC-10/CDMA2000" }, /* 71 */ -}; -# define NPRESETS 72 - -/* List of names with pointers to models, pre-sorted for use with bsearch() */ -static const struct malias aliases[] = { - {"ARC", models+47, 1}, /* 0 */ - {"B-CRC-32", models+ 4, 0}, /* 1 */ - {"CKSUM", models+ 2, 0}, /* 2 */ - {"CRC-10", models+58, 1}, /* 3 */ - {"CRC-10/CDMA2000", models+71, 1}, /* 4 */ - {"CRC-11", models+45, 1}, /* 5 */ - {"CRC-12/3GPP", models+53, 1}, /* 6 */ - {"CRC-12/CDMA2000", models+70, 1}, /* 7 */ - {"CRC-12/DECT", models+52, 1}, /* 8 */ - {"CRC-13/BBC", models+69, 1}, /* 9 */ - {"CRC-14/DARC", models+30, 1}, /* 10 */ - {"CRC-15", models+56, 1}, /* 11 */ - {"CRC-15/MPT1327", models+67, 1}, /* 12 */ - {"CRC-16", models+47, 0}, /* 13 */ - {"CRC-16/ACORN", models+15, 0}, /* 14 */ - {"CRC-16/ARC", models+47, 0}, /* 15 */ - {"CRC-16/AUG-CCITT", models+17, 1}, /* 16 */ - {"CRC-16/BUYPASS", models+46, 1}, /* 17 */ - {"CRC-16/CCITT", models+16, 0}, /* 18 */ - {"CRC-16/CCITT-FALSE", models+21, 1}, /* 19 */ - {"CRC-16/CCITT-TRUE", models+16, 0}, /* 20 */ - {"CRC-16/CDMA2000", models+66, 1}, /* 21 */ - {"CRC-16/DARC", models+22, 0}, /* 22 */ - {"CRC-16/DDS-110", models+49, 1}, /* 23 */ - {"CRC-16/DECT-R", models+ 8, 1}, /* 24 */ - {"CRC-16/DECT-X", models+ 7, 1}, /* 25 */ - {"CRC-16/DNP", models+36, 1}, /* 26 */ - {"CRC-16/EN-13757", models+35, 1}, /* 27 */ - {"CRC-16/EPC", models+22, 0}, /* 28 */ - {"CRC-16/GENIBUS", models+22, 1}, /* 29 */ - {"CRC-16/I-CODE", models+22, 0}, /* 30 */ - {"CRC-16/IBM-SDLC", models+24, 0}, /* 31 */ - {"CRC-16/ISO-HDLC", models+24, 0}, /* 32 */ - {"CRC-16/LHA", models+47, 0}, /* 33 */ - {"CRC-16/MAXIM", models+48, 1}, /* 34 */ - {"CRC-16/MCRF4XX", models+23, 1}, /* 35 */ - {"CRC-16/RIELLO", models+19, 1}, /* 36 */ - {"CRC-16/SPI-FUJITSU", models+17, 0}, /* 37 */ - {"CRC-16/T10-DIF", models+57, 1}, /* 38 */ - {"CRC-16/TELEDISK", models+63, 1}, /* 39 */ - {"CRC-16/TMS37157", models+18, 1}, /* 40 */ - {"CRC-16/USB", models+51, 1}, /* 41 */ - {"CRC-16/VERIFONE", models+46, 0}, /* 42 */ - {"CRC-24", models+55, 1}, /* 43 */ - {"CRC-24/FLEXRAY-A", models+42, 1}, /* 44 */ - {"CRC-24/FLEXRAY-B", models+41, 1}, /* 45 */ - {"CRC-24/OPENPGP", models+55, 0}, /* 46 */ - {"CRC-3/ROHC", models+43, 1}, /* 47 */ - {"CRC-31/PHILIPS", models+12, 1}, /* 48 */ - {"CRC-32", models+ 6, 1}, /* 49 */ - {"CRC-32/AAL5", models+ 4, 0}, /* 50 */ - {"CRC-32/ADCCP", models+ 6, 0}, /* 51 */ - {"CRC-32/BZIP2", models+ 4, 1}, /* 52 */ - {"CRC-32/CASTAGNOLI", models+29, 0}, /* 53 */ - {"CRC-32/DECT-B", models+ 4, 0}, /* 54 */ - {"CRC-32/ISCSI", models+29, 0}, /* 55 */ - {"CRC-32/MPEG-2", models+ 3, 1}, /* 56 */ - {"CRC-32/POSIX", models+ 2, 1}, /* 57 */ - {"CRC-32C", models+29, 1}, /* 58 */ - {"CRC-32D", models+65, 1}, /* 59 */ - {"CRC-32Q", models+54, 1}, /* 60 */ - {"CRC-4/ITU", models+32, 1}, /* 61 */ - {"CRC-40/GSM", models+ 1, 1}, /* 62 */ - {"CRC-5/EPC", models+40, 1}, /* 63 */ - {"CRC-5/ITU", models+64, 1}, /* 64 */ - {"CRC-5/USB", models+31, 1}, /* 65 */ - {"CRC-6/CDMA2000-A", models+61, 1}, /* 66 */ - {"CRC-6/CDMA2000-B", models+26, 1}, /* 67 */ - {"CRC-6/DARC", models+44, 1}, /* 68 */ - {"CRC-6/ITU", models+13, 1}, /* 69 */ - {"CRC-64", models+37, 1}, /* 70 */ - {"CRC-64/WE", models+38, 1}, /* 71 */ - {"CRC-64/XZ", models+39, 1}, /* 72 */ - {"CRC-7", models+25, 1}, /* 73 */ - {"CRC-7/ROHC", models+62, 1}, /* 74 */ - {"CRC-8", models+ 9, 1}, /* 75 */ - {"CRC-8/AES", models+28, 0}, /* 76 */ - {"CRC-8/CDMA2000", models+60, 1}, /* 77 */ - {"CRC-8/DARC", models+34, 1}, /* 78 */ - {"CRC-8/DVB-S2", models+68, 1}, /* 79 */ - {"CRC-8/EBU", models+28, 1}, /* 80 */ - {"CRC-8/I-CODE", models+27, 1}, /* 81 */ - {"CRC-8/ITU", models+10, 1}, /* 82 */ - {"CRC-8/MAXIM", models+33, 1}, /* 83 */ - {"CRC-8/ROHC", models+11, 1}, /* 84 */ - {"CRC-8/WCDMA", models+59, 1}, /* 85 */ - {"CRC-82/DARC", models+14, 1}, /* 86 */ - {"CRC-A", models+20, 1}, /* 87 */ - {"CRC-B", models+24, 0}, /* 88 */ - {"CRC-CCITT", models+16, 0}, /* 89 */ - {"CRC-IBM", models+47, 0}, /* 90 */ - {"DOW-CRC", models+33, 0}, /* 91 */ - {"JAMCRC", models+ 5, 1}, /* 92 */ - {"KERMIT", models+16, 1}, /* 93 */ - {"MODBUS", models+50, 1}, /* 94 */ - {"PKZIP", models+ 6, 0}, /* 95 */ - {"R-CRC-16", models+ 8, 0}, /* 96 */ - {"X-25", models+24, 1}, /* 97 */ - {"X-CRC-12", models+52, 0}, /* 98 */ - {"X-CRC-16", models+ 7, 0}, /* 99 */ - {"XFER", models+ 0, 1}, /* 100 */ - {"XMODEM", models+15, 1}, /* 101 */ - {"ZMODEM", models+15, 0}, /* 102 */ - {NULL, NULL, 0}, /* terminating entry */ -}; -# define NALIASES 103 - -# endif /* BMP_BIT */ -#else /* PRESETS */ - -static const struct mpreset models[] = { - { 0UL, 0, 0, P_BE, 0, 0, NULL }, /* terminating entry */ -}; -# define NPRESETS 0 - -static const struct malias aliases[] = { - {NULL, NULL, 0}, /* terminating entry */ -}; -# define NALIASES 0 - -#endif /* PRESETS */ - -static const poly_t pzero = PZERO; - -static int acmp(const struct malias *, const struct malias *); -static void munpack(model_t *, const struct mpreset *); - -/* copy a parameter of a preset into a model */ -#define MUNPACK(parm) \ - praloc(&dest->parm, (src->b##parm ? src->width : 0UL)); \ - for(iter=0UL, idx=0UL; iter < dest->parm.length; iter += BMP_BIT, ++idx)\ - dest->parm.bitmap[idx] = src->b##parm[idx]; - -/* Definitions */ - -void -mcpy(model_t *dest, const model_t *src) { - /* Copies the parameters of src to dest. - * dest must be an initialised model. - */ - if(!dest || !src) return; - pcpy(&dest->spoly, src->spoly); - pcpy(&dest->init, src->init); - pcpy(&dest->xorout, src->xorout); - pcpy(&dest->check, src->check); - dest->flags = src->flags; - /* link to the name as it is static */ - dest->name = src->name; -} - -void -mfree(model_t *model) { - /* Frees the parameters of model. */ - if(!model) return; - pfree(&model->spoly); - pfree(&model->init); - pfree(&model->xorout); - pfree(&model->check); - /* not name as it is static */ - /* not model either, it might point to an array! */ -} - -int -mcmp(const model_t *a, const model_t *b) { - /* Compares a and b for identical effect, i.e. disregarding - * trailing zeroes in parameter polys. - * Intended for bsearch() to find a matching model in models[]. - */ - int result; - if(!a || !b) return(!b - !a); - if((result = psncmp(&a->spoly, &b->spoly))) return(result); - if((result = psncmp(&a->init, &b->init))) return(result); - if((a->flags & P_REFIN) && (~b->flags & P_REFIN)) return(1); - if((~a->flags & P_REFIN) && (b->flags & P_REFIN)) return(-1); - if((a->flags & P_REFOUT) && (~b->flags & P_REFOUT)) return(1); - if((~a->flags & P_REFOUT) && (b->flags & P_REFOUT)) return(-1); - return(psncmp(&a->xorout, &b->xorout)); -} - -int -mbynam(model_t *dest, const char *key) { - /* Sets parameters in dest according to the model named by key. - */ - struct malias akey = {NULL, NULL, 0}, *aptr; - char *ukey, *uptr; - - if(!aliases->name) - return(-1); - if(!(ukey = malloc((size_t) 1 + strlen(key)))) - uerror("cannot allocate memory for comparison string"); - akey.name = uptr = ukey; - do - *uptr++ = toupper((unsigned char)*key); - while(*key++); - - aptr = bsearch(&akey, aliases, NALIASES, sizeof(struct malias), (int (*)(const void *, const void *)) &acmp); - free(ukey); - - if(aptr == NULL) - return(0); - munpack(dest, aptr->model); - return(1); -} - -void -mbynum(model_t *dest, int num) { - /* Sets parameters in dest according to the model indexed by num. */ - if(num > NPRESETS) - num = NPRESETS; - munpack(dest, models+num); -} - -int -mcount(void) { - /* Returns the number of preset models. */ - return(NPRESETS); -} - -char * -mnames(void) { - /* Returns a malloc()-ed string of the names of all preset - * models, separated by newlines and terminated by NULL. - * Aliases are not listed. - */ - size_t size = 0; - char *string, *sptr; - const struct malias *aptr = aliases; - - while(aptr->name) { - if(aptr->isprimry) - size += strlen(aptr->name) + 1; - ++aptr; - } - if(!size) return(NULL); - if((string = malloc(size))) { - aptr = aliases; - sptr = string; - while(aptr->name) { - if(aptr->isprimry) { - strcpy(sptr, aptr->name); - sptr += strlen(aptr->name); - *sptr++ = '\n'; - } - ++aptr; - } - *--sptr = '\0'; - } else - uerror("cannot allocate memory for list of models"); - - return(string); -} - -char * -mtostr(const model_t *model) { - /* Returns a malloc()-ed string containing a Williams model - * record representing the input model. - * mcanon() should be called on the argument before printing. - */ - size_t size; - char *polystr, *initstr, *xorotstr, *checkstr, strbuf[512], *string = NULL; - - if(!model) return(NULL); - polystr = ptostr(model->spoly, P_RTJUST, 4); - initstr = ptostr(model->init, P_RTJUST, 4); - xorotstr = ptostr(model->xorout, P_RTJUST, 4); - checkstr = ptostr(model->check, P_RTJUST, 4); - - sprintf(strbuf, "%lu", plen(model->spoly)); - size = - 70 - + (model->name && *model->name ? 2 + strlen(model->name) : 6) - + strlen(strbuf) - + (polystr && *polystr ? strlen(polystr) : 6) - + (initstr && *initstr ? strlen(initstr) : 6) - + (model->flags & P_REFIN ? 4 : 5) - + (model->flags & P_REFOUT ? 4 : 5) - + (xorotstr && *xorotstr ? strlen(xorotstr) : 6) - + (checkstr && *checkstr ? strlen(checkstr) : 6); - if((string = malloc(size))) { - sprintf(strbuf, "\"%s\"", model->name); - sprintf(string, - "width=%lu " - "poly=0x%s " - "init=0x%s " - "refin=%s " - "refout=%s " - "xorout=0x%s " - "check=0x%s " - "name=%s", - plen(model->spoly), - polystr && *polystr ? polystr : "(none)", - initstr && *initstr ? initstr : "(none)", - (model->flags & P_REFIN) ? "true" : "false", - (model->flags & P_REFOUT) ? "true" : "false", - xorotstr && *xorotstr ? xorotstr : "(none)", - checkstr && *checkstr ? checkstr : "(none)", - (model->name && *model->name) ? strbuf : "(none)"); - } - free(polystr); - free(initstr); - free(xorotstr); - free(checkstr); - if(!string) - uerror("cannot allocate memory for model description"); - return(string); -} - -void -mmatch(model_t *model, int flags) { - /* searches models[] for a model matching the argument, and links a name if found - * if flags & M_OVERWR, copies the found model onto the argument. */ - model_t *mptr; - if(!model) return; - - mptr = bsearch(model, models, NPRESETS, sizeof(model_t), (int (*)(const void *, const void *)) &mcmp); - if(mptr) { - model->name = mptr->name; - if(flags & M_OVERWR) - mcpy(model, mptr); - } -} - -void -mcanon(model_t *model) { - /* canonicalise a model */ - unsigned long dlen; - - if(!model) return; - - /* extending on the right here. This preserves the functionality - * of a presumed working model. - */ - psnorm(&model->spoly); - dlen = plen(model->spoly); - praloc(&model->init, dlen); - praloc(&model->xorout, dlen); - - if(!plen(model->check)) - mcheck(model); -} - -void -mcheck(model_t *model) { - /* calculate a check for the model */ - poly_t checkstr, check; - - /* generate the check string with the correct bit order */ - checkstr = strtop("313233343536373839", model->flags, 8); - check = pcrc(checkstr, model->spoly, model->init, pzero, model->flags); - if(model->flags & P_REFOUT) - prev(&check); - psum(&check, model->xorout, 0UL); - model->check = check; - pfree(&checkstr); -} - -void -mrev(model_t *model) { - /* reverse the model to calculate reversed CRCs */ - /* Here we invert RefIn and RefOut so that the user need only - * reverse the order of characters in the arguments, not the - * characters themselves. If RefOut=True, the mirror image of - * Init seen through RefOut becomes XorOut, and as RefOut - * becomes false, the XorOut value moved to Init stays upright. - * If RefOut=False, Init transfers to XorOut without reflection - * but the new Init must be reflected to present the same image, - * as RefOut becomes true. - */ - poly_t temp; - - prcp(&model->spoly); - if(model->flags & P_REFOUT) - prev(&model->init); - else - prev(&model->xorout); - - /* exchange init and xorout */ - temp = model->init; - model->init = model->xorout; - model->xorout = temp; - - /* invert refin and refout */ - model->flags ^= P_REFIN | P_REFOUT; - - mnovel(model); -} - -void -mnovel(model_t *model) { - /* remove name and check string from modified model */ - model->name = NULL; - pfree(&model->check); -} - -static int -acmp(const struct malias *a, const struct malias *b) { - /* compares two aliases, for use in bsearch */ - if(!a || !b) return(!b - !a); - if(!a->name || !b->name) return(!b->name - !a->name); - return(strcmp(a->name, b->name)); -} - -static void -munpack(model_t *dest, const struct mpreset *src) { - /* Copies the parameters of src to dest. - * dest must be an initialised model. - */ - unsigned long iter, idx; - if(!dest || !src) return; - MUNPACK(spoly); - MUNPACK(init); - MUNPACK(xorout); - MUNPACK(check); - dest->flags = src->flags; - /* link to the name as it is static */ - dest->name = src->name; -} diff --git a/client/reveng/poly.c b/client/reveng/poly.c deleted file mode 100644 index e4a8e8f9..00000000 --- a/client/reveng/poly.c +++ /dev/null @@ -1,1196 +0,0 @@ -/* poly.c - * Greg Cook, 9/Apr/2015 - */ - -/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder - * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Gregory Cook - * - * This file is part of CRC RevEng. - * - * CRC RevEng is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * CRC RevEng is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with CRC RevEng. If not, see . - */ - -/* 2015-04-03: added direct mode to strtop() - * 2014-01-11: added LOFS(), RNDUP() - * 2013-09-16: SIZE(), IDX(), OFS() macros bitshift if BMP_POF2 - * 2013-02-07: conditional non-2^n fix, pmpar() return mask constant type - * 2013-01-17: fixed pfirst(), plast() for non-2^n BMP_BIT - * 2012-07-16: added pident() - * 2012-05-23: added pmpar() - * 2012-03-03: internal lookup tables stored better - * 2012-03-02: fixed full-width masking in filtop() - * 2011-09-06: added prevch() - * 2011-08-27: fixed zero test in piter() - * 2011-01-17: fixed ANSI C warnings, uses bmp_t type - * 2011-01-15: palloc() and praloc() gracefully handle lengths slightly - * less than ULONG_MAX - * 2011-01-15: strtop() error on invalid argument. pkchop() special case - * when argument all zeroes - * 2011-01-14: added pkchop() - * 2011-01-04: fixed bogus final length calculation in wide pcrc() - * 2011-01-02: faster, more robust prcp() - * 2011-01-01: commented functions, full const declarations, all-LUT rev() - * 2010-12-26: renamed CRC RevEng - * 2010-12-18: removed pmods(), finished pcrc(), added piter() - * 2010-12-17: roughed out pcrc(). difficult, etiam aberat musa heri :( - * 2010-12-15: added psnorm(), psncmp(); optimised pnorm(); fix to praloc() - * 2010-12-14: strtop() resets count between passes - * 2010-12-12: added pright() - * 2010-12-11: filtop won't read more than length bits - * 2010-12-10: finished filtop. 26 public functions - * 2010-12-05: finished strtop, pxsubs; unit tests - * 2010-12-02: project started - */ - -/* Note: WELL-FORMED poly_t objects have a valid bitmap pointer pointing - * to a malloc()-ed array of at least as many bits as stated in its - * length field. Any poly_t with a length of 0 is also a WELL-FORMED - * poly_t (whatever value the bitmap pointer has.) - * All poly_t objects passed to and from functions must be WELL-FORMED - * unless otherwise stated. - * - * CLEAN (or CANONICAL) poly_t objects are WELL-FORMED objects in which - * all spare bits in the bitmap word containing the last bit are zero. - * (Any excess allocated words will not be accessed.) - * - * SEMI-NORMALISED poly_t objects are CLEAN objects in which the last - * bit, at position (length - 1), is one. - * - * NORMALISED poly_t objects are SEMI-NORMALISED objects in which the - * first bit is one. - * - * pfree() should be called on every poly_t object (including - * those returned by functions) after its last use. - * As always, free() should be called on every malloc()-ed string after - * its last use. - */ - -#include -#include -#include -#include "reveng.h" - -static bmp_t getwrd(const poly_t poly, unsigned long iter); -static bmp_t rev(bmp_t accu, int bits); -static void prhex(char **spp, bmp_t bits, int flags, int bperhx); - -static const poly_t pzero = PZERO; - -/* word number (0..m-1) of var'th bit (0..n-1) */ -#if BMP_POF2 >= 5 -# define IDX(var) ((var) >> BMP_POF2) -#else -# define IDX(var) ((var) / BMP_BIT) -#endif - -/* size of polynomial with var bits */ -#if BMP_POF2 >= 5 -# define SIZE(var) ((BMP_BIT - 1UL + (var)) >> BMP_POF2) -#else -# define SIZE(var) ((BMP_BIT - 1UL + (var)) / BMP_BIT) -#endif - -/* polynomial length rounded up to BMP_BIT */ -#ifdef BMP_POF2 -# define RNDUP(var) (~(BMP_BIT - 1UL) & (BMP_BIT - 1UL + (var))) -#else -# define RNDUP(var) ((BMP_BIT - (var) % BMP_BIT) % BMP_BIT + (var)) -#endif - -/* bit offset (0..BMP_BIT-1, 0 = LSB) of var'th bit (0..n-1) */ -#ifdef BMP_POF2 -# define OFS(var) ((int) ((BMP_BIT - 1UL) & ~(var))) -#else -# define OFS(var) ((int) (BMP_BIT - 1UL - (var) % BMP_BIT)) -#endif - -/* bit offset (0..BMP_BIT-1, 0 = MSB) of var'th bit (0..n-1) */ -#ifdef BMP_POF2 -# define LOFS(var) ((int) ((BMP_BIT - 1UL) & (var))) -#else -# define LOFS(var) ((int) ((var) % BMP_BIT)) -#endif - -poly_t -filtop(FILE *input, unsigned long length, int flags, int bperhx) { - /* reads binary data from input into a poly_t until EOF or until - * length bits are read. Characters are read until - * ceil(bperhx / CHAR_BIT) bits are collected; if P_LTLBYT is - * set in flags then the first character contains the LSB, - * otherwise the last one does. The least significant bperhx - * bits are taken, reflected (if P_REFIN) and appended to the - * result, then more characters are read. The maximum number of - * characters read is - * floor(length / bperhx) * ceil(bperhx / * CHAR_BIT). - * The returned poly_t is CLEAN. - */ - - bmp_t accu = BMP_C(0); - bmp_t mask = bperhx == BMP_BIT ? ~BMP_C(0) : (BMP_C(1) << bperhx) - BMP_C(1); - unsigned long iter = 0UL, idx; - int cmask = ~(~0U << CHAR_BIT), c; - int count = 0, ofs; - poly_t poly = PZERO; - if(bperhx == 0) return(poly); - - length -= length % bperhx; - palloc(&poly, length); /* >= 0 */ - - while(iter < length && (c = fgetc(input)) != EOF) { - if(flags & P_LTLBYT) - accu |= (bmp_t) (c & cmask) << count; - else - accu = (accu << CHAR_BIT) | (bmp_t) (c & cmask); - count += CHAR_BIT; - if(count >= bperhx) { - /* the low bperhx bits of accu contain bits of the poly.*/ - iter += bperhx; - count = 0; - if(flags & P_REFIN) - accu = rev(accu, bperhx); - accu &= mask; - - /* iter >= bperhx > 0 */ - idx = IDX(iter - 1UL); - ofs = OFS(iter - 1UL); - poly.bitmap[idx] |= accu << ofs; - if(ofs + bperhx > BMP_BIT) { - poly.bitmap[idx-1] |= accu >> (BMP_BIT - ofs); - } - accu = BMP_C(0); /* only needed for P_LTLBYT */ - } - } - praloc(&poly, iter); - return(poly); -} - -poly_t -strtop(const char *string, int flags, int bperhx) { - /* Converts a hex or character string to a poly_t. - * Each character is converted to a hex nibble yielding 4 bits - * unless P_DIRECT, when each character yields CHAR_BIT bits. - * Nibbles and characters are accumulated left-to-right - * unless P_DIRECT && P_LTLBYT, when they are accumulated - * right-to-left without reflection. - * As soon as at least bperhx bits are accumulated, the - * rightmost bperhx bits are reflected (if P_REFIN) - * and appended to the poly. When !P_DIRECT: - * bperhx=8 reads hex nibbles in pairs - * bperhx=7 reads hex nibbles in pairs and discards - * b3 of first nibble - * bperhx=4 reads hex nibbles singly - * bperhx=3 reads octal - * bperhx=1 reads longhand binary - * in theory if !P_REFIN, bperhx can be any multiple of 4 - * with equal effect - * The returned poly_t is CLEAN. - */ - - /* make two passes, one to determine the poly size - * one to populate the bitmap - */ - unsigned long length = 1UL, idx; - bmp_t accu; - bmp_t mask = bperhx == BMP_BIT ? ~BMP_C(0) : (BMP_C(1) << bperhx) - BMP_C(1); - int pass, count, ofs; - int cmask = ~(~0U << CHAR_BIT), c; - const char *s; - - poly_t poly = PZERO; - if(bperhx > BMP_BIT || bperhx <= 0 || string == NULL || *string == '\0') - return(poly); - - for(pass=0; pass<2 && length > 0UL; ++pass) { - s = string; - length = 0UL; - count = 0; - accu = BMP_C(0); - while((c = *s++)) { - if(flags & P_DIRECT) { - if(flags & P_LTLBYT) - accu |= (bmp_t) (c & cmask) << count; - else - accu = (accu << CHAR_BIT) | (bmp_t) (c & cmask); - count += CHAR_BIT; - } else { - if(c == ' ' || c == '\t' || c == '\r' || c == '\n') continue; - accu <<= 4; - count += 4; - switch(c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - accu |= (bmp_t) c - '0'; - break; - case 'A': - case 'a': - accu |= BMP_C(0xa); - break; - case 'B': - case 'b': - accu |= BMP_C(0xb); - break; - case 'C': - case 'c': - accu |= BMP_C(0xc); - break; - case 'D': - case 'd': - accu |= BMP_C(0xd); - break; - case 'E': - case 'e': - accu |= BMP_C(0xe); - break; - case 'F': - case 'f': - accu |= BMP_C(0xf); - break; - default: - uerror("invalid character in hexadecimal argument"); - } - } - - if(count >= bperhx) { - /* the low bperhx bits of accu contain bits of the poly. - * in pass 0, increment length by bperhx. - * in pass 1, put the low bits of accu into the bitmap. */ - length += bperhx; - count = 0; - if(pass == 1) { - if(flags & P_REFIN) - accu = rev(accu, bperhx); - accu &= mask; - - /* length >= bperhx > 0 */ - idx = IDX(length - 1); - ofs = OFS(length - 1); - poly.bitmap[idx] |= accu << ofs; - if(ofs + bperhx > BMP_BIT) - poly.bitmap[idx-1] |= accu >> (BMP_BIT - ofs); - accu = BMP_C(0); /* only needed for P_LTLBYT */ - } - } - } - if(pass == 0) palloc(&poly, length); - } - return(poly); -} - -char * -ptostr(const poly_t poly, int flags, int bperhx) { - /* Returns a malloc()-ed string containing a hexadecimal - * representation of poly. See phxsubs(). - */ - return(pxsubs(poly, flags, bperhx, 0UL, poly.length)); -} - -char * -pxsubs(const poly_t poly, int flags, int bperhx, unsigned long start, unsigned long end) { - /* Returns a malloc()-ed string containing a hexadecimal - * representation of a portion of poly, from bit offset start to - * (end - 1) inclusive. The output is grouped into words of - * bperhx bits each. If P_RTJUST then the first word is padded - * with zeroes at the MSB end to make a whole number of words, - * otherwise the last word is padded at the LSB end. After - * justification the bperhx bits of each word are reversed (if - * P_REFOUT) and printed as a hex sequence, with words - * optionally separated by spaces (P_SPACE). - * If end exceeds the length of poly then zero bits are appended - * to make up the difference, in which case poly must be CLEAN. - */ - char *string, *sptr; - unsigned long size, iter; - bmp_t accu; - bmp_t mask = bperhx == BMP_BIT ? ~BMP_C(0) : (BMP_C(1) << bperhx) - BMP_C(1); - int cperhx, part; - - if(bperhx <= 0 || bperhx > BMP_BIT) return(NULL); - - if(start > poly.length) start = poly.length; - if(end > poly.length) end = poly.length; - if(end < start) end = start; - - cperhx = (bperhx + 3) >> 2; - if(flags & P_SPACE) ++cperhx; - - size = (end - start + bperhx - 1UL) / bperhx; - size *= cperhx; - if(!size || ~flags & P_SPACE) ++size; /* for trailing null */ - - if(!(sptr = string = (char *) malloc(size))) - uerror("cannot allocate memory for string"); - - size = end - start; - part = (int) size % bperhx; - if(part && flags & P_RTJUST) { - iter = start + part; - accu = getwrd(poly, iter - 1UL) & ((BMP_C(1) << part) - BMP_C(1)); - if(flags & P_REFOUT) - /* best to reverse over bperhx rather than part, I think - * e.g. converting a 7-bit poly to 8-bit little-endian hex - */ - accu = rev(accu, bperhx); - prhex(&sptr, accu, flags, bperhx); - if(flags & P_SPACE && size > iter) *sptr++ = ' '; - } else { - iter = start; - } - - while((iter+=bperhx) <= end) { - accu = getwrd(poly, iter - 1UL) & mask; - if(flags & P_REFOUT) - accu = rev(accu, bperhx); - prhex(&sptr, accu, flags, bperhx); - if(flags & P_SPACE && size > iter) *sptr++ = ' '; - } - - if(part && ~flags & P_RTJUST) { - accu = getwrd(poly, end - 1UL); - if(flags & P_REFOUT) - accu = rev(accu, part); - else - accu = accu << (bperhx - part) & mask; - prhex(&sptr, accu, flags, bperhx); - } - *sptr = '\0'; - return(string); -} - -poly_t -pclone(const poly_t poly) { - /* Returns a freestanding copy of poly. Does not clean poly or - * the result. - */ - poly_t clone = PZERO; - - pcpy(&clone, poly); - return(clone); -} - -void -pcpy(poly_t *dest, const poly_t src) { - /* Assigns (copies) src into dest. Does not clean src or dest. - */ - unsigned long iter, idx; - - praloc(dest, src.length); - for(iter=0UL, idx=0UL; iter < src.length; iter += BMP_BIT, ++idx) - dest->bitmap[idx] = src.bitmap[idx]; -} - -void -pcanon(poly_t *poly) { - /* Converts poly into a CLEAN object by freeing unused bitmap words - * and clearing any bits in the last word beyond the last bit. - * The length field has absolute priority over the contents of the bitmap. - * Canonicalisation differs from normalisation in that leading and trailing - * zero terms are significant and preserved. - * poly may or may not be WELL-FORMED. - */ - praloc(poly, poly->length); -} - -void -pnorm(poly_t *poly) { - /* Converts poly into a NORMALISED object by removing leading - * and trailing zeroes, so that the polynomial starts and ends - * with significant terms. - * poly may or may not be WELL-FORMED. - */ - unsigned long first; - - /* call pcanon() here so pfirst() and plast() return the correct - * results - */ - pcanon(poly); - first = pfirst(*poly); - if(first) - pshift(poly, *poly, 0UL, first, plast(*poly), 0UL); - else - praloc(poly, plast(*poly)); -} - -void -psnorm(poly_t *poly) { - /* Converts poly into a SEMI-NORMALISED object by removing - * trailing zeroes, so that the polynomial ends with a - * significant term. - * poly may or may not be WELL-FORMED. - */ - - /* call pcanon() here so plast() returns the correct result */ - pcanon(poly); - praloc(poly, plast(*poly)); -} - -void -pchop(poly_t *poly) { - /* Normalise poly, then chop off the highest significant term - * (produces a SEMI-NORMALISED object). poly becomes a suitable - * divisor for pcrc(). - * poly may or may not be WELL-FORMED. - */ - - /* call pcanon() here so pfirst() and plast() return correct - * results - */ - pcanon(poly); - pshift(poly, *poly, 0UL, pfirst(*poly) + 1UL, plast(*poly), 0UL); -} - -void -pkchop(poly_t *poly) { - /* Convert poly from Koopman notation to chopped form (produces - * a SEMI-NORMALISED object). poly becomes a suitable divisor - * for pcrc(). - * poly may or may not be WELL-FORMED. - */ - unsigned long first; - - /* call pcanon() here so pfirst() returns the correct result */ - pcanon(poly); - first = pfirst(*poly); - if(first >= poly->length) { - pfree(poly); - return; - } - pshift(poly, *poly, 0UL, first + 1UL, poly->length, 1UL); - piter(poly); -} - -unsigned long -plen(const poly_t poly) { - /* Return length of polynomial. - * poly may or may not be WELL-FORMED. - */ - return(poly.length); -} - -int -pcmp(const poly_t *a, const poly_t *b) { - /* Compares poly_t objects for identical sizes and contents. - * a and b must be CLEAN. - * Defines a total order relation for sorting, etc. although - * mathematically, polynomials of equal degree are no greater or - * less than one another. - */ - unsigned long iter; - bmp_t *aptr, *bptr; - - if(!a || !b) return(!b - !a); - if(a->length < b->length) return(-1); - if(a->length > b->length) return(1); - aptr = a->bitmap; - bptr = b->bitmap; - for(iter=0UL; iter < a->length; iter += BMP_BIT) { - if(*aptr < *bptr) - return(-1); - if(*aptr++ > *bptr++) - return(1); - } - return(0); -} - -int -psncmp(const poly_t *a, const poly_t *b) { - /* Compares polys for identical effect, i.e. as though the - * shorter poly were padded with zeroes to the length of the - * longer. - * a and b must still be CLEAN, therefore psncmp() is *not* - * identical to pcmp() on semi-normalised polys as psnorm() - * clears the slack space. - */ - unsigned long length, iter, idx; - bmp_t aword, bword; - if(!a || !b) return(!b - !a); - length = (a->length > b->length) ? a->length : b->length; - for(iter = 0UL, idx = 0UL; iter < length; iter += BMP_BIT, ++idx) { - aword = (iter < a->length) ? a->bitmap[idx] : BMP_C(0); - bword = (iter < b->length) ? b->bitmap[idx] : BMP_C(0); - if(aword < bword) - return(-1); - if(aword > bword) - return(1); - } - return(0); -} - - -int -ptst(const poly_t poly) { - /* Tests whether a polynomial equals zero. Returns 0 if equal, - * a nonzero value otherwise. - * poly must be CLEAN. - */ - unsigned long iter; - bmp_t *bptr; - if(!poly.bitmap) return(0); - for(iter = 0UL, bptr = poly.bitmap; iter < poly.length; iter += BMP_BIT) - if(*bptr++) return(1); - return(0); -} - -unsigned long -pfirst(const poly_t poly) { - /* Returns the index of the first nonzero term in poly. If none - * is found, returns the length of poly. - * poly must be CLEAN. - */ - unsigned long idx = 0UL, size = SIZE(poly.length); - bmp_t accu = BMP_C(0); /* initialiser for Acorn C */ - unsigned int probe = BMP_SUB, ofs = 0; - - while(idx < size && !(accu = poly.bitmap[idx])) ++idx; - if(idx >= size) return(poly.length); - while(probe) { -#ifndef BMP_POF2 - while((ofs | probe) >= (unsigned int) BMP_BIT) probe >>= 1; -#endif - if(accu >> (ofs | probe)) ofs |= probe; - probe >>= 1; - } - - return(BMP_BIT - 1UL - ofs + idx * BMP_BIT); -} - -unsigned long -plast(const poly_t poly) { - /* Returns 1 plus the index of the last nonzero term in poly. - * If none is found, returns zero. - * poly must be CLEAN. - */ - unsigned long idx, size = SIZE(poly.length); - bmp_t accu; - unsigned int probe = BMP_SUB, ofs = 0; - - if(!poly.length) return(0UL); - idx = size - 1UL; - while(idx && !(accu = poly.bitmap[idx])) --idx; - if(!idx && !(accu = poly.bitmap[idx])) return(0UL); - /* now accu == poly.bitmap[idx] and contains last significant term */ - while(probe) { -#ifndef BMP_POF2 - while((ofs | probe) >= (unsigned int) BMP_BIT) probe >>= 1; -#endif - if(accu << (ofs | probe)) ofs |= probe; - probe >>= 1; - } - - return(idx * BMP_BIT + ofs + 1UL); -} - -poly_t -psubs(const poly_t src, unsigned long head, unsigned long start, unsigned long end, unsigned long tail) { - poly_t dest = PZERO; - pshift(&dest, src, head, start, end, tail); - return(dest); -} - -void -pright(poly_t *poly, unsigned long length) { - /* Trims or extends poly to length at the left edge, prepending - * zeroes if necessary. Analogous to praloc() except the - * rightmost terms of poly are preserved. - * On entry, poly may or may not be WELL-FORMED. - * On exit, poly is CLEAN. - */ - - if(length > poly->length) - pshift(poly, *poly, length - poly->length, 0UL, poly->length, 0UL); - else if(length < poly->length) - pshift(poly, *poly, 0UL, poly->length - length, poly->length, 0UL); - else - praloc(poly, poly->length); -} - -void -pshift(poly_t *dest, const poly_t src, unsigned long head, unsigned long start, unsigned long end, unsigned long tail) { - /* copies bits start to end-1 of src to dest, plus the number of leading and trailing zeroes given by head and tail. - * end may exceed the length of src in which case more zeroes are appended. - * dest may point to src, in which case the poly is edited in place. - * On exit, dest is CLEAN. - */ - - unsigned long length, fulllength, size, fullsize, iter, idx, datidx; - /* condition inputs; end, head and tail may be any value */ - if(end < start) end = start; - - length = end - start + head; - fulllength = length + tail; - if(fulllength > src.length) - praloc(dest, fulllength); - else - praloc(dest, src.length); - - /* number of words in new poly */ - size = SIZE(length); - fullsize = SIZE(fulllength); - /* array index of first word ending up with source material */ - datidx = IDX(head); - - if(head > start && end > start) { - /* shifting right, size > 0 */ - /* index of the source bit ending up in the LSB of the last word - * size * BMP_BIT >= length > head > 0 */ - iter = size * BMP_BIT - head - 1UL; - for(idx = size - 1UL; idx > datidx; iter -= BMP_BIT, --idx) - dest->bitmap[idx] = getwrd(src, iter); - dest->bitmap[idx] = getwrd(src, iter); - /* iter == size * BMP_BIT - head - 1 - BMP_BIT * (size - 1 - datidx) - * == BMP_BIT * (size - size + 1 + datidx) - head - 1 - * == BMP_BIT * (1 + head / BMP_BIT) - head - 1 - * == BMP_BIT + head - head % BMP_BIT - head - 1 - * == BMP_BIT - head % BMP_BIT - 1 - * >= 0 - */ - } else if(head <= start) { - /* shifting left or copying */ - /* index of the source bit ending up in the LSB of bitmap[idx] */ - iter = start - head + BMP_BIT - 1UL; - for(idx = datidx; idx < size; iter += BMP_BIT, ++idx) - dest->bitmap[idx] = getwrd(src, iter); - } - - /* clear head */ - for(idx = 0UL; idx < datidx; ++idx) - dest->bitmap[idx] = BMP_C(0); - if(size) - dest->bitmap[datidx] &= ~BMP_C(0) >> LOFS(head); - - /* clear tail */ - if(LOFS(length)) - dest->bitmap[size - 1UL] &= ~(~BMP_C(0) >> LOFS(length)); - for(idx = size; idx < fullsize; ++idx) - dest->bitmap[idx] = BMP_C(0); - - /* call praloc to shrink poly if required */ - if(dest->length > fulllength) - praloc(dest, fulllength); -} - -void -ppaste(poly_t *dest, const poly_t src, unsigned long skip, unsigned long seek, unsigned long end, unsigned long fulllength) { - /* pastes terms of src, starting from skip, to positions seek to end-1 of dest - * then sets length of dest to fulllength (>= end) - * to paste n terms of src, give end = seek + n - * to truncate dest at end of paste, set fulllength = end - * to avoid truncating, set fulllength = plen(*dest) - * dest may point to src, in which case the poly is edited in place. - * src must be CLEAN in the case that the end is overrun. - * On exit, dest is CLEAN. - */ - bmp_t mask; - unsigned long seekidx, endidx, iter; - int seekofs; - if(end < seek) end = seek; - if(fulllength < end) fulllength = end; - - /* expand dest if necessary. don't shrink as dest may be src */ - if(fulllength > dest->length) - praloc(dest, fulllength); - seekidx = IDX(seek); - endidx = IDX(end); - seekofs = OFS(seek); - /* index of the source bit ending up in the LSB of the first modified word */ - iter = skip + seekofs; - if(seekidx == endidx) { - /* paste affects one word (traps end = seek case) */ - mask = ((BMP_C(1) << seekofs) - (BMP_C(1) << OFS(end))) << 1; - dest->bitmap[seekidx] = (dest->bitmap[seekidx] & ~mask) | (getwrd(src, iter) & mask); - } else if(seek > skip) { - /* shifting right */ - /* index of the source bit ending up in the LSB of the last modified word */ - iter += (endidx - seekidx) * BMP_BIT; - mask = ~BMP_C(0) >> LOFS(end); - dest->bitmap[endidx] = (dest->bitmap[endidx] & mask) | (getwrd(src, iter) & ~mask); - for(iter -= BMP_BIT, --endidx; endidx > seekidx; iter -= BMP_BIT, --endidx) - dest->bitmap[endidx] = getwrd(src, iter); - mask = ~BMP_C(0) >> LOFS(seek); - dest->bitmap[endidx] = (dest->bitmap[endidx] & ~mask) | (getwrd(src, iter) & mask); - /* iter == skip + seekofs + (endidx - seekidx) * BMP_BIT - BMP_BIT * (endidx - seekidx) - * == skip + seekofs + BMP_BIT * (endidx - seekidx - endidx + seekidx) - * == skip + seekofs - * >= 0 - */ - } else { - /* shifting left or copying */ - mask = ~BMP_C(0) >> LOFS(seek); - dest->bitmap[seekidx] = (dest->bitmap[seekidx] & ~mask) | (getwrd(src, iter) & mask); - for(iter += BMP_BIT, ++seekidx; seekidx < endidx; iter += BMP_BIT, ++seekidx) - dest->bitmap[seekidx] = getwrd(src, iter); - mask = ~BMP_C(0) >> LOFS(end); - dest->bitmap[seekidx] = (dest->bitmap[seekidx] & mask) | (getwrd(src, iter) & ~mask); - } - /* shrink poly if required */ - if(dest->length > fulllength) - praloc(dest, fulllength); -} - -void -pdiff(poly_t *dest, const poly_t src, unsigned long ofs) { - /* Subtract src from dest (modulo 2) at offset ofs. - * In modulo 2 arithmetic, subtraction is equivalent to addition - * We include an alias for those who wish to retain the distinction - * src and dest must be CLEAN. - */ - psum(dest, src, ofs); -} - -void -psum(poly_t *dest, const poly_t src, unsigned long ofs) { - /* Adds src to dest (modulo 2) at offset ofs. - * When ofs == dest->length, catenates src on to dest. - * src and dest must be CLEAN. - */ - unsigned long fulllength, idx, iter, end; - - fulllength = ofs + src.length; - if(fulllength > dest->length) - praloc(dest, fulllength); - /* array index of first word in dest to be modified */ - idx = IDX(ofs); - /* index of bit in src to be added to LSB of dest->bitmap[idx] */ - iter = OFS(ofs); - /* stop value for iter */ - end = BMP_BIT - 1UL + src.length; - for(; iter < end; iter += BMP_BIT, ++idx) - dest->bitmap[idx] ^= getwrd(src, iter); -} - -void -prev(poly_t *poly) { - /* Reverse or reciprocate a polynomial. - * On exit, poly is CLEAN. - */ - unsigned long leftidx = 0UL, rightidx = SIZE(poly->length); - unsigned long ofs = LOFS(BMP_BIT - LOFS(poly->length)); - unsigned long fulllength = poly->length + ofs; - bmp_t accu; - - if(ofs) { - /* removable optimisation */ - if(poly->length < (unsigned long) BMP_BIT) { - *poly->bitmap = rev(*poly->bitmap >> ofs, (int) poly->length) << ofs; - return; - } - } - - /* claim remaining bits of last word (as we use public function pshift()) */ - poly->length = fulllength; - - /* reverse and swap words in the array, leaving it right-justified */ - while(leftidx < rightidx) { - /* rightidx > 0 */ - accu = rev(poly->bitmap[--rightidx], BMP_BIT); - poly->bitmap[rightidx] = rev(poly->bitmap[leftidx], BMP_BIT); - poly->bitmap[leftidx++] = accu; - } - /* shift polynomial to left edge if required */ - if(ofs) - pshift(poly, *poly, 0UL, ofs, fulllength, 0UL); -} - -void -prevch(poly_t *poly, int bperhx) { - /* Reverse each group of bperhx bits in a polynomial. - * Does not clean poly. - */ - unsigned long iter = 0, idx, ofs; - bmp_t mask, accu; - - if(bperhx < 2 || bperhx > BMP_BIT) - return; - if(poly->length % bperhx) - praloc(poly, bperhx - (poly->length % bperhx) + poly->length); - mask = ~BMP_C(0) >> (BMP_BIT - bperhx); - for(iter = (unsigned long) (bperhx - 1); iter < poly->length; iter += bperhx) { - accu = getwrd(*poly, iter) & mask; - accu ^= rev(accu, bperhx); - idx = IDX(iter); - ofs = OFS(iter); - poly->bitmap[idx] ^= accu << ofs; - if(ofs + bperhx > (unsigned int) BMP_BIT) - /* (BMP_BIT - 1UL - (iter) % BMP_BIT) + bperhx > BMP_BIT - * (-1UL - (iter) % BMP_BIT) + bperhx > 0 - * (- (iter % BMP_BIT)) + bperhx > 1 - * - (iter % BMP_BIT) > 1 - bperhx - * iter % BMP_BIT < bperhx - 1, iter >= bperhx - 1 - * iter >= BMP_BIT - * idx >= 1 - */ - poly->bitmap[idx-1] ^= accu >> (BMP_BIT - ofs); - } -} - -void -prcp(poly_t *poly) { - /* Reciprocate a chopped polynomial. Use prev() on whole - * polynomials. - * On exit, poly is SEMI-NORMALISED. - */ - unsigned long first; - - praloc(poly, RNDUP(poly->length)); - prev(poly); - first = pfirst(*poly); - if(first >= poly->length) { - pfree(poly); - return; - } - pshift(poly, *poly, 0UL, first + 1UL, poly->length, 1UL); - piter(poly); -} - -void -pinv(poly_t *poly) { - /* Invert a polynomial, i.e. add 1 (modulo 2) to the coefficient of each term - * on exit, poly is CLEAN. - */ - unsigned long idx, size = SIZE(poly->length); - - for(idx = 0UL; idxbitmap[idx] = ~poly->bitmap[idx]; - if(LOFS(poly->length)) - poly->bitmap[size - 1UL] &= ~(~BMP_C(0) >> LOFS(poly->length)); -} - -poly_t -pmod(const poly_t dividend, const poly_t divisor) { - /* Divide dividend by normalised divisor and return the remainder - * This function generates a temporary 'chopped' divisor for pcrc() - * If calling repeatedly with a constant divisor, produce a chopped copy - * with pchop() and call pcrc() directly for higher efficiency. - * dividend and divisor must be CLEAN. - */ - - /* perhaps generate an error if divisor is zero */ - poly_t subdivisor = psubs(divisor, 0UL, pfirst(divisor) + 1UL, plast(divisor), 0UL); - poly_t result = pcrc(dividend, subdivisor, pzero, pzero, 0); - pfree(&subdivisor); - return(result); -} - -poly_t -pcrc(const poly_t message, const poly_t divisor, const poly_t init, const poly_t xorout, int flags) { - /* Divide message by divisor and return the remainder. - * init is added to divisor, highest terms aligned, before - * division. - * xorout is added to the remainder, highest terms aligned. - * If P_MULXN is set in flags, message is multiplied by x^n - * (i.e. trailing zeroes equal to the CRC width are appended) - * before adding init and division. Set P_MULXN for most CRC - * calculations. - * All inputs must be CLEAN. - * If all inputs are CLEAN, the returned poly_t will be CLEAN. - */ - unsigned long max = 0UL, iter, ofs, resiter; - bmp_t probe, rem, dvsr, *rptr, *sptr; - const bmp_t *bptr, *eptr; - poly_t result = PZERO; - - if(flags & P_MULXN) - max = message.length; - else if(message.length > divisor.length) - max = message.length - divisor.length; - bptr=message.bitmap; - eptr=message.bitmap+SIZE(message.length); - probe=~(~BMP_C(0) >> 1); - if(divisor.length <= (unsigned long) BMP_BIT - && init.length <= (unsigned long) BMP_BIT) { - rem = init.length ? *init.bitmap : BMP_C(0); - dvsr = divisor.length ? *divisor.bitmap : BMP_C(0); - for(iter = 0UL, ofs = 0UL; iter < max; ++iter, --ofs) { - if(!ofs) { - ofs = BMP_BIT; - rem ^= *bptr++; - } - if(rem & probe) - rem = (rem << 1) ^ dvsr; - else - rem <<= 1; - } - if(bptr < eptr) - /* max < message.length */ - rem ^= *bptr >> OFS(BMP_BIT - 1UL + max); - if(init.length > max && init.length - max > divisor.length) { - palloc(&result, init.length - max); - *result.bitmap = rem; - } else if(divisor.length) { - palloc(&result, divisor.length); - *result.bitmap = rem; - } - } else { - /* allocate maximum size plus one word for shifted divisors and one word containing zero. - * This also ensures that result[1] exists - */ - palloc(&result, (init.length > divisor.length ? init.length : divisor.length) + (unsigned long) (BMP_BIT << 1)); - /*if there is content in init, there will be an extra word in result to clear it */ - psum(&result, init, 0UL); - if(max) - *result.bitmap ^= *bptr++; - for(iter = 0UL, ofs = 0UL; iter < max; ++iter, probe >>= 1) { - if(!probe) { - probe = ~(~BMP_C(0) >> 1); - ofs = 0UL; - sptr = rptr = result.bitmap; - ++sptr; - /* iter < max <= message.length, so bptr is valid - * shift result one word to the left, splicing in a message word - * and clearing the last active word - */ - *rptr++ = *sptr++ ^ *bptr++; - for(resiter = (unsigned long) (BMP_BIT << 1); resiter < result.length; resiter += BMP_BIT) - *rptr++ = *sptr++; - } - ++ofs; - if(*result.bitmap & probe) - psum(&result, divisor, ofs); - } - rptr = result.bitmap; - ++rptr; - while(bptr < eptr) - *rptr++ ^= *bptr++; - /* 0 <= ofs <= BMP_BIT, location of the first bit of the result */ - pshift(&result, result, 0UL, ofs, (init.length > max + divisor.length ? init.length - max - divisor.length : 0UL) + divisor.length + ofs, 0UL); - } - psum(&result, xorout, 0UL); - return(result); -} - -int -piter(poly_t *poly) { - /* Replace poly with the 'next' polynomial of equal length. - * Returns zero if the next polynomial is all zeroes, a nonzero - * value otherwise. - * Does not clean poly. - */ - bmp_t *bptr; - if(!poly->length) return(0); - - bptr = poly->bitmap + IDX(poly->length - 1UL); - *bptr += BMP_C(1) << OFS(poly->length - 1UL); - while(bptr != poly->bitmap && !*bptr) - ++(*--bptr); - return(*bptr != BMP_C(0)); -} - -void -palloc(poly_t *poly, unsigned long length) { - /* Replaces poly with a CLEAN object of the specified length, - * consisting of all zeroes. - * It is safe to call with length = 0, in which case the object - * is freed. - * poly may or may not be WELL-FORMED. - * On exit, poly is CLEAN. - */ - unsigned long size = SIZE(length); - - poly->length = 0UL; - free(poly->bitmap); - poly->bitmap = NULL; - if(!length) return; - if(!size) - size = IDX(length) + 1UL; - poly->bitmap = (bmp_t *) calloc(size, sizeof(bmp_t)); - if(poly->bitmap) { - poly->length = length; - } else - uerror("cannot allocate memory for poly"); -} - -void -pfree(poly_t *poly) { - /* Frees poly's bitmap storage and sets poly equal to the empty - * polynomial (PZERO). - * poly may or may not be WELL-FORMED. - * On exit, poly is CLEAN. - */ - - /* palloc(poly, 0UL); */ - - poly->length = 0UL; - free(poly->bitmap); - poly->bitmap = NULL; -} - -void -praloc(poly_t *poly, unsigned long length) { - /* Trims or extends poly to length at the right edge, appending - * zeroes if necessary. - * On entry, poly may or may not be WELL-FORMED. - * On exit, poly is CLEAN. - */ - unsigned long oldsize, size = SIZE(length); - if(!poly) return; - if(!length) { - poly->length = 0UL; - free(poly->bitmap); - poly->bitmap = NULL; - return; - } - if(!size) - size = IDX(length) + 1UL; - if(!poly->bitmap) - poly->length = 0UL; - oldsize = SIZE(poly->length); - if(oldsize != size) - /* reallocate if array pointer is null or array resized */ - poly->bitmap = (bmp_t *) realloc((void *)poly->bitmap, size * sizeof(bmp_t)); - if(poly->bitmap) { - if(poly->length < length) { - /* poly->length >= 0, length > 0, size > 0. - * poly expanded. clear old last word and all new words - */ - if(LOFS(poly->length)) - poly->bitmap[oldsize - 1UL] &= ~(~BMP_C(0) >> LOFS(poly->length)); - while(oldsize < size) - poly->bitmap[oldsize++] = BMP_C(0); - } else if(LOFS(length)) - /* poly->length >= length > 0. - * poly shrunk. clear new last word - */ - poly->bitmap[size - 1UL] &= ~(~BMP_C(0) >> LOFS(length)); - poly->length = length; - } else - uerror("cannot reallocate memory for poly"); -} - -int -pmpar(const poly_t poly, const poly_t mask) { - /* Return even parity of poly masked with mask. - * Poly and mask must be CLEAN. - */ - bmp_t res = BMP_C(0); - int i = BMP_SUB; - const bmp_t *pptr = poly.bitmap, *mptr = mask.bitmap; - const bmp_t *const pend = poly.bitmap + SIZE(poly.length); - const bmp_t *const mend = mask.bitmap + SIZE(mask.length); - - while(pptr < pend && mptr < mend) - res ^= *pptr++ & *mptr++; - do - res ^= res >> i; - while(i >>= 1); - - return((int) (res & BMP_C(1))); -} - -int -pident(const poly_t a, const poly_t b) { - /* Return nonzero if a and b have the same length - * and point to the same bitmap. - * a and b need not be CLEAN. - */ - return(a.length == b.length && a.bitmap == b.bitmap); -} - -/* Private functions */ - -static bmp_t -getwrd(const poly_t poly, unsigned long iter) { - /* Fetch unaligned word from poly where LSB of result is - * bit iter of the bitmap (counting from zero). If iter exceeds - * the length of poly then zeroes are appended as necessary. - * Factored from ptostr(). - * poly must be CLEAN. - */ - bmp_t accu = BMP_C(0); - unsigned long idx, size; - int ofs; - - idx = IDX(iter); - ofs = OFS(iter); - size = SIZE(poly.length); - - if(idx < size) - accu |= poly.bitmap[idx] >> ofs; - if(idx && idx <= size && ofs > 0) - accu |= poly.bitmap[idx - 1UL] << (BMP_BIT - ofs); - return(accu); -} - -static bmp_t -rev(bmp_t accu, int bits) { - /* Returns the bitmap word argument with the given number of - * least significant bits reversed and the rest cleared. - */ - static const unsigned char revtab[256] = { - 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0, - 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, - 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8, - 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, - 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4, - 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, - 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec, - 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, - 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2, - 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, - 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea, - 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, - 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6, - 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, - 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee, - 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, - 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1, - 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, - 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9, - 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, - 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5, - 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, - 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed, - 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, - 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3, - 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, - 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb, - 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, - 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7, - 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, - 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef, - 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff - }; - bmp_t result = BMP_C(0); - while(bits > 8) { - bits -= 8; - result = result << 8 | revtab[accu & 0xff]; - accu >>= 8; - } - result = result << bits | (bmp_t) (revtab[accu & 0xff] >> (8 - bits)); - return(result); -} - -static void -prhex(char **spp, bmp_t bits, int flags, int bperhx) { - /* Appends a hexadecimal string representing the bperhx least - * significant bits of bits to an external string. - * spp points to a character pointer that in turn points to the - * end of a hex string being built. prhex() advances this - * second pointer by the number of characters written. - * The unused MSBs of bits MUST be cleared. - * Set P_UPPER in flags to write A-F in uppercase. - */ - static const char hex[] = "0123456789abcdef0123456789ABCDEF"; - const int upper = (flags & P_UPPER ? 0x10 : 0); - while(bperhx > 0) { - bperhx -= ((bperhx + 3) & 3) + 1; - *(*spp)++ = hex[(bits >> bperhx & BMP_C(0xf)) | upper]; - } -} diff --git a/client/reveng/reveng.c b/client/reveng/reveng.c deleted file mode 100644 index dd50987c..00000000 --- a/client/reveng/reveng.c +++ /dev/null @@ -1,489 +0,0 @@ -/* reveng.c - * Greg Cook, 9/Apr/2015 - */ - -/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder - * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Gregory Cook - * - * This file is part of CRC RevEng. - * - * CRC RevEng is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * CRC RevEng is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with CRC RevEng. If not, see . - */ - -/* 2013-09-16: calini(), calout() work on shortest argument - * 2013-06-11: added sequence number to uprog() calls - * 2013-02-08: added polynomial range search - * 2013-01-18: refactored model checking to pshres(); renamed chkres() - * 2012-05-24: efficiently build Init contribution string - * 2012-05-24: removed broken search for crossed-endian algorithms - * 2012-05-23: rewrote engini() after Ewing; removed modini() - * 2011-01-17: fixed ANSI C warnings - * 2011-01-08: fixed calini(), modini() caters for crossed-endian algos - * 2011-01-04: renamed functions, added calini(), factored pshres(); - * rewrote engini() and implemented quick Init search - * 2011-01-01: reveng() initialises terminating entry, addparms() - * initialises all fields - * 2010-12-26: renamed CRC RevEng. right results, rejects polys faster - * 2010-12-24: completed, first tests (unsuccessful) - * 2010-12-21: completed modulate(), partial sketch of reveng() - * 2010-12-19: started reveng - */ - -/* reveng() can in theory be modified to search for polynomials shorter - * than the full width as well, but this imposes a heavy time burden on - * the full width search, which is the primary use case, as well as - * complicating the search range function introduced in version 1.1.0. - * It is more effective to search for each shorter width directly. - */ - -#include - -#define FILE void -#include "reveng.h" - -static poly_t *modpol(const poly_t init, int rflags, int args, const poly_t *argpolys); -static void engini(int *resc, model_t **result, const poly_t divisor, int flags, int args, const poly_t *argpolys); -static void calout(int *resc, model_t **result, const poly_t divisor, const poly_t init, int flags, int args, const poly_t *argpolys); -static void calini(int *resc, model_t **result, const poly_t divisor, int flags, const poly_t xorout, int args, const poly_t *argpolys); -static void chkres(int *resc, model_t **result, const poly_t divisor, const poly_t init, int flags, const poly_t xorout, int args, const poly_t *argpolys); - -static const poly_t pzero = PZERO; - -model_t * -reveng(const model_t *guess, const poly_t qpoly, int rflags, int args, const poly_t *argpolys) { - /* Complete the parameters of a model by calculation or brute search. */ - poly_t *pworks, *wptr, rem, gpoly; - model_t *result = NULL, *rptr; - int resc = 0; - unsigned long spin = 0, seq = 0; - - if(~rflags & R_HAVEP) { - /* The poly is not known. - * Produce a list of differences between the arguments. - */ - pworks = modpol(guess->init, rflags, args, argpolys); - if(!pworks || !plen(*pworks)) { - free(pworks); - goto requit; - } - /* Initialise the guessed poly to the starting value. */ - gpoly = pclone(guess->spoly); - /* Clear the least significant term, to be set in the - * loop. qpoly does not need fixing as it is only - * compared with odd polys. - */ - if(plen(gpoly)) - pshift(&gpoly, gpoly, 0UL, 0UL, plen(gpoly) - 1UL, 1UL); - - while(piter(&gpoly) && (~rflags & R_HAVEQ || pcmp(&gpoly, &qpoly) < 0)) { - /* For each possible poly of this size, try - * dividing all the differences in the list. - */ - if(!(spin++ & R_SPMASK)) { - uprog(gpoly, guess->flags, seq++); - } - for(wptr = pworks; plen(*wptr); ++wptr) { - /* straight divide message by poly, don't multiply by x^n */ - rem = pcrc(*wptr, gpoly, pzero, pzero, 0); - if(ptst(rem)) { - pfree(&rem); - break; - } else - pfree(&rem); - } - /* If gpoly divides all the differences, it is a - * candidate. Search for an Init value for this - * poly or if Init is known, log the result. - */ - if(!plen(*wptr)) { - /* gpoly is a candidate poly */ - if(rflags & R_HAVEI && rflags & R_HAVEX) - chkres(&resc, &result, gpoly, guess->init, guess->flags, guess->xorout, args, argpolys); - else if(rflags & R_HAVEI) - calout(&resc, &result, gpoly, guess->init, guess->flags, args, argpolys); - else if(rflags & R_HAVEX) - calini(&resc, &result, gpoly, guess->flags, guess->xorout, args, argpolys); - else - engini(&resc, &result, gpoly, guess->flags, args, argpolys); - } - if(!piter(&gpoly)) - break; - } - /* Finished with gpoly and the differences list, free them. - */ - pfree(&gpoly); - for(wptr = pworks; plen(*wptr); ++wptr) - pfree(wptr); - free(pworks); - } - else if(rflags & R_HAVEI && rflags & R_HAVEX) - /* All parameters are known! Submit the result if we get here */ - chkres(&resc, &result, guess->spoly, guess->init, guess->flags, guess->xorout, args, argpolys); - else if(rflags & R_HAVEI) - /* Poly and Init are known, calculate XorOut */ - calout(&resc, &result, guess->spoly, guess->init, guess->flags, args, argpolys); - else if(rflags & R_HAVEX) - /* Poly and XorOut are known, calculate Init */ - calini(&resc, &result, guess->spoly, guess->flags, guess->xorout, args, argpolys); - else - /* Poly is known but not Init; search for Init. */ - engini(&resc, &result, guess->spoly, guess->flags, args, argpolys); - -requit: - if(!(result = realloc(result, ++resc * sizeof(model_t)))) - uerror("cannot reallocate result array"); - rptr = result + resc - 1; - rptr->spoly = pzero; - rptr->init = pzero; - rptr->flags = 0; - rptr->xorout = pzero; - rptr->check = pzero; - rptr->name = NULL; - - return(result); -} - -static poly_t * -modpol(const poly_t init, int rflags, int args, const poly_t *argpolys) { - /* Produce, in ascending length order, a list of differences - * between the arguments in the list by summing pairs of arguments. - * If R_HAVEI is not set in rflags, only pairs of equal length are - * summed. - * Otherwise, sums of right-aligned pairs are also returned, with - * the supplied init poly added to the leftmost terms of each - * poly of the pair. - */ - poly_t work, swap, *result, *rptr, *iptr; - const poly_t *aptr, *bptr, *eptr = argpolys + args; - unsigned long alen, blen; - - if(args < 2) return(NULL); - - if(!(result = malloc(((((args - 1) * args) >> 1) + 1) * sizeof(poly_t)))) - uerror("cannot allocate memory for codeword table"); - - rptr = result; - - for(aptr = argpolys; aptr < eptr; ++aptr) { - alen = plen(*aptr); - for(bptr = aptr + 1; bptr < eptr; ++bptr) { - blen = plen(*bptr); - if(alen == blen) { - work = pclone(*aptr); - psum(&work, *bptr, 0UL); - } else if(rflags & R_HAVEI && alen < blen) { - work = pclone(*bptr); - psum(&work, *aptr, blen - alen); - psum(&work, init, 0UL); - psum(&work, init, blen - alen); - } else if(rflags & R_HAVEI /* && alen > blen */) { - work = pclone(*aptr); - psum(&work, *bptr, alen - blen); - psum(&work, init, 0UL); - psum(&work, init, alen - blen); - } else - work = pzero; - - if(plen(work)) - pnorm(&work); - if((blen = plen(work))) { - /* insert work into result[] in ascending order of length */ - for(iptr = result; iptr < rptr; ++iptr) { - if(plen(work) < plen(*iptr)) { - swap = *iptr; - *iptr = work; - work = swap; - } - else if(plen(*iptr) == blen && !pcmp(&work, iptr)) { - pfree(&work); - work = *--rptr; - break; - } - } - *rptr++ = work; - } - } - } - *rptr = pzero; - return(result); -} - -static void -engini(int *resc, model_t **result, const poly_t divisor, int flags, int args, const poly_t *argpolys) { - /* Search for init values implied by the arguments. - * Method from: Ewing, Gregory C. (March 2010). - * "Reverse-Engineering a CRC Algorithm". Christchurch: - * University of Canterbury. - * - */ - poly_t apoly = PZERO, bpoly, pone = PZERO, *mat, *jptr; - const poly_t *aptr, *bptr, *iptr; - unsigned long alen, blen, dlen, ilen, i, j; - int cy; - - dlen = plen(divisor); - - /* Allocate the CRC matrix */ - if(!(mat = (poly_t *) malloc((dlen << 1) * sizeof(poly_t)))) - uerror("cannot allocate memory for CRC matrix"); - - /* Find arguments of the two shortest lengths */ - alen = blen = plen(*(aptr = bptr = iptr = argpolys)); - for(++iptr; iptr < argpolys + args; ++iptr) { - ilen = plen(*iptr); - if(ilen < alen) { - bptr = aptr; blen = alen; - aptr = iptr; alen = ilen; - } else if(ilen > alen && (aptr == bptr || ilen < blen)) { - bptr = iptr; blen = ilen; - } - } - if(aptr == bptr) { - /* if no arguments are suitable, calculate Init with an - * assumed XorOut of 0. Create a padded XorOut - */ - palloc(&apoly, dlen); - calini(resc, result, divisor, flags, apoly, args, argpolys); - pfree(&apoly); - free(mat); - return; - } - - /* Find the potential contribution of the bottom bit of Init */ - palloc(&pone, 1UL); - piter(&pone); - if(blen < (dlen << 1)) { - palloc(&apoly, dlen); /* >= 1 */ - psum(&apoly, pone, (dlen << 1) - 1UL - blen); /* >= 0 */ - psum(&apoly, pone, (dlen << 1) - 1UL - alen); /* >= 1 */ - } else { - palloc(&apoly, blen - dlen + 1UL); /* > dlen */ - psum(&apoly, pone, 0UL); - psum(&apoly, pone, blen - alen); /* >= 1 */ - } - if(plen(apoly) > dlen) { - mat[dlen] = pcrc(apoly, divisor, pzero, pzero, 0); - pfree(&apoly); - } else { - mat[dlen] = apoly; - } - - /* Find the actual contribution of Init */ - apoly = pcrc(*aptr, divisor, pzero, pzero, 0); - bpoly = pcrc(*bptr, divisor, pzero, apoly, 0); - - /* Populate the matrix */ - palloc(&apoly, 1UL); - for(jptr=mat; jptr j */ - j = pfirst(apoly); - } - if(j < dlen) - mat[j] = apoly; /* pident(mat[j], pzero) || pfirst(mat[j]) == j */ - else - pfree(&apoly); - } - palloc(&bpoly, dlen + 1UL); - psum(&bpoly, pone, dlen); - - /* Iterate through all solutions */ - do { - /* Solve the matrix by Gaussian elimination. - * The parity of the result, masked by each row, should be even. - */ - cy = 1; - apoly = pclone(bpoly); - jptr = mat + dlen; - for(i=0UL; ispoly = pclone(divisor); - rptr->init = pclone(init); - rptr->flags = flags; - rptr->xorout = pclone(xorout); - rptr->name = NULL; - - /* compute check value for this model */ - mcheck(rptr); - - /* callback to notify new model */ - ufound(rptr); -} diff --git a/client/reveng/reveng.h b/client/reveng/reveng.h deleted file mode 100644 index 48dcb31c..00000000 --- a/client/reveng/reveng.h +++ /dev/null @@ -1,214 +0,0 @@ -/* reveng.h - * Greg Cook, 9/Apr/2015 - */ - -/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder - * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Gregory Cook - * - * This file is part of CRC RevEng. - * - * CRC RevEng is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * CRC RevEng is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with CRC RevEng. If not, see . - */ - -#ifndef REVENG_H -#define REVENG_H 1 - -/* Configuration options */ - -#include "config.h" - -#ifndef BMP_T -# error config.h: BMP_T must be defined as unsigned long or a longer unsigned type -#endif - -#ifndef BMP_C -# error config.h: BMP_C() must define a BMP_T constant -#endif - -#if !defined PRESETS && !defined BMPMACRO -# undef BMP_BIT -# undef BMP_SUB -#endif - -#undef BMP_POF2 - -#ifdef BMP_BIT -# ifndef BMP_SUB -# error config.h: BMP_SUB must be defined as the highest power of two that is strictly less than BMP_BIT -# elif BMP_BIT < 32 -# error config.h: BMP_BIT must be at least 32 -# elif BMP_SUB < 16 -# error config.h: BMP_SUB must be at least 16 -# elif (BMP_SUB >= BMP_BIT || BMP_SUB << 1 < BMP_BIT || BMP_SUB & (BMP_SUB - 1)) -# error config.h: BMP_SUB must be defined as the highest power of two that is strictly less than BMP_BIT -# else /* BMP_SUB */ -# define SETBMP() -# endif /* BMP_SUB */ -# if BMP_BIT == 32 -# define BMP_POF2 5 -# elif BMP_BIT == 64 -# define BMP_POF2 6 -# elif BMP_BIT == 128 -# define BMP_POF2 7 -# elif BMP_BIT == 256 -# define BMP_POF2 8 -# elif BMP_BIT == 512 -# define BMP_POF2 9 -# elif BMP_BIT == 1024 -# define BMP_POF2 10 -# elif BMP_BIT == 2048 -# define BMP_POF2 11 -# elif BMP_BIT == 4096 -# define BMP_POF2 12 -# elif BMP_BIT == 8192 -# define BMP_POF2 13 -# elif BMP_BIT == 16384 -# define BMP_POF2 14 -# elif BMP_BIT == 32768 -# define BMP_POF2 15 -# elif BMP_BIT == 65536 -# define BMP_POF2 16 -/* may extend list as required */ -# elif (BMP_BIT & (BMP_BIT - 1)) == 0 -# define BMP_POF2 1 -# endif -#else /* BMP_BIT */ -# define BMP_BIT bmpbit -# define BMP_SUB bmpsub -# define SETBMP() setbmp() -#endif /* BMP_BIT */ - -/* Global definitions */ - -/* CRC RevEng version string */ -#define VERSION "1.3.0" - -/* bmpbit.c */ -typedef BMP_T bmp_t; - -extern int bmpbit, bmpsub; -extern void setbmp(void); - -/* poly.c */ -#define P_REFIN 1 -#define P_REFOUT 2 -#define P_MULXN 4 -#define P_RTJUST 8 -#define P_UPPER 16 -#define P_SPACE 32 -#define P_LTLBYT 64 -#define P_DIRECT 128 - -/* default flags */ -#define P_BE (P_RTJUST | P_MULXN) -#define P_LE (P_REFIN | P_REFOUT | P_MULXN) -#define P_BELE (P_REFOUT | P_MULXN) -#define P_LEBE (P_REFIN | P_RTJUST | P_MULXN) - -/* A poly_t constant representing the polynomial 0. */ -#define PZERO {0UL, (bmp_t *) 0} - -typedef struct { - unsigned long length; /* number of significant bits */ - bmp_t *bitmap; /* bitmap, MSB first, */ - /* left-justified in each word */ -} poly_t; - -extern poly_t filtop(FILE *input, unsigned long length, int flags, int bperhx); -extern poly_t strtop(const char *string, int flags, int bperhx); -extern char *ptostr(const poly_t poly, int flags, int bperhx); -extern char *pxsubs(const poly_t poly, int flags, int bperhx, unsigned long start, unsigned long end); -extern poly_t pclone(const poly_t poly); -extern void pcpy(poly_t *dest, const poly_t src); -extern void pcanon(poly_t *poly); -extern void pnorm(poly_t *poly); -extern void psnorm(poly_t *poly); -extern void pchop(poly_t *poly); -extern void pkchop(poly_t *poly); -extern unsigned long plen(const poly_t poly); -extern int pcmp(const poly_t *a, const poly_t *b); -extern int psncmp(const poly_t *a, const poly_t *b); -extern int ptst(const poly_t poly); -extern unsigned long pfirst(const poly_t poly); -extern unsigned long plast(const poly_t poly); -extern poly_t psubs(const poly_t src, unsigned long head, unsigned long start, unsigned long end, unsigned long tail); -extern void pright(poly_t *poly, unsigned long length); -extern void pshift(poly_t *dest, const poly_t src, unsigned long head, unsigned long start, unsigned long end, unsigned long tail); -extern void ppaste(poly_t *dest, const poly_t src, unsigned long skip, unsigned long seek, unsigned long end, unsigned long fulllength); -extern void pdiff(poly_t *dest, const poly_t src, unsigned long ofs); -extern void psum(poly_t *dest, const poly_t src, unsigned long ofs); -extern void prev(poly_t *poly); -extern void prevch(poly_t *poly, int bperhx); -extern void prcp(poly_t *poly); -extern void pinv(poly_t *poly); -extern poly_t pmod(const poly_t dividend, const poly_t divisor); -extern poly_t pcrc(const poly_t message, const poly_t divisor, const poly_t init, const poly_t xorout, int flags); -extern int piter(poly_t *poly); -extern void palloc(poly_t *poly, unsigned long length); -extern void pfree(poly_t *poly); -extern void praloc(poly_t *poly, unsigned long length); -extern int pmpar(const poly_t poly, const poly_t mask); -extern int pident(const poly_t a, const poly_t b); - -/* model.c */ -#define M_OVERWR 256 - -typedef struct { - poly_t spoly; /* polynomial with highest-order term removed. length determines CRC width */ - poly_t init; /* initial register value. length == poly.length */ - int flags; /* P_REFIN and P_REFOUT indicate reflected input/output */ - poly_t xorout; /* final register XOR mask. length == poly.length */ - poly_t check; /* optional check value, the CRC of the UTF-8 string "123456789" */ - const char *name; /* optional canonical name of the model */ -} model_t; - -extern void mcpy(model_t *dest, const model_t *src); -extern void mfree(model_t *model); -extern int mcmp(const model_t *a, const model_t *b); -extern int mbynam(model_t *dest, const char *key); -extern void mbynum(model_t *dest, int num); -extern int mcount(void); -extern char *mnames(void); -extern char *mtostr(const model_t *model); -extern void mmatch(model_t *model, int flags); -extern void mcanon(model_t *model); -extern void mcheck(model_t *model); -extern void mrev(model_t *model); -extern void mnovel(model_t *model); - -/* reveng.c */ -#define R_HAVEP 512 -#define R_HAVEI 1024 -#define R_HAVERI 2048 -#define R_HAVERO 4096 -#define R_HAVEX 8192 -#define R_HAVEQ 16384 - -#define R_SPMASK 0x7FFFFFFUL - -extern model_t *reveng(const model_t *guess, const poly_t qpoly, int rflags, int args, const poly_t *argpolys); - -/* cli.c */ -#define C_INFILE 1 -#define C_FORCE 2 -#define C_RESULT 4 - -#define BUFFER 32768 - -extern int reveng_main(int argc, char *argv[]); -extern void ufound(const model_t *model); -extern void uerror(const char *msg); -extern void uprog(const poly_t gpoly, int flags, unsigned long seq); - -#endif /* REVENG_H */ diff --git a/client/scripting.c b/client/scripting.c index 3859fd48..232da889 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -15,6 +15,7 @@ #include #include #include "proxmark3.h" +#include "comms.h" #include "usb_cmd.h" #include "cmdmain.h" #include "util.h" @@ -25,7 +26,7 @@ #include "../common/crc64.h" #include "../common/polarssl/sha1.h" #include "../common/polarssl/aes.h" -#include "cmdcrc.h" + /** * The following params expected: * UsbCommand c @@ -220,7 +221,7 @@ static int l_iso14443b_crc(lua_State *L) unsigned char buf[USB_CMD_DATA_SIZE]; size_t len = 0; const char *data = luaL_checklstring(L, 1, &len); - if (USB_CMD_DATA_SIZE < len) + if (len > USB_CMD_DATA_SIZE-2) len = USB_CMD_DATA_SIZE-2; for (int i = 0; i < len; i += 2) { @@ -391,62 +392,6 @@ static int l_sha1(lua_State *L) return 1; } -static int l_reveng_models(lua_State *L){ - - char *models[80]; - int count = 0; - int in_width = luaL_checkinteger(L, 1); - - if( in_width > 89 ) return returnToLuaWithError(L,"Width cannot exceed 89, got %d", in_width); - - uint8_t width[80]; - width[0] = (uint8_t)in_width; - int ans = GetModels(models, &count, width); - if (!ans) return 0; - - lua_newtable(L); - - for (int i = 0; i < count; i++){ - lua_pushstring(L, (const char*)models[i]); - lua_rawseti(L,-2,i+1); - free(models[i]); - } - - return 1; -} - -//Called with 4 parameters. -// inModel ,string containing the crc model name: 'CRC-8' -// inHexStr ,string containing the hex representation of the data that will be used for CRC calculations. -// reverse ,int 0/1 (bool) if 1, calculate the reverse CRC -// endian ,char, 'B','b','L','l','t','r' describing if Big-Endian or Little-Endian should be used in different combinations. -// -// outputs: string with hex representation of the CRC result -static int l_reveng_RunModel(lua_State *L){ - //-c || -v - //inModel = valid model name string - CRC-8 - //inHexStr = input hex string to calculate crc on - //reverse = reverse calc option if true - //endian = {0 = calc default endian input and output, b = big endian input and output, B = big endian output, r = right justified - // l = little endian input and output, L = little endian output only, t = left justified} - //result = calculated crc hex string - char result[50]; - - const char *inModel = luaL_checkstring(L, 1); - const char *inHexStr = luaL_checkstring(L, 2); - bool reverse = lua_toboolean(L, 3); - const char endian = luaL_checkstring(L, 4)[0]; - - //PrintAndLog("mod: %s, hex: %s, rev %d", inModel, inHexStr, reverse); - //int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result) - int ans = RunModel( (char *)inModel, (char *)inHexStr, reverse, endian, result); - if (!ans) - return returnToLuaWithError(L,"Reveng failed"); - - lua_pushstring(L, (const char*)result); - return 1; -} - /** * @brief Sets the lua path to include "./lualibs/?.lua", in order for a script to be * able to do "require('foobar')" if foobar.lua is within lualibs folder. @@ -493,8 +438,6 @@ int set_pm3_libraries(lua_State *L) {"crc16", l_crc16}, {"crc64", l_crc64}, {"sha1", l_sha1}, - {"reveng_models", l_reveng_models}, - {"reveng_runmodel", l_reveng_RunModel}, {NULL, NULL} }; diff --git a/client/scripts/14araw.lua b/client/scripts/14araw.lua index 94b3020c..e2530929 100644 --- a/client/scripts/14araw.lua +++ b/client/scripts/14araw.lua @@ -106,7 +106,7 @@ function main(args) dbg("doconnect") -- We reuse the connect functionality from a -- common library - info, err = lib14a.read1443a(true, no_rats) + info, err = lib14a.read14443a(true, no_rats) if err then return oops(err) end print(("Connected to card, uid = %s"):format(info.uid)) diff --git a/client/scripts/didump.lua b/client/scripts/didump.lua index 124c3dc3..71bfd99c 100644 --- a/client/scripts/didump.lua +++ b/client/scripts/didump.lua @@ -406,7 +406,7 @@ function main(args) -- GET TAG UID - result, err = lib14a.read1443a(false, true) + result, err = lib14a.read14443a(false, true) if not result then return oops(err) end diff --git a/client/scripts/e.lua b/client/scripts/e.lua deleted file mode 100644 index a20b8e47..00000000 --- a/client/scripts/e.lua +++ /dev/null @@ -1,72 +0,0 @@ -local getopt = require('getopt') -local utils = require('utils') - -example = "script calculates many different checksums (CRC) over the provided hex input" -author = "Iceman" -desc = -[[ -This script calculates many checksums (CRC) over the provided hex input. - -Arguments: - -b data in hex - -w bitwidth of the CRC family of algorithm. defaults to all known CRC presets. -Examples : - script run e -b 010203040506070809 - script run e -b 010203040506070809 -w 16 -]] - ---- --- A debug printout-function -function dbg(args) - if DEBUG then - print("###", args) - end -end ---- --- This is only meant to be used when errors occur -function oops(err) - print("ERROR: ",err) - return nil,err -end ---- --- Usage help -function help() - print(desc) - print("Example usage") - print(example) -end ---- --- The main entry point -function main(args) - - local data - local width = 0 - - -- Read the parameters - for o, a in getopt.getopt(args, 'hb:w:') do - if o == "h" then return help() end - if o == "b" then data = a end - if o == "w" then width = a end - end - - data = data or '01020304' - - print( string.rep('-',60) ) - print('Bit width of CRC | '..width) - print('Bytes | '..data) - print('') - print( ('%-20s| %-16s| %s'):format('Model','CRC', 'CRC reverse')) - print( string.rep('-',60) ) - local lists = core.reveng_models(width) - for _,i in pairs(lists) do - local a1 = core.reveng_runmodel(i, data, false, '0') - local a2 = core.reveng_runmodel(i, data, true, '0') - local a3 = core.reveng_runmodel(i, data, false, 'b') - local a4 = core.reveng_runmodel(i, data, false, 'B') - local a5 = core.reveng_runmodel(i, data, false, 'l') - local a6 = core.reveng_runmodel(i, data, false, 'L') - print( ('%-20s| %-16s| %-16s| %-16s| %-16s| %-16s| %-16s'):format(i, a1:upper(), a2:upper(),a3:upper(),a4:upper(),a5:upper(),a6:upper() ) ) - end -end - -main(args) \ No newline at end of file diff --git a/client/scripts/formatMifare.lua b/client/scripts/formatMifare.lua index 56397acd..2861b542 100644 --- a/client/scripts/formatMifare.lua +++ b/client/scripts/formatMifare.lua @@ -71,7 +71,7 @@ end -- -- Read information from a card function GetCardInfo() - result, err = lib14a.read1443a(false, true) + result, err = lib14a.read14443a(false, true) if not result then print(err) return diff --git a/client/scripts/lf_bulk_program.lua b/client/scripts/lf_bulk_program.lua index 4758c203..2556f8a5 100644 --- a/client/scripts/lf_bulk_program.lua +++ b/client/scripts/lf_bulk_program.lua @@ -9,7 +9,7 @@ bit32 = require('bit32') usage = [[ script run lf_bulk_program.lua -f facility -b base_id_num -c count - e.g: + e.g: script run lf_bulk_program.lua -f 1 -b 1000 -c 10 ]] author = "Brian Redbeard" @@ -32,12 +32,12 @@ function toBits(num,bits) end --[[Likely, I'm an idiot, but I couldn't find any parity functions in Lua - This can also be done with a combination of bitwise operations (in fact, + This can also be done with a combination of bitwise operations (in fact, is the canonically "correct" way to do it, but my brain doesn't just default to this and so counting some ones is good enough for me]]-- local function evenparity(s) local _, count = string.gsub(s, "1", "") - + local p = count % 2 if (p == 0) then return(false) @@ -45,7 +45,7 @@ local function evenparity(s) return(true) end end - + local function isempty(s) return s == nil or s == '' @@ -57,12 +57,13 @@ end local function cardHex(i,f) fac = bit32.lshift(f,16) id = bit32.bor(i, fac) - stream=toBits(id,26) + stream=toBits(id,24) --As the function defaults to even parity and returns a boolean, --perform a 'not' function to get odd parity - high = evenparity(string.sub(stream,0,12)) and 1 or 0 - low = not evenparity(string.sub(stream,13)) and 1 or 0 + high = evenparity(string.sub(stream,1,12)) and 1 or 0 + low = not evenparity(string.sub(stream,13)) and 1 or 0 + bits = bit32.bor(bit32.lshift(id,1), low) bits = bit32.bor(bits, bit32.lshift(high,25)) @@ -71,13 +72,13 @@ local function cardHex(i,f) --to create a higher order and lower order component which we will --then assemble in the return. The math above defines the proper --encoding as per HID/Weigand/etc. These bit flips are due to the - --format length check on bit 38 (cmdlfhid.c:64) and + --format length check on bit 38 (cmdlfhid.c:64) and --bit 31 (cmdlfhid.c:66). preamble = bit32.bor(0, bit32.lshift(1,5)) bits = bit32.bor(bits, bit32.lshift(1,26)) return ("%04x%08x"):format(preamble,bits) - + end local function main(args) @@ -86,22 +87,22 @@ local function main(args) --long arguments, but it seems this library was chosen for BSD style --compatibility for o, a in getopt.getopt(args, 'f:b:c:h') do - if o == 'f' then - if isempty(a) then + if o == 'f' then + if isempty(a) then print("You did not supply a facility code, using 0") facility = 0 - else + else facility = a end - elseif o == 'b' then - if isempty(a) then + elseif o == 'b' then + if isempty(a) then print("You must supply the flag -b (base id)") return else baseid = a end - elseif o == 'c' then - if isempty(a) then + elseif o == 'c' then + if isempty(a) then print("You must supply the flag -c (count)") return else @@ -118,22 +119,22 @@ local function main(args) --works, specifying ":" does not enforce supplying a value, thus we --need to do these checks all over again. - if isempty(baseid) then + if isempty(baseid) then print("You must supply the flag -b (base id)") print(usage) return end - if isempty(count) then + if isempty(count) then print("You must supply the flag -c (count)") print(usage) return end --If the facility ID is non specified, ensure we code it as zero - if isempty(facility) then + if isempty(facility) then print("Using 0 for the facility code as -f was not supplied") - facility = 0 + facility = 0 end --The next baseid + count function presents a logic/UX conflict @@ -144,7 +145,7 @@ local function main(args) endid = baseid + count - for cardnum = baseid,endid do + for cardnum = baseid,endid do local card = cardHex(cardnum, facility) print("Press enter to program card "..cardnum..":"..facility.." (hex: "..card..")") --This would be better with "press any key", but we'll take diff --git a/client/scripts/mfkeys.lua b/client/scripts/mfkeys.lua index 8e54f908..e8abd0b9 100644 --- a/client/scripts/mfkeys.lua +++ b/client/scripts/mfkeys.lua @@ -1,11 +1,11 @@ --[[ This is an example of Lua-scripting within proxmark3. This is a lua-side - implementation of hf mf chk + implementation of hf mf chk 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. - + Copyright (C) 2013 m h swende --]] -- Loads the commands-library @@ -14,49 +14,15 @@ local cmds = require('commands') local keys = require('mf_default_keys') -- Ability to read what card is there local reader = require('read14a') +-- Asks the user for input +local utils = require('utils') -local desc = -("This script implements check keys. It utilises a large list of default keys (currently %d keys).\ +local desc = ("This script implements check keys. \ +It utilises a large list of default keys (currently %d keys).\ If you want to add more, just put them inside mf_default_keys.lua. "):format(#keys) local TIMEOUT = 10000 -- 10 seconds - ---[[This may be moved to a separate library at some point]] -local utils = -{ - --- - -- Asks the user for Yes or No - confirm = function(message, ...) - local answer - message = message .. " [y]/[n] ?" - repeat - io.write(message) - io.flush() - answer=io.read() - if answer == 'Y' or answer == "y" then - return true - elseif answer == 'N' or answer == 'n' then - return false - end - until false - end, - --- - -- Asks the user for input - input = function (message , default) - local answer - if default ~= nil then - message = message .. " (default: ".. default.. " )" - end - message = message .." \n > " - io.write(message) - io.flush() - answer=io.read() - if answer == '' then answer = default end - - return answer - end, -} local function checkCommand(command) @@ -83,7 +49,7 @@ end function checkBlock(blockNo, keys, keyType) - -- The command data is only 512 bytes, each key is 6 bytes, meaning that we can send max 85 keys in one go. + -- The command data is only 512 bytes, each key is 6 bytes, meaning that we can send max 85 keys in one go. -- If there's more, we need to split it up local start, remaining= 1, #keys local arg1 = bit32.bor(bit32.lshift(keyType, 8), blockNo) @@ -91,18 +57,18 @@ function checkBlock(blockNo, keys, keyType) while remaining > 0 do local n,data = remaining, nil if remaining > 85 then n = 85 end - local data = table.concat(keys,"",start,n) + local data = table.concat(keys, "", start, start + n - 1) --print("data",data) --print("data len", #data) print(("Testing block %d, keytype %d, with %d keys"):format(blockNo, keyType, n)) - local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS, - arg1 = arg1, - arg2 = 1, - arg3 = n, + local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS, + arg1 = arg1, + arg2 = 1, + arg3 = n, data = data} local status = checkCommand(command) if status then return status, blockNo end - start = start+n+1 + start = start + n remaining = remaining - n end return nil @@ -119,41 +85,43 @@ local function displayresults(results) for sector,_ in pairs(results) do blockNo, keyA, keyB = unpack(_) - print(("| %3d | %3d |%s|%s|"):format(sector, blockNo, keyA, keyB )) + print(("| %3d | %3d |%12s|%12s|"):format(sector, blockNo, keyA, keyB)) end print("|--------------------------------------|") end + -- A little helper to place an item first in the list local function placeFirst(akey, list) - akey = akey:lower() - if list[1] == akey then + akey = akey:lower() + if list[1] == akey then -- Already at pole position return list end local result = {akey} --print(("Putting '%s' first"):format(akey)) for i,v in ipairs(list) do - if v ~= akey then + if v ~= akey then result[#result+1] = v end end return result end + local function dumptofile(results) local sector, blockNo, keyA, keyB,_ - if utils.confirm("Do you wish to save the keys to dumpfile?") then + if utils.confirm("Do you wish to save the keys to dumpfile?") then local destination = utils.input("Select a filename to store to", "dumpkeys.bin") local file = io.open(destination, "w") - if file == nil then + if file == nil then print("Could not write to file ", destination) return end local key_a = "" local key_b = "" - + for sector,_ in pairs(results) do blockNo, keyA, keyB = unpack(_) key_a = key_a .. bin.pack("H",keyA); @@ -166,11 +134,11 @@ local function dumptofile(results) end -local function main( args) +local function main(args) print(desc); - result, err = reader.read1443a(false, true) + result, err = reader.read14443a(false, true) if not result then print(err) return @@ -181,11 +149,11 @@ local function main( args) core.clearCommandBuffer() local blockNo local keyType = 0 -- A=0, B=1 - local numSectors = 16 + local numSectors = 16 - if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k - -- IFARE Classic 4K offers 4096 bytes split into forty sectors, - -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors. + if 0x18 == result.sak then -- NXP MIFARE Classic 4k | Plus 4k + -- IFARE Classic 4K offers 4096 bytes split into forty sectors, + -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors. numSectors = 40 elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k -- 1K offers 1024 bytes of data storage, split into 16 sector @@ -193,7 +161,7 @@ local function main( args) elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k -- MIFARE Classic mini offers 320 bytes split into five sectors. numSectors = 5 - elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k" + elseif 0x10 == result.sak then -- NXP MIFARE Plus 2k numSectors = 32 else print("I don't know how many sectors there are on this type of card, defaulting to 16") @@ -203,25 +171,25 @@ local function main( args) for sector=1,numSectors,1 do --[[ - The mifare Classic 1k card has 16 sectors of 4 data blocks each. + The mifare Classic 1k card has 16 sectors of 4 data blocks each. The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining - 8 sectors consist of 16 data blocks. + 8 sectors consist of 16 data blocks. --]] - local blockNo = sector * 4 -1 - + local blockNo = sector * 4 - 1 + if sector > 32 then - blockNo = 32*4+ (sector-32)*16 -1 + blockNo = 32*4 + (sector-32)*16 - 1 end local keyA = checkBlock(blockNo, keys, 0) - if keyA then keys = placeFirst(keyA, keys) end + if keyA then keys = placeFirst(keyA, keys) end keyA = keyA or "" local keyB = checkBlock(blockNo, keys, 1) - if keyB then keys = placeFirst(keyB, keys) end + if keyB then keys = placeFirst(keyB, keys) end keyB = keyB or "" - result[sector] = {blockNo, keyA, keyB } + result[sector] = {blockNo, keyA, keyB} -- Check if user aborted if core.ukbhit() then @@ -233,5 +201,4 @@ local function main( args) dumptofile(result) end -main( args) - +main(args) diff --git a/client/scripts/mifarePlus.lua b/client/scripts/mifarePlus.lua new file mode 100644 index 00000000..061ff736 --- /dev/null +++ b/client/scripts/mifarePlus.lua @@ -0,0 +1,340 @@ +local cmds = require('commands') +local lib14a = require('read14a') +getopt = require('getopt') -- Used to get command line arguments + +example = "script run mifarePlus" +author = "Dominic Celiano" +desc = +[[ +Purpose: Lua script to communicate with the Mifare Plus EV1, including personalization (setting the keys) and proximity check. Manually edit the file to add to the commands you can send the card. + +Please read the NXP manual before running this script to prevent making irreversible changes. Also note: + - The Mifare Plus must start in SL0 for personalization. Card can then be moved to SL1 or SL3. + - The keys are hardcoded in the script to "00...". Unless you change this, only use this script for testing purposes. + - Make sure you choose your card size correctly (2kB or 4kB). + +Small changes can be to made this script to communicate with the Mifare Plus S, X, or SE. + +Arguments: + -h : this help +]] + +SIXTEEN_BYTES_ZEROS = "00000000000000000000000000000000" + +GETVERS_INIT = "0360" -- Begins the GetVersion command +GETVERS_CONT = "03AF" -- Continues the GetVersion command +POWEROFF = "OFF" +WRITEPERSO = "03A8" +COMMITPERSO = "03AA" +AUTH_FIRST = "0370" +AUTH_CONT = "0372" +AUTH_NONFIRST = "0376" +PREPAREPC = "03F0" +PROXIMITYCHECK = "03F2" +VERIFYPC = "03FD" +READPLAINNOMACUNMACED = "0336" + +--- +-- This is only meant to be used when errors occur +function oops(err) + print("ERROR: ",err) +end + +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end + +--- +-- Used to send raw data to the firmware to subsequently forward the data to the card. +function sendRaw(rawdata, crc, power) + print((": %s"):format(rawdata)) + + local flags = lib14a.ISO14A_COMMAND.ISO14A_RAW + if crc then + flags = flags + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC + end + if power then + flags = flags + lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + end + + local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, + arg1 = flags, -- Send raw + arg2 = string.len(rawdata) / 2, -- arg2 contains the length, which is half the length of the ASCII-string rawdata + data = rawdata} + local ignore_response = false + local result, err = lib14a.sendToDevice(command, ignore_response) + if result then + --unpack the first 4 parts of the result as longs, and the last as an extremely long string to later be cut down based on arg1, the number of bytes returned + local count,cmd,arg1,arg2,arg3,data = bin.unpack('LLLLH512',result) + returned_bytes = string.sub(data, 1, arg1 * 2) + if returned_bytes ~= "" then + print((": %s"):format(returned_bytes)) -- need to multiply by 2 because the hex digits are actually two bytes when they are strings + end + return returned_bytes + else + err = "Error sending the card raw data." + oops(err) + end +end + +function writePerso() + -- Used to write any data, including the keys (Key A and Key B), for all the sectors. + -- writePerso() command parameters: + -- 1 byte - 0xA8 - Command Code + -- 2 bytes - Address of the first block or key to be written to (40 blocks are numbered from 0x0000 to 0x00FF) + -- X bytes - The data bytes to be written, starting from the first block. Amount of data sent can be from 16 to 240 bytes in 16 byte increments. This allows + -- up to 15 blocks to be written at once. + -- response from PICC: + -- 0x90 - OK + -- 0x09 - targeted block is invalid for writes, i.e. block 0, which contains manufacturer data + -- 0x0B - command invalid + -- 0x0C - unexpected command length + + + + cardsize = 4 --need to set to 4 for 4k or 2 for 2k + if(cardsize == 4) then + numsectors = 39 + elseif(cardsize == 2) then + numsectors = 31 + else + oops("Invalid card size") + end + + -- Write to the AES sector keys + print("Setting AES Sector keys") + for i=0,numsectors do --for each sector number + local keyA_block = "40" .. string.format("%02x", i * 2) + local keyB_block = "40" .. string.format("%02x", (i * 2) + 1) + --Can also calculate the keys fancily to make them unique, if desired + keyA = SIXTEEN_BYTES_ZEROS + keyB = SIXTEEN_BYTES_ZEROS + writeBlock(keyA_block, keyA) + writeBlock(keyB_block, keyB) + end + print("Finished setting AES Sector keys") + + print("Setting misc keys which haven't been set yet.") + --CardMasterKey + blocknum = "9000" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --CardConfigurationKey + blocknum = "9001" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --L3SwitchKey + blocknum = "9003" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --SL1CardAuthKey + blocknum = "9004" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --L3SectorSwitchKey + blocknum = "9006" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --L1L3MixSectorSwitchKey + blocknum = "9007" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --VC Keys + --VCProximityKey + blocknum = "A001" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --VCSelectENCKey + blocknum = "A080" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --VCSelectMACKey + blocknum = "A081" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --TransactionMACKey1 + blocknum = "C000" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --TransactionMACConfKey1 + blocknum = "C001" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + print("Finished setting misc keys.") + + print("WritePerso finished! Card is ready to move into new security level.") +end + +function writeBlock(blocknum, data) + -- Method writes 16 bytes of the string sent (data) to the specified block number + -- The block numbers sent to the card need to be in little endian format (i.e. block 0x0001 is sent as 0x1000) + blocknum_little_endian = string.sub(blocknum, 3, 4) .. string.sub(blocknum, 1, 2) + commandString = WRITEPERSO .. blocknum_little_endian .. data --Write 16 bytes (32 hex chars). + response = sendRaw(commandString, true, true) --0x90 is returned upon success + if string.sub(response, 3, 4) ~= "90" then + oops(("error occurred while trying to write to block %s"):format(blocknum)) + end +end + +function authenticateAES() + -- Used to try to authenticate with the AES keys we programmed into the card, to ensure the authentication works correctly. + commandString = AUTH_FIRST + commandString = commandString .. "" +end + +function getVersion() + sendRaw(GETVERS_INIT, true, true) + sendRaw(GETVERS_CONT, true, true) + sendRaw(GETVERS_CONT, true, true) +end + +function commitPerso(SL) + --pass SL as "01" to move to SL1 or "03" to move to SL3. + commandString = COMMITPERSO .. SL + response = sendRaw(commandString, true, true) --0x90 is returned upon success + if string.sub(response, 3, 4) ~= "90" then + oops("error occurred while trying to switch security level") + end +end + +function calculateMAC(MAC_input) + -- Pad the input if it is not a multiple of 16 bytes (32 nibbles). + if(string.len(MAC_input) % 32 ~= 0) then + MAC_input = MAC_input .. "80" + end + while(string.len(MAC_input) % 32 ~= 0) do + MAC_input = MAC_input .. "0" + end + print("Padded MAC Input = " .. MAC_input .. ", length (bytes) = " .. string.len(MAC_input) / 2) + + --The MAC would actually be calculated here, and the output stored in raw_output + raw_output = "00010203040506070001020304050607" -- Dummy filler for now of 16-byte output. To be filled with actual MAC for testing purposes. + + -- The final 8-byte MAC output is a concatenation of every 2nd byte starting from the second MSB. + final_output = "" + j = 3 + for i = 1,8 do + final_output = final_output .. string.sub(RndR, j, j + 1) .. string.sub(RndC, j, j + 1) + j = j + 4 + end + return final_output +end + +function proximityCheck() + --PreparePC-- + commandString = PREPAREPC + response = sendRaw(commandString, true, true) + if(response == "") then + print("ERROR: This card does not support the Proximity Check command.") + return + end + OPT = string.sub(response, 5, 6) + if(tonumber(OPT) == 1) then + pps_present = true + else + pps_present = false + end + pubRespTime = string.sub(response, 7, 10) + if(pps_present == true) then + pps = string.sub(response, 11, 12) + else + pps = nil + end + print("OPT = " .. OPT .. " pubRespTime = " .. pubRespTime .. " pps = " .. pps) + + --PC-- + RndC = "0001020304050607" --Random Challenge + num_rounds = 8 --Needs to be 1, 2, 4, or 8 + part_len = 8 / num_rounds + j = 1 + RndR = "" + for i = 1,num_rounds do + pRndC = "" + for q = 1,(part_len*2) do + pRndC = pRndC .. string.sub(RndC,j,j) + j = j + 1 + end + commandString = PROXIMITYCHECK .. "0" .. tostring(part_len) .. pRndC + pRndR = string.sub(sendRaw(commandString, true, true), 3, 3+part_len) + RndR = RndR .. pRndR + end + print("RndC = " .. RndC .. " RndR = " .. RndR) + + --VerifyPC-- + MAC_input = "FD" .. OPT .. pubRespTime + if(pps_present == true) then + MAC_input = MAC_input .. pps + end + rnum_concat = "" + rnum_concat = RndR .. RndC --temporary (only works for when a single random challenge (8 bytes) is sent) + -- j = 1 + -- for i = 1,8 do + -- rnum_concat = rnum_concat .. string.sub(RndR, j, j + 1) .. string.sub(RndC, j, j + 1) + -- j = j + 2 + -- end + MAC_input = MAC_input .. rnum_concat + print("Concatenation of random numbers = " .. rnum_concat) + print("Final PCD concatenation before input into MAC function = " .. MAC_input) + MAC_tag = calculateMAC(MAC_input) + print("8-byte PCD MAC_tag (placeholder - currently incorrect) = " .. MAC_tag) + commandString = VERIFYPC .. MAC_tag + response = sendRaw(commandString, true, true) + print(response) + PICC_MAC = string.sub(response, 5, 20) + print("8-byte MAC returned by PICC = " .. PICC_MAC) + MAC_input = "90" .. string.sub(MAC_input, 3) + print("Final PICC concatenation before input into MAC function = " .. MAC_input) + MAC_tag = calculateMAC(MAC_input) + print("8-byte PICC MAC_tag (placeholder - currently incorrect) = " .. MAC_tag) + +end + +--- +-- The main entry point +function main(args) + print("") -- Print a blank line to make things look cleaner + for o, a in getopt.getopt(args, 'h') do -- Populate command line arguments + if o == "h" then help() return end + end + + -- Initialize the card using the already-present read14a library + info,err = lib14a.read14443a(true, false) + --Perform RATS and PPS (Protocol and Parameter Selection) check to finish the ISO 14443-4 protocol. + response = sendRaw("e050", true, true) + if(response == "") then + print("No response from RATS.") + end + response = sendRaw("D01100", true, true) + if(response == "") then + print("No response from PPS check.") + end + if err then + oops(err) + sendRaw(POWEROFF, false, false) + return + else + print(("Connected to card with a UID of %s."):format(info.uid)) + end + + + -- Now, the card is initialized and we can do more interesting things. + + --writePerso() + --commitPerso("03") --move to SL3 + --getVersion() + proximityCheck() + + --commandString = VERIFYPC .. "186EFDE8DDC7D30B" + -- MAC = f5180d6e 40fdeae8 e9dd6ac7 bcd3350b + -- response = sendRaw(commandString, true, true) + + -- attempt to read VCProximityKey at block A001 + -- commandString = READPLAINNOMACUNMACED .. "01A0" .. "01" + -- response = sendRaw(commandString, true, true) + + -- authenticate with CardConfigurationKey + -- commandString = AUTH_FIRST .. "0190" .. "00" + -- response = sendRaw(commandString, true, true) + + -- Power off the Proxmark + sendRaw(POWEROFF, false, false) + + + +end + + +main(args) -- Call the main function diff --git a/client/scripts/mifare_autopwn.lua b/client/scripts/mifare_autopwn.lua index bede483b..d743f21e 100644 --- a/client/scripts/mifare_autopwn.lua +++ b/client/scripts/mifare_autopwn.lua @@ -56,7 +56,7 @@ end -- @return if unsuccessfull : nil, error function wait_for_mifare() while not core.ukbhit() do - res, err = reader.read1443a(false, true) + res, err = reader.read14443a(false, true) if res then return res end -- err means that there was no response from card end diff --git a/client/scripts/tnp3clone.lua b/client/scripts/tnp3clone.lua index 2a8d2763..9441559b 100644 --- a/client/scripts/tnp3clone.lua +++ b/client/scripts/tnp3clone.lua @@ -122,7 +122,7 @@ local function main(args) -- find tag - result, err = lib14a.read1443a(false, true) + result, err = lib14a.read14443a(false, true) if not result then return oops(err) end -- load keys diff --git a/client/scripts/tnp3dump.lua b/client/scripts/tnp3dump.lua index aca7d046..3955137e 100644 --- a/client/scripts/tnp3dump.lua +++ b/client/scripts/tnp3dump.lua @@ -127,7 +127,7 @@ local function main(args) local cmdSetDbgOff = "hf mf dbg 0" core.console( cmdSetDbgOff) - result, err = lib14a.read1443a(false, true) + result, err = lib14a.read14443a(false, true) if not result then return oops(err) end diff --git a/client/ui.c b/client/ui.c index 8faed6e8..50a6ec7d 100644 --- a/client/ui.c +++ b/client/ui.c @@ -22,8 +22,7 @@ double CursorScaleFactor = 1; int PlotGridX=0, PlotGridY=0, PlotGridXdefault= 64, PlotGridYdefault= 64, CursorCPos= 0, CursorDPos= 0; -int offline; -int flushAfterWrite = 0; //buzzy +bool flushAfterWrite = false; //buzzy int GridOffset = 0; bool GridLocked = false; bool showDemod = true; @@ -31,8 +30,7 @@ bool showDemod = true; static char *logfilename = "proxmark3.log"; #ifndef EXTERNAL_PRINTANDLOG -// Declared in proxmark3.c -extern pthread_mutex_t print_lock; +static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER; void PrintAndLog(char *fmt, ...) { @@ -53,8 +51,11 @@ void PrintAndLog(char *fmt, ...) } } + // If there is an incoming message from the hardware (eg: lf hid read) in + // the background (while the prompt is displayed and accepting user input), + // stash the prompt and bring it back later. #ifdef RL_STATE_READCMD - // We are using GNU readline. + // We are using GNU readline. libedit (OSX) doesn't support this flag. int need_hack = (rl_readline_state & RL_STATE_READCMD) > 0; if (need_hack) { @@ -64,9 +65,6 @@ void PrintAndLog(char *fmt, ...) rl_replace_line("", 0); rl_redisplay(); } -#else - // We are using libedit (OSX), which doesn't support this flag. - int need_hack = 0; #endif va_start(argptr, fmt); @@ -76,6 +74,8 @@ void PrintAndLog(char *fmt, ...) va_end(argptr); printf("\n"); +#ifdef RL_STATE_READCMD + // We are using GNU readline. libedit (OSX) doesn't support this flag. if (need_hack) { rl_restore_prompt(); rl_replace_line(saved_line, 0); @@ -83,6 +83,7 @@ void PrintAndLog(char *fmt, ...) rl_redisplay(); free(saved_line); } +#endif if (logging && logfile) { vfprintf(logfile, fmt, argptr2); @@ -91,7 +92,7 @@ void PrintAndLog(char *fmt, ...) } va_end(argptr2); - if (flushAfterWrite == 1) //buzzy + if (flushAfterWrite) //buzzy { fflush(NULL); } @@ -104,3 +105,8 @@ void SetLogFilename(char *fn) { logfilename = fn; } + +void SetFlushAfterWrite(bool flush_after_write) { + flushAfterWrite = flush_after_write; +} + diff --git a/client/ui.h b/client/ui.h index 4049033d..1273fe9e 100644 --- a/client/ui.h +++ b/client/ui.h @@ -20,11 +20,10 @@ void ShowGraphWindow(void); void RepaintGraphWindow(void); void PrintAndLog(char *fmt, ...); void SetLogFilename(char *fn); +void SetFlushAfterWrite(bool flush_after_write); extern double CursorScaleFactor; extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault, CursorCPos, CursorDPos, GridOffset; -extern int offline; -extern int flushAfterWrite; //buzzy extern bool GridLocked; extern bool showDemod; diff --git a/client/util.c b/client/util.c index 7e6b4074..2be1e46b 100644 --- a/client/util.c +++ b/client/util.c @@ -16,7 +16,6 @@ #include #include #include -#include "data.h" #ifdef _WIN32 #include @@ -116,6 +115,7 @@ void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex char *tmp = (char *)buf; size_t i; + memset(tmp, 0x00, hex_max_len); int maxLen = ( hex_len > hex_max_len) ? hex_max_len : hex_len; @@ -226,7 +226,7 @@ char *sprint_hex_ascii(const uint8_t *data, const size_t len) { memset(buf, 0x00, 1024); size_t max_len = (len > 255) ? 255 : len; // max 255 bytes * 3 + 2 characters = 767 in buffer - sprintf(tmp, "%s| ", sprint_hex(data, max_len) ); + sprintf(tmp, "%.765s| ", sprint_hex(data, max_len) ); size_t i = 0; size_t pos = (max_len * 3)+2; @@ -356,6 +356,23 @@ char * printBits(size_t const size, void const * const ptr) return buf; } +char * printBitsPar(const uint8_t *b, size_t len) { + static char buf1[512] = {0}; + static char buf2[512] = {0}; + static char *buf; + if (buf != buf1) + buf = buf1; + else + buf = buf2; + memset(buf, 0x00, 512); + + for (int i = 0; i < len; i++) { + buf[i] = ((b[i / 8] << (i % 8)) & 0x80) ? '1':'0'; + } + return buf; +} + + // ------------------------------------------------------------------------- // string parameters lib // ------------------------------------------------------------------------- diff --git a/client/util.h b/client/util.h index fd7ceaff..878938f4 100644 --- a/client/util.h +++ b/client/util.h @@ -24,10 +24,17 @@ #ifndef MAX # define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif +#ifndef arraylen +#define arraylen(x) (sizeof(x)/sizeof((x)[0])) +#endif #define EVEN 0 #define ODD 1 +#ifndef FILE_PATH_SIZE +#define FILE_PATH_SIZE 2000 +#endif + extern int ukbhit(void); extern void AddLogLine(char *fileName, char *extData, char *c); @@ -54,6 +61,7 @@ extern uint64_t bytes_to_num(uint8_t* src, size_t len); extern void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest); extern void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest); extern char *printBits(size_t const size, void const * const ptr); +extern char * printBitsPar(const uint8_t *b, size_t len); extern uint32_t SwapBits(uint32_t value, int nrbits); extern uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize); extern void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest); diff --git a/client/util_posix.c b/client/util_posix.c index 8f3ed46b..435e41f3 100644 --- a/client/util_posix.c +++ b/client/util_posix.c @@ -37,8 +37,12 @@ void msleep(uint32_t n) { #ifdef __APPLE__ +#ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC (1) +#endif +#ifndef CLOCK_REALTIME #define CLOCK_REALTIME (2) +#endif #include #include @@ -113,7 +117,7 @@ uint64_t msclock() { #include struct _timeb t; _ftime(&t); - return 1000 * t.time + t.millitm; + return 1000 * (uint64_t)t.time + t.millitm; // NORMAL CODE (use _ftime_s) //struct _timeb t; diff --git a/common/Makefile.common b/common/Makefile.common index 29b72a4c..0ab89b3d 100644 --- a/common/Makefile.common +++ b/common/Makefile.common @@ -29,7 +29,7 @@ GZIP=gzip OBJDIR = obj -INCLUDE = -I../include -I../common +INCLUDE = -I../include -I../common -I. TAR=tar TARFLAGS = -C .. -rvf @@ -75,7 +75,7 @@ LIBS = -lgcc THUMBOBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(THUMBSRC))) ARMOBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(ARMSRC))) ASMOBJ = $(patsubst %.s,$(OBJDIR)/%.o,$(notdir $(ASMSRC))) -VERSIONOBJ = $(OBJDIR)/version.o +VERSIONOBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(VERSIONSRC))) $(THUMBOBJ): $(OBJDIR)/%.o: %.c $(INCLUDES) $(CC) $(CFLAGS) -mthumb -mthumb-interwork -o $@ $< @@ -99,11 +99,6 @@ OBJCOPY_TRANSLATIONS = --no-change-warnings \ $(OBJDIR)/%.s19: $(OBJDIR)/%.elf $(OBJCOPY) -Osrec --srec-forceS3 --strip-debug $(OBJCOPY_TRANSLATIONS) $^ $@ -# version.c should be remade on every compilation -.PHONY: version.c -version.c: default_version.c - perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@ - # Automatic dependency generation DEPENDENCY_FILES = $(patsubst %.c,$(OBJDIR)/%.d,$(notdir $(THUMBSRC))) \ $(patsubst %.c,$(OBJDIR)/%.d,$(notdir $(ARMSRC))) \ diff --git a/common/Makefile_Enabled_Options.common b/common/Makefile_Enabled_Options.common new file mode 100644 index 00000000..8774946e --- /dev/null +++ b/common/Makefile_Enabled_Options.common @@ -0,0 +1,42 @@ +#NOTES: +# Do not put any comments inside the definition below (before the final flag) +# All definition lines except the last must end in a \ +# +#BEGIN +APP_CFLAGS += -DWITH_ISO14443a_StandAlone \ + -DWITH_LF\ + -DWITH_ISO15693 \ + -DWITH_ISO14443a \ + -DWITH_ISO14443b \ + -DWITH_ICLASS \ + -DWITH_LEGICRF \ + -DWITH_HITAG \ + -DWITH_CRC \ + -DWITH_HFSNOOP \ + -DWITH_GUI +#END + + +### Standalone modes: +#-DWITH_ISO14443a_StandAlone +#-DWITH_LF_StandAlone +# +# if both WITH_LF_StandAlone and WITH_ISO4443a_StandAlone are defined +# ISO14443a_StandAlone will be the only one that runs +# You must remove it and define WITH_LF_StandAlone for LF standalone mode + +### Other options: +#-DWITH_LF \ include LF support in build +#-DWITH_ISO15693 \ include ISO15693 support in build +#-DWITH_ISO14443a \ include ISO14443a support in build +#-DWITH_ISO14443b \ include ISO14443b support in build +#-DWITH_ICLASS \ include ICLASS support in build +#-DWITH_LEGICRF \ include LEGIC support in build +#-DWITH_HITAG \ include HITAG support in build +#-DWITH_CRC \ include CRC support in build +#-DWITH_HFSNOOP \ include HFSNOOP support in build +#-DWITH_SMARTCARD \ include SMARTCARD support in build +#-DWITH_GUI \ include QT GUI/Graph support in build +#-DWITH_LCD \ include LCD support in build (experimental?) + +#marshmellow NOTE: tested GUI, and SMARTCARD removal only... diff --git a/common/fpga.h b/common/fpga.h new file mode 100644 index 00000000..b99a7593 --- /dev/null +++ b/common/fpga.h @@ -0,0 +1,18 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +#ifndef __FPGA_H +#define __FPGA_H + +#define FPGA_BITSTREAM_FIXED_HEADER_SIZE sizeof(bitparse_fixed_header) +#define FPGA_INTERLEAVE_SIZE 288 +#define FPGA_CONFIG_SIZE 42336L // our current fpga_[lh]f.bit files are 42175 bytes. Rounded up to next multiple of FPGA_INTERLEAVE_SIZE + +static const uint8_t bitparse_fixed_header[] = {0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01}; +extern const int fpga_bitstream_num; +extern const char* const fpga_version_information[]; + +#endif diff --git a/common/iso15693tools.c b/common/iso15693tools.c index 26e636ca..f1214458 100644 --- a/common/iso15693tools.c +++ b/common/iso15693tools.c @@ -11,6 +11,12 @@ #include #include //#include "iso15693tools.h" +#ifdef ON_DEVICE +#include "printf.h" +#else +#include +#endif + #define POLY 0x8408 @@ -51,8 +57,6 @@ int Iso15693AddCrc(uint8_t *req, int n) { } -int sprintf(char *str, const char *format, ...); - // returns a string representation of the UID // UID is transmitted and stored LSB first, displayed MSB first // target char* buffer, where to put the UID, if NULL a static buffer is returned diff --git a/common/parity.h b/common/parity.h index 615fdeee..c574db55 100644 --- a/common/parity.h +++ b/common/parity.h @@ -13,6 +13,7 @@ #include #include +#include "string.h" extern const uint8_t OddByteParity[256]; @@ -21,6 +22,11 @@ static inline bool oddparity8(const uint8_t x) { return OddByteParity[x]; } +static inline void oddparitybuf(const uint8_t *x, size_t len, uint8_t *parity) { + memset(parity, 0x00, (len - 1) / 8 + 1); + for (int i = 0; i < len; i++) + parity[i / 8] |= oddparity8(x[i]) << (7 - (i % 8)); +} static inline bool evenparity8(const uint8_t x) { return !OddByteParity[x]; diff --git a/common/protocols.h b/common/protocols.h index 31252ad3..57e6011f 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -200,10 +200,11 @@ NXP/Philips CUSTOM COMMANDS #define TOPAZ_WRITE_NE8 0x1B // Write-no-erase (eight bytes) -#define ISO_14443A 0 -#define ICLASS 1 -#define ISO_14443B 2 -#define TOPAZ 3 +#define ISO_14443A 0 +#define ICLASS 1 +#define ISO_14443B 2 +#define TOPAZ 3 +#define PROTO_MIFARE 4 //-- Picopass fuses #define FUSE_FPERS 0x80 diff --git a/common/usb_cdc.c b/common/usb_cdc.c index 348b97e9..d33bca7b 100644 --- a/common/usb_cdc.c +++ b/common/usb_cdc.c @@ -183,10 +183,16 @@ static const char StrDescManufacturer[] = { }; static const char StrDescProduct[] = { - 8, // Length + 20, // Length 0x03, // Type is string - 'P', 0x00, - 'M', 0x00, + 'p', 0x00, + 'r', 0x00, + 'o', 0x00, + 'x', 0x00, + 'm', 0x00, + 'a', 0x00, + 'r', 0x00, + 'k', 0x00, '3', 0x00 }; diff --git a/driver/proxmark3.inf b/driver/proxmark3.inf index 122ebd55..52dbd251 100644 --- a/driver/proxmark3.inf +++ b/driver/proxmark3.inf @@ -3,16 +3,18 @@ Signature="$Windows NT$" Class=Ports ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} Provider=%ProviderName% -DriverVer=31/05/2017,1.1.0.0 +DriverVer=03/05/2018,1.1.1.0 [MANUFACTURER] %ProviderName%=DeviceList, NTx86, NTamd64 [DeviceList.NTx86] %DeviceName%=DriverInstall,USB\VID_9AC4&PID_4B8F +%DeviceName_old%=DriverInstall,USB\VID_2d2d&PID_504d [DeviceList.NTamd64] %DeviceName%=DriverInstall,USB\VID_9AC4&PID_4B8F +%DeviceName_old%=DriverInstall,USB\VID_2d2d&PID_504d [DriverInstall] include=mdmcpq.inf @@ -30,3 +32,4 @@ HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" [Strings] ProviderName = "proxmark.org" DeviceName = "Proxmark3" +DeviceName_old = "Proxmark3 (old)" diff --git a/include/proxmark3.h b/include/proxmark3.h index 4a59636e..6fb6624f 100644 --- a/include/proxmark3.h +++ b/include/proxmark3.h @@ -61,9 +61,6 @@ #define SPI_FPGA_MODE 0 #define SPI_LCD_MODE 1 -#define TRUE 1 -#define FALSE 0 - //#define PACKED __attribute__((__packed__)) #define LED_A_ON() HIGH(GPIO_LED_A) diff --git a/tools/mfkey/mfkey32.c b/tools/mfkey/mfkey32.c index a5665ab2..d84305d0 100755 --- a/tools/mfkey/mfkey32.c +++ b/tools/mfkey/mfkey32.c @@ -10,7 +10,7 @@ // 32 bit recover key from 2 nonces int main (int argc, char *argv[]) { - nonces_t data; + nonces_t data = {0}; uint32_t ks2; // keystream used to encrypt reader response uint64_t key; // recovered key diff --git a/uart/uart.h b/uart/uart.h index fe75a683..3b563be2 100644 --- a/uart/uart.h +++ b/uart/uart.h @@ -39,7 +39,15 @@ #include #include -typedef unsigned char byte_t; +/* Used to substitute for an example serial port path on each platform. + */ +#ifdef _WIN32 +#define SERIAL_PORT_H "com3" +#elif __APPLE__ +#define SERIAL_PORT_H "/dev/tty.usbmodem*" +#else +#define SERIAL_PORT_H "/dev/ttyACM0" +#endif /* serial_port is declared as a void*, which you should cast to whatever type * makes sense to your connection method. Both the posix and win32 @@ -78,13 +86,13 @@ void uart_close(const serial_port sp); * partial read may have completed into the buffer by the corresponding * implementation, so pszRxLen should be checked to see if any data was written. */ -bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen); +bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen); /* Sends a buffer to a given serial port. * pbtTx: A pointer to a buffer containing the data to send. * szTxLen: The amount of data to be sent. */ -bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen); +bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen); /* Sets the current speed of the serial port, in baud. */ diff --git a/uart/uart_posix.c b/uart/uart_posix.c index 45e0d3d2..0e7f7f47 100644 --- a/uart/uart_posix.c +++ b/uart/uart_posix.c @@ -133,7 +133,7 @@ void uart_close(const serial_port sp) { free(sp); } -bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen) { +bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen) { int res; int byteCount; fd_set rfds; @@ -192,7 +192,7 @@ bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t pszMaxRxLen, size_ return true; } -bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen) { +bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen) { int32_t res; size_t szPos = 0; fd_set rfds; diff --git a/uart/uart_win32.c b/uart/uart_win32.c index 121b2b51..b15e8786 100644 --- a/uart/uart_win32.c +++ b/uart/uart_win32.c @@ -107,11 +107,11 @@ void uart_close(const serial_port sp) { free(sp); } -bool uart_receive(const serial_port sp, byte_t *pbtRx, size_t pszMaxRxLen, size_t *pszRxLen) { +bool uart_receive(const serial_port sp, uint8_t *pbtRx, size_t pszMaxRxLen, size_t *pszRxLen) { return ReadFile(((serial_port_windows*)sp)->hPort, pbtRx, pszMaxRxLen, (LPDWORD)pszRxLen, NULL); } -bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen) { +bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen) { DWORD dwTxLen = 0; return WriteFile(((serial_port_windows*)sp)->hPort, pbtTx, szTxLen, &dwTxLen, NULL); }