diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 3b04ea5f8..940722506 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,6 +1,9 @@ --- name: Bug report about: Create a report to help us improve +title: '' +labels: '' +assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..ff12e62f1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[idea]" +labels: Request, enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/CHANGELOG.md b/CHANGELOG.md index 64377c383..a99c8c522 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,20 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Chg 'data autocorrelate' - better visual representation and added extra peak detection (@iceman) + - Fix 'lf search' - false positive indala identification fixed (@iceman) + - Add 'lf keri' - basic support for Keri tags (@iceman) + - Add 'hf mf list' - re-added it again (@iceman) + - Fix - A lot of bugfixes, like memory leaks (@iceman) + - Change 'hf 14a antifuzz' - original implementation (@asfabw), reworked a bit + - Fix 'hf mf fchk' (@iceman) + - Fix 'usb slow on posix based systems' (@fl0-0) + - Change 'lf pcf7931' - improved read code (@sguerrini97) + - Change 'hf felica list' - started with some FeliCa annotations (@iceman) + - Fix 'hf tune' - now works as expected (@iceman) + - Add 'option to use flash memory to upload dictionary files' (RDV40) (@iceman) + - Fix 'printing percentage now standard compliant' (@fabled) + - Add 'emv roca' - command to test for ROCA vuln in public RSA modulus (@merlokk / @iceman) - Added TCP ports support (on linux) (@phcoder) - Added HF sniff standalone mode with optional storing of ULC/NTAG/ULEV1 authentication attempts (@bogiton) - Fix 'Lining up plot and control window' (@anticat) @@ -88,6 +102,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf emv` `gpo`, `readrec`, `genac`, `challenge`, `intauth` - separate commands from `hf emc exec` (@merlokk) - Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (@merlokk) - Added trailer block decoding to `hf mf rdbl` and `hf mf cgetbl` (@merlokk) + - Added `hf mf mad` and `hf mfp mad` MAD decode, check and print commands (@merlokk) ### Fixed - Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi) diff --git a/README.md b/README.md index fdf02f0a2..c8c04f852 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,33 @@ Proxmark3 RDV40 dedicated repo, based on iceman fork ## Notice This repo is based on iceman fork for proxmark3. It is dedicated to bring the most out of the new features for proxmark3 RDV40 device. +# Donations +Nothing says thank you as much as a donation, https://www.patreon.com/iceman1001 + +## ToC + +- Coverity Scan Config & Run +- Whats changed? +- Why didn't you based it on offical PM3 Master? +- Why don't you add this or that functionality? +- PM3 GUI +- Development +- KALI and ARCHLINUX users +- Setup and build for UBUNTU +- Setup and build for ArchLinux +- Homebrew (Mac OS X) +- Upgrading HomeBrew tap formula +- Building on Windows +- Gator96100 distro +- Build and run +- Validating proxmark client functionality +- Run the following commands +- Quit client +- First things on your RDV40 +- Verify sim module firmware version + +- The end + ## Coverity Scan Config & Run Download the Coverity Scan Self-buld and install it. You will need to configure ARM-NON-EABI- Compiler for it to use: @@ -37,19 +64,29 @@ The separation from offical pm3 repo gives us very much freedom to create a firm Give us a hint, and we'll see if we can't merge in the stuff you have. ## PM3 GUI -The official PM3-GUI from Gaucho will not work. -The new universial GUI will work. +The official PM3-GUI from Gaucho will not work. +The new universial GUI will work. [Proxmark3 Univerisal GUI](https://github.com/burma69/PM3UniversalGUI) ## Development This fork now compiles just fine on - Windows/mingw environment with Qt5.6.1 & GCC 4.8 - - Ubuntu 1404, 1510, 1604 + - Ubuntu 1404, 1510, 1604, 1804 - Mac OS X / Homebrew + - ParrotOS + - WSL (Windows subsystem linux) on Windows 10 - Docker container ## KALI and ARCHLINUX users Kali and ArchLinux users usually must kill their modem manager in order for the proxmark3 to enumerate properly. - +```sh +sudo apt remove modemmanager +``` +or +```sh +systemctl stop ModemManager +systemctl disable ModemManager +``` + ## Setup and build for UBUNTU GC made updates to allow this to build easily on Ubuntu 14.04.2 LTS, 15.10 or 16.04 See https://github.com/Proxmark/proxmark3/wiki/Ubuntu%20Linux @@ -60,7 +97,7 @@ I have also added this script to the fork. https://github.com/RfidResearchGroup/proxmark3/blob/master/install.sh - Run -`sudo apt-get install p7zip git build-essential libreadline5 libreadline-dev libusb-0.1-4 libusb-dev libqt4-dev perl pkg-config wget libncurses5-dev gcc-arm-none-eabi libjansson-dev` +`sudo apt-get install p7zip git build-essential libreadline5 libreadline-dev libusb-0.1-4 libusb-dev libqt4-dev perl pkg-config wget libncurses5-dev gcc-arm-none-eabi` - Clone fork `git clone https://github.com/RfidResearchGroup/proxmark3.git` @@ -85,9 +122,12 @@ https://github.com/RfidResearchGroup/proxmark3/blob/master/install.sh ## Setup and build for ArchLinux - Run -`sudo pacman -Sy base-devel p7zip libusb readline ncurses libjansson-dev arm-none-eabi-newlib --needed` +`sudo pacman -Sy base-devel p7zip libusb readline ncurses arm-none-eabi-newlib --needed` `yaourt -S termcap` +- Remove modemmanager +`sudo apt remove modemmanager` + - Clone fork `git clone https://github.com/RfidResearchGroup/proxmark3.git` @@ -155,7 +195,7 @@ Links - https://github.com/Gator96100/ProxSpace/releases/tag/v2.2 (release v2.2 with gcc v5.3.0 arm-none-eabi-gcc v7.1.0) -### 7. Build and run +### Build and run - Clone fork `git clone https://github.com/RfidResearchGroup/proxmark3.git` @@ -177,5 +217,106 @@ Assuming you have Proxmark3 Windows drivers installed you can run the Proxmark s - Run the client `proxmark3.exe comX` -iceman at host iuse.se -July 2018, Sweden + +## Validating proxmark client functionality + +If all went well you should get some information about the firmware and memory usage as well as the prompt, something like this. + +>[=] UART Setting serial baudrate 460800 +> +>Proxmark3 RFID instrument +> +> [ CLIENT ] +> +> client: iceman build for RDV40 with flashmem; smartcard; +> +> [ ARM ] +> +> bootrom: iceman/master/4517531c-dirty-unclean 2018-12-13 15:42:24 +> +> os: iceman/master/5a34550a-dirty-unclean 2019-01-07 23:04:07 +> +> [ FPGA ] +> +> LF image built for 2s30vq100 on 2018/ 9/ 8 at 13:57:51 +> +> HF image built for 2s30vq100 on 2018/ 9/ 3 at 21:40:23 +> +> [ Hardware ] +> +>--= uC: AT91SAM7S512 Rev B +> +>--= Embedded Processor: ARM7TDMI +> +>--= Nonvolatile Program Memory Size: 512K bytes, Used: 247065 bytes (47%) Free: 277223 bytes (53%) +> +>--= Second Nonvolatile Program Memory Size: None +> +>--= Internal SRAM Size: 64K bytes +> +>--= Architecture Identifier: AT91SAM7Sxx Series +> +>--= Nonvolatile Program Memory Type: Embedded Flash Memory +> +> pm3 --> + +### Run the following commands + pm3 --> hw status + pm3 --> hw version + pm3 --> hw tune + +You are now ready to use your newly upgraded proxmark3 device. Many commands uses the **h** parameter to show a help text. The client uses a arcaic command structure which will be hard to grasp at first. Here are some commands to start off with. + + pm3 --> hf + pm3 --> hf 14a info + pm3 --> lf + pm3 --> lf search + +### Quit client + pm3 --> quit + + +### First things on your RDV40 +You will need to run these commands to make sure your rdv4 is prepared + + pm3 --> mem load f default_keys m + pm3 --> mem load f default_pwd t + pm3 --> mem load f default_iclass_keys i + pm3 --> lf t55xx deviceconfig a 29 b 17 c 15 d 47 e 15 p + +### Verify sim module firmware version +To make sure you got the latest sim module firmware. +_Lastest version is v3.10_ + + pm3 --> hw status + +Find version in the long output, look for these two lines + + #db# Smart card module (ISO 7816) + #db# version.................v2.06 + +This version is obselete. The following command upgrades your device sim module firmware. +Don't not turn of your device during the execution of this command. + + pm3 --> sc upgrade f ../tools/simmodule/SIM010.BIN + +You get the following output, this is a successful execution. + + [!] WARNING - Smartcard socket firmware upgrade. + [!] A dangerous command, do wrong and you will brick the smart card socket + [+] Smartcard socket firmware uploading to PM3 + .. + [+] Smartcard socket firmware updating, don't turn off your PM3! + #db# FW 0000 + #db# FW 0080 + #db# FW 0100 + #db# FW 0180 + #db# FW 0200 + #db# FW 0280 + [+] Smartcard socket firmware upgraded successful + + +## the end + +`iceman at host iuse.se` +`July 2018, Sweden` diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 8f6bf9ca6..7b49c0619 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -30,8 +30,8 @@ static uint16_t BigBuf_hi = BIGBUF_SIZE; static uint8_t *emulator_memory = NULL; // trace related variables -static uint16_t traceLen = 0; -int tracing = 1; //Last global one.. todo static? +static uint32_t traceLen = 0; +static bool tracing = true; //todo static? // get the address of BigBuf uint8_t *BigBuf_get_addr(void) { @@ -112,7 +112,7 @@ uint16_t BigBuf_max_traceLen(void) { void clear_trace(void) { traceLen = 0; } -void set_tracelen(uint16_t value) { +void set_tracelen(uint32_t value) { traceLen = value; } void set_tracing(bool enable) { @@ -127,7 +127,7 @@ bool get_tracing(void) { * Get the number of bytes traced * @return */ -uint16_t BigBuf_get_traceLen(void) { +uint32_t BigBuf_get_traceLen(void) { return traceLen; } @@ -142,8 +142,8 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ uint8_t *trace = BigBuf_get_addr(); - uint16_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity - uint16_t duration = timestamp_end - timestamp_start; + uint32_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity + uint32_t duration = timestamp_end - timestamp_start; // Return when trace is full if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= BigBuf_max_traceLen()) { @@ -204,7 +204,7 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP if (!tracing) return false; uint8_t *trace = BigBuf_get_addr(); - uint16_t iLen = nbytes(iBits); + uint32_t iLen = nbytes(iBits); // Return when trace is full if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) return false; diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index e8c6f5cd4..679eed676 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -36,10 +36,10 @@ extern uint8_t *BigBuf_malloc(uint16_t); extern void BigBuf_free(void); extern void BigBuf_free_keep_EM(void); extern void BigBuf_print_status(void); -extern uint16_t BigBuf_get_traceLen(void); +extern uint32_t BigBuf_get_traceLen(void); extern void clear_trace(void); extern void set_tracing(bool enable); -extern void set_tracelen(uint16_t value); +extern void set_tracelen(uint32_t value); extern bool get_tracing(void); extern bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); extern int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int bReader); diff --git a/armsrc/Makefile b/armsrc/Makefile index b69e724e0..efc443227 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -21,7 +21,7 @@ APP_CFLAGS = -DWITH_CRC \ -DWITH_ISO14443a \ -DWITH_ICLASS \ -DWITH_FELICA \ - -DWITH_FLASH \ + -DWITH_FLASH \ -DWITH_SMARTCARD \ -DWITH_FPC \ -DWITH_HFSNOOP \ @@ -122,8 +122,9 @@ APP_CFLAGS += $(ZLIB_CFLAGS) # zlib includes: APP_CFLAGS += -I../zlib -# stdint.h provided locally until GCC 4.5 becomes C99 compliant -APP_CFLAGS += -I. +# stdint.h provided locally until GCC 4.5 becomes C99 compliant, +# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc +APP_CFLAGS += -I. -fno-stack-protector -fno-pie # Compile these in thumb mode (small size) THUMBSRC = start.c \ @@ -190,7 +191,7 @@ $(OBJDIR)/fpga_all.bit.z: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR) $(FPGA_COMPRESSOR) $(filter %.bit,$^) $@ $(FPGA_COMPRESSOR): - make -C ../client $(notdir $(FPGA_COMPRESSOR)) + $(MAKE) -C ../client $(notdir $(FPGA_COMPRESSOR)) $(OBJDIR)/fullimage.stage1.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ) $(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS) diff --git a/armsrc/Standalone/hf_bog.c b/armsrc/Standalone/hf_bog.c index 9079d5df3..65254bd5c 100644 --- a/armsrc/Standalone/hf_bog.c +++ b/armsrc/Standalone/hf_bog.c @@ -271,6 +271,11 @@ void RAMFUNC SniffAndStore(uint8_t param) { uint16_t writelen = Flash_WriteData(0, total_data, memoffset + 4 * auth_attempts); if (MF_DBGLEVEL > 1) Dbprintf("[!] Wrote %u bytes into flash mem", writelen); + // If pwd saved successfully, blink led A three times + if (writelen > 0) { + SpinErr(0, 200, 5); // blink led A + } + SpinDelay(100); // Reset the SPI Baudrate to the default value (24MHz) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index eed443599..5002a7138 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -113,7 +113,7 @@ void print_result(char *name, uint8_t *buf, size_t len) { void DbpStringEx(char *str, uint32_t cmd) { #if DEBUG uint8_t len = strlen(str); - cmd_send(CMD_DEBUG_PRINT_STRING, len, cmd, 0, (byte_t*)str, len); + cmd_send(CMD_DEBUG_PRINT_STRING, len, cmd, 0, (uint8_t*)str, len); #endif } @@ -307,10 +307,10 @@ void MeasureAntennaTuningHf(void) { } else { volt = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; } - DbprintfEx(CMD_MEASURE_ANTENNA_TUNING_HF, "%u mV / %5u V", volt, (uint16_t)(volt/1000)); + DbprintfEx(FLAG_NONEWLINE, "%u mV / %5u V", volt, (uint16_t)(volt/1000)); } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("\n[+] cancelled"); + DbprintfEx(FLAG_NOOPT, "\n[+] cancelled", 1); } void ReadMem(int addr) { @@ -724,6 +724,9 @@ void UsbPacketReceived(uint8_t *packet, int len) { case CMD_T55XX_RESET_READ: T55xxResetRead(); break; + case CMD_T55XX_CHKPWDS: + T55xx_ChkPwds(); + break; case CMD_PCF7931_READ: ReadPCF7931(); break; @@ -1250,11 +1253,11 @@ void UsbPacketReceived(uint8_t *packet, int len) { size_t size = MIN(USB_CMD_DATA_SIZE, len); - uint8_t *mem = BigBuf_malloc(size); - - if (!FlashInit()) { + if (!FlashInit()) { break; } + + uint8_t *mem = BigBuf_malloc(size); for(size_t i = 0; i < len; i += size) { len = MIN((len - i), size); @@ -1268,6 +1271,7 @@ void UsbPacketReceived(uint8_t *packet, int len) { break; } } + BigBuf_free(); FlashStop(); LED_B_OFF(); break; @@ -1285,10 +1289,20 @@ void UsbPacketReceived(uint8_t *packet, int len) { if (!FlashInit()) { break; } - + Flash_CheckBusy(BUSY_TIMEOUT); Flash_WriteEnable(); + + if ( startidx == DEFAULT_T55XX_KEYS_OFFSET ) + Flash_Erase4k(3, 0xC); + else if (startidx == DEFAULT_MF_KEYS_OFFSET ) + Flash_Erase4k(3, 0xB); + else if (startidx == DEFAULT_ICLASS_KEYS_OFFSET) + Flash_Erase4k(3, 0xA); + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + // inside 256b page? if ( (tmp & 0xFF) != 0) { diff --git a/armsrc/apps.h b/armsrc/apps.h index 1e8524d57..d17d9ef4b 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -34,7 +34,6 @@ extern "C" { extern const uint8_t OddByteParity[256]; extern int rsamples; // = 0; -extern int tracing; // = TRUE; extern uint8_t trigger; // This may be used (sparingly) to declare a function to be copied to @@ -104,6 +103,8 @@ void T55xxWriteBlock(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t PwdMode void T55xxWriteBlockExt(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t PwdMode); void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd); void T55xxWakeUp(uint32_t Pwd); +void T55xx_ChkPwds(void); + void TurnReadLFOn(uint32_t delay); void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd); void EM4xWriteWord(uint32_t flag, uint32_t data, uint32_t pwd); diff --git a/armsrc/epa.c b/armsrc/epa.c index 68b2711da..e97fda7a0 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -108,7 +108,7 @@ int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response) switch(iso_type) { case 'a': - return iso14_apdu(apdu, (uint16_t) length, response, NULL); + return iso14_apdu(apdu, (uint16_t) length, false, response, NULL); break; case 'b': return iso14443b_apdu(apdu, length, response); diff --git a/armsrc/felica.c b/armsrc/felica.c index b25653d80..d1e7bc344 100644 --- a/armsrc/felica.c +++ b/armsrc/felica.c @@ -29,27 +29,25 @@ static uint32_t felica_timeout; static uint32_t felica_nexttransfertime; static uint32_t felica_lasttime_prox2air_start; -static void felica_setup(uint8_t fpga_minor_mode); +static void iso18092_setup(uint8_t fpga_minor_mode); static uint8_t felica_select_card(felica_card_select_t *card); static void TransmitFor18092_AsReader(uint8_t * frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed); bool WaitForFelicaReply(uint16_t maxbytes); -void felica_set_timeout(uint32_t timeout) { +void iso18092_set_timeout(uint32_t timeout) { felica_timeout = timeout + (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) + 2; } -uint32_t felica_get_timeout(void) { +uint32_t iso18092_get_timeout(void) { return felica_timeout - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) - 2; } -//random service RW: 0x0009 -//random service RO: 0x000B -#ifndef NFC_MAX_FRAME_SIZE - #define NFC_MAX_FRAME_SIZE 260 +#ifndef FELICA_MAX_FRAME_SIZE + #define FELICA_MAX_FRAME_SIZE 260 #endif //structure to hold outgoing NFC frame -static uint8_t frameSpace[NFC_MAX_FRAME_SIZE+4]; +static uint8_t frameSpace[FELICA_MAX_FRAME_SIZE+4]; //structure to hold incoming NFC frame, used for ISO/IEC 18092-compatible frames static struct { @@ -71,114 +69,114 @@ static struct { uint8_t *framebytes; //should be enough. maxlen is 255, 254 for data, 2 for sync, 2 for crc // 0,1 -> SYNC, 2 - len, 3-(len+1)->data, then crc -} NFCFrame; +} FelicaFrame; //b2 4d is SYNC, 45645 in 16-bit notation, 10110010 01001101 binary. Frame will not start filling until this is shifted in //bit order in byte -reverse, I guess? [((bt>>0)&1),((bt>>1)&1),((bt>>2)&1),((bt>>3)&1),((bt>>4)&1),((bt>>5)&1),((bt>>6)&1),((bt>>7)&1)] -at least in the mode that I read those in #ifndef SYNC_16BIT -# define SYNC_16BIT 0x4DB2 +# define SYNC_16BIT 0xB24D #endif -static void NFCFrameReset() { - NFCFrame.state = STATE_UNSYNCD; - NFCFrame.posCnt = 0; - NFCFrame.crc_ok = false; - NFCFrame.byte_offset = 0; +static void FelicaFrameReset() { + FelicaFrame.state = STATE_UNSYNCD; + FelicaFrame.posCnt = 0; + FelicaFrame.crc_ok = false; + FelicaFrame.byte_offset = 0; } -static void NFCInit(uint8_t *data) { - NFCFrame.framebytes = data; - NFCFrameReset(); +static void FelicaFrameinit(uint8_t *data) { + FelicaFrame.framebytes = data; + FelicaFrameReset(); } //shift byte into frame, reversing it at the same time static void shiftInByte(uint8_t bt) { uint8_t j; - for(j=0; j < NFCFrame.byte_offset; j++) { - NFCFrame.framebytes[NFCFrame.posCnt] = ( NFCFrame.framebytes[NFCFrame.posCnt]<<1 ) + (bt & 1); + for(j=0; j < FelicaFrame.byte_offset; j++) { + FelicaFrame.framebytes[FelicaFrame.posCnt] = ( FelicaFrame.framebytes[FelicaFrame.posCnt]<<1 ) + (bt & 1); bt >>= 1; } - NFCFrame.posCnt++; - NFCFrame.rem_len--; - for(j = NFCFrame.byte_offset; j<8; j++) { - NFCFrame.framebytes[NFCFrame.posCnt] = (NFCFrame.framebytes[NFCFrame.posCnt]<<1 ) + (bt & 1); + FelicaFrame.posCnt++; + FelicaFrame.rem_len--; + for(j = FelicaFrame.byte_offset; j<8; j++) { + FelicaFrame.framebytes[FelicaFrame.posCnt] = (FelicaFrame.framebytes[FelicaFrame.posCnt]<<1 ) + (bt & 1); bt >>= 1; } } -static void ProcessNFCByte(uint8_t bt) { - switch (NFCFrame.state) { +static void Process18092Byte(uint8_t bt) { + switch (FelicaFrame.state) { case STATE_UNSYNCD: { //almost any nonzero byte can be start of SYNC. SYNC should be preceded by zeros, but that is not alsways the case if (bt > 0) { - NFCFrame.shiftReg = reflect8(bt); - NFCFrame.state = STATE_TRYING_SYNC; + FelicaFrame.shiftReg = reflect8(bt); + FelicaFrame.state = STATE_TRYING_SYNC; } break; } case STATE_TRYING_SYNC: { if (bt == 0) { //desync - NFCFrame.shiftReg = bt; - NFCFrame.state = STATE_UNSYNCD; + FelicaFrame.shiftReg = bt; + FelicaFrame.state = STATE_UNSYNCD; } else { for (uint8_t i=0; i<8; i++) { - if (NFCFrame.shiftReg == SYNC_16BIT) { + if (FelicaFrame.shiftReg == SYNC_16BIT) { //SYNC done! - NFCFrame.state = STATE_GET_LENGTH; - NFCFrame.framebytes[0] = 0xb2; - NFCFrame.framebytes[1] = 0x4d; //write SYNC - NFCFrame.byte_offset = i; + FelicaFrame.state = STATE_GET_LENGTH; + FelicaFrame.framebytes[0] = 0xb2; + FelicaFrame.framebytes[1] = 0x4d; + FelicaFrame.byte_offset = i; //shift in remaining byte, slowly... for(uint8_t j=i; j<8; j++) { - NFCFrame.framebytes[2] = (NFCFrame.framebytes[2] << 1) + (bt & 1); + FelicaFrame.framebytes[2] = (FelicaFrame.framebytes[2] << 1) + (bt & 1); bt >>= 1; } - NFCFrame.posCnt = 2; + FelicaFrame.posCnt = 2; if (i==0) break; } - NFCFrame.shiftReg = (NFCFrame.shiftReg << 1) + (bt & 1); + FelicaFrame.shiftReg = (FelicaFrame.shiftReg << 1) + (bt & 1); bt >>= 1; } //that byte was last byte of sync - if (NFCFrame.shiftReg == SYNC_16BIT) { + if (FelicaFrame.shiftReg == SYNC_16BIT) { //Force SYNC on next byte - NFCFrame.state = STATE_GET_LENGTH; - NFCFrame.framebytes[0] = 0xb2; - NFCFrame.framebytes[1] = 0x4d; - NFCFrame.byte_offset = 0; - NFCFrame.posCnt = 1; + FelicaFrame.state = STATE_GET_LENGTH; + FelicaFrame.framebytes[0] = 0xb2; + FelicaFrame.framebytes[1] = 0x4d; + FelicaFrame.byte_offset = 0; + FelicaFrame.posCnt = 1; } } break; } case STATE_GET_LENGTH: { shiftInByte(bt); - NFCFrame.rem_len = NFCFrame.framebytes[2] - 1; - NFCFrame.len = NFCFrame.framebytes[2] + 4; //with crc and sync - NFCFrame.state = STATE_GET_DATA; + FelicaFrame.rem_len = FelicaFrame.framebytes[2] - 1; + FelicaFrame.len = FelicaFrame.framebytes[2] + 4; //with crc and sync + FelicaFrame.state = STATE_GET_DATA; break; } case STATE_GET_DATA: { shiftInByte(bt); - if (NFCFrame.rem_len <= 0) { - NFCFrame.state = STATE_GET_CRC; - NFCFrame.rem_len = 2; + if (FelicaFrame.rem_len <= 0) { + FelicaFrame.state = STATE_GET_CRC; + FelicaFrame.rem_len = 2; } break; } case STATE_GET_CRC: { shiftInByte(bt); - if ( NFCFrame.rem_len <= 0 ) { + if ( FelicaFrame.rem_len <= 0 ) { // skip sync 2bytes. IF ok, residue should be 0x0000 - NFCFrame.crc_ok = check_crc(CRC_FELICA, NFCFrame.framebytes+2, NFCFrame.len-2); - NFCFrame.state = STATE_FULL; - NFCFrame.rem_len = 0; - if (MF_DBGLEVEL > 3) Dbprintf("[+] got 2 crc bytes [%s]", (NFCFrame.crc_ok) ? "OK" : "No" ); + FelicaFrame.crc_ok = check_crc(CRC_FELICA, FelicaFrame.framebytes+2, FelicaFrame.len-2); + FelicaFrame.state = STATE_FULL; + FelicaFrame.rem_len = 0; + if (MF_DBGLEVEL > 3) Dbprintf("[+] got 2 crc bytes [%s]", (FelicaFrame.crc_ok) ? "OK" : "No" ); } break; } @@ -207,7 +205,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) { // b0 = fc/64 (212kbps) // 0x00 = timeslot // 0x09 0x21 = crc - static uint8_t poll[10] = {0xb2,0x4d,0x06,0x00,0xFF,0xFF,0x00,0x00,0x09,0x21}; + static uint8_t poll[10] = {0xb2,0x4d,0x06,FELICA_POLL_REQ,0xFF,0xFF,0x00,0x00,0x09,0x21}; int len = 20; @@ -219,7 +217,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) { TransmitFor18092_AsReader(poll, sizeof(poll), NULL, 1, 0); // polling card, break if success - if (WaitForFelicaReply(512) && NFCFrame.framebytes[3] == FELICA_POLL_ACK) + if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK) break; WDT_HIT(); @@ -231,19 +229,19 @@ static uint8_t felica_select_card(felica_card_select_t *card) { return 1; // wrong answer - if (NFCFrame.framebytes[3] != FELICA_POLL_ACK) + if (FelicaFrame.framebytes[3] != FELICA_POLL_ACK) return 2; // VALIDATE CRC residue is 0, hence if crc is a value it failed. - if (!check_crc(CRC_FELICA, NFCFrame.framebytes+2, NFCFrame.len-2)) + if (!check_crc(CRC_FELICA, FelicaFrame.framebytes+2, FelicaFrame.len-2)) return 3; // copy UID // idm 8 if (card) { - memcpy(card->IDm, NFCFrame.framebytes + 4, 8); - memcpy(card->PMm, NFCFrame.framebytes + 4 + 8, 8); - //memcpy(card->servicecode, NFCFrame.framebytes + 4 + 8 + 8, 2); + memcpy(card->IDm, FelicaFrame.framebytes + 4, 8); + memcpy(card->PMm, FelicaFrame.framebytes + 4 + 8, 8); + //memcpy(card->servicecode, FelicaFrame.framebytes + 4 + 8 + 8, 2); memcpy(card->code, card->IDm, 2); memcpy(card->uid, card->IDm + 2, 6); memcpy(card->iccode, card->PMm, 2); @@ -269,7 +267,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) { static void BuildFliteRdblk(uint8_t* idm, int blocknum, uint16_t *blocks ) { if (blocknum > 4 || blocknum <= 0) - Dbprintf("Invalid number of blocks, %d. Up to 4 are allowed.", blocknum); + Dbprintf("Invalid number of blocks, %d != 4", blocknum); uint8_t c = 0, i = 0; @@ -389,19 +387,19 @@ bool WaitForFelicaReply(uint16_t maxbytes) { // power, no modulation FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); - NFCFrameReset(); + FelicaFrameReset(); // clear RXRDY: uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - uint32_t timeout = felica_get_timeout(); + uint32_t timeout = iso18092_get_timeout(); for(;;) { WDT_HIT(); if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { b = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); - ProcessNFCByte(b); - if (NFCFrame.state == STATE_FULL) { + Process18092Byte(b); + if (FelicaFrame.state == STATE_FULL) { felica_nexttransfertime = MAX( felica_nexttransfertime, @@ -410,19 +408,19 @@ bool WaitForFelicaReply(uint16_t maxbytes) { ; LogTrace( - NFCFrame.framebytes, - NFCFrame.len, + FelicaFrame.framebytes, + FelicaFrame.len, ((GetCountSspClk() & 0xfffffff8)<<4) - DELAY_AIR2ARM_AS_READER - timeout, ((GetCountSspClk() & 0xfffffff8)<<4) - DELAY_AIR2ARM_AS_READER, NULL, false ); return true; - } else if (c++ > timeout && NFCFrame.state == STATE_UNSYNCD) { + } else if (c++ > timeout && FelicaFrame.state == STATE_UNSYNCD) { return false; - } else if (NFCFrame.state == STATE_GET_CRC) { + } else if (FelicaFrame.state == STATE_GET_CRC) { Dbprintf(" Frame: "); - Dbhexdump(16, NFCFrame.framebytes, 0); + Dbhexdump(16, FelicaFrame.framebytes, 0); //return false; } } @@ -432,7 +430,7 @@ bool WaitForFelicaReply(uint16_t maxbytes) { // Set up FeliCa communication (similar to iso14443a_setup) // field is setup for "Sending as Reader" -static void felica_setup(uint8_t fpga_minor_mode) { +static void iso18092_setup(uint8_t fpga_minor_mode) { LEDsoff(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -442,11 +440,13 @@ static void felica_setup(uint8_t fpga_minor_mode) { // Initialize Demod and Uart structs //DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); - NFCInit(BigBuf_malloc(NFC_MAX_FRAME_SIZE)); + FelicaFrameinit(BigBuf_malloc(FELICA_MAX_FRAME_SIZE)); felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER; - felica_set_timeout(2120); // 106 * 20ms maximum start-up time of card + iso18092_set_timeout(2120); // 106 * 20ms maximum start-up time of card + init_table(CRC_FELICA); + // connect Demodulated Signal to ADC: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -455,8 +455,6 @@ static void felica_setup(uint8_t fpga_minor_mode) { // LSB transfer. Remember to set it back to MSB with AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); - - init_table(CRC_FELICA); // Signal field is on with the appropriate LED FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | fpga_minor_mode); @@ -492,7 +490,7 @@ void felica_sendraw(UsbCommand *c) { set_tracing(true); if ((param & FELICA_CONNECT)) { - felica_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); + iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); // notify client selecting status. // if failed selecting, turn off antenna and quite. @@ -526,7 +524,7 @@ void felica_sendraw(UsbCommand *c) { TransmitFor18092_AsReader(buf, buf[2]+4, NULL, 1, 0); arg0 = !WaitForFelicaReply(1024); - cmd_send(CMD_ACK, arg0, 0, 0, NFCFrame.framebytes+2, NFCFrame.len-2); + cmd_send(CMD_ACK, arg0, 0, 0, FelicaFrame.framebytes+2, FelicaFrame.len-2); } if ((param & FELICA_NO_DISCONNECT)) @@ -547,7 +545,7 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) { Dbprintf("Snoop FelicaLiteS: Getting first %d frames, Skipping %d triggers.\n", samplesToSkip, triggersToSkip); - felica_setup( FPGA_HF_ISO18092_FLAG_NOMOD); + iso18092_setup( FPGA_HF_ISO18092_FLAG_NOMOD); //the frame bits are slow enough. int n = BigBuf_max_traceLen() / sizeof(uint8_t); // take all memory @@ -563,24 +561,24 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); - ProcessNFCByte(dist); + Process18092Byte(dist); //to be sure we are in frame - if (NFCFrame.state == STATE_GET_LENGTH) { + if (FelicaFrame.state == STATE_GET_LENGTH) { //length is after 48 (PRE)+16 (SYNC) - 64 ticks +maybe offset? not 100% - uint16_t distance = GetCountSspClk() - endframe - 64 + (NFCFrame.byte_offset > 0 ? (8-NFCFrame.byte_offset) : 0); + uint16_t distance = GetCountSspClk() - endframe - 64 + (FelicaFrame.byte_offset > 0 ? (8-FelicaFrame.byte_offset) : 0); *dest = distance >> 8; dest++; *dest = (distance & 0xff); dest++; } //crc NOT checked - if (NFCFrame.state == STATE_FULL) { + if (FelicaFrame.state == STATE_FULL) { endframe = GetCountSspClk(); - //*dest = NFCFrame.crc_ok; //kind of wasteful + //*dest = FelicaFrame.crc_ok; //kind of wasteful dest++; - for(int i=0; i < NFCFrame.len; i++) { - *dest = NFCFrame.framebytes[i]; + for(int i=0; i < FelicaFrame.len; i++) { + *dest = FelicaFrame.framebytes[i]; dest++; if (dest >= destend ) break; @@ -590,9 +588,9 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) { if (remFrames <= 0) break; if (dest >= destend ) break; - numbts += NFCFrame.len; + numbts += FelicaFrame.len; - NFCFrameReset(); + FelicaFrameReset(); } } } @@ -621,9 +619,9 @@ void felica_sim_lite(uint64_t nfcid) { num_to_bytes(nfcid, 8, ndef); //prepare our 3 responses... - uint8_t resp_poll0[R_POLL0_LEN] = { 0xb2,0x4d,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00,0xb3,0x7f}; - uint8_t resp_poll1[R_POLL1_LEN] = { 0xb2,0x4d,0x14,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00, 0x88,0xb4,0xb3,0x7f}; - uint8_t resp_readblk[R_READBLK_LEN] = { 0xb2,0x4d,0x1d,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x04,0x01,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x23,0xcb,0x6e}; + uint8_t resp_poll0[R_POLL0_LEN] = { 0xb2,0x4d,0x12,FELICA_POLL_ACK,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00,0xb3,0x7f}; + uint8_t resp_poll1[R_POLL1_LEN] = { 0xb2,0x4d,0x14,FELICA_POLL_ACK,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00, 0x88,0xb4,0xb3,0x7f}; + uint8_t resp_readblk[R_READBLK_LEN] = { 0xb2,0x4d,0x1d,FELICA_RDBLK_ACK,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x04,0x01,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x23,0xcb,0x6e}; //NFC tag 3/ ISo technically. Many overlapping standards DbpString("Felica Lite-S sim start"); @@ -643,7 +641,7 @@ void felica_sim_lite(uint64_t nfcid) { AddCrc(resp_poll1, resp_poll1[2]); AddCrc(resp_readblk, resp_readblk[2]); - felica_setup( FPGA_HF_ISO18092_FLAG_NOMOD); + iso18092_setup( FPGA_HF_ISO18092_FLAG_NOMOD); bool listenmode = true; //uint32_t frtm = GetCountSspClk(); @@ -657,28 +655,28 @@ void felica_sim_lite(uint64_t nfcid) { uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); //frtm = GetCountSspClk(); - ProcessNFCByte(dist); + Process18092Byte(dist); - if (NFCFrame.state == STATE_FULL) { + if (FelicaFrame.state == STATE_FULL) { - if (NFCFrame.crc_ok) { + if (FelicaFrame.crc_ok) { - if (NFCFrame.framebytes[2] == 6 && NFCFrame.framebytes[3] == 0) { + if (FelicaFrame.framebytes[2] == 6 && FelicaFrame.framebytes[3] == 0) { //polling... there are two types of polling we answer to - if (NFCFrame.framebytes[6] == 0) { + if (FelicaFrame.framebytes[6] == 0) { curresp = resp_poll0; curlen = R_POLL0_LEN; listenmode = false; } - if (NFCFrame.framebytes[6] == 1) { + if (FelicaFrame.framebytes[6] == 1) { curresp = resp_poll1; curlen = R_POLL1_LEN; listenmode = true; } } - if (NFCFrame.framebytes[2] > 5 && NFCFrame.framebytes[3] == 0x06) { + if (FelicaFrame.framebytes[2] > 5 && FelicaFrame.framebytes[3] == 0x06) { //we should rebuild it depending on page size, but... //Let's see first curresp = resp_readblk; @@ -686,10 +684,10 @@ void felica_sim_lite(uint64_t nfcid) { listenmode = false; } //clear frame - NFCFrameReset(); + FelicaFrameReset(); } else { //frame invalid, clear it out to allow for the next one - NFCFrameReset(); + FelicaFrameReset(); } } } @@ -703,7 +701,7 @@ void felica_sim_lite(uint64_t nfcid) { //switch back FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_NOMOD); - NFCFrameReset(); + FelicaFrameReset(); listenmode = true; curlen = 0; curresp = NULL; @@ -721,11 +719,11 @@ void felica_sim_lite(uint64_t nfcid) { void felica_dump_lite_s() { uint8_t ndef[8]; - uint8_t poll[10] = { 0xb2,0x4d,0x06,0x00,0xff,0xff,0x00,0x00,0x09,0x21}; - uint16_t liteblks[28] = {0x00, 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x90,0x91,0x92,0xa0}; + uint8_t poll[10] = { 0xb2,0x4d,0x06,FELICA_POLL_REQ,0xff,0xff,0x00,0x00,0x09,0x21}; + uint16_t liteblks[28] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x90,0x91,0x92,0xa0}; // setup device. - felica_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); + iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); uint8_t blknum; bool isOK = false; @@ -740,12 +738,12 @@ void felica_dump_lite_s() { //TransmitFor18092_AsReader(poll, 10, GetCountSspClk()+512, 1, 0); TransmitFor18092_AsReader(poll, 10, NULL, 1, 0); - if (WaitForFelicaReply(512) && NFCFrame.framebytes[3] == FELICA_POLL_ACK) { + if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK) { // copy 8bytes to ndef. - memcpy(ndef, NFCFrame.framebytes + 4, 8); + memcpy(ndef, FelicaFrame.framebytes + 4, 8); // for (c=0; c < 8; c++) - // ndef[c] = NFCFrame.framebytes[c+4]; + // ndef[c] = FelicaFrame.framebytes[c+4]; for (blknum=0; blknum < sizeof(liteblks); ) { @@ -756,15 +754,15 @@ void felica_dump_lite_s() { TransmitFor18092_AsReader(frameSpace, frameSpace[2]+4, NULL, 1, 0); // read block - if (WaitForFelicaReply(1024) && NFCFrame.framebytes[3] == FELICA_RDBLK_ACK) { + if (WaitForFelicaReply(1024) && FelicaFrame.framebytes[3] == FELICA_RDBLK_ACK) { dest[cnt++] = liteblks[blknum]; - uint8_t *fb = NFCFrame.framebytes; + uint8_t *fb = FelicaFrame.framebytes; dest[cnt++] = fb[12]; dest[cnt++] = fb[13]; - //memcpy(dest+cnt, NFCFrame.framebytes + 15, 16); + //memcpy(dest+cnt, FelicaFrame.framebytes + 15, 16); //cnt += 16; for(uint8_t j=0; j < 16; j++) dest[cnt++] = fb[15+j]; @@ -773,8 +771,8 @@ void felica_dump_lite_s() { cntfails = 0; // // print raw log. - // Dbprintf("LEN %u | Dump bytes count %u ", NFCFrame.len, cnt); - Dbhexdump(NFCFrame.len, NFCFrame.framebytes+15, 0); + // Dbprintf("LEN %u | Dump bytes count %u ", FelicaFrame.len, cnt); + Dbhexdump(FelicaFrame.len, FelicaFrame.framebytes+15, 0); } else { cntfails++; if (cntfails > 12) { diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 20225f416..4267d28af 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -14,7 +14,10 @@ #define MAX_ISO14A_TIMEOUT 524288 static uint32_t iso14a_timeout; +uint8_t colpos = 0; int rsamples = 0; +//int ReqCount; +//char CollisionIndicators[10*8]; uint8_t trigger = 0; // the block number for the ISO14443-4 PCB @@ -103,6 +106,8 @@ static uint32_t LastProxToAirDuration; // Sequence D: 11110000 modulation with subcarrier during first half // Sequence E: 00001111 modulation with subcarrier during second half // Sequence F: 00000000 no modulation with subcarrier +// Sequence COLL: 11111111 load modulation over the full bitlenght. +// Tricks the reader to think that multiple cards answer (at least one card with 1 and at least one card with 0). // READER TO CARD - miller // Sequence X: 00001100 drop after half a period // Sequence Y: 00000000 no drop @@ -110,6 +115,7 @@ static uint32_t LastProxToAirDuration; #define SEC_D 0xf0 #define SEC_E 0x0f #define SEC_F 0x00 +#define SEC_COLL 0xff #define SEC_X 0x0c #define SEC_Y 0x00 #define SEC_Z 0xc0 @@ -643,7 +649,9 @@ void RAMFUNC SniffIso14443a(uint8_t param) { //----------------------------------------------------------------------------- // Prepare tag messages //----------------------------------------------------------------------------- -static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *parity) { +static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *parity, bool collision) { + + //uint8_t localCol = 0; ToSendReset(); // Correction bit, might be removed when not needed @@ -651,7 +659,7 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par ToSendStuffBit(0); ToSendStuffBit(0); ToSendStuffBit(0); - ToSendStuffBit(1); // 1 + ToSendStuffBit(1); // <----- ToSendStuffBit(0); ToSendStuffBit(0); ToSendStuffBit(0); @@ -665,21 +673,32 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par // Data bits for(uint16_t j = 0; j < 8; j++) { - if(b & 1) { - ToSend[++ToSendMax] = SEC_D; - } else { - ToSend[++ToSendMax] = SEC_E; + //if (collision && (localCol >= colpos)){ + if (collision) { + ToSend[++ToSendMax] = SEC_COLL; + //localCol++; + } else { + if (b & 1) { + ToSend[++ToSendMax] = SEC_D; + } else { + ToSend[++ToSendMax] = SEC_E; + } + b >>= 1; } - b >>= 1; } - // Get the parity bit - if (parity[i>>3] & (0x80>>(i&0x0007))) { - ToSend[++ToSendMax] = SEC_D; - LastProxToAirDuration = 8 * ToSendMax - 4; + if (collision) { + ToSend[++ToSendMax] = SEC_COLL; + LastProxToAirDuration = 8 * ToSendMax; } else { - ToSend[++ToSendMax] = SEC_E; - LastProxToAirDuration = 8 * ToSendMax; + // Get the parity bit + if (parity[i>>3] & (0x80>>(i&0x0007))) { + ToSend[++ToSendMax] = SEC_D; + LastProxToAirDuration = 8 * ToSendMax - 4; + } else { + ToSend[++ToSendMax] = SEC_E; + LastProxToAirDuration = 8 * ToSendMax; + } } } @@ -690,10 +709,13 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par ToSendMax++; } -static void CodeIso14443aAsTag(const uint8_t *cmd, uint16_t len) { +static void CodeIso14443aAsTagEx(const uint8_t *cmd, uint16_t len, bool collision) { uint8_t par[MAX_PARITY_SIZE] = {0}; GetParity(cmd, len, par); - CodeIso14443aAsTagPar(cmd, len, par); + CodeIso14443aAsTagPar(cmd, len, par, collision); +} +static void CodeIso14443aAsTag(const uint8_t *cmd, uint16_t len) { + CodeIso14443aAsTagEx(cmd, len, false); } static void Code4bitAnswerAsTag(uint8_t cmd) { @@ -781,12 +803,12 @@ bool prepare_tag_modulation(tag_response_info_t* response_info, size_t max_buffe // Make sure we do not exceed the free buffer space if (ToSendMax > max_buffer_size) { Dbprintf("Out of memory, when modulating bits for tag answer:"); - Dbhexdump(response_info->response_n,response_info->response,false); + Dbhexdump(response_info->response_n, response_info->response, false); return false; } // Copy the byte array, used for this modulation to the buffer position - memcpy(response_info->modulation,ToSend,ToSendMax); + memcpy(response_info->modulation, ToSend, ToSendMax); // Store the number of bytes that were used for encoding/modulation and the time needed to transfer them response_info->modulation_n = ToSendMax; @@ -1033,7 +1055,7 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t* data) { // Clean receive command buffer if (!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) { - Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); + Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen()); break; } p_response = NULL; @@ -1680,9 +1702,11 @@ int EmSend4bit(uint8_t resp){ par); return res; } - -int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){ - CodeIso14443aAsTagPar(resp, respLen, par); +int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par) { + return EmSendCmdParEx(resp, respLen, par, false); +} +int EmSendCmdParEx(uint8_t *resp, uint16_t respLen, uint8_t *par, bool collision){ + CodeIso14443aAsTagPar(resp, respLen, par, collision); int res = EmSendCmd14443aRaw(ToSend, ToSendMax); // do the tracing for the previous reader request and this tag answer: EmLogTrace(Uart.output, @@ -1697,11 +1721,13 @@ int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){ par); return res; } - int EmSendCmd(uint8_t *resp, uint16_t respLen){ + return EmSendCmdEx(resp, respLen, false); +} +int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool collision){ uint8_t par[MAX_PARITY_SIZE] = {0x00}; GetParity(resp, respLen, par); - return EmSendCmdPar(resp, respLen, par); + return EmSendCmdParEx(resp, respLen, par, collision); } bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity, @@ -1805,44 +1831,22 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) { // by fooling the reader there is a collision and forceing the reader to // increase the uid bytes. The might be an overflow, DoS will occure. void iso14443a_antifuzz(uint32_t flags){ - /* - uint8_t uidlen = 4+1+1+2; - if (( flags & 2 ) == 2 ) - uidlen = 7+1+1+2; - if (( flags & 4 ) == 4 ) - uidlen = 10+1+1+2; - - uint8_t *uid = BigBuf_malloc(uidlen); - - // The first response contains the ATQA (note: bytes are transmitted in reverse order). - // Mifare Classic 1K - uint8_t atqa[] = {0x04, 0}; - - if ( (flags & 2) == 2 ) { - uid[0] = 0x88; // Cascade Tag marker - uid[1] = 0x01; - - // Configure the ATQA accordingly - atqa[0] |= 0x40; - } else { - memcpy(response2, data, 4); - // Configure the ATQA accordingly - atqa[0] &= 0xBF; - } // We need to listen to the high-frequency, peak-detected path. iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); + BigBuf_free_keep_EM(); + clear_trace(); + set_tracing(true); + + int len = 0; + // allocate buffers: uint8_t *received = BigBuf_malloc(MAX_FRAME_SIZE); uint8_t *receivedPar = BigBuf_malloc(MAX_PARITY_SIZE); - uint16_t counter = 0; - - int len = 0; - - BigBuf_free(); - clear_trace(); - set_tracing(true); + uint8_t *resp = BigBuf_malloc(20); + + memset(resp, 0xFF , 20); LED_A_ON(); for (;;) { @@ -1850,50 +1854,53 @@ void iso14443a_antifuzz(uint32_t flags){ // Clean receive command buffer if (!GetIso14443aCommandFromReader(received, receivedPar, &len)) { - Dbprintf("Anti-fuzz stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); + Dbprintf("Anti-fuzz stopped. Trace length: %d ", BigBuf_get_traceLen()); break; } - p_response = NULL; + if ( received[0] == ISO14443A_CMD_WUPA || received[0] == ISO14443A_CMD_REQA) { + resp[0] = 0x04; + resp[1] = 0x00; + + if ( (flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA ) { + resp[0] = 0x44; + } + + EmSendCmd(resp, 2); + continue; + } - // look at the command now. - if (received[0] == ISO14443A_CMD_REQA) { // Received a REQUEST - p_response = &responses[0]; - } else if (received[0] == ISO14443A_CMD_WUPA) { // Received a WAKEUP - p_response = &responses[0]; - } else if (received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { // Received request for UID (cascade 1) - p_response = &responses[1]; - } else if (received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received request for UID (cascade 2) - p_response = &responses[2]; - } else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { // Received a SELECT (cascade 1) - p_response = &responses[3]; - } else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received a SELECT (cascade 2) - p_response = &responses[4]; - } - if (p_response != NULL) { + // Received request for UID (cascade 1) + //if (received[1] >= 0x20 && received[1] <= 0x57 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { + if (received[1] >= 0x20 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { + resp[0] = 0xFF; + resp[1] = 0xFF; + resp[2] = 0xFF; + resp[3] = 0xFF; + resp[4] = resp[0] ^ resp[1] ^ resp[2] ^ resp[3]; + colpos = 0; - EmSendCmd14443aRaw(p_response->modulation, p_response->modulation_n); - // do the tracing for the previous reader request and this tag answer: - uint8_t par[MAX_PARITY_SIZE] = {0x00}; - GetParity(p_response->response, p_response->response_n, par); + if ( (flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA ) { + resp[0] = 0x88; + colpos = 8; + } + + EmSendCmdEx(resp, 5, true); + if (MF_DBGLEVEL >= 4) Dbprintf("ANTICOLL or SELECT %x", received[1]); + LED_D_INV(); - EmLogTrace(Uart.output, - Uart.len, - Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, - Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, - Uart.parity, - p_response->response, - p_response->response_n, - LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, - (LastTimeProxToAirStart + p_response->ProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, - par); + continue; + } else if (received[1] == 0x20 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received request for UID (cascade 2) + if (MF_DBGLEVEL >= 4) Dbprintf("ANTICOLL or SELECT_2"); + } else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { // Received a SELECT (cascade 1) + } else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received a SELECT (cascade 2) + } else { + Dbprintf("unknown command %x", received[0]); } - counter++; } cmd_send(CMD_ACK,1,0,0,0,0); - switch_off(); - Dbprintf("-[ UID until no response [%d]", counter); -*/ + switch_off(); + BigBuf_free_keep_EM(); } static void iso14a_set_ATS_times(uint8_t *ats) { @@ -2212,13 +2219,16 @@ b8 b7 b6 b5 b4 b3 b2 b1 b5,b6 = 00 - DESELECT 11 - WTX */ -int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res) { +int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res) { uint8_t parity[MAX_PARITY_SIZE] = {0x00}; uint8_t real_cmd[cmd_len + 4]; if (cmd_len) { // ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02 real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00) + if (send_chaining) { + real_cmd[0] |= 0x10; + } // put block number into the PCB real_cmd[0] |= iso14_pcb_blocknum; memcpy(real_cmd + 1, cmd, cmd_len); @@ -2238,7 +2248,7 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res) { return 0; //DATA LINK ERROR } else{ // S-Block WTX - while((data_bytes[0] & 0xF2) == 0xF2) { + while(len && ((data_bytes[0] & 0xF2) == 0xF2)) { uint32_t save_iso14a_timeout = iso14a_get_timeout(); // temporarily increase timeout iso14a_set_timeout( MAX((data_bytes[1] & 0x3f) * save_iso14a_timeout, MAX_ISO14A_TIMEOUT) ); @@ -2256,32 +2266,34 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res) { iso14a_set_timeout(save_iso14a_timeout); } - // if we received an I- or R(ACK)-Block with a block number equal to the - // current block number, toggle the current block number + // if we received an I- or R(ACK)-Block with a block number equal to the + // current block number, toggle the current block number if (len >= 3 // PCB+CRC = 3 bytes && ((data_bytes[0] & 0xC0) == 0 // I-Block || (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 && (data_bytes[0] & 0x01) == iso14_pcb_blocknum) // equal block numbers - { - iso14_pcb_blocknum ^= 1; - } + { + iso14_pcb_blocknum ^= 1; + } // if we received I-block with chaining we need to send ACK and receive another block of data if (res) *res = data_bytes[0]; // crc check - if (len >=3 && !check_crc(CRC_14443_A, data_bytes, len)) { + if (len >= 3 && !check_crc(CRC_14443_A, data_bytes, len)) { return -1; } } - // cut frame byte - len -= 1; - // memmove(data_bytes, data_bytes + 1, len); - for (int i = 0; i < len; i++) - data_bytes[i] = data_bytes[i + 1]; + if (len) { + // cut frame byte + len -= 1; + // memmove(data_bytes, data_bytes + 1, len); + for (int i = 0; i < len; i++) + data_bytes[i] = data_bytes[i + 1]; + } return len; } @@ -2331,7 +2343,7 @@ void ReaderIso14443a(UsbCommand *c) { if ((param & ISO14A_APDU)) { uint8_t res; - arg0 = iso14_apdu(cmd, len, buf, &res); + arg0 = iso14_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, &res); cmd_send(CMD_ACK, arg0, res, 0, buf, sizeof(buf)); } @@ -3495,7 +3507,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } if (MF_DBGLEVEL >= 1) - Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); + Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen()); cmd_send(CMD_ACK,1,0,0,0,0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index ff34fa577..a23b5d7c2 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -114,7 +114,7 @@ extern void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32 extern int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par); extern void iso14443a_setup(uint8_t fpga_minor_mode); -extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res); +extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res); extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats); extern int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades); extern void iso14a_set_trigger(bool enable); @@ -122,8 +122,10 @@ extern void iso14a_set_trigger(bool enable); extern int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen); extern int EmSend4bit(uint8_t resp); extern int EmSendCmd(uint8_t *resp, uint16_t respLen); +extern int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool collision); extern int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity); extern int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par); +extern int EmSendCmdParEx(uint8_t *resp, uint16_t respLen, uint8_t *par, bool collision); extern int EmSendPrecompiledCmd(tag_response_info_t *response_info); bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity, diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index edf114134..6167ca785 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -710,7 +710,7 @@ void SimulateIso14443bTag(uint32_t pupi) { ++cmdsReceived; } if (MF_DBGLEVEL >= 2) - Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); + Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen()); switch_off(); //simulate } diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 00d284926..958d3421a 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -61,7 +61,7 @@ static inline uint8_t rx_byte_from_fpga() { WDT_HIT(); // wait for byte be become available in rx holding register - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { return AT91C_BASE_SSC->SSC_RHR; } } @@ -81,7 +81,7 @@ static inline uint8_t rx_byte_from_fpga() { // To reduce CPU time the amplitude is approximated by using linear functions: // am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq)) // -// Note: The SSC receiver is never synchronized the calculation my be performed +// Note: The SSC receiver is never synchronized the calculation may be performed // on a i/q pair from two subsequent correlations, but does not matter. static inline int32_t sample_power() { int32_t q = (int8_t)rx_byte_from_fpga(); q = ABS(q); @@ -100,7 +100,7 @@ static inline int32_t sample_power() { static inline bool rx_bit() { int32_t power; - for(size_t i = 0; i<5; ++i) { + for (size_t i = 0; i<5; ++i) { power = sample_power(); } @@ -120,12 +120,12 @@ static inline void tx_bit(bool bit) { // insert pause LOW(GPIO_SSC_DOUT); last_frame_end += RWD_TIME_PAUSE; - while(GET_TICKS < last_frame_end) { }; + while (GET_TICKS < last_frame_end) { }; HIGH(GPIO_SSC_DOUT); // return to high, wait for bit periode to end last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE; - while(GET_TICKS < last_frame_end) { }; + while (GET_TICKS < last_frame_end) { }; } //----------------------------------------------------------------------------- @@ -143,13 +143,13 @@ static void tx_frame(uint32_t frame, uint8_t len) { // wait for next tx timeslot last_frame_end += RWD_FRAME_WAIT; - while(GET_TICKS < last_frame_end) { }; + while (GET_TICKS < last_frame_end) { }; // backup ts for trace log uint32_t last_frame_start = last_frame_end; // transmit frame, MSB first - for(uint8_t i = 0; i < len; ++i) { + for (uint8_t i = 0; i < len; ++i) { bool bit = (frame >> i) & 0x01; tx_bit(bit ^ legic_prng_get_bit()); legic_prng_forward(1); @@ -158,7 +158,7 @@ static void tx_frame(uint32_t frame, uint8_t len) { // add pause to mark end of the frame LOW(GPIO_SSC_DOUT); last_frame_end += RWD_TIME_PAUSE; - while(GET_TICKS < last_frame_end) { }; + while (GET_TICKS < last_frame_end) { }; HIGH(GPIO_SSC_DOUT); // log @@ -173,19 +173,19 @@ static uint32_t rx_frame(uint8_t len) { // hold sampling until card is expected to respond last_frame_end += TAG_FRAME_WAIT; - while(GET_TICKS < last_frame_end) { }; + while (GET_TICKS < last_frame_end) { }; // backup ts for trace log uint32_t last_frame_start = last_frame_end; uint32_t frame = 0; - for(uint8_t i = 0; i < len; ++i) { + for (uint8_t i = 0; i < len; ++i) { frame |= (rx_bit() ^ legic_prng_get_bit()) << i; legic_prng_forward(1); // rx_bit runs only 95us, resync to TAG_BIT_PERIOD last_frame_end += TAG_BIT_PERIOD; - while(GET_TICKS < last_frame_end) { }; + while (GET_TICKS < last_frame_end) { }; } // log @@ -203,23 +203,23 @@ static bool rx_ack() { // hold sampling until card is expected to respond last_frame_end += TAG_FRAME_WAIT; - while(GET_TICKS < last_frame_end) { }; + while (GET_TICKS < last_frame_end) { }; // backup ts for trace log uint32_t last_frame_start = last_frame_end; uint32_t ack = 0; - for(uint8_t i = 0; i < TAG_WRITE_TIMEOUT; ++i) { + for (uint8_t i = 0; i < TAG_WRITE_TIMEOUT; ++i) { // sample bit ack = rx_bit(); legic_prng_forward(1); // rx_bit runs only 95us, resync to TAG_BIT_PERIOD last_frame_end += TAG_BIT_PERIOD; - while(GET_TICKS < last_frame_end) { }; + while (GET_TICKS < last_frame_end) { }; // check if it was an ACK - if(ack) { + if (ack) { break; } } @@ -282,7 +282,7 @@ static void init_reader(bool clear_mem) { // reserve a cardmem, meaning we can use the tracelog function in bigbuff easier. legic_mem = BigBuf_get_EM_addr(); - if(legic_mem) { + if (legic_mem) { memset(legic_mem, 0x00, LEGIC_CARD_MEMSIZE); } @@ -309,7 +309,7 @@ static uint32_t setup_phase(uint8_t iv) { // Switch on carrier and let the card charge for 5ms. last_frame_end += 7500; - while(GET_TICKS < last_frame_end) { }; + while (GET_TICKS < last_frame_end) { }; legic_prng_init(0); tx_frame(iv, 7); @@ -359,7 +359,7 @@ static int16_t read_byte(uint16_t index, uint8_t cmd_sz) { // check received against calculated crc uint8_t calc_crc = calc_crc4(cmd, cmd_sz, byte); - if(calc_crc != crc) { + if (calc_crc != crc) { Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc); return -1; } @@ -399,15 +399,15 @@ void LegicRfInfo(void) { // establish shared secret and detect card type uint8_t card_type = setup_phase(0x01); - if(init_card(card_type, &card) != 0) { + if (init_card(card_type, &card) != 0) { cmd_send(CMD_ACK, 0, 0, 0, 0, 0); goto OUT; } // read UID - for(uint8_t i = 0; i < sizeof(card.uid); ++i) { + for (uint8_t i = 0; i < sizeof(card.uid); ++i) { int16_t byte = read_byte(i, card.cmdsize); - if(byte == -1) { + if (byte == -1) { cmd_send(CMD_ACK, 0, 0, 0, 0, 0); goto OUT; } @@ -417,7 +417,7 @@ void LegicRfInfo(void) { // read MCC and check against UID int16_t mcc = read_byte(4, card.cmdsize); int16_t calc_mcc = CRC8Legic(card.uid, 4);; - if(mcc != calc_mcc) { + if (mcc != calc_mcc) { cmd_send(CMD_ACK, 0, 0, 0, 0, 0); goto OUT; } @@ -436,19 +436,19 @@ void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) { // establish shared secret and detect card type uint8_t card_type = setup_phase(iv); - if(init_card(card_type, &card) != 0) { + if (init_card(card_type, &card) != 0) { cmd_send(CMD_ACK, 0, 0, 0, 0, 0); goto OUT; } // do not read beyond card memory - if(len + offset > card.cardsize) { + if (len + offset > card.cardsize) { len = card.cardsize - offset; } - for(uint16_t i = 0; i < len; ++i) { + for (uint16_t i = 0; i < len; ++i) { int16_t byte = read_byte(offset + i, card.cmdsize); - if(byte == -1) { + if (byte == -1) { cmd_send(CMD_ACK, 0, 0, 0, 0, 0); goto OUT; } @@ -468,26 +468,26 @@ void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) { init_reader(false); // uid is not writeable - if(offset <= WRITE_LOWERLIMIT) { + if (offset <= WRITE_LOWERLIMIT) { cmd_send(CMD_ACK, 0, 0, 0, 0, 0); goto OUT; } // establish shared secret and detect card type uint8_t card_type = setup_phase(iv); - if(init_card(card_type, &card) != 0) { + if (init_card(card_type, &card) != 0) { cmd_send(CMD_ACK, 0, 0, 0, 0, 0); goto OUT; } // do not write beyond card memory - if(len + offset > card.cardsize) { + if (len + offset > card.cardsize) { len = card.cardsize - offset; } // write in reverse order, only then is DCF (decremental field) writable - while(len-- > 0 && !BUTTON_PRESS()) { - if(!write_byte(len + offset, data[len], card.addrsize)) { + while (len-- > 0 && !BUTTON_PRESS()) { + if (!write_byte(len + offset, data[len], card.addrsize)) { Dbprintf("operation failed | %02X | %02X | %02X", len + offset, len, data[len]); cmd_send(CMD_ACK, 0, 0, 0, 0, 0); goto OUT; diff --git a/armsrc/legicrfsim.c b/armsrc/legicrfsim.c index 1816a29ca..86448275f 100644 --- a/armsrc/legicrfsim.c +++ b/armsrc/legicrfsim.c @@ -46,7 +46,7 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */ #define RWD_TIME_PAUSE 4 /* 18.9us */ #define RWD_TIME_1 21 /* RWD_TIME_PAUSE 18.9us off + 80.2us on = 99.1us */ #define RWD_TIME_0 13 /* RWD_TIME_PAUSE 18.9us off + 42.4us on = 61.3us */ -#define RWD_CMD_TIMEOUT 40 /* 40 * 99.1us (arbitrary value) */ +#define RWD_CMD_TIMEOUT 120 /* 120 * 99.1us (arbitrary value) */ #define RWD_MIN_FRAME_LEN 6 /* Shortest frame is 6 bits */ #define RWD_MAX_FRAME_LEN 23 /* Longest frame is 23 bits */ @@ -59,8 +59,8 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */ // Returns true if a pulse/pause is received within timeout static inline bool wait_for(bool value, const uint32_t timeout) { - while((bool)(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN) != value) { - if(GetCountSspClk() > timeout) { + while ((bool)(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN) != value) { + if (GetCountSspClk() > timeout) { return false; } } @@ -81,12 +81,12 @@ static inline int8_t rx_bit() { uint32_t bit_start = last_frame_end; // wait for pause to end - if(!wait_for(RWD_PULSE, bit_start + RWD_TIME_1*3/2)) { + if (!wait_for(RWD_PULSE, bit_start + RWD_TIME_1*3/2)) { return -1; } // wait for next pause - if(!wait_for(RWD_PAUSE, bit_start + RWD_TIME_1*3/2)) { + if (!wait_for(RWD_PAUSE, bit_start + RWD_TIME_1*3/2)) { return -1; } @@ -94,7 +94,7 @@ static inline int8_t rx_bit() { last_frame_end = GetCountSspClk(); // check for code violation (bit to short) - if(last_frame_end - bit_start < RWD_TIME_PAUSE) { + if (last_frame_end - bit_start < RWD_TIME_PAUSE) { return -1; } @@ -122,7 +122,7 @@ static inline int8_t rx_bit() { static inline void tx_bit(bool bit) { LED_C_ON(); - if(bit) { + if (bit) { // modulate subcarrier HIGH(GPIO_SSC_DOUT); } else { @@ -132,7 +132,7 @@ static inline void tx_bit(bool bit) { // wait for tx timeslot to end last_frame_end += TAG_BIT_PERIOD; - while(GetCountSspClk() < last_frame_end) { }; + while (GetCountSspClk() < last_frame_end) { }; LED_C_OFF(); } @@ -150,13 +150,13 @@ static void tx_frame(uint32_t frame, uint8_t len) { // wait for next tx timeslot last_frame_end += TAG_FRAME_WAIT; legic_prng_forward(TAG_FRAME_WAIT/TAG_BIT_PERIOD - 1); - while(GetCountSspClk() < last_frame_end) { }; + while (GetCountSspClk() < last_frame_end) { }; // backup ts for trace log uint32_t last_frame_start = last_frame_end; // transmit frame, MSB first - for(uint8_t i = 0; i < len; ++i) { + for (uint8_t i = 0; i < len; ++i) { bool bit = (frame >> i) & 0x01; tx_bit(bit ^ legic_prng_get_bit()); legic_prng_forward(1); @@ -174,7 +174,7 @@ static void tx_ack() { // wait for ack timeslot last_frame_end += TAG_ACK_WAIT; legic_prng_forward(TAG_ACK_WAIT/TAG_BIT_PERIOD - 1); - while(GetCountSspClk() < last_frame_end) { }; + while (GetCountSspClk() < last_frame_end) { }; // backup ts for trace log uint32_t last_frame_start = last_frame_end; @@ -206,19 +206,19 @@ static int32_t rx_frame(uint8_t *len) { last_frame_end -= 2; // wait for first pause (start of frame) - for(uint8_t i = 0; true; ++i) { + for (uint8_t i = 0; true; ++i) { // increment prng every TAG_BIT_PERIOD last_frame_end += TAG_BIT_PERIOD; legic_prng_forward(1); // if start of frame was received exit delay loop - if(wait_for(RWD_PAUSE, last_frame_end)) { + if (wait_for(RWD_PAUSE, last_frame_end)) { last_frame_end = GetCountSspClk(); break; } // check for code violation - if(i > RWD_CMD_TIMEOUT) { + if (i > RWD_CMD_TIMEOUT) { return -1; } } @@ -227,19 +227,19 @@ static int32_t rx_frame(uint8_t *len) { uint32_t last_frame_start = last_frame_end; // receive frame - for(*len = 0; true; ++(*len)) { + for (*len = 0; true; ++(*len)) { // receive next bit LED_B_ON(); int8_t bit = rx_bit(); LED_B_OFF(); // check for code violation and to short / long frame - if((bit < 0) && ((*len < RWD_MIN_FRAME_LEN) || (*len > RWD_MAX_FRAME_LEN))) { + if ((bit < 0) && ((*len < RWD_MIN_FRAME_LEN) || (*len > RWD_MAX_FRAME_LEN))) { return -1; } // check for code violation caused by end of frame - if(bit < 0) { + if (bit < 0) { break; } @@ -256,7 +256,6 @@ static int32_t rx_frame(uint8_t *len) { // log uint8_t cmdbytes[] = {*len, BYTEx(frame, 0), BYTEx(frame, 1), BYTEx(frame, 2)}; LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, true); - return frame; } @@ -267,7 +266,7 @@ static int32_t rx_frame(uint8_t *len) { static int32_t init_card(uint8_t cardtype, legic_card_select_t *p_card) { p_card->tagtype = cardtype; - switch(p_card->tagtype) { + switch (p_card->tagtype) { case 0: p_card->cmdsize = 6; p_card->addrsize = 5; @@ -338,7 +337,7 @@ static int32_t setup_phase(legic_card_select_t *p_card) { // wait for iv int32_t iv = rx_frame(&len); - if((len != 7) || (iv < 0)) { + if ((len != 7) || (iv < 0)) { return -1; } @@ -346,7 +345,7 @@ static int32_t setup_phase(legic_card_select_t *p_card) { legic_prng_init(iv); // reply with card type - switch(p_card->tagtype) { + switch (p_card->tagtype) { case 0: tx_frame(0x0D, 6); break; @@ -360,12 +359,12 @@ static int32_t setup_phase(legic_card_select_t *p_card) { // wait for ack int32_t ack = rx_frame(&len); - if((len != 6) || (ack < 0)) { + if ((len != 6) || (ack < 0)) { return -1; } // validate data - switch(p_card->tagtype) { + switch (p_card->tagtype) { case 0: if(ack != 0x19) return -1; break; @@ -399,12 +398,12 @@ static int32_t connected_phase(legic_card_select_t *p_card) { // wait for command int32_t cmd = rx_frame(&len); - if(cmd < 0) { + if (cmd < 0) { return -1; } // check if command is LEGIC_READ - if(len == p_card->cmdsize) { + if (len == p_card->cmdsize) { // prepare data uint8_t byte = legic_mem[cmd >> 1]; uint8_t crc = calc_crc4(cmd, p_card->cmdsize, byte); @@ -416,7 +415,7 @@ static int32_t connected_phase(legic_card_select_t *p_card) { } // check if command is LEGIC_WRITE - if(len == p_card->cmdsize + 8 + 4) { + if (len == p_card->cmdsize + 8 + 4) { // decode data uint16_t mask = (1 << p_card->addrsize) - 1; uint16_t addr = (cmd >> 1) & mask; @@ -425,7 +424,7 @@ static int32_t connected_phase(legic_card_select_t *p_card) { // check received against calculated crc uint8_t calc_crc = calc_crc4(addr << 1, p_card->cmdsize, byte); - if(calc_crc != crc) { + if (calc_crc != crc) { Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc); return -1; } @@ -453,7 +452,7 @@ void LegicRfSimulate(uint8_t cardtype) { init_tag(); // verify command line input - if(init_card(cardtype, &card) != 0) { + if (init_card(cardtype, &card) != 0) { DbpString("Unknown tagtype."); goto OUT; } @@ -464,17 +463,17 @@ void LegicRfSimulate(uint8_t cardtype) { WDT_HIT(); // wait for carrier, restart after timeout - if(!wait_for(RWD_PULSE, GetCountSspClk() + TAG_BIT_PERIOD)) { + if (!wait_for(RWD_PULSE, GetCountSspClk() + TAG_BIT_PERIOD)) { continue; } // wait for connection, restart on error - if(setup_phase(&card)) { + if (setup_phase(&card)) { continue; } // conection is established, process commands until one fails - while(!connected_phase(&card)) { + while (!connected_phase(&card)) { WDT_HIT(); } } diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 0dac64bd1..96abd9b99 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -80,7 +80,7 @@ void setT55xxConfig(uint8_t arg0, t55xx_config *c) { printT55xxConfig(); -#if WITH_FLASH +#ifdef WITH_FLASH // shall persist to flashmem if (arg0 == 0) { return; @@ -103,7 +103,7 @@ void setT55xxConfig(uint8_t arg0, t55xx_config *c) { Flash_CheckBusy(BUSY_TIMEOUT); Flash_WriteEnable(); - Flash_Erase4k(3, 0xD); + Flash_Erase4k(3, 0xD); res = Flash_Write(T55XX_CONFIG_OFFSET, buf, T55XX_CONFIG_LEN); if ( res == T55XX_CONFIG_LEN && MF_DBGLEVEL > 1) { @@ -119,7 +119,7 @@ t55xx_config* getT55xxConfig(void) { } void loadT55xxConfig(void) { -#if WITH_FLASH +#ifdef WITH_FLASH if (!FlashInit()) { return; } @@ -598,9 +598,11 @@ void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycle AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; + + uint8_t check = 1; for(;;) { - + if ( numcycles > -1 ) { if ( x != numcycles ) { ++x; @@ -616,9 +618,11 @@ void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycle // used as a simple detection of a reader field? while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { WDT_HIT(); - if ( usb_poll_validate_length() || BUTTON_PRESS() ) - goto OUT; - } + if ( !check ) { + if ( usb_poll_validate_length() || BUTTON_PRESS() ) + goto OUT; + } + ++check; } if (buf[i]) OPEN_COIL(); @@ -628,9 +632,11 @@ void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycle //wait until SSC_CLK goes LOW while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { WDT_HIT(); - //if ( usb_poll_validate_length() || BUTTON_PRESS() ) - if ( BUTTON_PRESS() ) - goto OUT; + if ( !check ) { + if ( usb_poll_validate_length() || BUTTON_PRESS() ) + goto OUT; + } + ++check; } i++; @@ -1489,11 +1495,22 @@ void T55xxWriteBlock(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t arg) { // Read one card block in page [page] void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { LED_A_ON(); - bool PwdMode = arg0 & 0x1; - uint8_t Page = (arg0 & 0x2) >> 1; - uint32_t i = 0; - bool RegReadMode = (Block == 0xFF);//regular read mode + bool PwdMode = arg0 & 0x1; + uint8_t Page = ( arg0 & 0x2 ) >> 1; + bool brute_mem = arg0 & 0x4; + uint32_t i = 0; + + // regular read mode + bool RegReadMode = (Block == 0xFF); + + uint8_t start_wait = 4; + size_t samples = 12000; + if ( brute_mem ) { + start_wait = 0; + samples = 1024; + } + //clear buffer now so it does not interfere with timing later BigBuf_Clear_keep_EM(); @@ -1505,7 +1522,8 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { // Set up FPGA, 125kHz to power up the tag LFSetupFPGAForADC(95, true); // make sure tag is fully powered up... - WaitMS(4); + WaitMS(start_wait); + // Trigger T55x7 Direct Access Mode with start gap FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(t_config.start_gap); @@ -1529,17 +1547,118 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { // Turn field on to read the response // 137*8 seems to get to the start of data pretty well... - // but we want to go past the start and let the repeating data settle in... - TurnReadLFOn(210*8); + // but we want to go past the start and let the repeating data settle in... + TurnReadLFOn(200*8); // Acquisition // Now do the acquisition - DoPartialAcquisition(0, true, 12000, 0); + DoPartialAcquisition(0, true, samples, 0); // Turn the field off - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - cmd_send(CMD_ACK,0,0,0,0,0); - LED_A_OFF(); + if ( !brute_mem ) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); + } +} + +void T55xx_ChkPwds() { + + DbpString("[+] T55XX Check pwds using flashmemory starting"); + + uint8_t ret = 0; + // First get baseline and setup LF mode. + // tends to mess up BigBuf + uint8_t *buf = BigBuf_get_addr(); + + uint32_t b1, baseline = 0; + + // collect baseline for failed attempt + uint8_t x = 32; + while (x--) { + b1 = 0; + T55xxReadBlock(4, 1, 0); + for (uint16_t j=0; j < 1024; ++j) + b1 += buf[j]; + + b1 *= b1; + b1 >>= 8; + baseline += b1; + } + + baseline >>= 5; + Dbprintf("[=] Baseline determined [%u]", baseline); + + + uint8_t *pwds = BigBuf_get_EM_addr(); + uint16_t pwdCount = 0; + uint32_t candidate = 0; + +#ifdef WITH_FLASH + bool use_flashmem = true; + if ( use_flashmem ) { + BigBuf_Clear_EM(); + uint16_t isok = 0; + uint8_t counter[2] = {0x00, 0x00}; + isok = Flash_ReadData(DEFAULT_T55XX_KEYS_OFFSET, counter, sizeof(counter) ); + if ( isok != sizeof(counter) ) + goto OUT; + + pwdCount = counter[1] << 8 | counter[0]; + + if ( pwdCount == 0 && pwdCount == 0xFFFF) + goto OUT; + + isok = Flash_ReadData(DEFAULT_T55XX_KEYS_OFFSET+2, pwds, pwdCount * 4); + if ( isok != pwdCount * 4 ) + goto OUT; + + Dbprintf("[=] Password dictionary count %d ", pwdCount); + } +#endif + + uint32_t pwd = 0, curr = 0, prev = 0; + for (uint16_t i =0; i< pwdCount; ++i) { + + if (BUTTON_PRESS() && !usb_poll_validate_length()) { + goto OUT; + } + + pwd = bytes_to_num(pwds + i * 4, 4); + + + T55xxReadBlock(5, 0, pwd); + + // calc mean of BigBuf 1024 samples. + uint32_t sum = 0; + for (uint16_t j=0; j<1024; ++j) { + sum += buf[j]; + } + + sum *= sum; + sum >>= 8; + + int32_t tmp = (sum - baseline); + curr = ABS(tmp); + + Dbprintf("[=] Pwd %08X | ABS %u", pwd, curr ); + + if ( curr > prev ) { + + + Dbprintf("[=] --> ABS %u Candidate %08X <--", curr, pwd ); + candidate = pwd; + prev = curr; + } + } + + if ( candidate ) + ret = 1; + +OUT: + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + cmd_send(CMD_ACK,ret,candidate,0,0,0); + LEDsoff(); } void T55xxWakeUp(uint32_t Pwd){ @@ -1970,7 +2089,6 @@ void EM4xWriteWord(uint32_t flag, uint32_t data, uint32_t pwd) { //Wait 20ms for write to complete? WaitMS(7); - //Capture response if one exists DoPartialAcquisition(20, true, 6000, 1000); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -1994,7 +2112,7 @@ This triggers a COTAG tag to response */ void Cotag(uint32_t arg0) { #ifndef OFF -# define OFF { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(2035); } +# define OFF(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS((x)); } #endif #ifndef ON # define ON(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); WaitUS((x)); } @@ -2003,29 +2121,15 @@ void Cotag(uint32_t arg0) { LED_A_ON(); - // Switching to LF image on FPGA. This might empty BigBuff - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - + LFSetupFPGAForADC(89, true); + //clear buffer now so it does not interfere with timing later BigBuf_Clear_ext(false); - // Set up FPGA, 132kHz to power up the tag - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 89); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); - - // start clock - 1.5ticks is 1us - StartTicks(); - //send COTAG start pulse - ON(740) OFF - ON(3330) OFF - ON(740) OFF + ON(740) OFF(2035) + ON(3330) OFF(2035) + ON(740) OFF(2035) ON(1000) switch(rawsignal) { diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index 22171e2c3..96963d389 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -117,21 +117,21 @@ void LFSetupFPGAForADC(int divisor, bool lf_field) { * @return the number of bits occupied by the samples. */ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, uint32_t cancel_after) { - //bigbuf, to hold the aquired raw data signal + uint8_t *dest = BigBuf_get_addr(); bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen(); - if (bits_per_sample < 1) bits_per_sample = 1; if (bits_per_sample > 8) bits_per_sample = 8; if (decimation < 1) decimation = 1; - // Use a bit stream to handle the output + // use a bit stream to handle the output BitstreamOut data = { dest , 0, 0}; int sample_counter = 0; uint8_t sample = 0; - //If we want to do averaging + + // if we want to do averaging uint32_t sample_sum =0 ; uint32_t sample_total_numbers = 0; uint32_t sample_total_saved = 0; @@ -139,13 +139,13 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag while (!BUTTON_PRESS() && !usb_poll_validate_length() ) { WDT_HIT(); - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; - LED_D_ON(); - } + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + + // Testpoint 8 (TP8) can be used to trigger oscilliscope LED_D_OFF(); + // threshold either high or low values 128 = center 0. if trigger = 178 if ((trigger_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) { if (cancel_after > 0) { @@ -162,24 +162,26 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag if (averaging) sample_sum += sample; - //Check decimation + // check decimation if (decimation > 1) { sample_counter++; if (sample_counter < decimation) continue; sample_counter = 0; } - //Averaging + // averaging if (averaging && decimation > 1) { sample = sample_sum / decimation; sample_sum =0; } - //Store the sample + // store the sample sample_total_saved ++; - if (bits_per_sample == 8){ + if (bits_per_sample == 8) { dest[sample_total_saved-1] = sample; - data.numbits = sample_total_saved << 3;//Get the return value correct + + // Get the return value correct + data.numbits = sample_total_saved << 3; if (sample_total_saved >= bufsize) break; } else { @@ -190,9 +192,8 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag if (bits_per_sample > 4) pushBit(&data, sample & 0x08); if (bits_per_sample > 5) pushBit(&data, sample & 0x04); if (bits_per_sample > 6) pushBit(&data, sample & 0x02); - //Not needed, 8bps is covered above - //if (bits_per_sample > 7) pushBit(&data, sample & 0x01); - if ((data.numbits >> 3) +1 >= bufsize) break; + + if ((data.numbits >> 3) + 1 >= bufsize) break; } } } @@ -285,10 +286,8 @@ void doT55x7Acquisition(size_t sample_size) { while(!BUTTON_PRESS() && !usb_poll_validate_length() && skipCnt < 1000 && (i < bufsize) ) { WDT_HIT(); - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; //43 - LED_D_ON(); - } + + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { curSample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; LED_D_OFF(); @@ -352,11 +351,7 @@ void doCotagAcquisition(size_t sample_size) { while (!BUTTON_PRESS() && !usb_poll_validate_length() && (i < bufsize) && (noise_counter < (COTAG_T1 << 1)) ) { WDT_HIT(); - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; - LED_D_ON(); - } - + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; LED_D_OFF(); @@ -406,12 +401,8 @@ uint32_t doCotagAcquisitionManchester() { uint16_t noise_counter = 0; while (!BUTTON_PRESS() && !usb_poll_validate_length() && (sample_counter < bufsize) && (noise_counter < (COTAG_T1 << 1)) ) { - WDT_HIT(); - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; - LED_D_ON(); - } - + WDT_HIT(); + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; LED_D_OFF(); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 7d39b3f29..6b10ddd0d 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -17,7 +17,7 @@ #include #ifndef HARDNESTED_AUTHENTICATION_TIMEOUT -# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 //848 // card times out 1ms after wrong authentication (according to NXP documentation) +# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) #endif #ifndef HARDNESTED_PRE_AUTHENTICATION_LEADTIME # define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication @@ -1122,7 +1122,6 @@ uint8_t chkKey_readb(struct chk_t *c, uint8_t *keyb) { } void chkKey_scanA(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, uint8_t *sectorcnt, uint8_t *foundkeys) { - uint8_t status; for (uint8_t s = 0; s < *sectorcnt; s++) { // skip already found A keys @@ -1130,8 +1129,7 @@ void chkKey_scanA(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, ui continue; c->block = FirstBlockOfSector( s ); - status = chkKey( c ); - if ( status == 0 ) { + if ( chkKey( c ) == 0 ) { num_to_bytes(c->key, 6, k_sector[s].keyA); found[(s*2)] = 1; ++*foundkeys; @@ -1142,7 +1140,6 @@ void chkKey_scanA(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, ui } void chkKey_scanB(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, uint8_t *sectorcnt, uint8_t *foundkeys) { - uint8_t status; for (uint8_t s = 0; s < *sectorcnt; s++) { // skip already found B keys @@ -1150,8 +1147,7 @@ void chkKey_scanB(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, ui continue; c->block = FirstBlockOfSector( s ); - status = chkKey( c ); - if ( status == 0 ) { + if ( chkKey( c ) == 0 ) { num_to_bytes(c->key, 6, k_sector[s].keyB); found[(s*2)+1] = 1; ++*foundkeys; @@ -1167,7 +1163,12 @@ void chkKey_loopBonly(struct chk_t *c, struct sector_t *k_sector, uint8_t *found // read Block B, if A is found. for (uint8_t s = 0; s < *sectorcnt; ++s) { + + if ( found[(s*2)] && found[(s*2)+1] ) + continue; + c->block = (FirstBlockOfSector( s ) + NumBlocksPerSector( s ) - 1); + // A but not B if ( found[(s*2)] && !found[(s*2)+1] ){ c->key = bytes_to_num(k_sector[s].keyA, 6); @@ -1187,6 +1188,9 @@ void chkKey_loopBonly(struct chk_t *c, struct sector_t *k_sector, uint8_t *found } } } + + + // get Chunks of keys, to test authentication against card. // arg0 = antal sectorer // arg0 = first time @@ -1200,7 +1204,8 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da uint8_t firstchunk = (arg0 >> 8) & 0xF; uint8_t lastchunk = (arg0 >> 12) & 0xF; uint8_t strategy = arg1 & 0xFF; - uint8_t keyCount = arg2 & 0xFF; + uint8_t use_flashmem = (arg1 >> 8) & 0xFF; + uint16_t keyCount = arg2 & 0xFF; uint8_t status = 0; struct Crypto1State mpcs = {0, 0}; @@ -1217,33 +1222,56 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da static uint8_t found[80]; static uint8_t *uid; - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); +#ifdef WITH_FLASH + if ( use_flashmem ) { + BigBuf_free(); + uint16_t isok = 0; + uint8_t size[2] = {0x00, 0x00}; + isok = Flash_ReadData(DEFAULT_MF_KEYS_OFFSET, size, 2); + if ( isok != 2 ) + goto OUT; + + keyCount = size[1] << 8 | size[0]; + + if ( keyCount == 0 && keyCount == 0xFFFF) + goto OUT; + + datain = BigBuf_malloc( keyCount * 6); + if (datain == NULL ) + goto OUT; + + isok = Flash_ReadData(DEFAULT_MF_KEYS_OFFSET+2, datain, keyCount * 6); + if ( isok != keyCount * 6 ) + goto OUT; + + } +#endif if (uid == NULL || firstchunk) { uid = BigBuf_malloc(10); - if (uid == NULL ) { - if (MF_DBGLEVEL >= 3) Dbprintf("ChkKeys: uid malloc failed"); + if (uid == NULL ) goto OUT; - } } + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); LEDsoff(); LED_A_ON(); if ( firstchunk ) { - clear_trace(); set_tracing(false); memset(k_sector, 0x00, 480+10); memset(found, 0x00, sizeof(found)); foundkeys = 0; - + iso14a_card_select_t card_info; if ( !iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (ALL)"); + if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys_fast: Can't select card (ALL)"); goto OUT; } + switch (card_info.uidlen) { case 4 : cascade_levels = 1; break; case 7 : cascade_levels = 2; break; @@ -1262,19 +1290,23 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da chk_data.block = 0; // keychunk loop - depth first one sector. - if ( strategy == 1 ) { + if ( strategy == 1 || use_flashmem) { uint8_t newfound = foundkeys; + uint16_t lastpos = 0; + uint16_t s_point = 0; // Sector main loop // keep track of how many sectors on card. for (uint8_t s = 0; s < sectorcnt; ++s) { - if ( found[(s*2)] && found[(s*2)+1] ) + if ( found[(s*2)] && found[(s*2)+1] ) continue; - for (uint8_t i = 0; i < keyCount; ++i) { - + for (uint16_t i = s_point; i < keyCount; ++i) { + + //if ( i % 100 == 0) Dbprintf("ChkKeys_fast: sector %d | checking %d | %d found | s_point %d", s, i, foundkeys, s_point); + // Allow button press / usb cmd to interrupt device if (BUTTON_PRESS() && !usb_poll_validate_length()) { goto OUT; @@ -1292,8 +1324,6 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da // new key chk_data.key = bytes_to_num(datain + i * 6, 6); - // assume: block0,1,2 has more read rights in accessbits than the sectortrailer. authenticating against block0 in each sector - // skip already found A keys if( !found[(s*2)] ) { chk_data.keyType = 0; @@ -1303,12 +1333,26 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da found[(s*2)] = 1; ++foundkeys; - chkKey_scanA(&chk_data, k_sector, found, §orcnt, &foundkeys); + chkKey_scanA(&chk_data, k_sector, found, §orcnt, &foundkeys); // read Block B, if A is found. chkKey_loopBonly( &chk_data, k_sector, found, §orcnt, &foundkeys); + chk_data.keyType = 1; + chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys); + + chk_data.keyType = 0; chk_data.block = FirstBlockOfSector( s ); + + if ( use_flashmem ) { + if ( lastpos != i && lastpos != 0) { + if ( i - lastpos < 0xF) { + s_point = i & 0xFFF0; + } + } else { + lastpos = i; + } + } } } @@ -1322,25 +1366,46 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da ++foundkeys; chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys); + + if ( use_flashmem ) { + if ( lastpos != i && lastpos != 0) { + + if ( i - lastpos < 0xF) + s_point = i & 0xFFF0; + } else { + lastpos = i; + } + } } } - + + if ( found[(s*2)] && found[(s*2)+1] ) + break; + } // end keys test loop - depth first // assume1. if no keys found in first sector, get next keychunk from client - if ( newfound-foundkeys == 0 ) + if ( !use_flashmem && (newfound-foundkeys == 0) ) goto OUT; } // end loop - sector } // end strategy 1 + + if ( foundkeys == allkeys ) + goto OUT; - if ( strategy == 2 ) { + if ( strategy == 2 || use_flashmem ) { + // Keychunk loop - for (uint8_t i = 0; i < keyCount; i++) { - + for (uint16_t i = 0; i < keyCount; i++) { + // Allow button press / usb cmd to interrupt device if (BUTTON_PRESS() && !usb_poll_validate_length()) break; + // found all keys? + if ( foundkeys == allkeys ) + goto OUT; + WDT_HIT(); // new key @@ -1349,7 +1414,9 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da // Sector main loop // keep track of how many sectors on card. for (uint8_t s = 0; s < sectorcnt; ++s) { - + + if ( found[(s*2)] && found[(s*2)+1] ) continue; + // found all keys? if ( foundkeys == allkeys ) goto OUT; @@ -1387,36 +1454,39 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys); } } - - } // end loop sectors } // end loop keys } // end loop strategy 2 -OUT: +OUT: LEDsoff(); crypto1_destroy(pcs); // All keys found, send to client, or last keychunk from client if (foundkeys == allkeys || lastchunk ) { - + uint64_t foo = 0; + for (uint8_t m = 0; m < 64; m++) { + foo |= ((uint64_t)(found[m] & 1) << m); + } + uint16_t bar = 0; - for (uint8_t m = 0; m < 64; ++m) - foo |= (found[m] << m); - for (uint8_t m=64; m < sizeof(found); ++m) - bar |= (found[m] << (m-64)); - + uint8_t j = 0; + for (uint8_t m=64; m < sizeof(found); m++) { + bar |= ((uint16_t)(found[m] & 1) << j++); + } + uint8_t *tmp = BigBuf_malloc(480+10); memcpy(tmp, k_sector, sectorcnt * sizeof(sector_t) ); num_to_bytes(foo, 8, tmp+480); tmp[488] = bar & 0xFF; tmp[489] = bar >> 8 & 0xFF; + cmd_send(CMD_ACK, foundkeys, 0, 0, tmp, 480+10); set_tracing(false); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - BigBuf_free(); BigBuf_Clear_ext(false); + BigBuf_free(); BigBuf_Clear_ext(false); } else { // partial/none keys found cmd_send(CMD_ACK, foundkeys, 0, 0, 0, 0); diff --git a/armsrc/optimized_cipher.c b/armsrc/optimized_cipher.c index 36b25f593..223d73fea 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/pcf7931.c b/armsrc/pcf7931.c index 8405c96ce..c9a76bb3b 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -3,8 +3,7 @@ #define T0_PCF 8 //period for the pcf7931 in us #define ALLOC 16 -int DemodPCF7931(uint8_t **outBlocks) { - +size_t DemodPCF7931(uint8_t **outBlocks) { uint8_t bits[256] = {0x00}; uint8_t blocks[8][16]; uint8_t *dest = BigBuf_get_addr(); @@ -18,7 +17,7 @@ int DemodPCF7931(uint8_t **outBlocks) { int tolerance = clock / 8; int pmc, block_done; int lc, warnings = 0; - int num_blocks = 0; + size_t num_blocks = 0; int lmin=128, lmax=128; uint8_t dir; //clear read buffer @@ -40,8 +39,7 @@ int DemodPCF7931(uint8_t **outBlocks) { i++; } dir = 0; - } - else { + } else { while(i < GraphTraceLen) { if( !(dest[i] < dest[i-1]) && dest[i] < lmin) break; @@ -55,10 +53,8 @@ int DemodPCF7931(uint8_t **outBlocks) { pmc = 0; block_done = 0; - for (bitidx = 0; i < GraphTraceLen; i++) - { - if ( (dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin)) - { + for (bitidx = 0; i < GraphTraceLen; i++) { + if ((dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin)) { lc = i - lastval; lastval = i; @@ -72,8 +68,7 @@ int DemodPCF7931(uint8_t **outBlocks) { lastval = i; pmc = 0; block_done = 1; - } - else { + } else { pmc = i; } } else if (ABS(lc-clock/2) < tolerance) { @@ -84,8 +79,7 @@ int DemodPCF7931(uint8_t **outBlocks) { lastval = i; pmc = 0; block_done = 1; - } - else if(half_switch == 1) { + } else if(half_switch == 1) { bits[bitidx++] = 0; half_switch = 0; } @@ -96,26 +90,25 @@ int DemodPCF7931(uint8_t **outBlocks) { bits[bitidx++] = 1; } else { // Error - warnings++; - if (warnings > 10) - { - Dbprintf("Error: too many detection errors, aborting..."); + if (++warnings > 10) { + Dbprintf("Error: too many detection errors, aborting."); return 0; } } if(block_done == 1) { if(bitidx == 128) { - for(j=0; j<16; j++) { - blocks[num_blocks][j] = 128*bits[j*8+7]+ + for(j = 0; j < 16; ++j) { + blocks[num_blocks][j] = + 128 * bits[j*8 + 7]+ 64*bits[j*8+6]+ 32*bits[j*8+5]+ 16*bits[j*8+4]+ 8*bits[j*8+3]+ 4*bits[j*8+2]+ 2*bits[j*8+1]+ - bits[j*8]; - + bits[j*8] + ; } num_blocks++; } @@ -135,185 +128,209 @@ int DemodPCF7931(uint8_t **outBlocks) { return num_blocks; } -int IsBlock0PCF7931(uint8_t *Block) { - // Assume RFU means 0 :) - if((memcmp(Block, "\x00\x00\x00\x00\x00\x00\x00\x01", 8) == 0) && memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) // PAC enabled - return 1; - if((memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) && Block[7] == 0) // PAC disabled, can it *really* happen ? - return 1; - return 0; +bool IsBlock0PCF7931(uint8_t *block) { + // assuming all RFU bits are set to 0 + // if PAC is enabled password is set to 0 + if (block[7] == 0x01) + { + if (!memcmp(block, "\x00\x00\x00\x00\x00\x00\x00", 7) && !memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7)) + return true; + } + else if (block[7] == 0x00) + { + if (!memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7)) + return true; + } + return false; } -int IsBlock1PCF7931(uint8_t *Block) { - // Assume RFU means 0 :) - if( Block[10] == 0 && - Block[11] == 0 && - Block[12] == 0 && - Block[13] == 0) - if ( (Block[14] & 0x7f) <= 9 && Block[15] <= 9) - return 1; - return 0; +bool IsBlock1PCF7931(uint8_t *block) { + // assuming all RFU bits are set to 0 + if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0) + if((block[14] & 0x7f) <= 9 && block[15] <= 9) + return true; + + return false; } void ReadPCF7931() { - uint8_t Blocks[8][17]; - uint8_t tmpBlocks[4][16]; - int i, j, ind, ind2, n; - int num_blocks = 0; - int max_blocks = 8; - int ident = 0; - int error = 0; - int tries = 0; + int found_blocks = 0; // successfully read blocks + int max_blocks = 8; // readable blocks + uint8_t memory_blocks[8][17]; // PCF content + + uint8_t single_blocks[8][17]; // PFC blocks with unknown position + int single_blocks_cnt = 0; - memset(Blocks, 0, 8*17*sizeof(uint8_t)); + size_t n = 0; // transmitted blocks + uint8_t tmp_blocks[4][16]; // temporary read buffer + + uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found + int errors = 0; // error counter + int tries = 0; // tries counter + + memset(memory_blocks, 0, 8*17*sizeof(uint8_t)); + memset(single_blocks, 0, 8*17*sizeof(uint8_t)); + + int i = 0, j = 0; do { - memset(tmpBlocks, 0, 4*16*sizeof(uint8_t)); - n = DemodPCF7931((uint8_t**)tmpBlocks); + i = 0; + + memset(tmp_blocks, 0, 4*16*sizeof(uint8_t)); + n = DemodPCF7931((uint8_t**)tmp_blocks); if(!n) - error++; - if(error==10 && num_blocks == 0) { + ++errors; + + // exit if no block is received + if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) { Dbprintf("Error, no tag or bad tag"); return; } - else if (tries==20 || error==10) { + // exit if too many errors during reading + if (tries > 50 && (2*errors > tries)) { Dbprintf("Error reading the tag"); Dbprintf("Here is the partial content"); goto end; } - for(i=0; i= 0; ind--,ind2--) { - if(ind2 < 0) - ind2 = max_blocks; - if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found - // Dbprintf("Tmp %d -> Block %d", ind, ind2); - memcpy(Blocks[ind2], tmpBlocks[ind], 16); - Blocks[ind2][ALLOC] = 1; - num_blocks++; - if(num_blocks == max_blocks) goto end; - } - } - for(ind=i+1,ind2=j+1; ind < n; ind++,ind2++) { - if(ind2 > max_blocks) - ind2 = 0; - if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found - // Dbprintf("Tmp %d -> Block %d", ind, ind2); - memcpy(Blocks[ind2], tmpBlocks[ind], 16); - Blocks[ind2][ALLOC] = 1; - num_blocks++; - if(num_blocks == max_blocks) goto end; - } - } + ++tries; + continue; + } + + Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors); + + i = 0; + if(!found_0_1) { + while (i < n - 1) { + if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i+1])) { + found_0_1 = 1; + memcpy(memory_blocks[0], tmp_blocks[i], 16); + memcpy(memory_blocks[1], tmp_blocks[i+1], 16); + memory_blocks[0][ALLOC] = memory_blocks[1][ALLOC] = 1; + // block 1 tells how many blocks are going to be sent + max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1; + found_blocks = 2; + + Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks); + + // handle the following blocks + for (j = i + 2; j < n; ++j) { + memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16); + memory_blocks[found_blocks][ALLOC] = 1; + ++found_blocks; + } + break; + } + ++i; + } + } else { + // Trying to re-order blocks + // Look for identical block in memory blocks + while (i < n-1) { + // skip all zeroes blocks + if (memcmp(tmp_blocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) { + for (j = 1; j < max_blocks - 1; ++j) { + if (!memcmp(tmp_blocks[i], memory_blocks[j], 16) && !memory_blocks[j+1][ALLOC]) { + memcpy(memory_blocks[j+1], tmp_blocks[i+1], 16); + memory_blocks[j+1][ALLOC] = 1; + if (++found_blocks >= max_blocks) goto end; } } } + if (memcmp(tmp_blocks[i+1], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) { + for (j = 0; j < max_blocks; ++j) { + if (!memcmp(tmp_blocks[i+1], memory_blocks[j], 16) && !memory_blocks[(j == 0 ? max_blocks : j) -1][ALLOC]) { + if (j == 0) { + memcpy(memory_blocks[max_blocks - 1], tmp_blocks[i], 16); + memory_blocks[max_blocks - 1][ALLOC] = 1; + } else { + memcpy(memory_blocks[j-1], tmp_blocks[i], 16); + memory_blocks[j-1][ALLOC] = 1; + } + if (++found_blocks >= max_blocks) goto end; + } + } + } + ++i; } } - tries++; - if (BUTTON_PRESS()) return; - } while (num_blocks != max_blocks); + ++tries; + if (BUTTON_PRESS()) { + Dbprintf("Button pressed, stopping."); + goto end; + } + } + while (found_blocks != max_blocks); + end: Dbprintf("-----------------------------------------"); Dbprintf("Memory content:"); Dbprintf("-----------------------------------------"); - for(i=0; i", i); } Dbprintf("-----------------------------------------"); + if (found_blocks < max_blocks) { + Dbprintf("-----------------------------------------"); + Dbprintf("Blocks with unknown position:"); + Dbprintf("-----------------------------------------"); + for (i = 0; i < single_blocks_cnt; ++i) + print_result("Block", single_blocks[i], 16); + + Dbprintf("-----------------------------------------"); + } cmd_send(CMD_ACK,0,0,0,0,0); } - -/* Write on a byte of a PCF7931 tag - * @param address : address of the block to write - @param byte : address of the byte to write - @param data : data to write - */ -void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) -{ +static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) { uint32_t tab[1024] = {0}; // data times frame uint32_t u = 0; uint8_t parity = 0; bool comp = 0; //BUILD OF THE DATA FRAME - //alimentation of the tag (time for initializing) AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab); - - //PMC - Dbprintf("Initialization delay : %d us", init_delay); AddPatternPCF7931(8192/2*T0_PCF + 319*T0_PCF+70, 3*T0_PCF, 29*T0_PCF, tab); - - Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p); - //password indication bit AddBitPCF7931(1, tab, l, p); - //password (on 56 bits) - Dbprintf("Password (LSB first on each byte) : %02x %02x %02x %02x %02x %02x %02x", pass1,pass2,pass3,pass4,pass5,pass6,pass7); - AddBytePCF7931(pass1, tab, l, p); - AddBytePCF7931(pass2, tab, l, p); - AddBytePCF7931(pass3, tab, l, p); - AddBytePCF7931(pass4, tab, l, p); - AddBytePCF7931(pass5, tab, l, p); - AddBytePCF7931(pass6, tab, l, p); - AddBytePCF7931(pass7, tab, l, p); - - + AddBytePCF7931(pass[0], tab, l, p); + AddBytePCF7931(pass[1], tab, l, p); + AddBytePCF7931(pass[2], tab, l, p); + AddBytePCF7931(pass[3], tab, l, p); + AddBytePCF7931(pass[4], tab, l, p); + AddBytePCF7931(pass[5], tab, l, p); + AddBytePCF7931(pass[6], tab, l, p); //programming mode (0 or 1) AddBitPCF7931(0, tab, l, p); //block adress on 6 bits - Dbprintf("Block address : %02x", address); - for (u=0; u<6; u++) - { + for (u = 0; u < 6; ++u) { if (address&(1< 0xFFFF){ tab[u] -= 0xFFFF; comp = 0; } } - } SendCmdPCF7931(tab); } +/* Write on a byte of a PCF7931 tag + * @param address : address of the block to write + @param byte : address of the byte to write + @param data : data to write + */ +void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) { + Dbprintf("Initialization delay : %d us", init_delay); + Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p); + Dbprintf("Password (LSB first on each byte): %02x %02x %02x %02x %02x %02x %02x", pass1, pass2, pass3, pass4, pass5, pass6, pass7); + Dbprintf("Block address : %02x", address); + Dbprintf("Byte address : %02x", byte); + Dbprintf("Data : %02x", data); + + uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7}; + + RealWritePCF7931 (password, init_delay, l, p, address, byte, data); +} /* Send a trame to a PCF7931 tags @@ -386,9 +414,7 @@ void SendCmdPCF7931(uint32_t * tab){ Dbprintf("Sending data frame..."); FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU ); LED_A_ON(); @@ -405,21 +431,22 @@ void SendCmdPCF7931(uint32_t * tab){ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; AT91C_BASE_TCB->TCB_BCR = 1; - tempo = AT91C_BASE_TC0->TC_CV; for( u = 0; tab[u] != 0; u += 3){ - // modulate antenna HIGH(GPIO_SSC_DOUT); - while(tempo != tab[u]) tempo = AT91C_BASE_TC0->TC_CV; + while (tempo != tab[u]) + tempo = AT91C_BASE_TC0->TC_CV; // stop modulating antenna LOW(GPIO_SSC_DOUT); - while(tempo != tab[u+1]) tempo = AT91C_BASE_TC0->TC_CV; + while (tempo != tab[u+1]) + tempo = AT91C_BASE_TC0->TC_CV; // modulate antenna HIGH(GPIO_SSC_DOUT); - while(tempo != tab[u+2]) tempo = AT91C_BASE_TC0->TC_CV; + while (tempo != tab[u+2]) + tempo = AT91C_BASE_TC0->TC_CV; } LED_A_OFF(); @@ -437,18 +464,16 @@ void SendCmdPCF7931(uint32_t * tab){ * @param l : offset on low pulse width * @param p : offset on low pulse positioning */ - bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p){ - uint32_t u; - for ( u=0; u<8; u++) - { - if (byte&(1< - -int decode_ber_tlv_item(uint8_t* data, tlvtag* returnedtag) -{ - uint8_t tag[TAG_LENGTH] = {0x00,0x00}; - uint16_t length = 0; - //uint8_t value[VALUE_LENGTH]; - uint8_t lenlen = 0; - int i = 0; - int z = 0; - //decode tag - tag[0] = data[0]; - if((tag[0] & TLV_TAG_NUMBER_MASK) == TLV_TAG_NUMBER_MASK) { //see subsequent bytes - i++; - tag[i] = data[i]; - //assume tag is only two bytes long for now - /* - while((data[i] & TLV_TAG_MASK) == TLV_TAG_MASK){ - i++; - tag[i] = data[i]; - } - */ - } - i++; - //decode length - if((data[i] & TLV_LENGTH_MASK) == TLV_LENGTH_MASK) { - lenlen = data[i] ^ TLV_LENGTH_MASK; - i++; - length = (uint16_t)data[i]; - z = 1; - while(z < lenlen){ - i++; - z++; - length <<= 8; - length += (uint16_t)data[i]; - } - i++; - } - else { - length = (uint16_t)data[i]; - i++; - } - //copy results into the structure and return - memcpy(returnedtag->tag, tag, TAG_LENGTH); - (*returnedtag).valuelength = length; //return length of tag value - (*returnedtag).fieldlength = length + i + 1; //return length of total field - memcpy(returnedtag->value, &(data[i]), length); - return 0; -} - -//generate a TLV tag off input data -int encode_ber_tlv_item(uint8_t* tag, uint8_t taglen, uint8_t* data, uint32_t datalen, uint8_t* outputtag, uint32_t* outputtaglen) -{ - if(!tag || !data || !outputtag || !outputtaglen) //null pointer check - return 0; - - uint8_t datafieldlen = (datalen / 128) + 1; //field length of the tag - uint8_t tlvtotallen = taglen + datafieldlen + datalen; //total length of the tag - uint8_t returnedtag[tlvtotallen]; //buffer for the returned tag - uint8_t counter = 0; - memcpy(returnedtag, tag, taglen); //copy tag into buffer - counter += taglen; - if(datalen < 128){ // 1 byte length value - returnedtag[counter++] = datalen; - } - else{ - returnedtag[counter++] = datafieldlen | 0x80; //high bit set and number of length bytes - for(uint8_t i=datafieldlen; i !=0; i--){ - returnedtag[counter++] = (datalen >> (i * 8)) & 0xFF; //get current byte - } - } - memcpy(&returnedtag[counter], data, datalen); - *outputtaglen = tlvtotallen; - memcpy(outputtag, returnedtag,tlvtotallen); - return 0; -} - diff --git a/armsrc/tlv.h b/armsrc/tlv.h deleted file mode 100644 index c90756168..000000000 --- a/armsrc/tlv.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __TLV_H -#define __TLV_H - -#include -#include -#include - -//structure buffer definitions -#define TAG_LENGTH 2 -#define VALUE_LENGTH 1024 - -//masks -//if TLV_TAG_NUMBER_MASK bits are set, refer to the next byte for the tag number -//otherwise its located in bits 1-5 -#define TLV_TAG_NUMBER_MASK 0x1f -//if TLV_DATA_MASK set then its a 'constructed data object' -//otherwise a 'primitive data object' -#define TLV_DATA_MASK 0x20 -#define TLV_TAG_MASK 0x80 -#define TLV_LENGTH_MASK 0x80 - -//tlv tag structure, tag can be max of 2 bytes, length up to 65535 and value 1024 bytes long -typedef struct { - uint8_t tag[TAG_LENGTH]; - uint16_t fieldlength; - uint16_t valuelength; - uint8_t value[VALUE_LENGTH]; -}tlvtag; - -//decode a BER TLV -extern int decode_ber_tlv_item(uint8_t* data, tlvtag* returnedtag); -extern int encode_ber_tlv_item(uint8_t* tag, uint8_t taglen, uint8_t*data, uint32_t datalen, uint8_t* outputtag, uint32_t* outputtaglen); -#endif //__TLV_H diff --git a/bootrom/Makefile b/bootrom/Makefile index a579c46d3..c7e879bda 100644 --- a/bootrom/Makefile +++ b/bootrom/Makefile @@ -25,6 +25,10 @@ VERSIONSRC = version.c # stdint.h provided locally until GCC 4.5 becomes C99 compliant APP_CFLAGS = -I. -fno-strict-aliasing -ffunction-sections -fdata-sections +# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc +APP_CFLAGS += -fno-stack-protector -fno-pie + + # 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 766163c09..051468ba9 100644 --- a/client/Makefile +++ b/client/Makefile @@ -108,7 +108,7 @@ CORESRCS = uart_posix.c \ CMDSRCS = crapto1/crapto1.c \ crapto1/crypto1.c \ - mfkey.c \ + mifare/mfkey.c \ tea.c \ fido/additional_ca.c \ fido/cose.c \ @@ -126,7 +126,7 @@ CMDSRCS = crapto1/crapto1.c \ loclass/elite_crack.c \ loclass/fileutils.c \ whereami.c \ - mifarehost.c \ + mifare/mifarehost.c \ parity.c \ crc.c \ crc16.c \ @@ -155,7 +155,9 @@ CMDSRCS = crapto1/crapto1.c \ emv/test/dda_test.c\ emv/test/cda_test.c\ emv/cmdemv.c \ - mifare4.c \ + emv/emv_roca.c \ + mifare/mifare4.c \ + mifare/mad.c \ cmdanalyse.c \ cmdhf.c \ cmdhflist.c \ @@ -186,6 +188,7 @@ CMDSRCS = crapto1/crapto1.c \ cmdlfio.c \ cmdlfindala.c \ cmdlfjablotron.c \ + cmdlfkeri.c \ cmdlfnexwatch.c \ cmdlfnedap.c \ cmdlfnoralsy.c \ @@ -298,29 +301,29 @@ lualibs/mf_default_keys.lua : default_keys.dic clean: $(RM) $(CLEAN) - cd ../liblua && make clean - cd $(JANSSONLIBPATH) && make clean - cd $(MBEDTLSLIBPATH) && make clean - cd $(CBORLIBPATH) && make clean + cd ../liblua && $(MAKE) clean + cd $(JANSSONLIBPATH) && $(MAKE) clean + cd $(MBEDTLSLIBPATH) && $(MAKE) clean + cd $(CBORLIBPATH) && $(MAKE) clean tarbin: $(BINS) $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%) lua_build: @echo Compiling liblua, using platform $(LUAPLATFORM) - cd ../liblua && make $(LUAPLATFORM) + cd ../liblua && $(MAKE) $(LUAPLATFORM) jansson_build: @echo Compiling jansson - cd $(JANSSONLIBPATH) && make all + cd $(JANSSONLIBPATH) && $(MAKE) all mbedtls_build: @echo Compiling mbedtls - cd $(MBEDTLSLIBPATH) && make all + cd $(MBEDTLSLIBPATH) && $(MAKE) all cbor_build: @echo Compiling tinycbor - cd $(CBORLIBPATH) && make all + cd $(CBORLIBPATH) && $(MAKE) all .PHONY: all clean diff --git a/client/aidlist.json b/client/aidlist.json new file mode 100644 index 000000000..7ec139d46 --- /dev/null +++ b/client/aidlist.json @@ -0,0 +1 @@ +[{"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "315041592E5359532E4444463031", "Type": "", "Name": "Visa Payment System Environment - PSE (1PAY.SYS.DDF01)"}, {"Vendor": "Visa International", "Description": "Visa payWave for Mobile", "Country": "United States", "AID": "325041592E5359532E4444463031", "Type": "", "Name": "Visa Proximity Payment System Environment - PPSE (2PAY.SYS.DDF01)"}, {"Vendor": "DeviceFidelity", "Description": "http://www.nfcworld.com/2010/11/24/35207/devicefidelity-adds-nfc-support-for-android-and-mifare/", "Country": "United States", "AID": "44464D46412E44466172653234313031", "Type": "", "Name": "DeviceFidelity In2Pay DFare applet"}, {"Vendor": "PBS Danmnt A/S", "Description": "(Unlicensed use of this RID. Proposal to use A000000323 instead)", "Country": "Denmark", "AID": "A00000000101", "Type": "", "Name": "MUSCLE Card Applet"}, {"Vendor": "Visa International", "Description": "Used by most GP2.1.1 cards / Oberthur OP201 cards. Visa Proprietary Card Manager AID for OpenPlatform cards (visa.openplatform).", "Country": "United States", "AID": "A000000003000000", "Type": "GP", "Name": "(VISA) Card Manager"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A00000000300037561", "Type": "", "Name": "Bonuscard"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A00000000305076010", "Type": "EMV", "Name": "VISA ELO Credit"}, {"Vendor": "Visa International", "Description": "Standard/Gold VISA credit card", "Country": "United States", "AID": "A0000000031010", "Type": "EMV", "Name": "VISA Debit/Credit (Classic)"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A000000003101001", "Type": "EMV", "Name": "VISA Credit"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A000000003101002", "Type": "EMV", "Name": "VISA Debit"}, {"Vendor": "Visa International", "Description": "VISA Electron (Debit)", "Country": "United States", "AID": "A0000000032010", "Type": "EMV", "Name": "VISA Electron"}, {"Vendor": "Visa International", "Description": "V PAY", "Country": "United States", "AID": "A0000000032020", "Type": "EMV", "Name": "VISA"}, {"Vendor": "Visa International", "Description": "VISA Interlink", "Country": "United States", "AID": "A0000000033010", "Type": "EMV", "Name": "VISA Interlink"}, {"Vendor": "Visa International", "Description": "Visa Specific", "Country": "United States", "AID": "A0000000034010", "Type": "EMV", "Name": "VISA Specific"}, {"Vendor": "Visa International", "Description": "Visa Specific", "Country": "United States", "AID": "A0000000035010", "Type": "EMV", "Name": "VISA Specific"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A000000003534441", "Type": "GP", "Name": "Schlumberger Security Domain"}, {"Vendor": "Visa International", "Description": "OCS Oberthur Card System Security Domain Package AID / VGP Card Manager (for ISD and ASD)", "Country": "United States", "AID": "A0000000035350", "Type": "GP", "Name": "Security Domain"}, {"Vendor": "Visa International", "Description": "OCS Oberthur Card System Security Domain Applet AID / VGP Card Manager (for ISD and ASD)", "Country": "United States", "AID": "A000000003535041", "Type": "GP", "Name": "Security Domain"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A0000000036010", "Type": "EMV", "Name": "Domestic Visa Cash Stored Value"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A0000000036020", "Type": "EMV", "Name": "International Visa Cash Stored Value"}, {"Vendor": "Visa International", "Description": "VISA Auth dynamic passcode authentication (DPA). Used by Barclays/HBOS", "Country": "United States", "AID": "A0000000038002", "Type": "EMV", "Name": "VISA Auth, VisaRemAuthen EMV-CAP (DPA)"}, {"Vendor": "Visa International", "Description": "VISA plus", "Country": "United States", "AID": "A0000000038010", "Type": "EMV", "Name": "VISA Plus"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A0000000039010", "Type": "EMV", "Name": "VISA Loyalty"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A000000003999910", "Type": "EMV", "Name": "VISA Proprietary ATM"}, {"Vendor": "Mastercard International", "Description": "Security Domain", "Country": "United States", "AID": "A0000000040000", "Type": "GP", "Name": "MasterCard Card Manager"}, {"Vendor": "Mastercard International", "Description": "AEPM (Association Europenne Payez Mobile)", "Country": "United States", "AID": "A00000000401", "Type": "EMV", "Name": "MasterCard PayPass"}, {"Vendor": "Mastercard International", "Description": "Standard MasterCard", "Country": "United States", "AID": "A0000000041010", "Type": "EMV", "Name": "MasterCard Credit"}, {"Vendor": "Mastercard International", "Description": "Standard MasterCard", "Country": "United States", "AID": "A00000000410101213", "Type": "EMV", "Name": "MasterCard Credit"}, {"Vendor": "Mastercard International", "Description": "Standard MasterCard", "Country": "United States", "AID": "A00000000410101215", "Type": "EMV", "Name": "MasterCard Credit"}, {"Vendor": "Mastercard International", "Description": "Some co-branded card?", "Country": "United States", "AID": "A0000000041010BB5449435301", "Type": "", "Name": "[UNKNOWN]"}, {"Vendor": "Mastercard International", "Description": "MasterCard Specific", "Country": "United States", "AID": "A0000000042010", "Type": "EMV", "Name": "MasterCard Specific"}, {"Vendor": "Mastercard International", "Description": "MasterCard U.S. Maestro", "Country": "United States", "AID": "A0000000042203", "Type": "", "Name": "MasterCard Specific"}, {"Vendor": "Mastercard International", "Description": "MasterCard Specific", "Country": "United States", "AID": "A0000000043010", "Type": "EMV", "Name": "MasterCard Specific"}, {"Vendor": "Mastercard International", "Description": "Maestro (Debit) Card", "Country": "United States", "AID": "A0000000043060", "Type": "EMV", "Name": "Maestro (Debit)"}, {"Vendor": "Mastercard International", "Description": "Maestro (Debit) Card", "Country": "United States", "AID": "A000000004306001", "Type": "EMV", "Name": "Maestro (Debit)"}, {"Vendor": "Mastercard International", "Description": "MasterCard Specific", "Country": "United States", "AID": "A0000000044010", "Type": "EMV", "Name": "MasterCard Specific"}, {"Vendor": "Mastercard International", "Description": "MasterCard Specific", "Country": "United States", "AID": "A0000000045010", "Type": "EMV", "Name": "MasterCard Specific"}, {"Vendor": "Mastercard International", "Description": "AID on Cirrus Test Card", "Country": "United States", "AID": "A0000000045555", "Type": "", "Name": "APDULogger"}, {"Vendor": "Mastercard International", "Description": "Mastercard Cirrus (Interbank Network) ATM card only", "Country": "United States", "AID": "A0000000046000", "Type": "EMV", "Name": "Cirrus"}, {"Vendor": "Mastercard International", "Description": "Chip Authentication Protocol (CAP). Works with NatWest or SecureCode Aut", "Country": "United States", "AID": "A0000000048002", "Type": "EMV", "Name": "SecureCode Auth EMV-CAP"}, {"Vendor": "Mastercard International", "Description": "", "Country": "United States", "AID": "A0000000049999", "Type": "EMV", "Name": "MasterCard PayPass??"}, {"Vendor": "Switch Card Services Ltd.", "Description": "UK Domestic Maestro - Switch (debit card)", "Country": "United Kingdom", "AID": "A0000000050001", "Type": "EMV", "Name": "Maestro UK"}, {"Vendor": "Switch Card Services Ltd.", "Description": "UK Domestic Maestro - Switch (debit card)", "Country": "United Kingdom", "AID": "A0000000050002", "Type": "EMV", "Name": "Solo"}, {"Vendor": "ETSI", "Description": "Orange UK", "Country": "France", "AID": "A0000000090001FF44FF1289", "Type": "", "Name": "Orange"}, {"Vendor": "Europay International", "Description": "", "Country": "Belgium", "AID": "A0000000101030", "Type": "", "Name": "Maestro-CH"}, {"Vendor": "GEMPLUS", "Description": "", "Country": "France", "AID": "A00000001800", "Type": "", "Name": "Gemplus ?"}, {"Vendor": "GEMPLUS", "Description": "", "Country": "France", "AID": "A0000000181001", "Type": "", "Name": "com.gemplus.javacard.util packages"}, {"Vendor": "GEMPLUS", "Description": "434D = CM (ascii). Security domain for some GCX/GXP cards (GemXpresso Pro) (Gemalto)", "Country": "France", "AID": "A000000018434D", "Type": "GP", "Name": "Gemplus card manager"}, {"Vendor": "GEMPLUS", "Description": "(Gemalto)", "Country": "France", "AID": "A000000018434D00", "Type": "GP", "Name": "Gemplus Security Domain"}, {"Vendor": "Midland Bank Plc", "Description": "", "Country": "United Kingdom", "AID": "A00000002401", "Type": "EMV", "Name": "Self Service"}, {"Vendor": "American Express", "Description": "", "Country": "United Kingdom", "AID": "A000000025", "Type": "EMV", "Name": "American Express"}, {"Vendor": "American Express", "Description": "American Express (Credit/Debit)", "Country": "United Kingdom", "AID": "A0000000250000", "Type": "EMV", "Name": "American Express"}, {"Vendor": "American Express", "Description": "AEIPS-compliant (A-E contact EMV) payment application", "Country": "United Kingdom", "AID": "A00000002501", "Type": "EMV", "Name": "American Express"}, {"Vendor": "American Express", "Description": "", "Country": "United Kingdom", "AID": "A000000025010104", "Type": "", "Name": "American Express"}, {"Vendor": "American Express", "Description": "", "Country": "United Kingdom", "AID": "A000000025010402", "Type": "EMV", "Name": "American Express"}, {"Vendor": "American Express", "Description": "", "Country": "United Kingdom", "AID": "A000000025010701", "Type": "EMV", "Name": "ExpressPay"}, {"Vendor": "American Express", "Description": "", "Country": "United Kingdom", "AID": "A000000025010801", "Type": "EMV", "Name": "American Express"}, {"Vendor": "LINK Interchange Network Ltd", "Description": "Link (UK) ATM Network, or AMEX (Portugal?)", "Country": "United Kingdom", "AID": "A0000000291010", "Type": "EMV", "Name": "Link / American Express"}, {"Vendor": "LINK Interchange Network Ltd", "Description": "", "Country": "United Kingdom", "AID": "A00000002945087510100000", "Type": "", "Name": "CO-OP"}, {"Vendor": "LINK Interchange Network Ltd", "Description": "", "Country": "United Kingdom", "AID": "A00000002949034010100001", "Type": "", "Name": "HSBC"}, {"Vendor": "LINK Interchange Network Ltd", "Description": "", "Country": "United Kingdom", "AID": "A00000002949282010100000", "Type": "", "Name": "Barclay"}, {"Vendor": "LINK Interchange Network Ltd", "Description": "", "Country": "United Kingdom", "AID": "A000000029564182", "Type": "", "Name": "HAFX"}, {"Vendor": "Schlumberger Industries Identif d'Encarteur PR050", "Description": "Schlumberger (Gemalto) RID", "Country": "France", "AID": "A00000003029057000AD13100101FF", "Type": "", "Name": "BelPIC (Belgian Personal Identity Card) JavaCard Applet"}, {"Vendor": "Schlumberger Industries Identif d'Encarteur PR050", "Description": "", "Country": "France", "AID": "A0000000308000000000280101", "Type": "", "Name": "Gemalto .NET Card AID"}, {"Vendor": "Groupement des Cartes Bancaires \"CB\"", "Description": "Groupement des Cartes Bancaires (France)", "Country": "France", "AID": "A0000000421010", "Type": "EMV", "Name": "Cartes Bancaire EMV Card"}, {"Vendor": "Groupement des Cartes Bancaires \"CB\"", "Description": "", "Country": "France", "AID": "A0000000422010", "Type": "EMV", "Name": ""}, {"Vendor": "Groupement des Cartes Bancaires \"CB\"", "Description": "", "Country": "France", "AID": "A0000000423010", "Type": "EMV", "Name": ""}, {"Vendor": "Groupement des Cartes Bancaires \"CB\"", "Description": "", "Country": "France", "AID": "A0000000424010", "Type": "EMV", "Name": ""}, {"Vendor": "Groupement des Cartes Bancaires \"CB\"", "Description": "", "Country": "France", "AID": "A0000000425010", "Type": "EMV", "Name": ""}, {"Vendor": "Zentraler Kreditausschuss (ZKA)", "Description": "", "Country": "Germany", "AID": "A00000005945430100", "Type": "", "Name": "Girocard Electronic Cash"}, {"Vendor": "RSA Laboratories", "Description": "RSA PKCS-15 PKI application (Predecessor to ISO7816-15) / ID-card in Finland", "Country": "United States", "AID": "A000000063504B43532D3135", "Type": "", "Name": "PKCS-15"}, {"Vendor": "RSA Laboratories", "Description": "WAP (Wireless Application Protocol) Identity Module / Wireless Identification Module", "Country": "United States", "AID": "A0000000635741502D57494D", "Type": "", "Name": "WAP-WIM"}, {"Vendor": "JCB CO., LTD.", "Description": "Japan Credit Bureau", "Country": "Japan", "AID": "A00000006510", "Type": "EMV", "Name": "JCB"}, {"Vendor": "JCB CO., LTD.", "Description": "Japan Credit Bureau", "Country": "Japan", "AID": "A0000000651010", "Type": "EMV", "Name": "JCB J Smart Credit"}, {"Vendor": "Socit Europenne de Monnaie Electronique SEME", "Description": "", "Country": "France", "AID": "A00000006900", "Type": "EMV", "Name": "Moneo"}, {"Vendor": "Oberthur Technologies", "Description": "", "Country": "France", "AID": "A000000077010000021000000000003B", "Type": "EMV", "Name": "Visa AEPN"}, {"Vendor": "Activcard Europe S.A.", "Description": "Identity Key", "Country": "France", "AID": "A0000000790100", "Type": "", "Name": "CACv2 PKI ID"}, {"Vendor": "Activcard Europe S.A.", "Description": "Digital Signature Key", "Country": "France", "AID": "A0000000790101", "Type": "", "Name": "CACv2 PKI Sign"}, {"Vendor": "Activcard Europe S.A.", "Description": "Key Management Key", "Country": "France", "AID": "A0000000790102", "Type": "", "Name": "CACv2 PKI Enc"}, {"Vendor": "Activcard Europe S.A.", "Description": "Re-directs to CACv2 PKI Identity key", "Country": "France", "AID": "A00000007901F0", "Type": "", "Name": "CACv1 PKI Identity Key"}, {"Vendor": "Activcard Europe S.A.", "Description": "Re-directs to CACv2 Digital Signature key", "Country": "France", "AID": "A00000007901F1", "Type": "", "Name": "CACv1 PKI Digital Signature Key"}, {"Vendor": "Activcard Europe S.A.", "Description": "Re-directs to CACv2 Key Management key", "Country": "France", "AID": "A00000007901F2", "Type": "", "Name": "CACv1 PKI Key Management Key"}, {"Vendor": "Activcard Europe S.A.", "Description": "DoD Demographic", "Country": "France", "AID": "A0000000790200", "Type": "", "Name": "CACv2 DoD Person"}, {"Vendor": "Activcard Europe S.A.", "Description": "DoD Demographic", "Country": "France", "AID": "A0000000790201", "Type": "", "Name": "CACv2 DoD Personnel"}, {"Vendor": "Activcard Europe S.A.", "Description": "General Configuration", "Country": "France", "AID": "A00000007902FB", "Type": "", "Name": "CACv1 BC"}, {"Vendor": "Activcard Europe S.A.", "Description": "PKI Certificate Attributes", "Country": "France", "AID": "A00000007902FD", "Type": "", "Name": "CACv1 BC"}, {"Vendor": "Activcard Europe S.A.", "Description": "PKI Cert", "Country": "France", "AID": "A00000007902FE", "Type": "", "Name": "CACv1 BC"}, {"Vendor": "Activcard Europe S.A.", "Description": "CAC PIN / ID PIN Management Applet", "Country": "France", "AID": "A0000000790300", "Type": "", "Name": "CACv2 Access Control Applet"}, {"Vendor": "Activcard Europe S.A.", "Description": "Joint Data Model. BCAdmin", "Country": "France", "AID": "A0000000791201", "Type": "", "Name": "CAC JDM"}, {"Vendor": "Activcard Europe S.A.", "Description": "Joint Data Model. BCMedical", "Country": "France", "AID": "A0000000791202", "Type": "", "Name": "CAC JDM"}, {"Vendor": "Third Generation Partnership Project (3GPP)", "Description": "", "Country": "France", "AID": "A0000000871002FF49FF0589", "Type": "USIM", "Name": "Telenor USIM"}, {"Vendor": "Buypass AS", "Description": "Used by norwegian public betting company Norsk-Tipping?", "Country": "Norway", "AID": "A00000008810200105C100", "Type": "BuyPass", "Name": "BuyPass BIDA"}, {"Vendor": "Buypass AS", "Description": "", "Country": "Norway", "AID": "A000000088102201034221", "Type": "BuyPass", "Name": "BuyPass BEID (BuyPass Electronic ID?)"}, {"Vendor": "Buypass AS", "Description": "", "Country": "Norway", "AID": "A000000088102201034321", "Type": "BuyPass", "Name": "BuyPass BEID (BuyPass Electronic ID?)"}, {"Vendor": "Sa Proton World International N.V.", "Description": "Proton, which is owned in part by Visa International and American Express Co., is in three other European countries: the original Proton program in Belgium, Chipknip in the Netherlands, and Cash in Switzerland", "Country": "Belgium", "AID": "A0000000960200", "Type": "GP", "Name": "Proton World International Security Domain"}, {"Vendor": "Visa USA", "Description": "Bank of America Debit Card", "Country": "United States", "AID": "A000000098", "Type": "EMV", "Name": "Debit Card"}, {"Vendor": "Visa USA", "Description": "", "Country": "United States", "AID": "A0000000980840", "Type": "", "Name": "Visa Common Debit"}, {"Vendor": "Visa USA", "Description": "Schwab Bank Debit Card", "Country": "United States", "AID": "A0000000980848", "Type": "EMV", "Name": "Debit Card"}, {"Vendor": "Die Post Postfinance", "Description": "", "Country": "Switzerland", "AID": "A0000001110101", "Type": "", "Name": "Postcard"}, {"Vendor": "GSA - TFCS", "Description": "CHUID", "Country": "United States", "AID": "A0000001160300", "Type": "", "Name": "PIV CHUID"}, {"Vendor": "GSA - TFCS", "Description": "Fingerprints", "Country": "United States", "AID": "A0000001166010", "Type": "", "Name": "PIV Fingerprints"}, {"Vendor": "GSA - TFCS", "Description": "Facial Image", "Country": "United States", "AID": "A0000001166030", "Type": "", "Name": "PIV Facial Image"}, {"Vendor": "GSA - TFCS", "Description": "Security Object", "Country": "United States", "AID": "A0000001169000", "Type": "", "Name": "PIV Security Object"}, {"Vendor": "GSA - TFCS", "Description": "PIV Authentication Key", "Country": "United States", "AID": "A000000116A001", "Type": "", "Name": "PIV Authentication Key"}, {"Vendor": "GSA - TFCS", "Description": "Card Capability Container", "Country": "United States", "AID": "A000000116DB00", "Type": "", "Name": "CCC"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.3)", "Country": "Austria", "AID": "A000000118010000", "Type": "", "Name": "DF_Verkehr"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.3)", "Country": "Austria", "AID": "A000000118020000", "Type": "", "Name": "DF_Partner"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.3)", "Country": "Austria", "AID": "A000000118030000", "Type": "", "Name": "DF_Schlerdaten"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.32)", "Country": "Austria", "AID": "A000000118040000", "Type": "", "Name": "DF_KEP_SIG"}, {"Vendor": "Austria Card", "Description": "Digital Signature Application", "Country": "Austria", "AID": "A0000001184543", "Type": "", "Name": "Digital Signature (SSCA)"}, {"Vendor": "Austria Card", "Description": "Encryption Application (Version 1.10)", "Country": "Austria", "AID": "A000000118454E", "Type": "", "Name": "Encryption Application"}, {"Vendor": "PBS Danmark A/S", "Description": "Danish domestic debit card", "Country": "Denmark", "AID": "A0000001211010", "Type": "EMV", "Name": "Dankort (VISA GEM Vision)"}, {"Vendor": "Java Card Forum", "Description": "", "Country": "United States", "AID": "A0000001320001", "Type": "", "Name": "org.javacardforum.javacard.biometry"}, {"Vendor": "TDS TODOS DATA SYSTEM AB", "Description": "", "Country": "Sweden", "AID": "A0000001408001", "Type": "", "Name": "eCode"}, {"Vendor": "Associazione Bancaria Italiana", "Description": "CoGeBan Consorzio BANCOMAT (Italian domestic debit card)", "Country": "Italy", "AID": "A0000001410001", "Type": "EMV", "Name": "PagoBANCOMAT"}, {"Vendor": "GlobalPlatform, Inc.", "Description": "GP Card Manager", "Country": "United States", "AID": "A0000001510000", "Type": "GP", "Name": "Global Platform Security Domain AID"}, {"Vendor": "GlobalPlatform, Inc.", "Description": "SPCASD", "Country": "United States", "AID": "A00000015153504341534400", "Type": "GP", "Name": "CASD_AID"}, {"Vendor": "Diners Club International Ltd.", "Description": "Discover Card", "Country": "United States", "AID": "A0000001523010", "Type": "EMV", "Name": "Discover, Pulse D Pas"}, {"Vendor": "Diners Club International Ltd.", "Description": "Discover Debit Common Card", "Country": "United States", "AID": "A0000001524010", "Type": "EMV", "Name": "Discover"}, {"Vendor": "Banrisul - Banco do Estado do Rio Grande do SUL - S.A.", "Description": "Banrisul (Brazil)", "Country": "Brazil", "AID": "A0000001544442", "Type": "EMV", "Name": "Banricompras Debito"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570010", "Type": "", "Name": "AMEX"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570020", "Type": "", "Name": "MasterCard"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570021", "Type": "", "Name": "Maestro"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570022", "Type": "", "Name": "Maestro"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570023", "Type": "", "Name": "CASH"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570030", "Type": "", "Name": "VISA"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570031", "Type": "", "Name": "VISA"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570040", "Type": "", "Name": "JCB"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570050", "Type": "", "Name": "Postcard"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570051", "Type": "", "Name": "Postcard"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570100", "Type": "", "Name": "MCard"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570104", "Type": "", "Name": "MyOne"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570109", "Type": "", "Name": "Mediamarkt Card"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A000000157010A", "Type": "", "Name": "Gift Card"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A000000157010B", "Type": "", "Name": "Bonuscard"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A000000157010C", "Type": "", "Name": "WIRCard"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A000000157010D", "Type": "", "Name": "Power Card"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001574443", "Type": "", "Name": "DINERS CLUB"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001574444", "Type": "", "Name": "Supercard Plus"}, {"Vendor": "IBM", "Description": "identify in JCOP-tools returns eg 27 34 01 2E 00 00 00 00 4E 58 37 35 31 41 00 03 28 62 B3 6A 82", "Country": "Germany", "AID": "A000000167413000FF", "Type": "JCOP", "Name": "JCOP Identify Applet"}, {"Vendor": "IBM", "Description": "?", "Country": "Germany", "AID": "A000000167413001", "Type": "", "Name": "FIPS 140-2"}, {"Vendor": "Financial Information Service Co. Ltd.", "Description": "The Bankers Association of the Republic of China", "Country": "Taiwan", "AID": "A000000172950001", "Type": "EMV", "Name": "BAROC Financial Application Taiwan"}, {"Vendor": "Ministre de L'Intrieur", "Description": "", "Country": "Belgium", "AID": "A000000177504B43532D3135", "Type": "", "Name": "BelPIC (Belgian Personal Identity Card)"}, {"Vendor": "Post Office Limited", "Description": "", "Country": "United Kingdom", "AID": "A0000001850002", "Type": "EMV", "Name": "UK Post Office Account card"}, {"Vendor": "Diners Club Switzerland Ltd", "Description": "", "Country": "Switzerland", "AID": "A0000001884443", "Type": "", "Name": "DINERS CLUB"}, {"Vendor": "Association for Payment Clearing Services", "Description": "", "Country": "United Kingdom", "AID": "A0000002040000", "Type": "", "Name": "?"}, {"Vendor": "Saudi Arabian Monetary Agency (SAMA)", "Description": "SPAN2 (Saudi Payments Network) - Saudi Arabia domestic credit/debit card (Saudi Arabia Monetary Agency)", "Country": "Kingdom of Saudi Arabia", "AID": "A0000002281010", "Type": "EMV", "Name": "SPAN (M/Chip)"}, {"Vendor": "Saudi Arabian Monetary Agency (SAMA)", "Description": "SPAN2 (Saudi Payments Network) - Saudi Arabia domestic credit/debit card (Saudi Arabia Monetary Agency)", "Country": "Kingdom of Saudi Arabia", "AID": "A0000002282010", "Type": "EMV", "Name": "SPAN (VIS)"}, {"Vendor": "Saudi Arabian Monetary Agency (SAMA)", "Description": "SPAN2 (Saudi Payments Network) - Saudi Arabia domestic credit/debit card (Saudi Arabia Monetary Agency)", "Country": "Kingdom of Saudi Arabia", "AID": "A00000022820101010", "Type": "", "Name": "SPAN"}, {"Vendor": "ISO JTC1/SC17/WG3", "Description": "Electronic (Biometric) Passport. Issuer stored data application (The last three digits of the PIX shall be used to denote future version levels.)", "Country": "United Kingdom", "AID": "A0000002471001", "Type": "MRTD", "Name": "Machine Readable Travel Documents (MRTD)"}, {"Vendor": "ISO JTC1/SC17/WG3", "Description": "Electronic (Biometric) Passport. Application for hashes, digital signature, and certificate (The last three digits of the PIX shall be used to denote future version levels.)", "Country": "United Kingdom", "AID": "A0000002472001", "Type": "MRTD", "Name": "Machine Readable Travel Documents (MRTD)"}, {"Vendor": "Interac Association", "Description": "Canadian domestic credit/debit card", "Country": "Canada", "AID": "A0000002771010", "Type": "EMV", "Name": "INTERAC"}, {"Vendor": "PS/SC Workgroup", "Description": "Possibly not an application...", "Country": "United States", "AID": "A00000030600000000000000", "Type": "", "Name": "PC/SC Initial access data AID"}, {"Vendor": "National Institute of Standards and Technology", "Description": "PIV End Point Applet. Last 2 bytes designate version?", "Country": "United States", "AID": "A000000308000010000100", "Type": "", "Name": "Personal Identity Verification (PIV) / ID-ONE PIV BIO"}, {"Vendor": "Currence Holding/PIN BV", "Description": "", "Country": "The Netherlands", "AID": "A00000031510100528", "Type": "EMV", "Name": "Currence PuC"}, {"Vendor": "Currence Holding/PIN BV", "Description": "", "Country": "The Netherlands", "AID": "A0000003156020", "Type": "EMV", "Name": "Chipknip"}, {"Vendor": "Identity Alliance", "Description": "http://osdir.com/ml/lib.muscle/2005-12/msg00066.html", "Country": "United States", "AID": "A00000032301", "Type": "", "Name": "MUSCLE Applet Package"}, {"Vendor": "Identity Alliance", "Description": "http://osdir.com/ml/lib.muscle/2005-12/msg00066.html", "Country": "United States", "AID": "A0000003230101", "Type": "", "Name": "MUSCLE Applet Instance"}, {"Vendor": "Discover Financial Services LLC", "Description": "", "Country": "United States", "AID": "A0000003241010", "Type": "", "Name": "Discover Expresspay (ZIP)"}, {"Vendor": "China Unionpay Co. Ltd", "Description": "", "Country": "China", "AID": "A000000333010101", "Type": "", "Name": "UnionPay Debit"}, {"Vendor": "China Unionpay Co. Ltd", "Description": "", "Country": "China", "AID": "A000000333010102", "Type": "", "Name": "UnionPay Credit"}, {"Vendor": "China Unionpay Co. Ltd", "Description": "", "Country": "China", "AID": "A000000333010103", "Type": "", "Name": "UnionPay Quasi Credit"}, {"Vendor": "China Unionpay Co. Ltd", "Description": "", "Country": "China", "AID": "A000000333010106", "Type": "", "Name": "UnionPay Electronic Cash"}, {"Vendor": "China Unionpay Co. Ltd", "Description": "", "Country": "China", "AID": "A000000333010108", "Type": "", "Name": "U.S. UnionPay Common Debit AID"}, {"Vendor": "Euro Alliance of Payment Schemes s.c.r.l. - EAPS", "Description": "Unknown", "Country": "Belgium", "AID": "A0000003591010", "Type": "", "Name": ""}, {"Vendor": "Euro Alliance of Payment Schemes s.c.r.l. - EAPS", "Description": "ZKA (Germany)", "Country": "Belgium", "AID": "A0000003591010028001", "Type": "EMV", "Name": "Girocard EAPS"}, {"Vendor": "Euro Alliance of Payment Schemes s.c.r.l. - EAPS", "Description": "PagoBANCOMAT", "Country": "Belgium", "AID": "A00000035910100380", "Type": "", "Name": ""}, {"Vendor": "Poste Italiane S.P.A", "Description": "", "Country": "Italy", "AID": "A0000003660001", "Type": "", "Name": "Postamat"}, {"Vendor": "Poste Italiane S.P.A", "Description": "", "Country": "Italy", "AID": "A0000003660002", "Type": "", "Name": "Postamat VISA"}, {"Vendor": "Interswitch Limited", "Description": "Nigerian local switch company", "Country": "Nigeria", "AID": "A0000003710001", "Type": "EMV", "Name": "InterSwitch Verve Card"}, {"Vendor": "NXP Semiconductors Germany GmbH", "Description": "NXP Mf4M", "Country": "Germany", "AID": "A0000003964D66344D0002", "Type": "", "Name": "MIFARE4MOBILE"}, {"Vendor": "Microsoft Corporation", "Description": "Identity Device With Microsoft Generic Profile application. 2 bytes can be added at the end. This byte must be set to the IDMP specification revision number which is currently 0x01. The second byte (yy) is reserved for use by the card application.", "Country": "United States", "AID": "A00000039742544659", "Type": "", "Name": "Microsoft IDMP AID"}, {"Vendor": "Microsoft Corporation", "Description": "MS Plug and Play", "Country": "United States", "AID": "A0000003974349445F0100", "Type": "", "Name": "Microsoft PNP AID"}, {"Vendor": "Unibanco (Hipercard)", "Description": "", "Country": "Brazil", "AID": "A0000004271010", "Type": "", "Name": "Hiperchip"}, {"Vendor": "100", "Description": "", "Country": "Russia", "AID": "A0000004320001", "Type": "", "Name": "Universal Electronic Card"}, {"Vendor": "Edenred", "Description": "", "Country": "Belgium", "AID": "A0000004360100", "Type": "", "Name": "Ticket Restaurant"}, {"Vendor": "ACCEL/Exchange", "Description": "The Exchange Network ATM Network", "Country": "United States", "AID": "A0000004391010", "Type": "", "Name": "Exchange ATM card"}, {"Vendor": "eTranzact", "Description": "Nigerian local switch company", "Country": "Nigeria", "AID": "A0000004540010", "Type": "EMV", "Name": "Etranzact Genesis Card"}, {"Vendor": "eTranzact", "Description": "Nigerian local switch company", "Country": "Nigeria", "AID": "A0000004540011", "Type": "EMV", "Name": "Etranzact Genesis Card 2"}, {"Vendor": "Google", "Description": "GOOGLE_LOCKET_AID", "Country": "United States", "AID": "A0000004762010", "Type": "", "Name": "GOOGLE_CONTROLLER_AID"}, {"Vendor": "Google", "Description": "", "Country": "United States", "AID": "A0000004763030", "Type": "", "Name": "GOOGLE_MIFARE_MANAGER_AID"}, {"Vendor": "Google", "Description": "", "Country": "United States", "AID": "A0000004766C", "Type": "EMV", "Name": "GOOGLE_PAYMENT_AID"}, {"Vendor": "Google", "Description": "", "Country": "United States", "AID": "A000000476A010", "Type": "GP", "Name": "GSD_MANAGER_AID"}, {"Vendor": "Google", "Description": "", "Country": "United States", "AID": "A000000476A110", "Type": "GP", "Name": "GSD_MANAGER_AID"}, {"Vendor": "JVL Ventures, LLC (Softcard)", "Description": "", "Country": "United States", "AID": "A000000485", "Type": "", "Name": "Softcard SmartTap"}, {"Vendor": "RuPay", "Description": "RuPay (India)", "Country": "India", "AID": "A0000005241010", "Type": "EMV", "Name": "RuPay"}, {"Vendor": "Yubico", "Description": "Universal 2-Factor Proof-of-concept/Demo", "Country": "Sweden", "AID": "A0000005271002", "Type": "YKNEO", "Name": "Yubikey NEO U2F Demo applet"}, {"Vendor": "Yubico", "Description": "Javacard Applet AID", "Country": "Sweden", "AID": "A000000527200101", "Type": "YKNEO", "Name": "Yubikey NEO Yubikey2 applet interface"}, {"Vendor": "Yubico", "Description": "Javacard Applet AID", "Country": "Sweden", "AID": "A000000527210101", "Type": "YKNEO", "Name": "Yubikey NEO OATH Applet"}, {"Vendor": "GSMA (GSM Association)", "Description": "", "Country": "United Kingdom", "AID": "A0000005591010FFFFFFFF8900000100", "Type": "", "Name": "ISD-R Application. Used as TAR."}, {"Vendor": "GSMA (GSM Association)", "Description": "", "Country": "United Kingdom", "AID": "A0000005591010FFFFFFFF8900000200", "Type": "", "Name": "ECASD Application. Used as TAR."}, {"Vendor": "GSMA (GSM Association)", "Description": "", "Country": "United Kingdom", "AID": "A0000005591010FFFFFFFF8900000D00", "Type": "", "Name": "ISD-P Executable Load File."}, {"Vendor": "GSMA (GSM Association)", "Description": "", "Country": "United Kingdom", "AID": "A0000005591010FFFFFFFF8900000E00", "Type": "", "Name": "ISD-P Executable Module."}, {"Vendor": "GSMA (GSM Association)", "Description": "", "Country": "United Kingdom", "AID": "A0000005591010FFFFFFFF8900000F00", "Type": "", "Name": "Reserved value for the Profile's ISD-P"}, {"Vendor": "GSMA (GSM Association)", "Description": "", "Country": "United Kingdom", "AID": "A0000005591010FFFFFFFF8900001000", "Type": "", "Name": "ISD-P Application ('1010FFFFFFFF89000010' to '1010FFFFFFFF8900FFFF'. Used as TAR. The value is allocated during the 'Profile Download and Installation procedure'"}, {"Vendor": "Fidesmo", "Description": "", "Country": "Sweden", "AID": "A00000061700", "Type": "", "Name": "Fidesmo javacard"}, {"Vendor": "Debit Network Alliance (DNA)", "Description": "Common U.S. Debit", "Country": "United States", "AID": "A0000006200620", "Type": "", "Name": "Debit Network Alliance (DNA)"}, {"Vendor": "MIR", "Description": "", "Country": "Russia", "AID": "A0000006581010", "Type": "", "Name": "MIR Credit"}, {"Vendor": "MIR", "Description": "", "Country": "Russia", "AID": "A0000006582010", "Type": "", "Name": "MIR Debit"}, {"Vendor": "TROY", "Description": "Turkey's Payment Method", "Country": "Turkey", "AID": "A0000006723010", "Type": "EMV", "Name": "TROY chip credit card"}, {"Vendor": "TROY", "Description": "Turkey's Payment Method", "Country": "Turkey", "AID": "A0000006723020", "Type": "EMV", "Name": "TROY chip debit card"}, {"Vendor": "Indian Oil Corporation Limited", "Description": "Indian Oils Pre Paid Program", "Country": "India", "AID": "A0000007705850", "Type": "EMV", "Name": "XTRAPOWER Fleet Card Program"}, {"Vendor": "MasterCard International", "Description": "Used for development", "Country": "United States", "AID": "B012345678", "Type": "EMV", "Name": "Maestro TEST"}, {"Vendor": "Paylife", "Description": "Domestic Payment System (Version 2.1)", "Country": "Austria", "AID": "D040000001000002", "Type": "", "Name": "Paylife Quick (IEP). Preloaded Electronic Purse"}, {"Vendor": "Austria Card", "Description": "Domestic Payment System (Version 2.1)", "Country": "Austria", "AID": "D040000002000002", "Type": "", "Name": "RFU"}, {"Vendor": "Austria Card", "Description": "Domestic Payment System (Version 2.1)", "Country": "Austria", "AID": "D040000003000002", "Type": "", "Name": "POS"}, {"Vendor": "Austria Card", "Description": "Domestic Payment System (Version 2.1)", "Country": "Austria", "AID": "D040000004000002", "Type": "", "Name": "ATM"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.1)", "Country": "Austria", "AID": "D04000000B000002", "Type": "", "Name": "Retail"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.1)", "Country": "Austria", "AID": "D04000000C000002", "Type": "", "Name": "Bank_Data"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.1)", "Country": "Austria", "AID": "D04000000D000002", "Type": "", "Name": "Shopping"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.0)", "Country": "Austria", "AID": "D040000013000001", "Type": "", "Name": "DF_UNI_Kepler1"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.3)", "Country": "Austria", "AID": "D040000013000001", "Type": "", "Name": "DF_Schler1"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.0)", "Country": "Austria", "AID": "D040000013000002", "Type": "", "Name": "DF_UNI_Kepler2"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.3)", "Country": "Austria", "AID": "D040000013000002", "Type": "", "Name": "DF_Schler2"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.0)", "Country": "Austria", "AID": "D040000014000001", "Type": "", "Name": "DF_Mensa"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.0)", "Country": "Austria", "AID": "D040000015000001", "Type": "", "Name": "DF_UNI_Ausweis"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.3)", "Country": "Austria", "AID": "D040000015000001", "Type": "", "Name": "DF_Ausweis"}, {"Vendor": "Austria Card", "Description": "Domestic EMV Application (Version 2.1)", "Country": "Austria", "AID": "D0400000190001", "Type": "", "Name": "EMV ATM Maestro"}, {"Vendor": "Austria Card", "Description": "Domestic EMV Application (Version 2.1)", "Country": "Austria", "AID": "D0400000190002", "Type": "", "Name": "EMV POS Maestro"}, {"Vendor": "Austria Card", "Description": "Domestic EMV Application (Version 2.1)", "Country": "Austria", "AID": "D0400000190003", "Type": "", "Name": "EMV ATM MasterCard"}, {"Vendor": "Austria Card", "Description": "Domestic EMV Application (Version 2.1)", "Country": "Austria", "AID": "D0400000190004", "Type": "", "Name": "EMV POS MasterCard"}, {"Vendor": "Austria Card", "Description": "Domestic Payment System (Version 2.1)", "Country": "Austria", "AID": "D0400000190010", "Type": "", "Name": "Digital ID"}, {"Vendor": "Ministry of Finance of Georgia", "Description": "Georgia Revenue Service application for fiscal cash registers", "Country": "Georgia", "AID": "D268000001", "Type": "", "Name": "Fiscal module application"}, {"Vendor": "Giesecke&Devrient", "Description": "Giesecke & Devrient", "Country": "Germany", "AID": "D276000005", "Type": "", "Name": ""}, {"Vendor": "Giesecke&Devrient", "Description": "", "Country": "Germany", "AID": "D276000005AA040360010410", "Type": "", "Name": "G D App Nokia 6212"}, {"Vendor": "Giesecke&Devrient", "Description": "", "Country": "Germany", "AID": "D276000005AA0503E00401", "Type": "", "Name": "G D App Nokia 6212"}, {"Vendor": "Giesecke&Devrient", "Description": "", "Country": "Germany", "AID": "D276000005AA0503E00501", "Type": "", "Name": "G D App Nokia 6212"}, {"Vendor": "Giesecke&Devrient", "Description": "", "Country": "Germany", "AID": "D276000005AA0503E0050101", "Type": "", "Name": "G D App Nokia 6212"}, {"Vendor": "Giesecke&Devrient", "Description": "", "Country": "Germany", "AID": "D276000005AB0503E0040101", "Type": "", "Name": "G D App Nokia 6212"}, {"Vendor": "IBM Laboratories", "Description": "IBM Test card from the book 'Smart Card Application Development Using Java'", "Country": "Germany", "AID": "D27600002200000001", "Type": "", "Name": "SCT LOYALTY"}, {"Vendor": "IBM Laboratories", "Description": "IBM Test card from the book 'Smart Card Application Development Using Java'", "Country": "Germany", "AID": "D27600002200000002", "Type": "", "Name": "BUSINESS CARD"}, {"Vendor": "IBM Laboratories", "Description": "IBM Test card from the book 'Smart Card Application Development Using Java'", "Country": "Germany", "AID": "D27600002200000060", "Type": "", "Name": "PKCS#11 Token"}, {"Vendor": "ZKA", "Description": "Girocard (Geldkarte) in Germany", "Country": "Germany", "AID": "D276000025", "Type": "", "Name": "Girocard"}, {"Vendor": "ZKA", "Description": "Unknown", "Country": "Germany", "AID": "D27600002545410100", "Type": "", "Name": ""}, {"Vendor": "ZKA", "Description": "ZKA Girocard (Geldkarte) (Germany)", "Country": "Germany", "AID": "D27600002545500100", "Type": "EMV", "Name": "Girocard"}, {"Vendor": "ZKA", "Description": "", "Country": "Germany", "AID": "D27600002547410100", "Type": "", "Name": "Girocard ATM"}, {"Vendor": "Wolfgang Rankl", "Description": "", "Country": "Germany", "AID": "D276000060", "Type": "", "Name": ""}, {"Vendor": "NXP Semiconductors / NFC Forum", "Description": "NFC Forum Type 4 Tag", "Country": "Germany", "AID": "D2760000850100", "Type": "", "Name": "NDEF Tag Application / Mifare DESFire Tag Application"}, {"Vendor": "NXP Semiconductors / NFC Forum", "Description": "NFC Tag type 4 tag", "Country": "Germany", "AID": "D2760000850101", "Type": "", "Name": "NDEF Tag Application"}, {"Vendor": "Giesecke&Devrient Java Card Telecommunikation", "Description": "", "Country": "Germany", "AID": "D276000118", "Type": "", "Name": ""}, {"Vendor": "Giesecke&Devrient Java Card Telecommunikation", "Description": "Devrient Test Applet?", "Country": "Germany", "AID": "D2760001180101", "Type": "", "Name": "Giesecke &"}, {"Vendor": "fsfEurope", "Description": "For selection when not knowing the exact full AID", "Country": "Germany", "AID": "D27600012401", "Type": "OpenPGP", "Name": "OpenPGP Card"}, {"Vendor": "fsfEurope", "Description": "Version 1", "Country": "Germany", "AID": "D276000124010101FFFF000000010000", "Type": "OpenPGP", "Name": "OpenPGP Card"}, {"Vendor": "fsfEurope", "Description": "Version 2", "Country": "Germany", "AID": "D2760001240102000000000000010000", "Type": "OpenPGP", "Name": "OpenPGP Card"}, {"Vendor": "fsfEurope", "Description": "http://smartchess.de/englisch/SmartChess_1.0.pdf", "Country": "Germany", "AID": "D27600012402", "Type": "SmartChess", "Name": "SmartChess"}, {"Vendor": "fsfEurope", "Description": "http://smartchess.de/englisch/SmartChess_1.0.pdf", "Country": "Germany", "AID": "D2760001240200010000000000000000", "Type": "SmartChess", "Name": "SmartChess"}, {"Vendor": "", "Description": "", "Country": "Republic of Korea", "AID": "D4100000011010", "Type": "", "Name": ""}, {"Vendor": "", "Description": "(Netherlands)", "Country": "The Netherlands", "AID": "D5280050218002", "Type": "EMV", "Name": "?"}, {"Vendor": "Bankaxept", "Description": "Norwegian domestic debit card", "Country": "Norway", "AID": "D5780000021010", "Type": "EMV", "Name": "Bankaxept"}, {"Vendor": "Swiss Travel Fund (Reka)", "Description": "prepaid functional debit card", "Country": "Switzerland", "AID": "D7560000010101", "Type": "", "Name": "Reka Card"}, {"Vendor": "Migros (FCM, GE Money Bank and MasterCard)", "Description": "", "Country": "Switzerland", "AID": "D7560000300101", "Type": "", "Name": "M Budget"}, {"Vendor": "", "Description": "German eID", "Country": "", "AID": "E80704007F00070302", "Type": "", "Name": "nPA"}, {"Vendor": "", "Description": "", "Country": "", "AID": "E82881C11702", "Type": "", "Name": "AlphaCard application"}, {"Vendor": "", "Description": "Iso adoption of PKCS-15", "Country": "", "AID": "E828BD080F", "Type": "", "Name": "ISO-7816-15 EF.DIR"}, {"Vendor": "", "Description": "Brazilian Bank Banco Bradesco", "Country": "", "AID": "F0000000030001", "Type": "EMV", "Name": "BRADESCO"}] \ No newline at end of file diff --git a/client/amiitool/LICENSE b/client/amiitool/LICENSE new file mode 100644 index 000000000..35627b40f --- /dev/null +++ b/client/amiitool/LICENSE @@ -0,0 +1,21 @@ +(c) 2015-2017 Marcos Del Sol Vives +(c) 2016 javiMaD +(c) 2016 Michael Armbruster + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/client/amiitool/amiibo.c b/client/amiitool/amiibo.c new file mode 100644 index 000000000..6391ae830 --- /dev/null +++ b/client/amiitool/amiibo.c @@ -0,0 +1,180 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * (c) 2016 javiMaD + * + * SPDX-License-Identifier: MIT + */ + +#include "amiibo.h" +#include "mbedtls/md.h" +#include "mbedtls/aes.h" + +#define HMAC_POS_DATA 0x008 +#define HMAC_POS_TAG 0x1B4 + +void nfc3d_amiibo_calc_seed(const uint8_t * dump, uint8_t * key) { + memcpy(key + 0x00, dump + 0x029, 0x02); + memset(key + 0x02, 0x00, 0x0E); + memcpy(key + 0x10, dump + 0x1D4, 0x08); + memcpy(key + 0x18, dump + 0x1D4, 0x08); + memcpy(key + 0x20, dump + 0x1E8, 0x20); +} + +void nfc3d_amiibo_keygen(const nfc3d_keygen_masterkeys * masterKeys, const uint8_t * dump, nfc3d_keygen_derivedkeys * derivedKeys) { + uint8_t seed[NFC3D_KEYGEN_SEED_SIZE]; + + nfc3d_amiibo_calc_seed(dump, seed); + nfc3d_keygen(masterKeys, seed, derivedKeys); +} + +void nfc3d_amiibo_cipher(const nfc3d_keygen_derivedkeys * keys, const uint8_t * in, uint8_t * out) { + mbedtls_aes_context aes; + size_t nc_off = 0; + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; + + mbedtls_aes_setkey_enc( &aes, keys->aesKey, 128 ); + memset(nonce_counter, 0, sizeof(nonce_counter)); + memset(stream_block, 0, sizeof(stream_block)); + memcpy(nonce_counter, keys->aesIV, sizeof(nonce_counter)); + mbedtls_aes_crypt_ctr( &aes, 0x188, &nc_off, nonce_counter, stream_block, in + 0x02C, out + 0x02C ); + + memcpy(out + 0x000, in + 0x000, 0x008); + // Data signature NOT copied + memcpy(out + 0x028, in + 0x028, 0x004); + // Tag signature NOT copied + memcpy(out + 0x1D4, in + 0x1D4, 0x034); +} + +void nfc3d_amiibo_tag_to_internal(const uint8_t * tag, uint8_t * intl) { + memcpy(intl + 0x000, tag + 0x008, 0x008); + memcpy(intl + 0x008, tag + 0x080, 0x020); + memcpy(intl + 0x028, tag + 0x010, 0x024); + memcpy(intl + 0x04C, tag + 0x0A0, 0x168); + memcpy(intl + 0x1B4, tag + 0x034, 0x020); + memcpy(intl + 0x1D4, tag + 0x000, 0x008); + memcpy(intl + 0x1DC, tag + 0x054, 0x02C); +} + +void nfc3d_amiibo_internal_to_tag(const uint8_t * intl, uint8_t * tag) { + memcpy(tag + 0x008, intl + 0x000, 0x008); + memcpy(tag + 0x080, intl + 0x008, 0x020); + memcpy(tag + 0x010, intl + 0x028, 0x024); + memcpy(tag + 0x0A0, intl + 0x04C, 0x168); + memcpy(tag + 0x034, intl + 0x1B4, 0x020); + memcpy(tag + 0x000, intl + 0x1D4, 0x008); + memcpy(tag + 0x054, intl + 0x1DC, 0x02C); +} + +bool nfc3d_amiibo_unpack(const nfc3d_amiibo_keys * amiiboKeys, const uint8_t * tag, uint8_t * plain) { + uint8_t internal[NFC3D_AMIIBO_SIZE]; + nfc3d_keygen_derivedkeys dataKeys; + nfc3d_keygen_derivedkeys tagKeys; + + // Convert format + nfc3d_amiibo_tag_to_internal(tag, internal); + + // Generate keys + nfc3d_amiibo_keygen(&amiiboKeys->data, internal, &dataKeys); + nfc3d_amiibo_keygen(&amiiboKeys->tag, internal, &tagKeys); + + // Decrypt + nfc3d_amiibo_cipher(&dataKeys, internal, plain); + + // Regenerate tag HMAC. Note: order matters, data HMAC depends on tag HMAC! + mbedtls_md_hmac( mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tagKeys.hmacKey, sizeof(tagKeys.hmacKey), + plain + 0x1D4, 0x34, plain + HMAC_POS_TAG ); + + // Regenerate data HMAC + mbedtls_md_hmac( mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), dataKeys.hmacKey, sizeof(dataKeys.hmacKey), + plain + 0x029, 0x1DF, plain + HMAC_POS_DATA ); + + return + memcmp(plain + HMAC_POS_DATA, internal + HMAC_POS_DATA, 32) == 0 && + memcmp(plain + HMAC_POS_TAG, internal + HMAC_POS_TAG, 32) == 0; +} + +void nfc3d_amiibo_pack(const nfc3d_amiibo_keys * amiiboKeys, const uint8_t * plain, uint8_t * tag) { + uint8_t cipher[NFC3D_AMIIBO_SIZE]; + nfc3d_keygen_derivedkeys tagKeys; + nfc3d_keygen_derivedkeys dataKeys; + + // Generate keys + nfc3d_amiibo_keygen(&amiiboKeys->tag, plain, &tagKeys); + nfc3d_amiibo_keygen(&amiiboKeys->data, plain, &dataKeys); + + // Generate tag HMAC + mbedtls_md_hmac( mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tagKeys.hmacKey, sizeof(tagKeys.hmacKey), + plain + 0x1D4, 0x34, cipher + HMAC_POS_TAG ); + + // Init mbedtls HMAC context + mbedtls_md_context_t ctx; + mbedtls_md_init( &ctx ); + mbedtls_md_setup( &ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1 ); + + // Generate data HMAC + mbedtls_md_hmac_starts( &ctx, dataKeys.hmacKey, sizeof(dataKeys.hmacKey) ); + mbedtls_md_hmac_update( &ctx, plain + 0x029, 0x18B ); // Data + mbedtls_md_hmac_update( &ctx, cipher + HMAC_POS_TAG, 0x20 ); // Tag HMAC + mbedtls_md_hmac_update( &ctx, plain + 0x1D4, 0x34 ); // Here be dragons + + mbedtls_md_hmac_finish( &ctx, cipher + HMAC_POS_DATA ); + + // HMAC cleanup + mbedtls_md_free( &ctx ); + + // Encrypt + nfc3d_amiibo_cipher(&dataKeys, plain, cipher); + + // Convert back to hardware + nfc3d_amiibo_internal_to_tag(cipher, tag); +} + +bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys * amiiboKeys, const char * path) { + FILE * f = fopen(path, "rb"); + if (!f) { + return false; + } + + if (!fread(amiiboKeys, sizeof(*amiiboKeys), 1, f)) { + fclose(f); + return false; + } + fclose(f); + + if ( + (amiiboKeys->data.magicBytesSize > 16) || + (amiiboKeys->tag.magicBytesSize > 16) + ) { + return false; + } + + return true; +} + +void nfc3d_amiibo_copy_app_data(const uint8_t * src, uint8_t * dst) { + + + //uint16_t *ami_nb_wr = (uint16_t*)(dst + 0x29); + //uint16_t *cfg_nb_wr = (uint16_t*)(dst + 0xB4); + + /* increment write counters */ + //*ami_nb_wr = htobe16(be16toh(*ami_nb_wr) + 1); + //*cfg_nb_wr = htobe16(be16toh(*cfg_nb_wr) + 1); + + uint16_t ami_nb_wr = ((uint16_t)bytes_to_num(dst + 0x29, 2)) + 1; + uint16_t cfg_nb_wr = ((uint16_t)bytes_to_num(dst + 0xB4, 2)) + 1; + + num_to_bytes(ami_nb_wr, 2, dst + 0x29); + num_to_bytes(cfg_nb_wr, 2, dst + 0xB4); + + /* copy flags */ + dst[0x2C] = src[0x2C]; + /* copy programID */ + memcpy(dst + 0xAC, src + 0xAC, 8); + /* copy AppID */ + memcpy(dst + 0xB6, src + 0xB6, 4); + /* copy AppData */ + memcpy(dst + 0xDC, src + 0xDC, 216); +} + diff --git a/client/amiitool/amiibo.h b/client/amiitool/amiibo.h new file mode 100644 index 000000000..3c7dccc70 --- /dev/null +++ b/client/amiitool/amiibo.h @@ -0,0 +1,32 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * (c) 2016 javiMaD + * + * SPDX-License-Identifier: MIT + */ + +#ifndef HAVE_NFC3D_AMIIBO_H +#define HAVE_NFC3D_AMIIBO_H + +#include +#include +#include +#include +#include "keygen.h" +#include "util.h" + +#define NFC3D_AMIIBO_SIZE 520 + +#pragma pack(1) +typedef struct { + nfc3d_keygen_masterkeys data; + nfc3d_keygen_masterkeys tag; +} nfc3d_amiibo_keys; +#pragma pack() + +bool nfc3d_amiibo_unpack(const nfc3d_amiibo_keys * amiiboKeys, const uint8_t * tag, uint8_t * plain); +void nfc3d_amiibo_pack(const nfc3d_amiibo_keys * amiiboKeys, const uint8_t * plain, uint8_t * tag); +bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys * amiiboKeys, const char * path); +void nfc3d_amiibo_copy_app_data(const uint8_t * src, uint8_t * dst); + +#endif diff --git a/client/amiitool/amiitool.c b/client/amiitool/amiitool.c new file mode 100644 index 000000000..40e7b05eb --- /dev/null +++ b/client/amiitool/amiitool.c @@ -0,0 +1,175 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * (c) 2016 javiMaD + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "../loclass/fileutil.h" + +#define NTAG215_SIZE 540 + +static char * self; + +void amiitool_usage() { + fprintf(stderr, + "amiitool build %i (commit %s-%08x)\n" + "by Marcos Del Sol Vives \n" + "\n" + "Usage: %s (-e|-d|-c) -k keyfile [-i input] [-s input2] [-o output]\n" + " -e encrypt and sign amiibo\n" + " -d decrypt and test amiibo\n" + " -c decrypt, copy AppData and encrypt amiibo\n" + " -k key set file. For retail amiibo, use \"retail unfixed\" key set\n" + " -i input file. If not specified, stdin will be used.\n" + " -s input save file, save from this file will replace input file ones.\n" + " -o output file. If not specified, stdout will be used.\n" + " -l decrypt files with invalid signatures.\n", + , self + ); +} + +static bool LoadAmiikey(nfc3d_amiibo_keys keys, char* keyfile) { + + if (!nfc3d_amiibo_load_keys(&keys, keyfile)) { + PrintAndLogEx(ERR, "Could not load keys from '%s'", keyfile); + return false; + } + return true; +} + +int main(int argc, char ** argv) { + self = argv[0]; + + char * infile = NULL; + char * savefile = NULL; + char * outfile = NULL; + char * keyfile = NULL; + char op = '\0'; + bool lenient = false; + + char c; + while ((c = getopt(argc, argv, "edci:s:o:k:l")) != -1) { + switch (c) { + case 'e': + case 'd': + case 'c': + op = c; + break; + case 'i': + infile = optarg; + break; + case 's': + savefile = optarg; + break; + case 'o': + outfile = optarg; + break; + case 'l': + lenient = true; + break; + default: + amiitool_usage(); + return 2; + } + } + + if (op == '\0' || keyfile == NULL) { + amiitool_usage(); + return 1; + } + + nfc3d_amiibo_keys amiiboKeys; + + + uint8_t original[NTAG215_SIZE]; + uint8_t modified[NFC3D_AMIIBO_SIZE]; + + FILE * f = stdin; + if (infile) { + f = fopen(infile, "rb"); + if (!f) { + fprintf(stderr, "Could not open input file\n"); + return 3; + } + } + size_t readPages = fread(original, 4, NTAG215_SIZE / 4, f); + if (readPages < NFC3D_AMIIBO_SIZE / 4) { + fprintf(stderr, "Could not read from input\n"); + fclose(f); + return 3; + } + fclose(f); + + + if (op == 'e') { + nfc3d_amiibo_pack(&amiiboKeys, original, modified); + } else if (op == 'd') { + if (!nfc3d_amiibo_unpack(&amiiboKeys, original, modified)) { + fprintf(stderr, "!!! WARNING !!!: Tag signature was NOT valid\n"); + if (!lenient) { + return 6; + } + } + } else { /* copy */ + uint8_t plain_base[NFC3D_AMIIBO_SIZE]; + uint8_t plain_save[NFC3D_AMIIBO_SIZE]; + + if (!nfc3d_amiibo_unpack(&amiiboKeys, original, plain_base)) { + fprintf(stderr, "!!! WARNING !!!: Tag signature was NOT valid\n"); + if (!lenient) { + return 6; + } + } + if (savefile) { + f = fopen(savefile, "rb"); + if (!f) { + fprintf(stderr, "Could not open save file\n"); + return 3; + } + } + size_t readPages = fread(original, 4, NTAG215_SIZE / 4, f); + if (readPages < NFC3D_AMIIBO_SIZE / 4) { + fprintf(stderr, "Could not read from save\n"); + fclose(f); + return 3; + } + fclose(f); + + if (!nfc3d_amiibo_unpack(&amiiboKeys, original, plain_save)) { + fprintf(stderr, "!!! WARNING !!!: Tag signature was NOT valid\n"); + if (!lenient) { + return 6; + } + } + + nfc3d_amiibo_copy_app_data(plain_save, plain_base); + nfc3d_amiibo_pack(&amiiboKeys, plain_base, modified); + } + + f = stdout; + if (outfile) { + f = fopen(outfile, "wb"); + if (!f) { + fprintf(stderr, "Could not open output file\n"); + return 4; + } + } + if (fwrite(modified, NFC3D_AMIIBO_SIZE, 1, f) != 1) { + fprintf(stderr, "Could not write to output\n"); + fclose(f); + return 4; + } + if (readPages > NFC3D_AMIIBO_SIZE / 4) { + if (fwrite(original + NFC3D_AMIIBO_SIZE, readPages * 4 - NFC3D_AMIIBO_SIZE, 1, f) != 1) { + fprintf(stderr, "Could not write to output:\n"); + fclose(f); + return 4; + } + } + fclose(f); + return 0; +} diff --git a/client/amiitool/drbg.c b/client/amiitool/drbg.c new file mode 100644 index 000000000..d56366077 --- /dev/null +++ b/client/amiitool/drbg.c @@ -0,0 +1,78 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * (c) 2016 javiMaD + * + * SPDX-License-Identifier: MIT + */ + +#include "drbg.h" +#include +#include +#include + +void nfc3d_drbg_init(nfc3d_drbg_ctx * ctx, const uint8_t * hmacKey, size_t hmacKeySize, const uint8_t * seed, size_t seedSize) { + assert(ctx != NULL); + assert(hmacKey != NULL); + assert(seed != NULL); + assert(seedSize <= NFC3D_DRBG_MAX_SEED_SIZE); + + // Initialize primitives + ctx->used = false; + ctx->iteration = 0; + ctx->bufferSize = sizeof(ctx->iteration) + seedSize; + + // The 16-bit counter is prepended to the seed when hashing, so we'll leave 2 bytes at the start + memcpy(ctx->buffer + sizeof(uint16_t), seed, seedSize); + + // Initialize underlying HMAC context + mbedtls_md_init(&ctx->hmacCtx); + mbedtls_md_setup(&ctx->hmacCtx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1); + mbedtls_md_hmac_starts(&ctx->hmacCtx, hmacKey, hmacKeySize); +} + +void nfc3d_drbg_step(nfc3d_drbg_ctx * ctx, uint8_t * output) { + assert(ctx != NULL); + assert(output != NULL); + + if (ctx->used) { + // If used at least once, reinitialize the HMAC + mbedtls_md_hmac_reset(&ctx->hmacCtx); + } else { + ctx->used = true; + } + + // Store counter in big endian, and increment it + ctx->buffer[0] = ctx->iteration >> 8; + ctx->buffer[1] = ctx->iteration >> 0; + ctx->iteration++; + + // Do HMAC magic + mbedtls_md_hmac_update(&ctx->hmacCtx, ctx->buffer, ctx->bufferSize); + mbedtls_md_hmac_finish(&ctx->hmacCtx, output); +} + +void nfc3d_drbg_cleanup(nfc3d_drbg_ctx * ctx) { + assert(ctx != NULL); + mbedtls_md_free(&ctx->hmacCtx); +} + +void nfc3d_drbg_generate_bytes(const uint8_t * hmacKey, size_t hmacKeySize, const uint8_t * seed, size_t seedSize, uint8_t * output, size_t outputSize) { + uint8_t temp[NFC3D_DRBG_OUTPUT_SIZE]; + + nfc3d_drbg_ctx rngCtx; + nfc3d_drbg_init(&rngCtx, hmacKey, hmacKeySize, seed, seedSize); + + while (outputSize > 0) { + if (outputSize < NFC3D_DRBG_OUTPUT_SIZE) { + nfc3d_drbg_step(&rngCtx, temp); + memcpy(output, temp, outputSize); + break; + } + + nfc3d_drbg_step(&rngCtx, output); + output += NFC3D_DRBG_OUTPUT_SIZE; + outputSize -= NFC3D_DRBG_OUTPUT_SIZE; + } + + nfc3d_drbg_cleanup(&rngCtx); +} diff --git a/client/amiitool/drbg.h b/client/amiitool/drbg.h new file mode 100644 index 000000000..0e93abfc0 --- /dev/null +++ b/client/amiitool/drbg.h @@ -0,0 +1,33 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * (c) 2016 javiMaD + * + * SPDX-License-Identifier: MIT + */ + +#ifndef HAVE_NFC3D_DRBG_H +#define HAVE_NFC3D_DRBG_H + +#include +#include +#include "mbedtls/md.h" + +#define NFC3D_DRBG_MAX_SEED_SIZE 480 /* Hardcoded max size in 3DS NFC module */ +#define NFC3D_DRBG_OUTPUT_SIZE 32 /* Every iteration generates 32 bytes */ + +typedef struct { + mbedtls_md_context_t hmacCtx; + bool used; + uint16_t iteration; + + uint8_t buffer[sizeof(uint16_t) + NFC3D_DRBG_MAX_SEED_SIZE]; + size_t bufferSize; +} nfc3d_drbg_ctx; + +void nfc3d_drbg_init(nfc3d_drbg_ctx * ctx, const uint8_t * hmacKey, size_t hmacKeySize, const uint8_t * seed, size_t seedSize); +void nfc3d_drbg_step(nfc3d_drbg_ctx * ctx, uint8_t * output); +void nfc3d_drbg_cleanup(nfc3d_drbg_ctx * ctx); +void nfc3d_drbg_generate_bytes(const uint8_t * hmacKey, size_t hmacKeySize, const uint8_t * seed, size_t seedSize, uint8_t * output, size_t outputSize); + +#endif + diff --git a/client/amiitool/key_retail.bin b/client/amiitool/key_retail.bin new file mode 100644 index 000000000..9ecc9e35a Binary files /dev/null and b/client/amiitool/key_retail.bin differ diff --git a/client/amiitool/keygen.c b/client/amiitool/keygen.c new file mode 100644 index 000000000..c82e3abee --- /dev/null +++ b/client/amiitool/keygen.c @@ -0,0 +1,53 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * + * SPDX-License-Identifier: MIT + */ + +#include "drbg.h" +#include "keygen.h" +#include +#include +#include + +void nfc3d_keygen_prepare_seed(const nfc3d_keygen_masterkeys * baseKeys, const uint8_t * baseSeed, uint8_t * output, size_t * outputSize) { + assert(baseKeys != NULL); + assert(baseSeed != NULL); + assert(output != NULL); + assert(outputSize != NULL); + + uint8_t * start = output; + + // 1: Copy whole type string + output = memccpy(output, baseKeys->typeString, '\0', sizeof(baseKeys->typeString)); + + // 2: Append (16 - magicBytesSize) from the input seed + size_t leadingSeedBytes = 16 - baseKeys->magicBytesSize; + memcpy(output, baseSeed, leadingSeedBytes); + output += leadingSeedBytes; + + // 3: Append all bytes from magicBytes + memcpy(output, baseKeys->magicBytes, baseKeys->magicBytesSize); + output += baseKeys->magicBytesSize; + + // 4: Append bytes 0x10-0x1F from input seed + memcpy(output, baseSeed + 0x10, 16); + output += 16; + + // 5: Xor last bytes 0x20-0x3F of input seed with AES XOR pad and append them + unsigned int i; + for (i = 0; i < 32; i++) { + output[i] = baseSeed[i + 32] ^ baseKeys->xorPad[i]; + } + output += 32; + + *outputSize = output - start; +} + +void nfc3d_keygen(const nfc3d_keygen_masterkeys * baseKeys, const uint8_t * baseSeed, nfc3d_keygen_derivedkeys * derivedKeys) { + uint8_t preparedSeed[NFC3D_DRBG_MAX_SEED_SIZE]; + size_t preparedSeedSize; + + nfc3d_keygen_prepare_seed(baseKeys, baseSeed, preparedSeed, &preparedSeedSize); + nfc3d_drbg_generate_bytes(baseKeys->hmacKey, sizeof(baseKeys->hmacKey), preparedSeed, preparedSeedSize, (uint8_t *) derivedKeys, sizeof(*derivedKeys)); +} diff --git a/client/amiitool/keygen.h b/client/amiitool/keygen.h new file mode 100644 index 000000000..35595e3ef --- /dev/null +++ b/client/amiitool/keygen.h @@ -0,0 +1,34 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * + * SPDX-License-Identifier: MIT + */ + +#ifndef HAVE_NFC3D_KEYGEN_H +#define HAVE_NFC3D_KEYGEN_H + +#include +#include + +#define NFC3D_KEYGEN_SEED_SIZE 64 + +#pragma pack(1) +typedef struct { + uint8_t hmacKey[16]; + char typeString[14]; + uint8_t rfu; + uint8_t magicBytesSize; + uint8_t magicBytes[16]; + uint8_t xorPad[32]; +} nfc3d_keygen_masterkeys; + +typedef struct { + const uint8_t aesKey[16]; + const uint8_t aesIV[16]; + const uint8_t hmacKey[16]; +} nfc3d_keygen_derivedkeys; +#pragma pack() + +void nfc3d_keygen(const nfc3d_keygen_masterkeys * baseKeys, const uint8_t * baseSeed, nfc3d_keygen_derivedkeys * derivedKeys); + +#endif diff --git a/client/cmdanalyse.h b/client/cmdanalyse.h index f834c717d..ab7606f5c 100644 --- a/client/cmdanalyse.h +++ b/client/cmdanalyse.h @@ -16,15 +16,15 @@ #include #include "cmdmain.h" #include "proxmark3.h" -#include "ui.h" // PrintAndLog +#include "ui.h" // PrintAndLog #include "util.h" #include "crc.h" #include "crc16.h" // crc16 ccitt #include "tea.h" #include "legic_prng.h" #include "loclass/elite_crack.h" -#include "mfkey.h" //nonce2key -#include "util_posix.h" // msclock +#include "mifare/mfkey.h" //nonce2key +#include "util_posix.h" // msclock int usage_analyse_lcr(void); diff --git a/client/cmdcrc.c b/client/cmdcrc.c index 25653dbab..a34c7d351 100644 --- a/client/cmdcrc.c +++ b/client/cmdcrc.c @@ -39,8 +39,7 @@ int split(char *str, char *arr[MAX_ARGS]){ return wordCnt; } -int CmdCrc(const char *Cmd) -{ +int CmdCrc(const char *Cmd) { char name[] = {"reveng "}; char Cmd2[100 + 7]; memcpy(Cmd2, name, 7); @@ -198,6 +197,11 @@ int GetModels(char *Models[], int *count, uint8_t *width){ pfree(qptr); } } + if(uflags & C_NOBFS && ~rflags & R_HAVEP) { + PrintAndLogEx(WARNING, "no models found"); + return 0; + } + if (!(model.flags & P_REFIN) != !(model.flags & P_REFOUT)){ PrintAndLogEx(WARNING, "cannot search for crossed-endian models"); return 0; @@ -259,8 +263,9 @@ int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *res SETBMP(); //set model - if (!(c = mbynam(&model, inModel))) { - PrintAndLogEx(WARNING, "error: preset model '%s' not found. Use reveng -D to list presets.", inModel); + c = mbynam(&model, inModel); + if (!c) { + PrintAndLogEx(WARNING, "error: preset model '%s' not found. Use reveng -D to list presets. [%d]", inModel, c); return 0; } if (c < 0){ @@ -396,7 +401,7 @@ char *SwapEndianStr(const char *inStr, const size_t len, const uint8_t blockSize // takes hex string in and searches for a matching result (hex string must include checksum) int CmdrevengSearch(const char *Cmd){ -#define NMODELS 103 +#define NMODELS 105 char inHexStr[100] = {0x00}; int dataLen = param_getstr(Cmd, 0, inHexStr, sizeof(inHexStr)); @@ -432,7 +437,7 @@ int CmdrevengSearch(const char *Cmd){ char *outHex = calloc(dataLen-crcChars+1, sizeof(char)); memcpy(outHex, inHexStr, dataLen-crcChars); - // PrintAndLogEx(DEBUG, "DEBUG: dataLen: %d, crcChars: %d, Model: %s, CRC: %s, width: %d, outHex: %s",dataLen, crcChars, Models[i], inCRC, width[i], outHex); + PrintAndLogEx(DEBUG, "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 diff --git a/client/cmddata.c b/client/cmddata.c index a9f58b962..ba3d61156 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -754,19 +754,53 @@ int AutoCorrelate(const int *in, int *out, size_t len, int window, bool SaveGrph lastmax = i; } } - - if (verbose && ( correlation > 1 ) ) { - PrintAndLogEx(SUCCESS, "possible correlation %4d samples", correlation); - } else { - PrintAndLogEx(FAILED, "no repeating pattern found"); + + // + int hi = 0, idx = 0; + int distance = 0, hi_1 = 0, idx_1 = 0; + for (int i = 0; i <= len; ++i){ + if ( CorrelBuffer[i] > hi) { + hi = CorrelBuffer[i]; + idx = i; + } } - if (SaveGrph){ + for (int i = idx+1; i <= window; ++i){ + if ( CorrelBuffer[i] > hi_1 ) { + hi_1 = CorrelBuffer[i]; + idx_1 = i; + } + } + + int foo = ABS(hi-hi_1); + int bar = (int)(((hi+hi_1) / 2) * 0.03); + if ( verbose && foo < bar ) { + distance = idx_1 - idx; + PrintAndLogEx(SUCCESS, "possible 3% visible correlation %4d samples", distance); + } else if (verbose && ( correlation > 1 ) ) { + PrintAndLogEx(SUCCESS, "possible correlation %4d samples", correlation); + } else { + PrintAndLogEx(FAILED, "no repeating pattern found, try increasing window size"); + } + + int retval = correlation; + if (SaveGrph) { //GraphTraceLen = GraphTraceLen - window; memcpy(out, CorrelBuffer, len * sizeof(int)); + if ( distance > 0) { + setClockGrid(distance, idx); + retval = distance; + } + else + setClockGrid(correlation, idx); + + CursorCPos = idx_1; + CursorDPos = idx_1+retval; + DemodBufferLen = 0; RepaintGraphWindow(); } - return correlation; + + return retval; } int CmdAutoCorr(const char *Cmd) { @@ -1461,6 +1495,13 @@ int CmdTuneSamples(const char *Cmd) { #define HF_UNUSABLE_V 3000 #define HF_MARGINAL_V 5000 #define ANTENNA_ERROR 1.03 // current algo has 3% error margin. + + // hide demod plot line + DemodBufferLen = 0; + setClockGrid(0, 0); + RepaintGraphWindow(); + + int timeout = 0; PrintAndLogEx(INFO, "\nmeasuring antenna characteristics, please wait..."); @@ -1541,6 +1582,7 @@ int CmdTuneSamples(const char *Cmd) { PrintAndLogEx(FAILED, "\nNot showing LF tuning graph since all values is zero.\n\n"); } + return 0; } @@ -1786,7 +1828,7 @@ int Cmdbin2hex(const char *Cmd) { //Number of digits supplied as argument size_t length = en - bg + 1; size_t bytelen = (length+7) / 8; - uint8_t* arr = (uint8_t *) malloc(bytelen); + uint8_t* arr = (uint8_t *) calloc(bytelen, sizeof(uint8_t)); memset(arr, 0, bytelen); BitstreamOut bout = { arr, 0, 0 }; diff --git a/client/cmdflashmem.c b/client/cmdflashmem.c index 2ff68bd3d..34bb89cbc 100644 --- a/client/cmdflashmem.c +++ b/client/cmdflashmem.c @@ -7,10 +7,13 @@ //----------------------------------------------------------------------------- // Proxmark3 RDV40 Flash memory commands //----------------------------------------------------------------------------- +#ifdef WITH_FLASH + #include "cmdflashmem.h" #include "mbedtls/rsa.h" #include "mbedtls/sha1.h" +#include "mbedtls/base64.h" #define MCK 48000000 //#define FLASH_BAUD 24000000 @@ -50,13 +53,19 @@ int usage_flashmem_read(void){ } int usage_flashmem_load(void){ PrintAndLogEx(NORMAL, "Loads binary file into flash memory on device"); - PrintAndLogEx(NORMAL, "Usage: mem load o f "); + PrintAndLogEx(NORMAL, "Usage: mem load o f m t i"); PrintAndLogEx(NORMAL, " o : offset in memory"); PrintAndLogEx(NORMAL, " f : file name"); + PrintAndLogEx(NORMAL, " m : upload 6 bytes keys (mifare key dictionary)"); + PrintAndLogEx(NORMAL, " i : upload 8 bytes keys (iClass key dictionary)"); + PrintAndLogEx(NORMAL, " t : upload 4 bytes keys (pwd dictionary)"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " mem load f myfile"); // upload file myfile at default offset 0 PrintAndLogEx(NORMAL, " mem load f myfile o 1024"); // upload file myfile at offset 1024 + PrintAndLogEx(NORMAL, " mem load f default_keys m"); + PrintAndLogEx(NORMAL, " mem load f default_pwd t"); + PrintAndLogEx(NORMAL, " mem load f default_iclass_keys i"); return 0; } int usage_flashmem_save(void){ @@ -154,7 +163,8 @@ int CmdFlashMemLoad(const char *Cmd){ uint32_t start_index = 0; char filename[FILE_PATH_SIZE] = {0}; bool errors = false; - uint8_t cmdp = 0; + uint8_t cmdp = 0; + Dictionary_t d = DICTIONARY_NONE; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { @@ -171,7 +181,19 @@ int CmdFlashMemLoad(const char *Cmd){ case 'o': start_index = param_get32ex(Cmd, cmdp+1, 0, 10); cmdp += 2; - break; + break; + case 'm': + d = DICTIONARY_MIFARE; + cmdp++; + break; + case 't': + d = DICTIONARY_T55XX; + cmdp++; + break; + case 'i': + d = DICTIONARY_ICLASS; + cmdp++; + break; default: PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -181,20 +203,60 @@ int CmdFlashMemLoad(const char *Cmd){ //Validations if (errors || cmdp == 0 ) return usage_flashmem_load(); - - uint8_t *data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t)); + size_t datalen = 0; - int res = loadFile(filename, "bin", data, &datalen); - //int res = loadFileEML( filename, "eml", data, &datalen); - if ( res ) { - free(data); - return 1; - } + uint16_t keycount = 0; + int res = 0; + uint8_t *data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t)); - if (datalen > FLASH_MEM_MAX_SIZE) { - PrintAndLogDevice(WARNING, "error, filesize is larger than available memory"); - free(data); - return 1; + switch (d) { + case DICTIONARY_MIFARE: + start_index = DEFAULT_MF_KEYS_OFFSET; + res = loadFileDICTIONARY(filename, "dic", data+2, &datalen, 6, &keycount ); + if ( res || !keycount) { + free(data); + return 1; + } + data[0] = (keycount >> 0) & 0xFF; + data[1] = (keycount >> 8) & 0xFF; + datalen += 2; + break; + case DICTIONARY_T55XX: + start_index = DEFAULT_T55XX_KEYS_OFFSET; + res = loadFileDICTIONARY(filename, "dic", data+2, &datalen, 4, &keycount ); + if ( res || !keycount) { + free(data); + return 1; + } + data[0] = (keycount >> 0) & 0xFF; + data[1] = (keycount >> 8) & 0xFF; + datalen += 2; + break; + case DICTIONARY_ICLASS: + start_index = DEFAULT_ICLASS_KEYS_OFFSET; + res = loadFileDICTIONARY(filename, "dic", data+2, &datalen, 8, &keycount ); + if ( res || !keycount) { + free(data); + return 1; + } + data[0] = (keycount >> 0) & 0xFF; + data[1] = (keycount >> 8) & 0xFF; + datalen += 2; + break; + default: + + res = loadFile(filename, "bin", data, &datalen); + //int res = loadFileEML( filename, "eml", data, &datalen); + if ( res ) { + return 1; + } + + if (datalen > FLASH_MEM_MAX_SIZE) { + PrintAndLogDevice(WARNING, "error, filesize is larger than available memory"); + free(data); + return 1; + } + break; } data = realloc(data, datalen); @@ -544,3 +606,5 @@ int CmdHelp(const char *Cmd) { CmdsHelp(CommandTable); return 0; } + +#endif \ No newline at end of file diff --git a/client/cmdflashmem.h b/client/cmdflashmem.h index 843c17d6f..ee661bf18 100644 --- a/client/cmdflashmem.h +++ b/client/cmdflashmem.h @@ -8,6 +8,8 @@ // Proxmark3 RDV40 Flash memory commands //----------------------------------------------------------------------------- +#ifdef WITH_FLASH + #ifndef CMDFLASHMEM_H__ #define CMDFLASHMEM_H__ @@ -24,6 +26,13 @@ #include "loclass/fileutils.h" //saveFile #include "comms.h" //getfromdevice +typedef enum { + DICTIONARY_NONE = 0, + DICTIONARY_MIFARE, + DICTIONARY_T55XX, + DICTIONARY_ICLASS +} Dictionary_t; + extern int CmdFlashMem(const char *Cmd); extern int CmdFlashMemRead(const char* cmd); @@ -31,4 +40,6 @@ extern int CmdFlashMemLoad(const char* cmd); extern int CmdFlashMemSave(const char* cmd); extern int CmdFlashMemWipe(const char *Cmd); extern int CmdFlashMemInfo(const char *Cmd); +#endif + #endif \ No newline at end of file diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index b9d7bfcae..27f670fac 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh , Hagen Fritsch -// 2011, 2017 Merlok +// 2011, 2017 - 2019 Merlok // 2014, Peter Fillmore // 2015, 2016, 2017 Iceman // @@ -12,6 +12,8 @@ //----------------------------------------------------------------------------- #include "cmdhf14a.h" +bool APDUInFramingEnable = true; + static int CmdHelp(const char *Cmd); static int waitCmd(uint8_t iLen); @@ -147,6 +149,10 @@ char* getTagInfo(uint8_t uid) { return manufactureMapping[len-1].desc; } +// iso14a apdu input frame length +static uint16_t frameLength = 0; +uint16_t atsFSC[] = {16, 24, 32, 40, 48, 64, 96, 128, 256}; + int usage_hf_14a_sim(void) { // PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"); PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 byte UID\n"); @@ -213,11 +219,6 @@ int usage_hf_14a_info(void){ PrintAndLogEx(NORMAL, " n test for nack bug"); return 0; } -int usage_hf_14a_antifuzz(void) { - PrintAndLogEx(NORMAL, "Usage: hf 14a antifuzz [4|7|10]"); - PrintAndLogEx(NORMAL, " determine which anticollision phase the command will target."); - return 0; -} int CmdHF14AList(const char *Cmd) { //PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list 14a' instead"); @@ -491,10 +492,7 @@ int CmdHF14AInfo(const char *Cmd) { (tb1 ? "" : " NOT"), (tc1 ? "" : " NOT"), fsci, - fsci < 5 ? (fsci - 2) * 8 : - fsci < 8 ? (fsci - 3) * 32 : - fsci == 8 ? 256 : - -1 + fsci < sizeof(atsFSC) ? atsFSC[fsci] : -1 ); } pos = 2; @@ -581,11 +579,11 @@ int CmdHF14AInfo(const char *Cmd) { if (isMifareClassic) { int res = detect_classic_prng(); if ( res == 1 ) - PrintAndLogEx(SUCCESS, "Prng detection: WEAK"); + PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_(WEAK)); else if (res == 0 ) - PrintAndLogEx(SUCCESS, "Prng detection: HARD"); + PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_(HARD)); else - PrintAndLogEx(FAILED, "prng detection: failed"); + PrintAndLogEx(FAILED, "prng detection: " _RED_(failed)); if ( do_nack_test ) detect_classic_nackbug(silent); @@ -841,15 +839,90 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav return 0; } -int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chaining) { - uint16_t cmdc = 0; +int SelectCard14443_4(bool disconnect, iso14a_card_select_t *card) { + UsbCommand resp; - *chaining = false; + frameLength = 0; + + if (card) + memset(card, 0, sizeof(iso14a_card_select_t)); - if (activateField) { - cmdc |= ISO14A_CONNECT; + DropField(); + + // Anticollision + SELECT card + UsbCommand ca = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; + SendCommand(&ca); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(ERR, "Proxmark connection timeout."); + return 1; } + // check result + if (resp.arg[0] == 0) { + PrintAndLogEx(ERR, "No card in field."); + return 1; + } + + if (resp.arg[0] != 1 && resp.arg[0] != 2) { + PrintAndLogEx(ERR, "Card not in iso14443-4. res=%d.", resp.arg[0]); + return 1; + } + + if (resp.arg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + // get ATS + UsbCommand cr = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0}}; + uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 + memcpy(cr.d.asBytes, rats, 2); + SendCommand(&cr); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(ERR, "Proxmark connection timeout."); + return 1; + } + + if (resp.arg[0] <= 0) { // ats_len + PrintAndLogEx(ERR, "Can't get ATS."); + return 1; + } + + // get frame length from ATS in data field + if (resp.arg[0] > 1) { + uint8_t fsci = resp.d.asBytes[1] & 0x0f; + if (fsci < sizeof(atsFSC)) + frameLength = atsFSC[fsci]; + } + } else { + // get frame length from ATS in card data structure + iso14a_card_select_t *vcard = (iso14a_card_select_t *) resp.d.asBytes; + if (vcard->ats_len > 1) { + uint8_t fsci = vcard->ats[1] & 0x0f; + if (fsci < sizeof(atsFSC)) + frameLength = atsFSC[fsci]; + } + + if (card) + memcpy(card, vcard, sizeof(iso14a_card_select_t)); + } + + if (disconnect) + DropField(); + + return 0; +} + +int CmdExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout) { + *chainingout = false; + + if (activateField) { + // select with no disconnect and set frameLength + int selres = SelectCard14443_4(false, NULL); + if (selres) + return selres; + } + + uint16_t cmdc = 0; + if (chainingin) + cmdc = ISO14A_SEND_CHAINING; + // "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes // https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size // here length USB_CMD_DATA_SIZE=512 @@ -861,18 +934,6 @@ int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t uint8_t *recv; UsbCommand resp; - if (activateField) { - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLogEx(ERR, "APDU: Proxmark connection timeout."); - return 1; - } - if (resp.arg[0] != 1) { - PrintAndLogEx(ERR, "APDU: Proxmark error %d.", resp.arg[0]); - DropField(); - return 1; - } - } - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { recv = resp.d.asBytes; int iLen = resp.arg[0]; @@ -888,13 +949,20 @@ int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t return 2; } + // I-block ACK + if ((res & 0xf2) == 0xa2) { + *dataoutlen = 0; + *chainingout = true; + return 0; + } + if(!iLen) { PrintAndLogEx(ERR, "APDU: No APDU response."); return 1; } // check apdu length - if (iLen < 4 && iLen >= 0) { + if (iLen < 2 && iLen >= 0) { PrintAndLogEx(ERR, "APDU: Small APDU response. Len=%d", iLen); return 2; } @@ -909,7 +977,7 @@ int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t // chaining if ((res & 0x10) != 0) { - *chaining = true; + *chainingout = true; } // CRC Check @@ -928,12 +996,57 @@ int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { *dataoutlen = 0; bool chaining = false; - - int res = CmdExchangeAPDU(datain, datainlen, activateField, dataout, maxdataoutlen, dataoutlen, &chaining); + int res; + // 3 byte here - 1b framing header, 2b crc16 + if (APDUInFramingEnable && + ( (frameLength && (datainlen > frameLength - 3)) || (datainlen > USB_CMD_DATA_SIZE - 3)) ) { + int clen = 0; + + bool vActivateField = activateField; + + do { + int vlen = MIN(frameLength - 3, datainlen - clen); + bool chainBlockNotLast = ((clen + vlen) < datainlen); + + *dataoutlen = 0; + res = CmdExchangeAPDU(chainBlockNotLast, &datain[clen], vlen, vActivateField, dataout, maxdataoutlen, dataoutlen, &chaining); + if (res) { + if (!leaveSignalON) + DropField(); + + return 200; + } + + // check R-block ACK + if ((*dataoutlen == 0) && (*dataoutlen != 0 || chaining != chainBlockNotLast)) { + if (!leaveSignalON) + DropField(); + + return 201; + } + + clen += vlen; + vActivateField = false; + if (*dataoutlen) { + if (clen != datainlen) + PrintAndLogEx(WARNING, "APDU: I-block/R-block sequence error. Data len=%d, Sent=%d, Last packet len=%d", datainlen, clen, *dataoutlen); + break; + } + } while (clen < datainlen); + } else { + res = CmdExchangeAPDU(false, datain, datainlen, activateField, dataout, maxdataoutlen, dataoutlen, &chaining); + if (res) { + if (!leaveSignalON) + DropField(); + + return res; + } + } + while (chaining) { // I-block with chaining - res = CmdExchangeAPDU(NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining); + res = CmdExchangeAPDU(false, NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining); if (res) { if (!leaveSignalON) @@ -1183,27 +1296,75 @@ static int waitCmd(uint8_t iSelect) { int CmdHF14AAntiFuzz(const char *cmd) { - if (strlen(cmd) < 1) return usage_hf_14a_antifuzz(); + CLIParserInit("hf 14a antifuzz", + "Tries to fuzz the ISO14443a anticollision phase", + "Usage:\n" + "\thf 14a antifuzz -4\n"); - // read param length - uint8_t arg0 = 4; - + void* argtable[] = { + arg_param_begin, + arg_lit0("4", NULL, "4 byte uid"), + arg_lit0("7", NULL, "7 byte uid"), + arg_lit0(NULL, "10", "10 byte uid"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, false); + + uint8_t arg0 = FLAG_4B_UID_IN_DATA; + if (arg_get_lit(2)) + arg0 = FLAG_7B_UID_IN_DATA; + if (arg_get_lit(3)) + arg0 = FLAG_10B_UID_IN_DATA; + + CLIParserFree(); UsbCommand c = {CMD_ANTIFUZZ_ISO_14443a, {arg0, 0, 0}}; clearCommandBuffer(); SendCommand(&c); return 0; } +int CmdHF14AChaining(const char *cmd) { + + CLIParserInit("hf 14a chaining", + "Enable/Disable ISO14443a input chaining. Maximum input length goes from ATS.", + "Usage:\n" + "\thf 14a chaining disable -> disable chaining\n" + "\thf 14a chaining -> show chaining enable/disable state\n"); + + void* argtable[] = { + arg_param_begin, + arg_str0(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + struct arg_str *str = arg_get_str(1); + int len = arg_get_str_len(1); + + if (len && (!strcmp(str->sval[0], "enable") || !strcmp(str->sval[0], "1"))) + APDUInFramingEnable = true; + + if (len && (!strcmp(str->sval[0], "disable") || !strcmp(str->sval[0], "0"))) + APDUInFramingEnable = false; + + CLIParserFree(); + + PrintAndLogEx(INFO, "\nISO 14443-4 input chaining %s.\n", APDUInFramingEnable ? "enabled" : "disabled"); + + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443-a history"}, {"info", CmdHF14AInfo, 0, "Tag information"}, - {"reader", CmdHF14AReader, 0, "Act like an ISO14443-a reader"}, + {"reader", CmdHF14AReader, 0, "Act like an ISO14443-a reader"}, {"cuids", CmdHF14ACUIDs, 0, " Collect n>0 ISO14443-a UIDs in one go"}, - {"sim", CmdHF14ASim, 0, " -- Simulate ISO 14443-a tag"}, + {"sim", CmdHF14ASim, 0, " -- Simulate ISO 14443-a tag"}, {"sniff", CmdHF14ASniff, 0, "sniff ISO 14443-a traffic"}, {"apdu", CmdHF14AAPDU, 0, "Send ISO 14443-4 APDU to tag"}, - {"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"}, + {"chaining", CmdHF14AChaining, 0, "Control ISO 14443-4 input chaining"}, + {"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"}, {"antifuzz", CmdHF14AAntiFuzz, 0, "Fuzzing the anticollision phase. Warning! Readers may react strange"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index 723c31100..3fe04d26c 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -29,7 +29,7 @@ #include "cmdhfmf.h" #include "cmdhfmfu.h" #include "cmdhf.h" // list cmd -#include "mifarehost.h" +#include "mifare/mifarehost.h" #include "emv/apduinfo.h" #include "emv/emvcore.h" diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index 4077e16e6..4109a999a 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -246,7 +246,7 @@ static bool get_14b_UID(iso14b_card_select_t *card) { if (!card) return false; - uint8_t retry = 3; + int8_t retry = 3; UsbCommand resp; UsbCommand c = {CMD_ISO_14443B_COMMAND, {ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0}}; @@ -283,7 +283,7 @@ static bool get_14b_UID(iso14b_card_select_t *card) { } } // retry - if ( !retry ) + if ( retry <= 0 ) PrintAndLogEx(WARNING, "timeout while waiting for reply."); return false; @@ -461,6 +461,7 @@ bool HF14B_Std_Info(bool verbose){ PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid); print_atqb_resp(card.atqb, card.cid); isSuccess = true; + break; case 2: if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); break; diff --git a/client/cmdhf15.c b/client/cmdhf15.c index d8a212130..097a52704 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -519,21 +519,21 @@ int CmdHF15Info(const char *Cmd) { SendCommand(&c); if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { - PrintAndLogEx(NORMAL, "iso15693 card select failed"); + PrintAndLogEx(WARNING, "iso15693 card select failed"); return 1; } uint32_t status = resp.arg[0]; if ( status < 2 ) { - PrintAndLogEx(NORMAL, "iso15693 card doesn't answer to systeminfo command"); + PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command"); return 1; } recv = resp.d.asBytes; if ( recv[0] & ISO15_RES_ERROR ) { - PrintAndLogEx(NORMAL, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + PrintAndLogEx(WARNING, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); return 3; } @@ -575,8 +575,8 @@ int CmdHF15Info(const char *Cmd) { // Record Activity without enabeling carrier //helptext int CmdHF15Record(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_15_record(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_15_record(); UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693, {0,0,0}}; clearCommandBuffer(); @@ -598,8 +598,8 @@ int HF15Reader(const char *Cmd, bool verbose) { } int CmdHF15Reader(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_15_reader(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_15_reader(); HF15Reader(Cmd, true); return 0; @@ -608,16 +608,16 @@ int CmdHF15Reader(const char *Cmd) { // Simulation is still not working very good // helptext int CmdHF15Sim(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') return usage_15_sim(); + char cmdp =tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_sim(); uint8_t uid[8] = {0,0,0,0,0,0,0,0}; if (param_gethex(Cmd, 0, uid, 16)) { - PrintAndLogEx(NORMAL, "UID must include 16 HEX symbols"); + PrintAndLogEx(WARNING, "UID must include 16 HEX symbols"); return 0; } - PrintAndLogEx(NORMAL, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid)) ); + PrintAndLogEx(SUCCESS, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid)) ); UsbCommand c = {CMD_SIMTAG_ISO_15693, {0, 0, 0}}; memcpy(c.d.asBytes, uid, 8); @@ -630,10 +630,10 @@ int CmdHF15Sim(const char *Cmd) { // (There is no standard way of reading the AFI, allthough some tags support this) // helptext int CmdHF15Afi(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_15_findafi(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_15_findafi(); - PrintAndLogEx(NORMAL, "press pm3-button to cancel"); + PrintAndLogEx(SUCCESS, "press pm3-button to cancel"); UsbCommand c = {CMD_ISO_15693_FIND_AFI, {strtol(Cmd, NULL, 0), 0, 0}}; clearCommandBuffer(); @@ -689,7 +689,7 @@ int CmdHF15Dump(const char*Cmd) { } // detect blocksize from card :) - PrintAndLogEx(NORMAL, "Reading memory from tag UID %s", sprintUID(NULL, uid)); + PrintAndLogEx(NORMAL, "Reading memory from tag UID " _YELLOW_(%s), sprintUID(NULL, uid)); int blocknum = 0; uint8_t *recv = NULL; @@ -764,7 +764,7 @@ int CmdHF15Dump(const char*Cmd) { } int CmdHF15Restore(const char*Cmd) { - FILE *file; + FILE *f; uint8_t uid[8]={0x00}; char filename[FILE_PATH_SIZE] = {0x00}; @@ -774,10 +774,10 @@ int CmdHF15Restore(const char*Cmd) { char newCmdPrefix[255] = {0x00}, tmpCmd[255] = {0x00}; char param[FILE_PATH_SIZE]=""; char hex[255]=""; - uint8_t retries = 3, tried = 0; + uint8_t retries = 3, tried = 0, i = 0; int retval=0; size_t bytes_read; - uint8_t i=0; + while(param_getchar(Cmd, cmdp) != 0x00) { switch(tolower(param_getchar(Cmd, cmdp))) { case '-': @@ -785,7 +785,8 @@ int CmdHF15Restore(const char*Cmd) { switch(param[1]) { case '2': - case 'o': strncpy(newCmdPrefix, " ",sizeof(newCmdPrefix)-1); + case 'o': + strncpy(newCmdPrefix, " ", sizeof(newCmdPrefix)-1); strncat(newCmdPrefix, param, sizeof(newCmdPrefix)-1); break; default: @@ -815,60 +816,64 @@ int CmdHF15Restore(const char*Cmd) { default: PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); return usage_15_restore(); - break; } cmdp++; } + PrintAndLogEx(INFO,"Blocksize: %u",blocksize); - if(filename[0]=='\0') - { + + if ( !strlen(filename)) { PrintAndLogEx(WARNING,"Please provide a filename"); - return 1; + return usage_15_restore(); } - if ((file = fopen(filename,"rb")) == NULL) { + if ((f = fopen(filename, "rb")) == NULL) { PrintAndLogEx(WARNING, "Could not find file %s", filename); return 2; } if (!getUID(uid)) { PrintAndLogEx(WARNING, "No tag found"); + fclose(f); return 3; } + while (1) { - tried=0; - hex[0]=0x00; - tmpCmd[0]=0x00; + tried = 0; + hex[0] = 0x00; + tmpCmd[0] = 0x00; - bytes_read = fread( buff, 1, blocksize, file ); + bytes_read = fread( buff, 1, blocksize, f ); if ( bytes_read == 0) { - PrintAndLogEx(SUCCESS, "File reading done (%s).", filename); - fclose(file); + PrintAndLogEx(SUCCESS, "File reading done `%s`", filename); + fclose(f); return 0; - } - else if ( bytes_read != blocksize) { + } else if ( bytes_read != blocksize) { PrintAndLogEx(WARNING, "File reading error (%s), %u bytes read instead of %u bytes.", filename, bytes_read, blocksize); - fclose(file); + fclose(f); return 2; } - for(int j=0;j= retries) return retval; + i++; } - fclose(file); + fclose(f); } int CmdHF15List(const char *Cmd) { @@ -1241,7 +1246,7 @@ int CmdHF15Write(const char *Cmd) { AddCrc(req, reqlen); c.arg[0] = reqlen+2; - PrintAndLogEx(NORMAL, "iso15693 writing to page %02d (0x&02X) | data ", pagenum, pagenum); + PrintAndLogEx(NORMAL, "iso15693 writing to page %02d (0x%02X) | data ", pagenum, pagenum); clearCommandBuffer(); SendCommand(&c); diff --git a/client/cmdhfemv.c b/client/cmdhfemv.c deleted file mode 100644 index ab9396a14..000000000 --- a/client/cmdhfemv.c +++ /dev/null @@ -1,351 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2014 Peter Fillmore -// 2017 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. -//----------------------------------------------------------------------------- -// High frequency EMV commands -//----------------------------------------------------------------------------- -#include "cmdhfemv.h" - -static int CmdHelp(const char *Cmd); - -int usage_hf_emv_test(void){ - PrintAndLogEx(NORMAL, "EMV test "); - PrintAndLogEx(NORMAL, "Usage: hf emv test [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv test"); - return 0; -} -int usage_hf_emv_readrecord(void){ - PrintAndLogEx(NORMAL, "Read a EMV record "); - PrintAndLogEx(NORMAL, "Usage: hf emv readrecord [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " : number of records"); - PrintAndLogEx(NORMAL, " : number of SFI records"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv readrecord 1 1"); - return 0; -} -int usage_hf_emv_clone(void){ - PrintAndLogEx(NORMAL, "Usage: hf emv clone [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " : number of records"); - PrintAndLogEx(NORMAL, " : number of SFI records"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv clone 10 10"); - return 0; -} -int usage_hf_emv_transaction(void){ - PrintAndLogEx(NORMAL, "Performs EMV reader transaction"); - PrintAndLogEx(NORMAL, "Usage: hf emv trans [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv trans"); - return 0; -} -int usage_hf_emv_getrnd(void){ - PrintAndLogEx(NORMAL, "retrieve the UN number from a terminal"); - PrintAndLogEx(NORMAL, "Usage: hf emv getrnd [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv getrnd"); - return 0; -} -int usage_hf_emv_eload(void){ - PrintAndLogEx(NORMAL, "set EMV tags in the device to use in a transaction"); - PrintAndLogEx(NORMAL, "Usage: hf emv eload [h] o "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " o : filename w/o '.bin'"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv eload o myfile"); - return 0; -} -int usage_hf_emv_dump(void){ - PrintAndLogEx(NORMAL, "Gets EMV contactless tag values."); - PrintAndLogEx(NORMAL, "and saves binary dump into the file `filename.bin` or `cardUID.bin`"); - PrintAndLogEx(NORMAL, "Usage: hf emv dump [h] o "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " o : filename w/o '.bin' to dump bytes"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv dump"); - PrintAndLogEx(NORMAL, " hf emv dump o myfile"); - return 0; -} -int usage_hf_emv_sim(void){ - PrintAndLogEx(NORMAL, "Simulates a EMV contactless card"); - PrintAndLogEx(NORMAL, "Usage: hf emv sim [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv sim"); - return 0; -} - -int CmdHfEmvTest(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if ( cmdp == 'h' || cmdp == 'H') return usage_hf_emv_test(); - - UsbCommand c = {CMD_EMV_TEST, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(WARNING, "Command execute time-out"); - return 1; - } - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLogEx(NORMAL, "isOk: %02x", isOK); - return 0; -} - -int CmdHfEmvReadRecord(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if ((strlen(Cmd)<3) || cmdp == 'h' || cmdp == 'H') return usage_hf_emv_readrecord(); - - uint8_t record = param_get8(Cmd, 0); - uint8_t sfi = param_getchar(Cmd, 1); - if(record > 32){ - PrintAndLogEx(WARNING, "Record must be less than 32"); - return 1; - } - PrintAndLogEx(NORMAL, "--record no:%02x SFI:%02x ", record, sfi); - - UsbCommand c = {CMD_EMV_READ_RECORD, {record, sfi, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(WARNING, "Command execute timeout"); - return 1; - } - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLogEx(NORMAL, "isOk:%02x", isOK); - return 0; -} - -int CmdHfEmvClone(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if ((strlen(Cmd)<3) || cmdp == 'h' || cmdp == 'H') return usage_hf_emv_clone(); - - uint8_t record = param_get8(Cmd, 0); - uint8_t sfi = param_get8(Cmd, 1); - if(record > 32){ - PrintAndLogEx(WARNING, "Record must be less than 32"); - return 1; - } - UsbCommand c = {CMD_EMV_CLONE, {sfi, record, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(WARNING, "Command execute timeout"); - return 1; - } - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLogEx(NORMAL, "isOk:%02x", isOK); - return 0; -} - -int CmdHfEmvTrans(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if ( cmdp == 'h' || cmdp == 'H') return usage_hf_emv_transaction(); - - UsbCommand c = {CMD_EMV_TRANSACTION, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 5000)) { - PrintAndLogEx(WARNING, "Command execute time-out"); - return 1; - } - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLogEx(NORMAL, "isOk: %02x", isOK); - print_hex_break(resp.d.asBytes, 512, 32); - return 0; -} -//retrieve the UN number from a terminal -int CmdHfEmvGetrng(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if ( cmdp == 'h' || cmdp == 'H') return usage_hf_emv_getrnd(); - UsbCommand c = {CMD_EMV_GET_RANDOM_NUM, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; -} -//Load a dumped EMV tag on to emulator memory -int CmdHfEmvELoad(const char *Cmd) { - FILE * f; - char filename[FILE_PATH_SIZE]; - char *fnameptr = filename; - int len; - bool errors = false; - uint8_t cmdp = 0; - - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { - case 'h': - case 'H': - return usage_hf_emv_eload(); - case 'o': - case 'O': - len = param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE); - if (!len) - errors = true; - if (len > FILE_PATH_SIZE-5) - len = FILE_PATH_SIZE-5; - sprintf(fnameptr + len,".bin"); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors || cmdp == 0) return usage_hf_emv_eload(); - - // open file - f = fopen(filename,"r"); - if (!f) { - PrintAndLogEx(WARNING, "File %s not found or locked", filename); - return 1; - } - - char line[512]; - char *token; - uint16_t tag; - - UsbCommand c = {CMD_EMV_LOAD_VALUE, {0,0,0}}; - - // transfer to device - while (fgets(line, sizeof (line), f)) { - PrintAndLogEx(NORMAL, "LINE = %s\n", line); - - token = strtok(line, ":"); - tag = (uint16_t)strtol(token, NULL, 0); - token = strtok(NULL,""); - - c.arg[0] = tag; - memcpy(c.d.asBytes, token, strlen(token)); - - clearCommandBuffer(); - SendCommand(&c); - - PrintAndLogEx(NORMAL, "Loaded TAG = %04x\n", tag); - PrintAndLogEx(NORMAL, "Loaded VALUE = %s\n", token); - } - - fclose(f); - PrintAndLogEx(NORMAL, "loaded %s", filename); - //PrintAndLogEx(NORMAL, "\nLoaded %d bytes from file: %s to emulator memory", numofbytes, filename); - return 0; -} - -int CmdHfEmvDump(const char *Cmd){ - - bool errors = false; - uint8_t cmdp = 0; - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { - case 'h': - case 'H': - return usage_hf_emv_dump(); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors) return usage_hf_emv_dump(); - - UsbCommand c = {CMD_EMV_DUMP_CARD, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) { - PrintAndLogEx(WARNING, "Command execute time-out"); - return 1; - } - return 0; -} - -int CmdHfEmvSim(const char *Cmd) { - - bool errors = false; - uint8_t cmdp = 0; - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { - case 'h': - case 'H': - return usage_hf_emv_sim(); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors) return usage_hf_emv_sim(); - - UsbCommand c = {CMD_EMV_SIM, {0,0,0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(WARNING, "Command execute time-out"); - return 1; - } - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLogEx(NORMAL, "isOk:%02x", isOK); - return 0; -} - -int CmdHfEmvList(const char *Cmd) { - return CmdTraceList("7816"); -} - -static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"readrecord", CmdHfEmvReadRecord, 0, "EMV Read Record"}, - {"transaction", CmdHfEmvTrans, 0, "Perform EMV Transaction"}, - {"getrng", CmdHfEmvGetrng, 0, "get random number from terminal"}, - {"eload", CmdHfEmvELoad, 0, "load EMV tag into device"}, - {"dump", CmdHfEmvDump, 0, "dump EMV tag values"}, - {"sim", CmdHfEmvSim, 0, "simulate EMV tag"}, - {"clone", CmdHfEmvClone, 0, "clone an EMV tag"}, - {"list", CmdHfEmvList, 0, "[Deprecated] List ISO7816 history"}, - {"test", CmdHfEmvTest, 0, "Test Function"}, - {NULL, NULL, 0, NULL} -}; - -int CmdHFEmv(const char *Cmd) { - clearCommandBuffer(); - CmdsParse(CommandTable, Cmd); - return 0; -} - -int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; -} \ No newline at end of file diff --git a/client/cmdhfemv.h b/client/cmdhfemv.h deleted file mode 100644 index 0b68a455c..000000000 --- a/client/cmdhfemv.h +++ /dev/null @@ -1,45 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2014 Peter Fillmore -// 2017 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. -//----------------------------------------------------------------------------- -// High frequency EMV commands -//----------------------------------------------------------------------------- - -#ifndef CMDHFEMV_H__ -#define CMDHFEMV_H__ - -#include -#include -#include "proxmark3.h" -#include "ui.h" -#include "cmdparser.h" -#include "cmdmain.h" -#include "util.h" -#include "cmdhf.h" // "hf list" - -int CmdHFEmv(const char *Cmd); - -int CmdHfEmvTest(const char *Cmd); -int CmdHfEmvReadRecord(const char *Cmd); -int CmdHfEmvClone(const char *Cmd); -int CmdHfEmvTrans(const char *Cmd); -int CmdHfEmvGetrng(const char *Cmd); -int CmdHfEmvELoad(const char *Cmd); -int CmdHfEmvDump(const char *Cmd); -int CmdHfEmvSim(const char *Cmd); -int CmdHfEmvList(const char *Cmd); - -int usage_hf_emv_test(void); -int usage_hf_emv_readrecord(void); -int usage_hf_emv_clone(void); -int usage_hf_emv_transaction(void); -int usage_hf_emv_getrnd(void); -int usage_hf_emv_eload(void); -int usage_hf_emv_dump(void); -int usage_hf_emv_sim(void); - -#endif diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index b681810ed..dd110c9c0 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -43,7 +43,7 @@ int CmdHFEPACollectPACENonces(const char *Cmd) PrintAndLogEx(FAILED, "Error in step %d, Return code: %d",resp.arg[0],(int)resp.arg[1]); } else { size_t nonce_length = resp.arg[1]; - char *nonce = (char *) malloc(2 * nonce_length + 1); + char *nonce = (char *) calloc(2 * nonce_length + 1, sizeof(uint8_t)); for(int j = 0; j < nonce_length; j++) { sprintf(nonce + (2 * j), "%02X", resp.d.asBytes[j]); } diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index e8eeceb5e..efb6b68d7 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -66,7 +66,7 @@ int usage_hf_felica_raw(void){ int CmdHFFelicaList(const char *Cmd) { //PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list felica' instead"); - CmdTraceList("raw"); + CmdTraceList("felica"); return 0; } @@ -242,7 +242,7 @@ static void printSep() { PrintAndLogEx(NORMAL, "------------------------------------------------------------------------------------"); } -uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) { +uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace, uint16_t tracelen) { if (tracepos+19 >= tracelen) return tracelen; @@ -253,7 +253,7 @@ uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) { char line[110] = {0}; for (int j = 0; j < 16; j++) { - snprintf(line+( j * 4),110, "%02x ", trace[j+3]); + snprintf(line + (j * 4), sizeof(line) - 1 - (j*4) , "%02x ", trace[j+3]); } PrintAndLogEx(NORMAL, "block number %02x, status: %02x %02x",blocknum,status1, status2); @@ -273,11 +273,12 @@ uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) { case 0x0c: PrintAndLogEx(NORMAL, "S_PAD12: %s",line);break; case 0x0d: PrintAndLogEx(NORMAL, "S_PAD13: %s",line);break; case 0x0E: { - uint32_t regA = trace[3] + (trace[4]>>8) + (trace[5]>>16) + (trace[6]>>24); - uint32_t regB = trace[7] + (trace[8]>>8) + (trace[9]>>16) + (trace[10]>>24); + uint32_t regA = trace[3] | trace[4] << 8 | trace[5] << 16 | trace[ 6] << 24; + uint32_t regB = trace[7] | trace[8] << 8 | trace[9] << 16 | trace[10] << 24; line[0] = 0; for (int j = 0; j < 8; j++) - snprintf(line+( j * 2),110, "%02x", trace[j+11]); + snprintf(line + (j*2), sizeof(line)-1-(j*2), "%02x", trace[j+11]); + PrintAndLogEx(NORMAL, "REG: regA: %d regB: %d regC: %s ", regA, regB, line); } break; @@ -287,10 +288,10 @@ uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) { char idd[20]; char idm[20]; for (int j = 0; j < 8; j++) - snprintf(idd+( j * 2),20, "%02x", trace[j+3]); + snprintf(idd + (j*2), sizeof(idd)-1-(j*2), "%02x", trace[j+3]); for (int j = 0; j < 6; j++) - snprintf(idm+( j * 2),20, "%02x", trace[j+13]); + snprintf(idm + (j*2), sizeof(idm)-1-(j*2), "%02x", trace[j+13]); PrintAndLogEx(NORMAL, "ID Block, IDd: 0x%s DFC: 0x%02x%02x Arb: %s ", idd, trace[11], trace [12], idm); } @@ -299,10 +300,10 @@ uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) { char idm[20]; char pmm[20]; for (int j = 0; j < 8; j++) - snprintf(idm+( j * 2),20, "%02x", trace[j+3]); + snprintf(idm + (j*2), sizeof(idm)-1-(j*2), "%02x", trace[j+3]); for (int j = 0; j < 8; j++) - snprintf(pmm+( j * 2),20, "%02x", trace[j+11]); + snprintf(pmm + (j*2), sizeof(pmm)-1-(j*2), "%02x", trace[j+11]); PrintAndLogEx(NORMAL, "DeviceId: IDm: 0x%s PMm: 0x%s ", idm, pmm); } diff --git a/client/cmdhffido.c b/client/cmdhffido.c index 9ce554ce2..6d7741153 100644 --- a/client/cmdhffido.c +++ b/client/cmdhffido.c @@ -914,7 +914,7 @@ static command_t CommandTable[] = }; int CmdHFFido(const char *Cmd) { - (void)WaitForResponseTimeout(CMD_ACK,NULL,100); + (void)WaitForResponseTimeout(CMD_ACK, NULL, 100); CmdsParse(CommandTable, Cmd); return 0; } diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 6cc2aa191..82e14d5ea 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -404,7 +404,7 @@ int CmdHFiClassSim(const char *Cmd) { break; size_t datalen = NUM_CSNS * 24; - void* dump = malloc(datalen); + void* dump = calloc(datalen, sizeof(uint8_t)); if ( !dump ) { PrintAndLogEx(WARNING, "Failed to allocate memory"); return 2; @@ -456,7 +456,7 @@ int CmdHFiClassSim(const char *Cmd) { break; size_t datalen = NUM_CSNS * 24; - void* dump = malloc(datalen); + void* dump = calloc(datalen, sizeof(uint8_t)); if ( !dump ) { PrintAndLogEx(WARNING, "Failed to allocate memory"); return 2; @@ -626,7 +626,7 @@ int CmdHFiClassELoad(const char *Cmd) { f = fopen(filename, "rb"); if ( !f ){ - PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename); + PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename); return 1; } @@ -2162,10 +2162,10 @@ static int cmp_uint32( const void *a, const void *b) { int CmdHFiClassLookUp(const char *Cmd) { uint8_t CSN[8]; - uint8_t EPURSE[8]; - uint8_t MACS[8]; + uint8_t EPURSE[8] = { 0,0,0,0,0,0,0,0 }; + uint8_t MACS[8]= { 0,0,0,0,0,0,0,0 }; uint8_t CCNR[12]; - uint8_t MAC_TAG[4] = {0x00,0x00,0x00,0x00}; + uint8_t MAC_TAG[4] = { 0,0,0,0 }; // elite key, raw key, standard key bool use_elite = false; @@ -2304,7 +2304,7 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) { int keyitems = 0; if ( !(f = fopen( filename , "r")) ) { - PrintAndLogEx(ERR, "file: %s: not found or locked.", filename); + PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename); return 1; } @@ -2316,7 +2316,8 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) { while (fgetc(f) != '\n' && !feof(f)) {}; //The line start with # is comment, skip - if( buf[0]=='#' ) continue; + if( buf[0]=='#' ) + continue; // doesn't this only test first char only? if (!isxdigit(buf[0])){ @@ -2329,7 +2330,7 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) { p = realloc(*keys, 8 * (keyitems += 64)); if (!p) { - PrintAndLogEx(NORMAL, _RED_([!])" cannot allocate memory for default keys"); + PrintAndLogEx(ERR, "cannot allocate memory for default keys"); fclose(f); return 2; } @@ -2341,7 +2342,7 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) { memset(buf, 0, sizeof(buf)); } fclose(f); - PrintAndLogEx(NORMAL, _BLUE_([+]) "Loaded " _GREEN_(%2d) " keys from %s", *keycnt, filename); + PrintAndLogEx(SUCCESS, "Loaded " _GREEN_(%2d) " keys from %s", *keycnt, filename); return 0; } @@ -2462,7 +2463,7 @@ static void shave(uint8_t *data, uint8_t len){ data[i] &= 0xFE; } static void generate_rev(uint8_t *data, uint8_t len) { - uint8_t *key = calloc(len,1); + uint8_t *key = calloc(len, sizeof(uint8_t)); PrintAndLogEx(SUCCESS, "input permuted key | %s \n", sprint_hex(data, len)); permute_rev(data, len, key); PrintAndLogEx(SUCCESS, " unpermuted key | %s \n", sprint_hex(key, len)); @@ -2471,8 +2472,8 @@ static void generate_rev(uint8_t *data, uint8_t len) { free(key); } static void generate(uint8_t *data, uint8_t len) { - uint8_t *key = calloc(len,1); - uint8_t *pkey = calloc(len,1); + uint8_t *key = calloc(len, sizeof(uint8_t)); + uint8_t *pkey = calloc(len, sizeof(uint8_t)); PrintAndLogEx(SUCCESS, " input key | %s \n", sprint_hex(data, len)); permute(data, len, pkey); PrintAndLogEx(SUCCESS, "permuted key | %s \n", sprint_hex(pkey, len)); diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 393d73ed0..41df287a9 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -180,15 +180,14 @@ int CmdLegicInfo(const char *Cmd) { return 1; } - PrintAndLogEx(NORMAL, "Reading tag memory %d b...", card.cardsize); + PrintAndLogEx(SUCCESS, "Reading tag memory %d b...", card.cardsize); // allocate receiver buffer - uint8_t *data = malloc(card.cardsize); + uint8_t *data = calloc(card.cardsize, sizeof(uint8_t)); if (!data) { PrintAndLogEx(WARNING, "Cannot allocate memory"); return 2; } - memset(data, 0, card.cardsize); int status = legic_read_mem(0, card.cardsize, 0x55, data, &datalen); if ( status > 0 ) { @@ -480,15 +479,20 @@ int CmdLegicRdmem(const char *Cmd) { uint16_t datalen = 0; sscanf(Cmd, "%x %x %x", &offset, &len, &iv); - PrintAndLogEx(NORMAL, "Reading %d bytes, from offset %d", len, offset); + // sanity checks + if ( len + offset >= MAX_LENGTH ) { + PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", MAX_LENGTH, len + offset); + return -1; + } + + PrintAndLogEx(SUCCESS, "Reading %d bytes, from offset %d", len, offset); // allocate receiver buffer - uint8_t *data = malloc(len); + uint8_t *data = calloc(len, sizeof(uint8_t)); if ( !data ){ PrintAndLogEx(WARNING, "Cannot allocate memory"); - return 2; + return -2; } - memset(data, 0, len); int status = legic_read_mem(offset, len, iv, data, &datalen); if ( status == 0 ) { @@ -540,9 +544,9 @@ int CmdLegicRfWrite(const char *Cmd) { } // limit number of bytes to write. This is not a 'restore' command. - if ( (len>>1) > 100 ){ - PrintAndLogEx(NORMAL, "Max bound on 100bytes to write a one time."); - PrintAndLogEx(NORMAL, "Use the 'hf legic restore' command if you want to write the whole tag at once"); + if ( (len >> 1) > 100 ){ + PrintAndLogEx(WARNING, "Max bound on 100bytes to write a one time."); + PrintAndLogEx(WARNING, "Use the 'hf legic restore' command if you want to write the whole tag at once"); errors = true; } @@ -551,7 +555,7 @@ int CmdLegicRfWrite(const char *Cmd) { if (data) free(data); - data = malloc(len >> 1); + data = calloc(len >> 1, sizeof(uint8_t)); if ( data == NULL ) { PrintAndLogEx(WARNING, "Can't allocate memory. exiting"); errors = true; @@ -598,12 +602,12 @@ int CmdLegicRfWrite(const char *Cmd) { // OUT-OF-BOUNDS checks // UID 4+1 bytes can't be written to. if ( offset < 5 ) { - PrintAndLogEx(NORMAL, "Out-of-bounds, bytes 0-1-2-3-4 can't be written to. Offset = %d", offset); + PrintAndLogEx(WARNING, "Out-of-bounds, bytes 0-1-2-3-4 can't be written to. Offset = %d", offset); return -2; } if ( len + offset >= card.cardsize ) { - PrintAndLogEx(NORMAL, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", card.cardsize, len + offset); + PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", card.cardsize, len + offset); return -2; } @@ -622,7 +626,7 @@ int CmdLegicRfWrite(const char *Cmd) { legic_chk_iv(&IV); - PrintAndLogEx(NORMAL, "Writing to tag"); + PrintAndLogEx(SUCCESS, "Writing to tag"); UsbCommand c = {CMD_WRITER_LEGIC_RF, {offset, len, IV}}; memcpy(c.d.asBytes, data, len); @@ -630,10 +634,18 @@ int CmdLegicRfWrite(const char *Cmd) { clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(WARNING, "command execution time out"); - return 1; - } + + uint8_t timeout = 0; + while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + ++timeout; + printf("."); fflush(stdout); + if (timeout > 7) { + PrintAndLogEx(WARNING, "\ncommand execution time out"); + return 1; + } + } + PrintAndLogEx(NORMAL, "\n"); + uint8_t isOK = resp.arg[0] & 0xFF; if ( !isOK ) { PrintAndLogEx(WARNING, "Failed writing tag"); @@ -673,7 +685,7 @@ int CmdLegicCalcCrc(const char *Cmd){ // it's possible for user to accidentally enter "b" parameter // more than once - we have to clean previous malloc if (data) free(data); - data = malloc(len >> 1); + data = calloc(len >> 1, sizeof(uint8_t) ); if ( data == NULL ) { PrintAndLogEx(WARNING, "Can't allocate memory. exiting"); errors = true; @@ -714,10 +726,10 @@ int CmdLegicCalcCrc(const char *Cmd){ switch (type){ case 16: init_table(CRC_LEGIC); - PrintAndLogEx(NORMAL, "Legic crc16: %X", crc16_legic(data, len, uidcrc)); + PrintAndLogEx(SUCCESS, "Legic crc16: %X", crc16_legic(data, len, uidcrc)); break; default: - PrintAndLogEx(NORMAL, "Legic crc8: %X", CRC8Legic(data, len) ); + PrintAndLogEx(SUCCESS, "Legic crc8: %X", CRC8Legic(data, len) ); break; } @@ -733,11 +745,18 @@ int legic_read_mem(uint32_t offset, uint32_t len, uint32_t iv, uint8_t *out, uin clearCommandBuffer(); SendCommand(&c); UsbCommand resp; - if ( !WaitForResponseTimeout(CMD_ACK, &resp, 3000) ) { - PrintAndLogEx(WARNING, "command execution time out"); - return 1; - } - + + uint8_t timeout = 0; + while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + ++timeout; + printf("."); fflush(stdout); + if (timeout > 7) { + PrintAndLogEx(WARNING, "\ncommand execution time out"); + return 1; + } + } + PrintAndLogEx(NORMAL, "\n"); + uint8_t isOK = resp.arg[0] & 0xFF; *outlen = resp.arg[1]; if ( !isOK ) { @@ -762,13 +781,13 @@ int legic_print_type(uint32_t tagtype, uint8_t spaces){ char *spacer = spc + (10-spaces); if ( tagtype == 22 ) - PrintAndLogEx(NORMAL, "%sTYPE : MIM%d card (outdated)", spacer, tagtype); + PrintAndLogEx(SUCCESS, "%sTYPE : MIM%d card (outdated)", spacer, tagtype); else if ( tagtype == 256 ) - PrintAndLogEx(NORMAL, "%sTYPE : MIM%d card (234 bytes)", spacer, tagtype); + PrintAndLogEx(SUCCESS, "%sTYPE : MIM%d card (234 bytes)", spacer, tagtype); else if ( tagtype == 1024 ) - PrintAndLogEx(NORMAL, "%sTYPE : MIM%d card (1002 bytes)", spacer, tagtype); + PrintAndLogEx(SUCCESS, "%sTYPE : MIM%d card (1002 bytes)", spacer, tagtype); else - PrintAndLogEx(NORMAL, "%sTYPE : Unknown %06x", spacer, tagtype); + PrintAndLogEx(INFO, "%sTYPE : Unknown %06x", spacer, tagtype); return 0; } int legic_get_type(legic_card_select_t *card){ @@ -792,12 +811,12 @@ int legic_get_type(legic_card_select_t *card){ void legic_chk_iv(uint32_t *iv){ if ( (*iv & 0x7F) != *iv ){ *iv &= 0x7F; - PrintAndLogEx(NORMAL, "Truncating IV to 7bits, %u", *iv); + PrintAndLogEx(INFO, "Truncating IV to 7bits, %u", *iv); } // IV must be odd if ( (*iv & 1) == 0 ){ *iv |= 0x01; - PrintAndLogEx(NORMAL, "LSB of IV must be SET %u", *iv); + PrintAndLogEx(INFO, "LSB of IV must be SET %u", *iv); } } void legic_seteml(uint8_t *src, uint32_t offset, uint32_t numofbytes) { @@ -828,11 +847,11 @@ int HFLegicReader(const char *Cmd, bool verbose) { if ( verbose ) PrintAndLogEx(WARNING, "command execution time out"); return 1; case 3: - if ( verbose ) PrintAndLogEx(NORMAL, "legic card select failed"); + if ( verbose ) PrintAndLogEx(WARNING, "legic card select failed"); return 2; default: break; } - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, sizeof(card.uid))); + PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, sizeof(card.uid))); legic_print_type(card.cardsize, 0); return 0; } @@ -882,16 +901,23 @@ int CmdLegicDump(const char *Cmd){ dumplen = card.cardsize; legic_print_type(dumplen, 0); - PrintAndLogEx(NORMAL, "Reading tag memory %d b...", dumplen); + PrintAndLogEx(SUCCESS, "Reading tag memory %d b...", dumplen); UsbCommand c = {CMD_READER_LEGIC_RF, {0x00, dumplen, 0x55}}; clearCommandBuffer(); SendCommand(&c); UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) { - PrintAndLogEx(NORMAL, "Command execute time-out"); - return 1; - } + + uint8_t timeout = 0; + while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + ++timeout; + printf("."); fflush(stdout); + if (timeout > 7) { + PrintAndLogEx(WARNING, "\ncommand execution time out"); + return 1; + } + } + PrintAndLogEx(NORMAL, "\n"); uint8_t isOK = resp.arg[0] & 0xFF; if ( !isOK ) { @@ -900,12 +926,11 @@ int CmdLegicDump(const char *Cmd){ } uint16_t readlen = resp.arg[1]; - uint8_t *data = malloc(readlen); + uint8_t *data = calloc(readlen, sizeof(uint8_t)); if (!data) { PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); return 3; } - memset(data, 0, readlen); if ( readlen != dumplen ) PrintAndLogEx(WARNING, "Fail, only managed to read 0x%02X bytes of 0x%02X", readlen, dumplen); @@ -923,7 +948,7 @@ int CmdLegicDump(const char *Cmd){ else sprintf(fnameptr + fileNlen,".bin"); - f = fopen(filename,"wb"); + f = fopen(filename, "wb"); if (!f) { PrintAndLogEx(WARNING, "Could not create file name %s", filename); if (data) @@ -934,7 +959,7 @@ int CmdLegicDump(const char *Cmd){ fflush(f); fclose(f); free(data); - PrintAndLogEx(NORMAL, "Wrote %d bytes to %s", readlen, filename); + PrintAndLogEx(SUCCESS, "Wrote %d bytes to %s", readlen, filename); return 0; } @@ -982,12 +1007,11 @@ int CmdLegicRestore(const char *Cmd){ numofbytes = card.cardsize; // set up buffer - uint8_t *data = malloc(numofbytes); + uint8_t *data = calloc(numofbytes, sizeof(uint8_t) ); if (!data) { PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); return 2; } - memset(data, 0, numofbytes); legic_print_type(numofbytes, 0); @@ -997,7 +1021,8 @@ int CmdLegicRestore(const char *Cmd){ f = fopen(filename,"rb"); if (!f) { - PrintAndLogEx(NORMAL, "File %s not found or locked", filename); + PrintAndLogEx(WARNING, "File %s not found or locked", filename); + free(data); return 3; } @@ -1018,12 +1043,12 @@ int CmdLegicRestore(const char *Cmd){ fclose(f); if ( bytes_read == 0){ - PrintAndLogEx(NORMAL, "File reading error"); + PrintAndLogEx(WARNING, "File reading error"); free(data); return 2; } - PrintAndLogEx(NORMAL, "Restoring to card"); + PrintAndLogEx(SUCCESS, "Restoring to card"); // transfer to device size_t len = 0; @@ -1038,22 +1063,29 @@ int CmdLegicRestore(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) { - PrintAndLogEx(WARNING, "command execution time out"); - free(data); - return 1; - } + uint8_t timeout = 0; + while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + ++timeout; + printf("."); fflush(stdout); + if (timeout > 7) { + PrintAndLogEx(WARNING, "\ncommand execution time out"); + free(data); + return 1; + } + } + PrintAndLogEx(NORMAL, "\n"); + uint8_t isOK = resp.arg[0] & 0xFF; if ( !isOK ) { PrintAndLogEx(WARNING, "Failed writing tag [msg = %u]", resp.arg[1] & 0xFF); free(data); return 1; } - PrintAndLogEx(NORMAL, "Wrote chunk [offset %d | len %d | total %d", i, len, i+len); + PrintAndLogEx(SUCCESS, "Wrote chunk [offset %d | len %d | total %d", i, len, i+len); } free(data); - PrintAndLogEx(NORMAL, "\nWrote %d bytes to card from file %s", numofbytes, filename); + PrintAndLogEx(SUCCESS, "\nWrote %d bytes to card from file %s", numofbytes, filename); return 0; } @@ -1077,12 +1109,11 @@ int CmdLegicELoad(const char *Cmd) { } // set up buffer - uint8_t *data = malloc(numofbytes); + uint8_t *data = calloc(numofbytes, sizeof(uint8_t)); if (!data) { PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); return 3; } - memset(data, 0, numofbytes); // set up file len = param_getstr(Cmd, nameParamNo, filename, FILE_PATH_SIZE); @@ -1094,7 +1125,7 @@ int CmdLegicELoad(const char *Cmd) { // open file f = fopen(filename,"rb"); if (!f) { - PrintAndLogEx(NORMAL, "File %s not found or locked", filename); + PrintAndLogEx(WARNING, "File %s not found or locked", filename); free(data); return 1; } @@ -1102,7 +1133,7 @@ int CmdLegicELoad(const char *Cmd) { // load file size_t bytes_read = fread(data, 1, numofbytes, f); if ( bytes_read == 0){ - PrintAndLogEx(NORMAL, "File reading error"); + PrintAndLogEx(WARNING, "File reading error"); free(data); fclose(f); f = NULL; @@ -1115,7 +1146,7 @@ int CmdLegicELoad(const char *Cmd) { legic_seteml(data, 0, numofbytes); free(data); - PrintAndLogEx(NORMAL, "\nLoaded %d bytes from file: %s to emulator memory", numofbytes, filename); + PrintAndLogEx(SUCCESS, "\nLoaded %d bytes from file: %s to emulator memory", numofbytes, filename); return 0; } @@ -1146,15 +1177,14 @@ int CmdLegicESave(const char *Cmd) { fileNlen = FILE_PATH_SIZE - 5; // set up buffer - uint8_t *data = malloc(numofbytes); + uint8_t *data = calloc(numofbytes, sizeof(uint8_t)); if (!data) { PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); return 3; } - memset(data, 0, numofbytes); // download emulator memory - PrintAndLogEx(NORMAL, "Reading emulator memory..."); + PrintAndLogEx(SUCCESS, "Reading emulator memory..."); if (!GetFromDevice( BIG_BUF_EML, data, numofbytes, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); free(data); @@ -1185,16 +1215,15 @@ int CmdLegicWipe(const char *Cmd){ } // set up buffer - uint8_t *data = malloc(card.cardsize); + uint8_t *data = calloc(card.cardsize, sizeof(uint8_t)); if (!data) { PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); return 2; } - memset(data, 0, card.cardsize); legic_print_type(card.cardsize, 0); - PrintAndLogEx(NORMAL, "Erasing"); + PrintAndLogEx(SUCCESS, "Erasing"); // transfer to device size_t len = 0; @@ -1210,11 +1239,18 @@ int CmdLegicWipe(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) { - PrintAndLogEx(WARNING, "command execution time out"); - free(data); - return 3; - } + uint8_t timeout = 0; + while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + ++timeout; + printf("."); fflush(stdout); + if (timeout > 7) { + PrintAndLogEx(WARNING, "\ncommand execution time out"); + free(data); + return 3; + } + } + PrintAndLogEx(NORMAL, "\n"); + uint8_t isOK = resp.arg[0] & 0xFF; if ( !isOK ) { PrintAndLogEx(WARNING, "Failed writing tag [msg = %u]", resp.arg[1] & 0xFF); @@ -1222,7 +1258,7 @@ int CmdLegicWipe(const char *Cmd){ return 4; } } - PrintAndLogEx(NORMAL, "ok\n"); + PrintAndLogEx(SUCCESS, "ok\n"); return 0; } @@ -1236,7 +1272,7 @@ static command_t CommandTable[] = { {"reader", CmdLegicReader, 1, "LEGIC Prime Reader UID and tag info"}, {"info", CmdLegicInfo, 0, "Display deobfuscated and decoded LEGIC Prime tag data"}, {"dump", CmdLegicDump, 0, "Dump LEGIC Prime tag to binary file"}, - {"restore", CmdLegicRestore, 0, "Restore a dump onto a LEGIC Prime tag"}, + {"restore", CmdLegicRestore, 0, "Restore a dump file onto a LEGIC Prime tag"}, {"rdmem", CmdLegicRdmem, 0, "Read bytes from a LEGIC Prime tag"}, {"sim", CmdLegicRfSim, 0, "Start tag simulator"}, {"write", CmdLegicRfWrite, 0, "Write data to a LEGIC Prime tag"}, diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 14dcc6039..faed275cd 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -159,6 +159,7 @@ int applyIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) { MifareAuthState = masNone; break; case ISO14443A_CMD_RATS: snprintf(exp,size,"RATS"); break; + case ISO14443A_CMD_OPTS: snprintf(exp,size,"OPTIONAL TIMESLOT"); 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; @@ -356,7 +357,7 @@ void annotateIso7816(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){ case ISO7816_EXTERNAL_AUTHENTICATION :snprintf(exp, size, "EXTERNAL AUTH");break; case ISO7816_GET_CHALLENGE :snprintf(exp, size, "GET CHALLENGE");break; case ISO7816_MANAGE_CHANNEL :snprintf(exp, size, "MANAGE CHANNEL");break; - case ISO7816_GETSTATUS :snprintf(exp, size, "GET RESPONSE");break; + case ISO7816_GET_RESPONSE :snprintf(exp, size, "GET RESPONSE");break; default :snprintf(exp,size,"?"); break; } } @@ -535,7 +536,48 @@ void annotateLegic(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){ } void annotateFelica(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){ + switch(cmd[0]){ + case FELICA_POLL_REQ: snprintf(exp,size ,"POLLING");break; + case FELICA_POLL_ACK: snprintf(exp,size ,"POLL ACK");break; + case FELICA_REQSRV_REQ: snprintf(exp,size ,"REQUEST SERVICE");break; + case FELICA_REQSRV_ACK: snprintf(exp,size ,"REQ SERV ACK");break; + case FELICA_REQRESP_REQ: snprintf(exp,size ,"REQUEST RESPONSE");break; + case FELICA_REQRESP_ACK: snprintf(exp,size ,"REQ RESP ACK");break; + case FELICA_RDBLK_REQ: snprintf(exp,size ,"READ BLK");break; + case FELICA_RDBLK_ACK: snprintf(exp,size ,"READ BLK ACK");break; + case FELICA_WRTBLK_REQ: snprintf(exp,size ,"WRITE BLK");break; + case FELICA_WRTBLK_ACK: snprintf(exp,size ,"WRITE BLK ACK");break; + case FELICA_SRCHSYSCODE_REQ: snprintf(exp,size ,"SEARCH SERVICE CODE");break; + case FELICA_SRCHSYSCODE_ACK: snprintf(exp,size ,"SSC ACK");break; + case FELICA_REQSYSCODE_REQ: snprintf(exp,size ,"REQUEST SYSTEM CODE");break; + case FELICA_REQSYSCODE_ACK: snprintf(exp,size ,"RSC ACK");break; + case FELICA_AUTH1_REQ: snprintf(exp,size ,"AUTH 1");break; + case FELICA_AUTH1_ACK: snprintf(exp,size ,"AUTH 1 ACK");break; + case FELICA_AUTH2_REQ: snprintf(exp,size ,"AUTH 2");break; + case FELICA_AUTH2_ACK: snprintf(exp,size ,"AUTH 2 ACK");break; + case FELICA_RDSEC_REQ: snprintf(exp,size ,"READ");break; + case FELICA_RDSEC_ACK: snprintf(exp,size ,"READ ACK");break; + case FELICA_WRTSEC_REQ: snprintf(exp,size ,"WRITE");break; + case FELICA_WRTSEC_ACK: snprintf(exp,size ,"WRITE ACK");break; + case FELICA_REQSRV2_REQ: snprintf(exp,size ,"REQUEST SERVICE v2");break; + case FELICA_REQSRV2_ACK: snprintf(exp,size ,"REQ SERV v2 ACK");break; + case FELICA_GETSTATUS_REQ: snprintf(exp,size ,"GET STATUS");break; + case FELICA_GETSTATUS_ACK: snprintf(exp,size ,"GET STATUS ACK");break; + case FELICA_OSVER_REQ: snprintf(exp,size ,"REQUEST SPECIFIC VERSION");break; + case FELICA_OSVER_ACK: snprintf(exp,size ,"RSV ACK");break; + case FELICA_RESET_MODE_REQ: snprintf(exp,size ,"RESET MODE");break; + case FELICA_RESET_MODE_ACK: snprintf(exp,size ,"RESET MODE ACK");break; + case FELICA_AUTH1V2_REQ: snprintf(exp,size ,"AUTH 1 v2");break; + case FELICA_AUTH1V2_ACK: snprintf(exp,size ,"AUTH 1 v2 ACK");break; + case FELICA_AUTH2V2_REQ: snprintf(exp,size ,"AUTH 2 v2");break; + case FELICA_AUTH2V2_ACK: snprintf(exp,size ,"AUTH 2 v2 ACK");break; + case FELICA_RDSECV2_REQ: snprintf(exp,size ,"READ v2");break; + case FELICA_RDSECV2_ACK: snprintf(exp,size ,"READ v2 ACK");break; + case FELICA_WRTSECV2_REQ: snprintf(exp,size ,"WRITE v2");break; + case FELICA_WRTSECV2_ACK: snprintf(exp,size ,"WRITE v2 ACK");break; + case FELICA_UPDATE_RNDID_REQ: snprintf(exp,size ,"UPDATE RANDOM ID");break; + case FELICA_UPDATE_RNDID_ACK: snprintf(exp,size ,"URI ACK");break; default : snprintf(exp,size ,"?");break; } } @@ -644,7 +686,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes PrintAndLogEx(NORMAL, " | | * |%49s %012"PRIx64" prng %s | |", "key", mfLastKey, - validate_prng_nonce(AuthData.nt) ? "WEAK": "HARD"); + validate_prng_nonce(AuthData.nt) ? _GREEN_(WEAK): _YELLOW_(HARD)); AuthData.first_auth = false; diff --git a/client/cmdhflist.h b/client/cmdhflist.h index 1955119f2..60a0a0dfd 100644 --- a/client/cmdhflist.h +++ b/client/cmdhflist.h @@ -31,8 +31,8 @@ #include "emv/cmdemv.h" // EMV #include "protocols.h" #include "crapto1/crapto1.h" -#include "mifarehost.h" -#include "mifaredefault.h" +#include "mifare/mifarehost.h" +#include "mifare/mifaredefault.h" #include "parity.h" // oddparity #include "iso15693tools.h" // ISO15693 crc diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 1bfbf10eb..8823ea2d9 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -9,13 +9,22 @@ //----------------------------------------------------------------------------- #include "cmdhfmf.h" -#include "mifare4.h" +#include "mifare/mifare4.h" +#include "mifare/mad.h" -#define MIFARE_4K_MAXBLOCK 255 + +#define MFBLOCK_SIZE 16 + +#define MIFARE_4K_MAXBLOCK 256 #define MIFARE_2K_MAXBLOCK 128 #define MIFARE_1K_MAXBLOCK 64 #define MIFARE_MINI_MAXBLOCK 20 +#define MIFARE_MINI_MAXSECTOR 5 +#define MIFARE_1K_MAXSECTOR 16 +#define MIFARE_2K_MAXSECTOR 32 +#define MIFARE_4K_MAXSECTOR 40 + static int CmdHelp(const char *Cmd); int usage_hf14_ice(void){ @@ -170,7 +179,7 @@ int usage_hf14_chk(void){ } int usage_hf14_chk_fast(void){ PrintAndLogEx(NORMAL, "This is a improved checkkeys method speedwise. It checks Mifare Classic tags sector keys against a dictionary file with keys"); - PrintAndLogEx(NORMAL, "Usage: hf mf fchk [h] [t|d] [] []"); + PrintAndLogEx(NORMAL, "Usage: hf mf fchk [h] [t|d|f] [] []"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " all sectors based on card memory, other values than below defaults to 1k"); @@ -179,12 +188,16 @@ int usage_hf14_chk_fast(void){ PrintAndLogEx(NORMAL, " 2 - 2K"); PrintAndLogEx(NORMAL, " 4 - 4K"); PrintAndLogEx(NORMAL, " d write keys to binary file"); - PrintAndLogEx(NORMAL, " t write keys to emulator memory\n"); + PrintAndLogEx(NORMAL, " t write keys to emulator memory"); + PrintAndLogEx(NORMAL, " m use dictionary from flashmemory\n"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf fchk 1 1234567890ab keys.dic -- target 1K using key 1234567890ab, using dictionary file"); PrintAndLogEx(NORMAL, " hf mf fchk 1 t -- target 1K, write to emulator memory"); PrintAndLogEx(NORMAL, " hf mf fchk 1 d -- target 1K, write to file"); +#ifdef WITH_FLASH + PrintAndLogEx(NORMAL, " hf mf fchk 1 m -- target 1K, use dictionary from flashmemory"); +#endif return 0; } int usage_hf14_keybrute(void){ @@ -411,11 +424,12 @@ int GetHFMF14AUID(uint8_t *uid, int *uidlen) { char * GenerateFilename(const char *prefix, const char *suffix){ uint8_t uid[10] = {0,0,0,0,0,0,0,0,0,0}; int uidlen=0; - char * fptr = malloc (sizeof (char) * (strlen(prefix) + strlen(suffix)) + sizeof(uid)*2 + 1); + char * fptr = calloc (sizeof (char) * (strlen(prefix) + strlen(suffix)) + sizeof(uid)*2 + 1, sizeof(uint8_t)); GetHFMF14AUID(uid, &uidlen); if (!uidlen) { PrintAndLogEx(WARNING, "No tag found."); + free(fptr); return NULL; } @@ -424,7 +438,7 @@ char * GenerateFilename(const char *prefix, const char *suffix){ return fptr; } -int CmdHF14ADarkside(const char *Cmd) { +int CmdHF14AMfDarkside(const char *Cmd) { uint8_t blockno = 0, key_type = MIFARE_AUTH_KEYA; uint64_t key = 0; @@ -587,7 +601,7 @@ int CmdHF14AMfRdSc(const char *Cmd) { } sectorNo = param_get8(Cmd, 0); - if (sectorNo > 39) { + if (sectorNo > MIFARE_4K_MAXSECTOR ) { PrintAndLogEx(NORMAL, "Sector number must be less than 40"); return 1; } @@ -641,7 +655,7 @@ int CmdHF14AMfRdSc(const char *Cmd) { return 0; } -uint8_t NumOfBlocks(char card){ +uint16_t NumOfBlocks(char card){ switch(card){ case '0' : return MIFARE_MINI_MAXBLOCK; case '1' : return MIFARE_1K_MAXBLOCK; @@ -652,11 +666,11 @@ uint8_t NumOfBlocks(char card){ } uint8_t NumOfSectors(char card){ switch(card){ - case '0' : return 5; - case '1' : return 16; - case '2' : return 32; - case '4' : return 40; - default : return 16; + case '0' : return MIFARE_MINI_MAXSECTOR; + case '1' : return MIFARE_1K_MAXSECTOR; + case '2' : return MIFARE_2K_MAXSECTOR; + case '4' : return MIFARE_4K_MAXSECTOR; + default : return MIFARE_1K_MAXSECTOR; } } @@ -687,10 +701,13 @@ int CmdHF14AMfDump(const char *Cmd) { uint8_t cmdp = 0; char keyFilename[FILE_PATH_SIZE] = {0}; - char dataFilename[FILE_PATH_SIZE] = {0}; + char dataFilename[FILE_PATH_SIZE]; char * fptr; - FILE *fin, *fout; + memset(keyFilename, 0, sizeof(keyFilename)); + memset(dataFilename, 0, sizeof(dataFilename)); + + FILE *f; UsbCommand resp; while(param_getchar(Cmd, cmdp) != 0x00) { @@ -724,37 +741,37 @@ int CmdHF14AMfDump(const char *Cmd) { strcpy(keyFilename, fptr); } - if ((fin = fopen(keyFilename, "rb")) == NULL) { - PrintAndLogEx(WARNING, "Could not find file %s", keyFilename); + if ((f = fopen(keyFilename, "rb")) == NULL) { + PrintAndLogEx(WARNING, "Could not find file " _YELLOW_(%s), keyFilename); return 1; } // Read keys A from file size_t bytes_read; for (sectorNo=0; sectorNo= FILE_PATH_SIZE ) { @@ -1534,7 +1560,7 @@ int CmdHF14AMfChk_fast(const char *Cmd) { f = fopen( filename, "r"); if ( !f ){ - PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename); + PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename); continue; } @@ -1548,7 +1574,7 @@ int CmdHF14AMfChk_fast(const char *Cmd) { if( buf[0]=='#' ) continue; //The line start with # is comment, skip if (!isxdigit(buf[0])){ - PrintAndLogEx(FAILED, "File content error. '%s' must include 12 HEX symbols",buf); + PrintAndLogEx(FAILED, "File content error. '" _YELLOW_(%s)"' must include 12 HEX symbols", buf); continue; } @@ -1570,11 +1596,11 @@ int CmdHF14AMfChk_fast(const char *Cmd) { memset(buf, 0, sizeof(buf)); } fclose(f); - PrintAndLogEx(SUCCESS, "Loaded %2d keys from %s", keycnt, filename); + PrintAndLogEx(SUCCESS, "Loaded %2d keys from " _YELLOW_(%s), keycnt, filename); } } - if (keycnt == 0) { + if (keycnt == 0 && !use_flashmemory) { PrintAndLogEx(SUCCESS, "No key specified, trying default keys"); for (;keycnt < MIFARE_DEFAULTKEYS_SIZE; keycnt++) PrintAndLogEx(NORMAL, "[%2d] %02x%02x%02x%02x%02x%02x", keycnt, @@ -1594,82 +1620,105 @@ int CmdHF14AMfChk_fast(const char *Cmd) { // time uint64_t t1 = msclock(); - - // strategys. 1= deep first on sector 0 AB, 2= width first on all sectors - for (uint8_t strategy = 1; strategy < 3; strategy++) { - PrintAndLogEx(SUCCESS, "Running strategy %u", strategy); - // main keychunk loop - for (uint32_t i = 0; i < keycnt; i += chunksize) { - - if (ukbhit()) { - int gc = getchar(); (void)gc; - PrintAndLogEx(NORMAL, "\naborted via keyboard!\n"); - goto out; - } - - uint32_t size = ((keycnt - i) > chunksize) ? chunksize : keycnt - i; - - // last chunk? - if ( size == keycnt - i) - lastChunk = true; - - int res = mfCheckKeys_fast( sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * 6), e_sector); - if ( firstChunk ) - firstChunk = false; - - // all keys, aborted - if ( res == 0 || res == 2 ) - goto out; - } // end chunks of keys - firstChunk = true; - lastChunk = false; - } // end strategy + if ( use_flashmemory ) { + PrintAndLogEx(SUCCESS, "Using dictionary in flash memory"); + mfCheckKeys_fast( sectorsCnt, true, true, 1, 0, keyBlock, e_sector, use_flashmemory); + } else { + + // strategys. 1= deep first on sector 0 AB, 2= width first on all sectors + for (uint8_t strategy = 1; strategy < 3; strategy++) { + PrintAndLogEx(SUCCESS, "Running strategy %u", strategy); + + // main keychunk loop + for (uint32_t i = 0; i < keycnt; i += chunksize) { + + if (ukbhit()) { + int gc = getchar(); (void)gc; + PrintAndLogEx(WARNING, "\naborted via keyboard!\n"); + goto out; + } + + uint32_t size = ((keycnt - i) > chunksize) ? chunksize : keycnt - i; + + // last chunk? + if ( size == keycnt - i) + lastChunk = true; + + int res = mfCheckKeys_fast( sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * 6), e_sector, false); + + if ( firstChunk ) + firstChunk = false; + + // all keys, aborted + if ( res == 0 || res == 2 ) + goto out; + } // end chunks of keys + firstChunk = true; + lastChunk = false; + } // end strategy + } out: t1 = msclock() - t1; PrintAndLogEx(SUCCESS, "Time in checkkeys (fast): %.1fs\n", (float)(t1/1000.0)); - printKeyTable( sectorsCnt, e_sector ); - - if (transferToEml) { - uint8_t block[16] = {0x00}; - for (uint8_t i = 0; i < sectorsCnt; ++i ) { - mfEmlGetMem(block, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1); - if (e_sector[i].foundKey[0]) - num_to_bytes(e_sector[i].Key[0], 6, block); - if (e_sector[i].foundKey[1]) - num_to_bytes(e_sector[i].Key[1], 6, block+10); - mfEmlSetMem(block, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1); - } - PrintAndLogEx(NORMAL, "Found keys have been transferred to the emulator memory"); + // check.. + uint8_t found_keys = 0; + for (uint8_t i = 0; i < sectorsCnt; ++i) { + + if ( e_sector[i].foundKey[0] ) + found_keys++; + + if ( e_sector[i].foundKey[1] ) + found_keys++; } - if (createDumpFile) { - fptr = GenerateFilename("hf-mf-", "-key.bin"); - if (fptr == NULL) - return 1; - - FILE *fkeys = fopen(fptr, "wb"); - if (fkeys == NULL) { - PrintAndLogEx(WARNING, "Could not create file %s", fptr); - free(keyBlock); - free(e_sector); - return 1; - } - PrintAndLogEx(NORMAL, "Printing keys to binary file %s...", fptr); + if ( found_keys == 0 ) { + PrintAndLogEx(WARNING, "No keys found"); + } else { - for (i=0; i 0xffffffffffff has been inserted for unknown keys.", fptr); + FILE *fkeys = fopen(fptr, "wb"); + if (fkeys == NULL) { + PrintAndLogEx(WARNING, "Could not create file " _YELLOW_(%s), fptr); + free(keyBlock); + free(e_sector); + return 1; + } + PrintAndLogEx(SUCCESS, "Printing keys to binary file " _YELLOW_(%s)"...", fptr); + + for (i=0; i 0xffffffffffff has been inserted for unknown keys.", fptr); + } } free(keyBlock); @@ -1680,11 +1729,11 @@ out: int CmdHF14AMfChk(const char *Cmd) { - char ctmp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 3 || ctmp == 'h' || ctmp == 'H') return usage_hf14_chk(); + char ctmp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) < 3 || ctmp == 'h') return usage_hf14_chk(); FILE * f; - char filename[FILE_PATH_SIZE]={0}; + char filename[FILE_PATH_SIZE] = {0}; char buf[13]; uint8_t *keyBlock = NULL, *p; sector_t *e_sector = NULL; @@ -1714,23 +1763,21 @@ int CmdHF14AMfChk(const char *Cmd) { blockNo = param_get8(Cmd, 0); } - ctmp = param_getchar(Cmd, 1); + ctmp = tolower(param_getchar(Cmd, 1)); clen = param_getlength(Cmd, 1); if (clen == 1) { switch (ctmp) { case 'a': - case 'A': keyType = 0; break; case 'b': - case 'B': keyType = 1; break; case '?': keyType = 2; break; default: - PrintAndLogEx(NORMAL, "Key type must be A , B or ?"); + PrintAndLogEx(FAILED, "Key type must be A , B or ?"); free(keyBlock); return 1; }; @@ -1738,7 +1785,7 @@ int CmdHF14AMfChk(const char *Cmd) { for (i = 2; param_getchar(Cmd, i); i++) { - ctmp = param_getchar(Cmd, i); + ctmp = tolower(param_getchar(Cmd, i)); clen = param_getlength(Cmd, i); if (clen == 12) { @@ -1760,8 +1807,8 @@ int CmdHF14AMfChk(const char *Cmd) { PrintAndLogEx(NORMAL, "[%2d] key %s", keycnt, sprint_hex( (keyBlock + 6*keycnt), 6 ) );; keycnt++; } else if ( clen == 1 ) { - if (ctmp == 't' || ctmp == 'T') { transferToEml = 1; continue; } - if (ctmp == 'd' || ctmp == 'D') { createDumpFile = 1; continue; } + if (ctmp == 't' ) { transferToEml = 1; continue; } + if (ctmp == 'd' ) { createDumpFile = 1; continue; } } else { // May be a dic file if ( param_getstr(Cmd, i, filename, sizeof(filename)) >= FILE_PATH_SIZE ) { @@ -1771,7 +1818,7 @@ int CmdHF14AMfChk(const char *Cmd) { f = fopen( filename , "r"); if ( !f ) { - PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename); + PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename); continue; } @@ -1786,7 +1833,7 @@ int CmdHF14AMfChk(const char *Cmd) { // codesmell, only checks first char? if (!isxdigit(buf[0])){ - PrintAndLogEx(FAILED, "File content error. '%s' must include 12 HEX symbols",buf); + PrintAndLogEx(FAILED, "File content error. '" _YELLOW_(%s)"' must include 12 HEX symbols",buf); continue; } @@ -1809,12 +1856,12 @@ int CmdHF14AMfChk(const char *Cmd) { memset(buf, 0, sizeof(buf)); } fclose(f); - PrintAndLogEx(SUCCESS, "Loaded %2d keys from %s", keycnt, filename); + PrintAndLogEx(SUCCESS, "Loaded %2d keys from " _YELLOW_(%s), keycnt, filename); } } if (keycnt == 0) { - PrintAndLogEx(NORMAL, "No key specified, trying default keys"); + PrintAndLogEx(INFO, "No key specified, trying default keys"); for (;keycnt < MIFARE_DEFAULTKEYS_SIZE; keycnt++) PrintAndLogEx(NORMAL, "[%2d] %02x%02x%02x%02x%02x%02x", keycnt, (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], @@ -1858,7 +1905,7 @@ int CmdHF14AMfChk(const char *Cmd) { printf("."); fflush(stdout); if (ukbhit()) { int gc = getchar(); (void)gc; - PrintAndLogEx(NORMAL, "\naborted via keyboard!\n"); + PrintAndLogEx(INFO, "\naborted via keyboard!\n"); goto out; } @@ -1877,12 +1924,12 @@ int CmdHF14AMfChk(const char *Cmd) { } } t1 = msclock() - t1; - PrintAndLogEx(NORMAL, "\nTime in checkkeys: %.0f seconds\n", (float)t1/1000.0); + PrintAndLogEx(SUCCESS, "\nTime in checkkeys: %.0f seconds\n", (float)t1/1000.0); // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag? if ( keyType != 1 ) { - PrintAndLogEx(NORMAL, "testing to read key B..."); + PrintAndLogEx(INFO, "testing to read key B..."); for (i = 0; i < SectorsCnt; i++) { // KEY A but not KEY B if ( e_sector[i].foundKey[0] && !e_sector[i].foundKey[1] ) { @@ -1928,22 +1975,25 @@ out: num_to_bytes(e_sector[i].Key[1], 6, block+10); mfEmlSetMem(block, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1); } - PrintAndLogEx(NORMAL, "Found keys have been transferred to the emulator memory"); + PrintAndLogEx(SUCCESS, "Found keys have been transferred to the emulator memory"); } if (createDumpFile) { fptr = GenerateFilename("hf-mf-", "-key.bin"); - if (fptr == NULL) + if (fptr == NULL) { + free(keyBlock); + free(e_sector); return 1; + } FILE *fkeys = fopen(fptr, "wb"); if (fkeys == NULL) { - PrintAndLogEx(WARNING, "Could not create file %s", fptr); + PrintAndLogEx(WARNING, "Could not create file " _YELLOW_(%s), fptr); free(keyBlock); free(e_sector); return 1; } - PrintAndLogEx(NORMAL, "Printing keys to binary file %s...", fptr); + PrintAndLogEx(INFO, "Printing keys to binary file " _YELLOW_(%s)"...", fptr); for( i=0; i bufsize || buf == NULL) { uint8_t *p; if (buf == NULL) // not yet allocated - p = malloc(traceLen); + p = calloc(traceLen, sizeof(uint8_t)); else // need more memory p = realloc(buf, traceLen); @@ -2195,11 +2245,7 @@ int CmdHF14AMfSniff(const char *Cmd){ bufsize = traceLen; memset(buf, 0x00, traceLen); } - if (bufPtr == NULL) { - PrintAndLogEx(FAILED, "Cannot allocate memory for trace"); - free(buf); - return 2; - } + // what happens if LEN is bigger then TRACELEN --iceman memcpy(bufPtr, resp.d.asBytes, len); bufPtr += len; @@ -2397,14 +2443,14 @@ int CmdHF14AMfELoad(const char *Cmd) { return usage_hf14_eload(); switch (c) { - case '0' : numBlocks = 5*4; break; + case '0' : numBlocks = MIFARE_MINI_MAXBLOCK; break; case '1' : - case '\0': numBlocks = 16*4; break; - case '2' : numBlocks = 32*4; break; - case '4' : numBlocks = 256; break; + case '\0': numBlocks = MIFARE_1K_MAXBLOCK; break; + case '2' : numBlocks = MIFARE_2K_MAXBLOCK; break; + case '4' : numBlocks = MIFARE_4K_MAXBLOCK; break; case 'u' : numBlocks = 255; blockWidth = 4; break; default: { - numBlocks = 16*4; + numBlocks = MIFARE_1K_MAXBLOCK; nameParamNo = 0; } } @@ -2452,19 +2498,21 @@ int CmdHF14AMfELoad(const char *Cmd) { if ( blockWidth == 4 ) { if ((blockNum != numBlocks)) { PrintAndLogEx(FAILED, "Warning, Ultralight/Ntag file content, Loaded %d blocks into emulator memory", blockNum); + free(data); return 0; } } else { if ((blockNum != numBlocks)) { PrintAndLogEx(FAILED, "Error, file content, Only loaded %d blocks, must be %d blocks into emulator memory", blockNum, numBlocks); + free(data); return 4; } } - PrintAndLogEx(SUCCESS, "Loaded %d blocks from file: %s", blockNum, filename); + PrintAndLogEx(SUCCESS, "Loaded %d blocks from file: " _YELLOW_(%s), blockNum, filename); + free(data); return 0; } -#define MFBLOCK_SIZE 16 int CmdHF14AMfESave(const char *Cmd) { char filename[FILE_PATH_SIZE]; @@ -2481,14 +2529,14 @@ int CmdHF14AMfESave(const char *Cmd) { blocks = NumOfBlocks(c); bytes = blocks * MFBLOCK_SIZE; - dump = calloc(sizeof(uint8_t), bytes); + dump = calloc(bytes, sizeof(uint8_t)); if (!dump) { PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); return 1; } memset(dump, 0, bytes); - PrintAndLogEx(INFO, "dowingloading from emulator memory"); + PrintAndLogEx(INFO, "downloading from emulator memory"); if (!GetFromDevice( BIG_BUF_EML, dump, bytes, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); free(dump); @@ -2506,6 +2554,7 @@ int CmdHF14AMfESave(const char *Cmd) { saveFile(filename, "bin", dump, bytes); saveFileEML(filename, "eml", dump, bytes, MFBLOCK_SIZE); + saveFileJSON(filename, "json", jsfCardMemory, dump, bytes); free(dump); return 0; } @@ -2705,8 +2754,10 @@ int CmdHF14AMfCLoad(const char *Cmd) { res = loadFileEML( Cmd, "eml", data, &datalen); } } + if ( res ) { - free(data); + if ( data ) + free(data); return 1; } @@ -2746,7 +2797,7 @@ int CmdHF14AMfCLoad(const char *Cmd) { blockNum++; // magic card type - mifare 1K - if (blockNum >= 16 * 4) break; + if (blockNum >= MIFARE_1K_MAXBLOCK ) break; } PrintAndLogEx(NORMAL, "\n"); @@ -2768,8 +2819,8 @@ int CmdHF14AMfCGetBlk(const char *Cmd) { int res; memset(data, 0x00, sizeof(data)); - char ctmp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_hf14_cgetblk(); + char ctmp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) < 1 || ctmp == 'h') return usage_hf14_cgetblk(); blockNo = param_get8(Cmd, 0); @@ -2804,8 +2855,8 @@ int CmdHF14AMfCGetSc(const char *Cmd) { uint8_t sector = 0; int i, res, flags; - char ctmp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_hf14_cgetsc(); + char ctmp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) < 1 || ctmp == 'h') return usage_hf14_cgetsc(); sector = param_get8(Cmd, 0); if (sector > 39) { @@ -2880,7 +2931,6 @@ int CmdHF14AMfCSave(const char *Cmd) { errors = true; break; } - if (len > FILE_PATH_SIZE - 5) len = FILE_PATH_SIZE - 5; useuid = false; hasname = true; @@ -2897,7 +2947,7 @@ int CmdHF14AMfCSave(const char *Cmd) { if (errors || cmdp == 0) return usage_hf14_csave(); - dump = malloc(bytes); + dump = calloc(bytes, sizeof(uint8_t)); if (!dump) { PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); return 1; @@ -2943,8 +2993,8 @@ int CmdHF14AMfCSave(const char *Cmd) { //needs nt, ar, at, Data to decrypt int CmdHf14AMfDecryptBytes(const char *Cmd){ - char ctmp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_hf14_decryptbytes(); + char ctmp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) < 1 || ctmp == 'h') return usage_hf14_decryptbytes(); uint32_t nt = param_get32ex(Cmd,0,0,16); uint32_t ar_enc = param_get32ex(Cmd,1,0,16); @@ -2995,7 +3045,7 @@ int CmdHf14AMfSetMod(const char *Cmd) { UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t ok = resp.arg[0] & 0xff; - PrintAndLogEx(NORMAL, "isOk:%02x", ok); + PrintAndLogEx(SUCCESS, "isOk:%02x", ok); if (!ok) PrintAndLogEx(FAILED, "Failed."); } else { @@ -3008,12 +3058,12 @@ int CmdHf14AMfSetMod(const char *Cmd) { int CmdHf14AMfNack(const char *Cmd) { bool verbose = false; - char ctmp = param_getchar(Cmd, 0); - if ( ctmp == 'h' || ctmp == 'H' ) return usage_hf14_nack(); - if ( ctmp == 'v' || ctmp == 'V' ) verbose = true; + char ctmp = tolower(param_getchar(Cmd, 0)); + if ( ctmp == 'h' ) return usage_hf14_nack(); + if ( ctmp == 'v' ) verbose = true; if ( verbose ) - PrintAndLogEx(NORMAL, "Started testing card for NACK bug. Press key to abort"); + PrintAndLogEx(INFO, "Started testing card for NACK bug. Press key to abort"); detect_classic_nackbug(verbose); return 0; @@ -3071,7 +3121,7 @@ int CmdHF14AMfice(const char *Cmd) { PrintAndLogEx(NORMAL, "Collecting %u nonces \n", limit); if ((fnonces = fopen(filename,"wb")) == NULL) { - PrintAndLogEx(WARNING, "Could not create file %s",filename); + PrintAndLogEx(WARNING, "Could not create file " _YELLOW_(%s),filename); return 3; } @@ -3082,7 +3132,7 @@ int CmdHF14AMfice(const char *Cmd) { do { if (ukbhit()) { int gc = getchar(); (void)gc; - PrintAndLogEx(NORMAL, "\naborted via keyboard!\n"); + PrintAndLogEx(INFO, "\naborted via keyboard!\n"); break; } @@ -3104,7 +3154,7 @@ int CmdHF14AMfice(const char *Cmd) { total_num_nonces += items; if ( total_num_nonces > part_limit ) { - PrintAndLogEx(NORMAL, "Total nonces %u\n", total_num_nonces); + PrintAndLogEx(INFO, "Total nonces %u\n", total_num_nonces); part_limit += 3000; } @@ -3115,7 +3165,7 @@ int CmdHF14AMfice(const char *Cmd) { } while (!acquisition_completed); out: - PrintAndLogEx(NORMAL, "time: %" PRIu64 " seconds\n", (msclock()-t1)/1000); + PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds\n", (msclock()-t1)/1000); if ( fnonces ) { fflush(fnonces); @@ -3128,7 +3178,7 @@ out: return 0; } -int CmdHF14AMfAuth4(const char *cmd) { +int CmdHF14AMfAuth4(const char *Cmd) { uint8_t keyn[20] = {0}; int keynlen = 0; uint8_t key[16] = {0}; @@ -3145,7 +3195,7 @@ int CmdHF14AMfAuth4(const char *cmd) { arg_str1(NULL, NULL, "", NULL), arg_param_end }; - CLIExecWithReturn(cmd, argtable, true); + CLIExecWithReturn(Cmd, argtable, true); CLIGetHexWithReturn(1, keyn, &keynlen); CLIGetHexWithReturn(2, key, &keylen); @@ -3164,9 +3214,106 @@ int CmdHF14AMfAuth4(const char *cmd) { return MifareAuth4(NULL, keyn, key, true, false, true); } +// https://www.nxp.com/docs/en/application-note/AN10787.pdf +int CmdHF14AMfMAD(const char *cmd) { + + CLIParserInit("hf mf mad", + "Checks and prints Mifare Application Directory (MAD)", + "Usage:\n\thf mf mad -> shows MAD if exists\n" + "\thf mf mad -a 03e1 -k d3f7d3f7d3f7 -> shows NDEF data if exists\n"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show technical data"), + arg_str0("aA", "aid", "print all sectors with aid", NULL), + arg_str0("kK", "key", "key for printing sectors", NULL), + arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + bool verbose = arg_get_lit(1); + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[6] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); + + CLIParserFree(); + + if (aidlen != 2 && keylen > 0) { + PrintAndLogEx(WARNING, "do not need a key without aid."); + } + + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { + PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + if (verbose) { + for(int i = 0; i < 4; i ++) + PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); + } + + bool haveMAD2 = false; + MAD1DecodeAndPrint(sector0, verbose, &haveMAD2); + + if (haveMAD2) { + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { + PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + MAD2DecodeAndPrint(sector10, verbose); + } + + if (aidlen == 2) { + uint16_t aaid = (aid[0] << 8) + aid[1]; + PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid); + + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, sector10, mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } + + uint8_t akey[6] = {0}; + memcpy(akey, g_mifare_ndef_key, 6); + if (keylen == 6) { + memcpy(akey, key, 6); + } + + for (int i = 0; i < madlen; i++) { + if (aaid == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } + + for(int j = 0; j < (verbose ? 4 : 3); j ++) + PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); + } + } + } + + return 0; +} + +int CmdHF14AMfList(const char *Cmd) { + CmdTraceList("mf"); + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"darkside", CmdHF14ADarkside, 0, "Darkside attack. read parity error messages."}, + {"list", CmdHF14AMfList, 0, "[Deprecated] List ISO 14443-a / Mifare history"}, + {"darkside", CmdHF14AMfDarkside, 0, "Darkside attack. read parity error messages."}, {"nested", CmdHF14AMfNested, 0, "Nested attack. Test nested authentication"}, {"hardnested", CmdHF14AMfNestedHard, 0, "Nested attack for hardened Mifare cards"}, {"keybrute", CmdHF14AMfKeyBrute, 0, "J_Run's 2nd phase of multiple sector nested authentication key recovery"}, @@ -3200,6 +3347,9 @@ static command_t CommandTable[] = { {"cgetsc", CmdHF14AMfCGetSc, 0, "Read sector - Magic Chinese card"}, {"cload", CmdHF14AMfCLoad, 0, "Load dump into magic Chinese card"}, {"csave", CmdHF14AMfCSave, 0, "Save dump from magic Chinese card into file or emulator"}, + {"-----------", CmdHelp, 1, ""}, + {"mad", CmdHF14AMfMAD, 0, "Checks and prints MAD"}, +// {"ndef", CmdHF14AMfHDEF, 0, "Checks and prints NDEF records from card"}, {"ice", CmdHF14AMfice, 0, "collect Mifare Classic nonces to file"}, {NULL, NULL, 0, NULL} diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h index eeb7a74f6..c819d5bef 100644 --- a/client/cmdhfmf.h +++ b/client/cmdhfmf.h @@ -23,18 +23,19 @@ #include "cmdparser.h" #include "common.h" #include "util.h" -#include "mifare.h" // nonces_t struct -#include "mfkey.h" // mfkey32_moebious +#include "mifare.h" // nonces_t struct +#include "mifare/mfkey.h" // mfkey32_moebious #include "cmdhfmfhard.h" -#include "mifarehost.h" // icesector_t, sector_t -#include "util_posix.h" // msclock -#include "mifaredefault.h" // mifare default key array -#include "cmdhf14a.h" // dropfield -#include "cliparser/cliparser.h" // argtable +#include "mifare/mifarehost.h" // icesector_t, sector_t +#include "util_posix.h" // msclock +#include "mifare/mifaredefault.h" // mifare default key array +#include "cmdhf14a.h" // dropfield +#include "cliparser/cliparser.h" // argtable #include "hardnested/hardnested_bf_core.h" // SetSIMDInstr extern int CmdHFMF(const char *Cmd); +extern int CmdHF14AMfList(const char *Cmd); extern int CmdHF14AMfDbg(const char* cmd); extern int CmdHF14AMfRdBl(const char* cmd); extern int CmdHF14AMfURdBl(const char* cmd); @@ -45,7 +46,7 @@ extern int CmdHF14AMfRestore(const char* cmd); extern int CmdHF14AMfWrBl(const char* cmd); extern int CmdHF14AMfUWrBl(const char* cmd); extern int CmdHF14AMfChk(const char* cmd); -extern int CmdHF14ADarkside(const char* cmd); +extern int CmdHF14AMfDarkside(const char* cmd); extern int CmdHF14AMfNested(const char* cmd); extern int CmdHF14AMfNestedHard(const char *Cmd); //extern int CmdHF14AMfSniff(const char* cmd); diff --git a/client/cmdhfmfhard.c b/client/cmdhfmfhard.c index 07e05a81e..1ebf2131d 100644 --- a/client/cmdhfmfhard.c +++ b/client/cmdhfmfhard.c @@ -209,7 +209,7 @@ static int compare_count_bitflip_bitarrays(const void *b1, const void *b2) static voidpf inflate_malloc(voidpf opaque, uInt items, uInt size) { - return malloc(items*size); + return calloc(items*size, sizeof(uint8_t)); } @@ -266,14 +266,20 @@ static void init_bitflip_bitarrays(void) continue; } else { fseek(statesfile, 0, SEEK_END); - uint32_t filesize = (uint32_t)ftell(statesfile); + int fsize = ftell(statesfile); + if ( fsize == -1 ){ + PrintAndLogEx(WARNING, "File read error with %s. Aborting...\n", state_file_name); + fclose(statesfile); + exit(5); + } + uint32_t filesize = (uint32_t)fsize; rewind(statesfile); uint8_t input_buffer[filesize]; size_t bytesread = fread(input_buffer, 1, filesize, statesfile); if (bytesread != filesize) { PrintAndLogEx(WARNING, "File read error with %s. Aborting...\n", state_file_name); fclose(statesfile); - inflateEnd(&compressed_stream); + //inflateEnd(&compressed_stream); exit(5); } fclose(statesfile); @@ -1038,8 +1044,11 @@ static bool shrink_key_space(float *brute_forces) } *brute_forces = MIN(brute_forces1, brute_forces2); float reduction_rate = update_reduction_rate(*brute_forces, false); - return ((hardnested_stage & CHECK_2ND_BYTES) - && reduction_rate >= 0.0 && reduction_rate < brute_force_per_second * sample_period / 1000.0); + +//iceman 2018 + return ((hardnested_stage & CHECK_2ND_BYTES) && + reduction_rate >= 0.0 && + ( reduction_rate < brute_force_per_second * (float)sample_period / 1000.0 || *brute_forces < 0x1F00000000)); } @@ -1663,9 +1672,9 @@ static inline bool bitflips_match(uint8_t byte, uint32_t state, odd_even_t odd_e } #endif return false; - } else { - return true; } + + return true; } @@ -1705,11 +1714,13 @@ static bool all_bitflips_match(uint8_t byte, uint32_t state, odd_even_t odd_even #ifdef DEBUG_KEY_ELIMINATION if (known_target_key != -1 && state == test_state[odd_even]) { PrintAndLogEx(NORMAL, "all_bitflips_match() 1st Byte: %s test state (0x%06x): Eliminated. Bytes = %02x, %02x, Common Bits = %d\n", - odd_even==ODD_STATE?"odd":"even", + odd_even == ODD_STATE ? "odd" : "even", test_state[odd_even], - byte, byte2, num_common); + byte, + byte2, + num_common); if (failstr[0] == '\0') { - sprintf(failstr, "Other 1st Byte %s, all_bitflips_match(), no match", odd_even?"odd":"even"); + sprintf(failstr, "Other 1st Byte %s, all_bitflips_match(), no match", odd_even ? "odd" : "even"); } } #endif @@ -1761,12 +1772,10 @@ static void add_matching_states(statelist_t *candidates, uint8_t part_sum_a0, ui uint32_t *bitarray_a8 = part_sum_a8_bitarrays[odd_even][part_sum_a8/2]; uint32_t *bitarray_bitflips = nonces[best_first_bytes[0]].states_bitarray[odd_even]; - // for (uint32_t i = 0; i < (1<<19); i++) { - // candidates_bitarray[i] = bitarray_a0[i] & bitarray_a8[i] & bitarray_bitflips[i]; - // } bitarray_AND4(candidates_bitarray, bitarray_a0, bitarray_a8, bitarray_bitflips); bitarray_to_list(best_first_bytes[0], candidates_bitarray, candidates->states[odd_even], &(candidates->len[odd_even]), odd_even); + if (candidates->len[odd_even] == 0) { free(candidates->states[odd_even]); candidates->states[odd_even] = NULL; @@ -1775,17 +1784,14 @@ static void add_matching_states(statelist_t *candidates, uint8_t part_sum_a0, ui } free_bitarray(candidates_bitarray); - pthread_mutex_lock(&statelist_cache_mutex); sl_cache[part_sum_a0/2][part_sum_a8/2][odd_even].sl = candidates->states[odd_even]; sl_cache[part_sum_a0/2][part_sum_a8/2][odd_even].len = candidates->len[odd_even]; sl_cache[part_sum_a0/2][part_sum_a8/2][odd_even].cache_status = COMPLETED; pthread_mutex_unlock(&statelist_cache_mutex); - return; } - static statelist_t *add_more_candidates(void) { statelist_t *new_candidates = candidates; @@ -1879,7 +1885,6 @@ static bool TestIfKeyExists(uint64_t key) static work_status_t book_of_work[NUM_PART_SUMS][NUM_PART_SUMS][NUM_PART_SUMS][NUM_PART_SUMS]; - static void init_book_of_work(void) { for (uint8_t p = 0; p < NUM_PART_SUMS; p++) { @@ -2043,19 +2048,6 @@ __attribute__((force_align_arg_pointer)) static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx) { - // PrintAndLogEx(NORMAL, "Generating crypto1 state candidates... \n"); - - // estimate maximum candidate states - // maximum_states = 0; - // for (uint16_t sum_odd = 0; sum_odd <= 16; sum_odd += 2) { - // for (uint16_t sum_even = 0; sum_even <= 16; sum_even += 2) { - // if (sum_odd*(16-sum_even) + (16-sum_odd)*sum_even == sum_a0) { - // maximum_states += (uint64_t)count_states(part_sum_a0_bitarrays[EVEN_STATE][sum_even/2]) - // * count_states(part_sum_a0_bitarrays[ODD_STATE][sum_odd/2]); - // } - // } - // } - // PrintAndLogEx(NORMAL, "Number of possible keys with Sum(a0) = %d: %" PRIu64 " (2^%1.1f)\n", sum_a0, maximum_states, log(maximum_states)/log(2.0)); init_statelist_cache(); init_book_of_work(); @@ -2102,12 +2094,11 @@ static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx) static void free_candidates_memory(statelist_t *sl) { - if (sl == NULL) { + if (sl == NULL) return; - } else { - free_candidates_memory(sl->next); - free(sl); - } + + free_candidates_memory(sl->next); + free(sl); } @@ -2128,7 +2119,6 @@ static void pre_XOR_nonces(void) } } } - static bool brute_force(uint64_t *found_key) { @@ -2138,7 +2128,6 @@ static bool brute_force(uint64_t *found_key) return brute_force_bs(NULL, candidates, cuid, num_acquired_nonces, maximum_states, nonces, best_first_bytes, found_key); } - static uint16_t SumProperty(struct Crypto1State *s) { uint16_t sum_odd = PartialSumProperty(s->odd, ODD_STATE); @@ -2214,11 +2203,11 @@ 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, uint64_t *foundkey, char *filename) { - char progress_text[80]; - + char progress_text[80]; char instr_set[12] = {0}; + get_SIMD_instruction_set(instr_set); - PrintAndLog("Using %s SIMD core.", instr_set); + PrintAndLogEx(SUCCESS,"Using %s SIMD core.", instr_set); srand((unsigned) time(NULL)); brute_force_per_second = brute_force_benchmark(); @@ -2232,6 +2221,7 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc PrintAndLogEx(WARNING, "Could not create/open file hardnested_stats.txt"); return 3; } + for (uint32_t i = 0; i < tests; i++) { start_time = msclock(); print_progress_header(); @@ -2273,6 +2263,7 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc float expected_brute_force1 = (float)num_odd * num_even / 2.0; float expected_brute_force2 = nonces[best_first_bytes[0]].expected_num_brute_force; fprintf(fstats, "%1.1f;%1.1f;", log(expected_brute_force1)/log(2.0), log(expected_brute_force2)/log(2.0)); + if (expected_brute_force1 < expected_brute_force2) { hardnested_print_progress(num_acquired_nonces, "(Ignoring Sum(a8) properties)", expected_brute_force1, 0); set_test_state(best_first_byte_smallest_bitarray); @@ -2282,12 +2273,11 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc for (statelist_t *sl = candidates; sl != NULL; sl = sl->next) { maximum_states += (uint64_t)sl->len[ODD_STATE] * sl->len[EVEN_STATE]; } - //PrintAndLogEx(NORMAL, "Number of remaining possible keys: %" PRIu64 " (2^%1.1f)\n", maximum_states, log(maximum_states)/log(2.0)); - // fPrintAndLogEx(NORMAL, "fstats, "%" PRIu64 ";", maximum_states); + best_first_bytes[0] = best_first_byte_smallest_bitarray; pre_XOR_nonces(); prepare_bf_test_nonces(nonces, best_first_bytes[0]); - //hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force1, 0); + key_found = brute_force(foundkey); free(candidates->states[ODD_STATE]); free(candidates->states[EVEN_STATE]); @@ -2304,10 +2294,8 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc sprintf(progress_text, "(Estimated Sum(a8) is WRONG! Correct Sum(a8) = %" PRIu16 ")", real_sum_a8); hardnested_print_progress(num_acquired_nonces, progress_text, expected_brute_force, 0); } - // PrintAndLogEx(NORMAL, "Estimated remaining states: %" PRIu64 " (2^%1.1f)\n", nonces[best_first_bytes[0]].sum_a8_guess[j].num_states, log(nonces[best_first_bytes[0]].sum_a8_guess[j].num_states)/log(2.0)); generate_candidates(first_byte_Sum, nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx); - // PrintAndLogEx(NORMAL, "Time for generating key candidates list: %1.0f sec (%1.1f sec CPU)\n", difftime(time(NULL), start_time), (float)(msclock() - start_clock)/1000.0); - //hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force, 0); + key_found = brute_force(foundkey); free_statelist_cache(); free_candidates_memory(candidates); @@ -2390,40 +2378,43 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc uint32_t num_even = nonces[best_first_byte_smallest_bitarray].num_states_bitarray[EVEN_STATE]; float expected_brute_force1 = (float)num_odd * num_even / 2.0; float expected_brute_force2 = nonces[best_first_bytes[0]].expected_num_brute_force; + if (expected_brute_force1 < expected_brute_force2) { hardnested_print_progress(num_acquired_nonces, "(Ignoring Sum(a8) properties)", expected_brute_force1, 0); set_test_state(best_first_byte_smallest_bitarray); add_bitflip_candidates(best_first_byte_smallest_bitarray); Tests2(); maximum_states = 0; + for (statelist_t *sl = candidates; sl != NULL; sl = sl->next) { maximum_states += (uint64_t)sl->len[ODD_STATE] * sl->len[EVEN_STATE]; } - // PrintAndLogEx(NORMAL, "Number of remaining possible keys: %" PRIu64 " (2^%1.1f)\n", maximum_states, log(maximum_states)/log(2.0)); + best_first_bytes[0] = best_first_byte_smallest_bitarray; pre_XOR_nonces(); prepare_bf_test_nonces(nonces, best_first_bytes[0]); - //hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force1, 0); + key_found = brute_force(foundkey); free(candidates->states[ODD_STATE]); free(candidates->states[EVEN_STATE]); free_candidates_memory(candidates); candidates = NULL; } else { + pre_XOR_nonces(); prepare_bf_test_nonces(nonces, best_first_bytes[0]); + for (uint8_t j = 0; j < NUM_SUMS && !key_found; j++) { float expected_brute_force = nonces[best_first_bytes[0]].expected_num_brute_force; sprintf(progress_text, "(%d. guess: Sum(a8) = %" PRIu16 ")", j+1, sums[nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx]); hardnested_print_progress(num_acquired_nonces, progress_text, expected_brute_force, 0); + if (trgkey != NULL && sums[nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx] != real_sum_a8) { sprintf(progress_text, "(Estimated Sum(a8) is WRONG! Correct Sum(a8) = %" PRIu16 ")", real_sum_a8); hardnested_print_progress(num_acquired_nonces, progress_text, expected_brute_force, 0); } - // PrintAndLogEx(NORMAL, "Estimated remaining states: %" PRIu64 " (2^%1.1f)\n", nonces[best_first_bytes[0]].sum_a8_guess[j].num_states, log(nonces[best_first_bytes[0]].sum_a8_guess[j].num_states)/log(2.0)); + generate_candidates(first_byte_Sum, nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx); - // PrintAndLogEx(NORMAL, "Time for generating key candidates list: %1.0f sec (%1.1f sec CPU)\n", difftime(time(NULL), start_time), (float)(msclock() - start_clock)/1000.0); - //hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force, 0); key_found = brute_force(foundkey); free_statelist_cache(); free_candidates_memory(candidates); diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 0d7a623d4..725dbca04 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -22,109 +22,15 @@ #include "ui.h" #include "cmdhf14a.h" #include "mifare.h" -#include "mifare4.h" +#include "mifare/mifare4.h" +#include "mifare/mad.h" #include "cliparser/cliparser.h" #include "crypto/libpcrypto.h" static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -typedef struct { - uint8_t Code; - const char *Description; -} PlusErrorsElm; - -static const PlusErrorsElm PlusErrors[] = { - {0xFF, ""}, - {0x00, "Transfer cannot be granted within the current authentication."}, - {0x06, "Access Conditions not fulfilled. Block does not exist, block is not a value block."}, - {0x07, "Too many read or write commands in the session or in the transaction."}, - {0x08, "Invalid MAC in command or response"}, - {0x09, "Block Number is not valid"}, - {0x0a, "Invalid block number, not existing block number"}, - {0x0b, "The current command code not available at the current card state."}, - {0x0c, "Length error"}, - {0x0f, "General Manipulation Error. Failure in the operation of the PICC (cannot write to the data block), etc."}, - {0x90, "OK"}, -}; -int PlusErrorsLen = sizeof(PlusErrors) / sizeof(PlusErrorsElm); - -const char * GetErrorDescription(uint8_t errorCode) { - for(int i = 0; i < PlusErrorsLen; i++) - if (errorCode == PlusErrors[i].Code) - return PlusErrors[i].Description; - - return PlusErrors[0].Description; -} - static int CmdHelp(const char *Cmd); -static bool VerboseMode = false; -void SetVerboseMode(bool verbose) { - VerboseMode = verbose; -} - -int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { - if(VerboseMode) - PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen)); - - int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); - - if(VerboseMode) - PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen)); - - return res; -} - -int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { - uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00}; - memmove(&rcmd[3], key, 16); - - return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); -} - -int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { - uint8_t rcmd[1] = {0xaa}; - - return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); -} - -int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { - uint8_t rcmd[4 + 8] = {(plain?(0x37):(0x33)), blockNum, 0x00, blockCount}; - if (!plain && session) - CalculateMAC(session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode); - - int res = intExchangeRAW14aPlus(rcmd, plain?4:sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); - if(res) - return res; - - if (session) - session->R_Ctr++; - - if(session && mac && *dataoutlen > 11) - CalculateMAC(session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode); - - return 0; -} - -int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { - uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00}; - memmove(&rcmd[3], data, 16); - if (session) - CalculateMAC(session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode); - - int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); - if(res) - return res; - - if (session) - session->W_Ctr++; - - if(session && mac && *dataoutlen > 3) - CalculateMAC(session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode); - - return 0; -} - int CmdHFMFPInfo(const char *cmd) { if (cmd && strlen(cmd) > 0) @@ -229,7 +135,7 @@ int CmdHFMFPWritePerso(const char *cmd) { CLIGetHexWithReturn(3, key, &keyLen); CLIParserFree(); - SetVerboseMode(verbose); + mfpSetVerboseMode(verbose); if (!keyLen) { memmove(key, DefaultKey, 16); @@ -260,7 +166,7 @@ int CmdHFMFPWritePerso(const char *cmd) { } if (data[0] != 0x90) { - PrintAndLogEx(ERR, "Command error: %02x %s", data[0], GetErrorDescription(data[0])); + PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0])); return 1; } PrintAndLogEx(INFO, "Write OK."); @@ -304,7 +210,7 @@ int CmdHFMFPInitPerso(const char *cmd) { if (!keyLen) memmove(key, DefaultKey, 16); - SetVerboseMode(verbose2); + mfpSetVerboseMode(verbose2); for (uint16_t sn = 0x4000; sn < 0x4050; sn++) { keyNum[0] = sn >> 8; keyNum[1] = sn & 0xff; @@ -319,7 +225,7 @@ int CmdHFMFPInitPerso(const char *cmd) { } } - SetVerboseMode(verbose); + mfpSetVerboseMode(verbose); for (int i = 0; i < sizeof(CardAddresses) / 2; i++) { keyNum[0] = CardAddresses[i] >> 8; keyNum[1] = CardAddresses[i] & 0xff; @@ -360,7 +266,7 @@ int CmdHFMFPCommitPerso(const char *cmd) { bool verbose = arg_get_lit(1); CLIParserFree(); - SetVerboseMode(verbose); + mfpSetVerboseMode(verbose); uint8_t data[250] = {0}; int datalen = 0; @@ -377,7 +283,7 @@ int CmdHFMFPCommitPerso(const char *cmd) { } if (data[0] != 0x90) { - PrintAndLogEx(ERR, "Command error: %02x %s", data[0], GetErrorDescription(data[0])); + PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0])); return 1; } PrintAndLogEx(INFO, "Switch level OK."); @@ -453,7 +359,7 @@ int CmdHFMFPRdbl(const char *cmd) { CLIGetHexWithReturn(6, key, &keylen); CLIParserFree(); - SetVerboseMode(verbose); + mfpSetVerboseMode(verbose); if (!keylen) { memmove(key, DefaultKey, 16); @@ -504,7 +410,7 @@ int CmdHFMFPRdbl(const char *cmd) { } if (datalen && data[0] != 0x90) { - PrintAndLogEx(ERR, "Card read error: %02x %s", data[0], GetErrorDescription(data[0])); + PrintAndLogEx(ERR, "Card read error: %02x %s", data[0], mfpGetErrorDescription(data[0])); return 6; } @@ -563,7 +469,7 @@ int CmdHFMFPRdsc(const char *cmd) { CLIGetHexWithReturn(5, key, &keylen); CLIParserFree(); - SetVerboseMode(verbose); + mfpSetVerboseMode(verbose); if (!keylen) { memmove(key, DefaultKey, 16); @@ -605,7 +511,7 @@ int CmdHFMFPRdsc(const char *cmd) { } if (datalen && data[0] != 0x90) { - PrintAndLogEx(ERR, "Card read error: %02x %s", data[0], GetErrorDescription(data[0])); + PrintAndLogEx(ERR, "Card read error: %02x %s", data[0], mfpGetErrorDescription(data[0])); DropField(); return 6; } @@ -661,7 +567,7 @@ int CmdHFMFPWrbl(const char *cmd) { CLIGetHexWithReturn(5, key, &keylen); CLIParserFree(); - SetVerboseMode(verbose); + mfpSetVerboseMode(verbose); if (!keylen) { memmove(key, DefaultKey, 16); @@ -714,7 +620,7 @@ int CmdHFMFPWrbl(const char *cmd) { } if (datalen && data[0] != 0x90) { - PrintAndLogEx(ERR, "Card write error: %02x %s", data[0], GetErrorDescription(data[0])); + PrintAndLogEx(ERR, "Card write error: %02x %s", data[0], mfpGetErrorDescription(data[0])); DropField(); return 6; } @@ -733,6 +639,100 @@ int CmdHFMFPWrbl(const char *cmd) { return 0; } +int CmdHFMFPMAD(const char *cmd) { + + CLIParserInit("hf mfp mad", + "Checks and prints Mifare Application Directory (MAD)", + "Usage:\n\thf mfp mad -> shows MAD if exists\n" + "\thf mfp mad -a 03e1 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data if exists\n"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show technical data"), + arg_str0("aA", "aid", "print all sectors with aid", NULL), + arg_str0("kK", "key", "key for printing sectors", NULL), + arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool verbose = arg_get_lit(1); + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[16] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); + + CLIParserFree(); + + if (aidlen != 2 && keylen > 0) { + PrintAndLogEx(WARNING, "do not need a key without aid."); + } + + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + + if (mfpReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector0, verbose)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + if (verbose) { + for(int i = 0; i < 4; i ++) + PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); + } + + bool haveMAD2 = false; + MAD1DecodeAndPrint(sector0, verbose, &haveMAD2); + + if (haveMAD2) { + if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + MAD2DecodeAndPrint(sector10, verbose); + } + + if (aidlen == 2) { + uint16_t aaid = (aid[0] << 8) + aid[1]; + PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid); + + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, sector10, mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } + + uint8_t akey[16] = {0}; + memcpy(akey, g_mifarep_ndef_key, 16); + if (keylen == 16) { + memcpy(akey, key, 16); + } + + for (int i = 0; i < madlen; i++) { + if (aaid == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfpReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector, false)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } + + for(int j = 0; j < (verbose ? 4 : 3); j ++) + PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); + } + } + } + + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, @@ -744,6 +744,7 @@ static command_t CommandTable[] = {"rdbl", CmdHFMFPRdbl, 0, "Read blocks"}, {"rdsc", CmdHFMFPRdsc, 0, "Read sectors"}, {"wrbl", CmdHFMFPWrbl, 0, "Write blocks"}, + {"mad", CmdHFMFPMAD, 0, "Checks and prints MAD"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhfmfp.h b/client/cmdhfmfp.h index b1ac7c349..a5cacb518 100644 --- a/client/cmdhfmfp.h +++ b/client/cmdhfmfp.h @@ -10,7 +10,7 @@ #ifndef CMDHFMFP_H__ #define CMDHFMFP_H__ -#include "mifaredefault.h" +#include "mifare/mifaredefault.h" extern int CmdHFMFP(const char *Cmd); diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index b5be04593..8b27d9b22 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -980,11 +980,11 @@ int CmdHF14AMfUInfo(const char *Cmd){ if ( hasAuthKey ) return 1; // also try to diversify default keys.. look into CmdHF14AMfuGenDiverseKeys - PrintAndLogEx(NORMAL, "Trying some default 3des keys"); + PrintAndLogEx(INFO, "Trying some default 3des keys"); for (uint8_t i = 0; i < KEYS_3DES_COUNT; ++i ) { key = default_3des_keys[i]; if (ulc_authentication(key, true)) { - PrintAndLogEx(NORMAL, "Found default 3des key: "); + PrintAndLogEx(SUCCESS, "Found default 3des key: "); uint8_t keySwap[16]; memcpy(keySwap, SwapEndian64(key,16,8), 16); ulc_print_3deskey(keySwap); @@ -1079,7 +1079,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ num_to_bytes( ul_ev1_pwdgenA(card.uid), 4, key); len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(NORMAL, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); goto out; } @@ -1089,7 +1089,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ num_to_bytes( ul_ev1_pwdgenB(card.uid), 4, key); len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(NORMAL, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); goto out; } @@ -1099,7 +1099,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ num_to_bytes( ul_ev1_pwdgenC(card.uid), 4, key); len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(NORMAL, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); goto out; } @@ -1109,7 +1109,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ num_to_bytes( ul_ev1_pwdgenD(card.uid), 4, key); len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(NORMAL, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); goto out; } @@ -1119,13 +1119,13 @@ int CmdHF14AMfUInfo(const char *Cmd){ key = default_pwd_pack[i]; len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(NORMAL, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); break; } else { if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; } } - if (len < 1) PrintAndLogEx(NORMAL, "password not known"); + if (len < 1) PrintAndLogEx(WARNING, "password not known"); } } out: @@ -1250,7 +1250,7 @@ int CmdHF14AMfUWrBl(const char *Cmd){ UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLogEx(NORMAL, "isOk:%02x", isOK); + PrintAndLogEx(SUCCESS, "isOk:%02x", isOK); } else { PrintAndLogEx(WARNING, "Command execute timeout"); } @@ -1365,7 +1365,7 @@ int CmdHF14AMfURdBl(const char *Cmd){ PrintAndLogEx(WARNING, "Failed reading block: (%02x)", isOK); } } else { - PrintAndLogEx(NORMAL, "Command execute time-out"); + PrintAndLogEx(WARNING, "Command execute time-out"); } return 0; } @@ -1743,7 +1743,7 @@ int CmdHF14AMfUDump(const char *Cmd){ } } ul_print_type(tagtype, 0); - PrintAndLogEx(NORMAL, "Reading tag memory..."); + PrintAndLogEx(SUCCESS, "Reading tag memory..."); UsbCommand c = {CMD_MIFAREU_READCARD, {startPage, pages}}; if ( hasAuthKey ) { if (tagtype & UL_C) @@ -1912,12 +1912,10 @@ int CmdHF14AMfURestore(const char *Cmd){ memset(authkey, 0x00, sizeof(authkey)); while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { + switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': - case 'H': return usage_hf_mfu_restore(); case 'k': - case 'K': keylen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); if (keylen == 32 || keylen == 8) { //ul-c or ev1/ntag key length errors = param_gethex(tempStr, 0, authkey, keylen); @@ -1930,12 +1928,10 @@ int CmdHF14AMfURestore(const char *Cmd){ hasKey = true; break; case 'l': - case 'L': swapEndian = true; cmdp++; break; case 'f': - case 'F': filelen = param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE); if (filelen > FILE_PATH_SIZE-5) @@ -1947,17 +1943,14 @@ int CmdHF14AMfURestore(const char *Cmd){ cmdp += 2; break; case 's': - case 'S': cmdp++; write_special = true; break; case 'e': - case 'E': cmdp++; write_extra = true; break; case 'r': - case 'R': cmdp++; read_key = true; break; @@ -1972,7 +1965,7 @@ int CmdHF14AMfURestore(const char *Cmd){ if (errors || cmdp == 0) return usage_hf_mfu_restore(); if ((f = fopen(filename,"rb")) == NULL) { - PrintAndLogEx(WARNING, "Could not find file %s", filename); + PrintAndLogEx(WARNING, "Could not find file " _YELLOW_(%s), filename); return 1; } @@ -1989,6 +1982,7 @@ int CmdHF14AMfURestore(const char *Cmd){ uint8_t *dump = calloc(fsize, sizeof(uint8_t)); if ( !dump ) { PrintAndLogEx(WARNING, "Failed to allocate memory"); + fclose(f); return 1; } @@ -1997,10 +1991,11 @@ int CmdHF14AMfURestore(const char *Cmd){ fclose(f); if ( bytes_read < 48 ) { PrintAndLogEx(WARNING, "Error, dump file is too small"); + free(dump); return 1; } - PrintAndLogEx(NORMAL, "Restoring %s to card", filename); + PrintAndLogEx(INFO, "Restoring " _YELLOW_(%s)" to card", filename); mfu_dump_t *mem = (mfu_dump_t*)dump; uint8_t pages = (bytes_read-48)/4; @@ -2084,7 +2079,7 @@ int CmdHF14AMfURestore(const char *Cmd){ } } - PrintAndLogEx(NORMAL, "Restoring data blocks."); + PrintAndLogEx(INFO, "Restoring data blocks."); // write all other data // Skip block 0,1,2,3 (only magic tags can write to them) // Skip last 5 blocks usually is configuration @@ -2103,7 +2098,7 @@ int CmdHF14AMfURestore(const char *Cmd){ // write special data last if (write_special) { - PrintAndLogEx(NORMAL, "Restoring configuration blocks.\n"); + PrintAndLogEx(INFO, "Restoring configuration blocks.\n"); PrintAndLogEx(NORMAL, "authentication with keytype[%x] %s\n", (uint8_t)(c.arg[1] & 0xff), sprint_hex(p_authkey,4)); @@ -2128,16 +2123,16 @@ int CmdHF14AMfURestore(const char *Cmd){ // Load emulator with dump file // int CmdHF14AMfUeLoad(const char *Cmd){ - char c = param_getchar(Cmd, 0); - if ( c == 'h' || c == 'H' || c == 0x00) return usage_hf_mfu_eload(); + char c = tolower(param_getchar(Cmd, 0)); + if ( c == 'h' || c == 0x00) return usage_hf_mfu_eload(); return CmdHF14AMfELoad(Cmd); } // // Simulate tag // int CmdHF14AMfUSim(const char *Cmd){ - char c = param_getchar(Cmd, 0); - if ( c == 'h' || c == 'H' || c == 0x00) return usage_hf_mfu_sim(); + char c = tolower(param_getchar(Cmd, 0)); + if ( c == 'h' || c == 0x00) return usage_hf_mfu_sim(); return CmdHF14ASim(Cmd); } @@ -2153,16 +2148,16 @@ int CmdHF14AMfucAuth(const char *Cmd){ uint8_t keyNo = 3; bool errors = false; - char cmdp = param_getchar(Cmd, 0); + char cmdp = tolower(param_getchar(Cmd, 0)); //Change key to user defined one - if (cmdp == 'k' || cmdp == 'K'){ + if (cmdp == 'k'){ keyNo = param_get8(Cmd, 1); if(keyNo >= KEYS_3DES_COUNT) errors = true; } - if (cmdp == 'h' || cmdp == 'H') errors = true; + if (cmdp == 'h') errors = true; if (errors) return usage_hf_mfu_ucauth(); @@ -2278,9 +2273,9 @@ int CmdTestDES(const char * cmd) int CmdHF14AMfucSetPwd(const char *Cmd){ uint8_t pwd[16] = {0x00}; - char cmdp = param_getchar(Cmd, 0); + char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_hf_mfu_ucsetpwd(); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_ucsetpwd(); if (param_gethex(Cmd, 0, pwd, 32)) { PrintAndLogEx(WARNING, "Password must include 32 HEX symbols"); @@ -2295,7 +2290,7 @@ int CmdHF14AMfucSetPwd(const char *Cmd){ UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { if ( (resp.arg[0] & 0xff) == 1) { - PrintAndLogEx(NORMAL, "Ultralight-C new password: %s", sprint_hex(pwd,16)); + PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd,16)); } else { PrintAndLogEx(WARNING, "Failed writing at block %d", resp.arg[1] & 0xff); return 1; @@ -2315,9 +2310,9 @@ int CmdHF14AMfucSetUid(const char *Cmd){ UsbCommand c = {CMD_MIFAREU_READBL}; UsbCommand resp; uint8_t uid[7] = {0x00}; - char cmdp = param_getchar(Cmd, 0); + char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_hf_mfu_ucsetuid(); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_ucsetuid(); if (param_gethex(Cmd, 0, uid, 14)) { PrintAndLogEx(WARNING, "UID must include 14 HEX symbols"); @@ -2386,7 +2381,7 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_gendiverse(); if ( cmdp == 'r' ) { - // read uid from tag + // read uid from tag UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0}}; clearCommandBuffer(); SendCommand(&c); @@ -2395,8 +2390,13 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ iso14a_card_select_t card; memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - if(select_status == 0) { + uint64_t select_status = resp.arg[0]; + // 0: couldn't read, + // 1: OK, with ATS + // 2: OK, no ATS + // 3: proprietary Anticollision + + if ( select_status == 0 ) { PrintAndLogEx(WARNING, "iso14443a card select failed"); return 1; } @@ -2451,12 +2451,12 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ PrintAndLogEx(NORMAL, "Diversified key: %s", sprint_hex(divkey+1, 6)); for (int i=0; i < sizeof(mifarekeyA); ++i){ - dkeyA[i] = (mifarekeyA[i] << 1) & 0xff; - dkeyA[6] |= ((mifarekeyA[i] >> 7) & 1) << (i+1); + dkeyA[i] = (mifarekeyA[i] << 1) & 0xff; + dkeyA[6] |= ((mifarekeyA[i] >> 7) & 1) << (i+1); } for (int i=0; i < sizeof(mifarekeyB); ++i){ - dkeyB[1] |= ((mifarekeyB[i] >> 7) & 1) << (i+1); + dkeyB[1] |= ((mifarekeyB[i] >> 7) & 1) << (i+1); dkeyB[2+i] = (mifarekeyB[i] << 1) & 0xff; } @@ -2493,6 +2493,7 @@ int CmdHF14AMfuPwdGen(const char *Cmd){ uint8_t uid[7] = {0x00}; char cmdp = tolower(param_getchar(Cmd, 0)); if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_pwdgen(); + if (cmdp == 't') return ul_ev1_pwdgen_selftest(); if ( cmdp == 'r') { @@ -2505,8 +2506,12 @@ int CmdHF14AMfuPwdGen(const char *Cmd){ iso14a_card_select_t card; memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - if(select_status == 0) { + uint64_t select_status = resp.arg[0]; + // 0: couldn't read + // 1: OK with ATS + // 2: OK, no ATS + // 3: proprietary Anticollision + if ( select_status == 0 ) { PrintAndLogEx(WARNING, "iso14443a card select failed"); return 1; } @@ -2519,6 +2524,7 @@ int CmdHF14AMfuPwdGen(const char *Cmd){ else { if (param_gethex(Cmd, 0, uid, 14)) return usage_hf_mfu_pwdgen(); } + PrintAndLogEx(NORMAL, "---------------------------------"); PrintAndLogEx(NORMAL, " Using UID : %s", sprint_hex(uid, 7)); PrintAndLogEx(NORMAL, "---------------------------------"); @@ -2536,8 +2542,7 @@ int CmdHF14AMfuPwdGen(const char *Cmd){ //------------------------------------ // Menu Stuff //------------------------------------ -static command_t CommandTable[] = -{ +static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, {"info", CmdHF14AMfUInfo, 0, "Tag information"}, @@ -2557,7 +2562,6 @@ static command_t CommandTable[] = int CmdHFMFUltra(const char *Cmd){ clearCommandBuffer(); - //WaitForResponseTimeout(CMD_ACK,NULL,100); CmdsParse(CommandTable, Cmd); return 0; } diff --git a/client/cmdhftopaz.c b/client/cmdhftopaz.c index ea4699f1b..2f80b054c 100644 --- a/client/cmdhftopaz.c +++ b/client/cmdhftopaz.c @@ -194,7 +194,7 @@ static int topaz_print_CC(uint8_t *data) { PrintAndLogEx(NORMAL, " %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); uint16_t memsize = (data[2] + 1) * 8; topaz_tag.size = memsize; - topaz_tag.dynamic_memory = malloc(memsize - TOPAZ_STATIC_MEMORY); + topaz_tag.dynamic_memory = calloc(memsize - TOPAZ_STATIC_MEMORY, sizeof(uint8_t)); PrintAndLogEx(NORMAL, " %02x: Physical Memory Size of this tag: %d bytes", data[2], memsize); PrintAndLogEx(NORMAL, " %02x: %s / %s", data[3], (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", @@ -278,12 +278,12 @@ static void topaz_print_control_TLVs(uint8_t *memory) { dynamic_lock_area_t *old = topaz_tag.dynamic_lock_areas; dynamic_lock_area_t *new = topaz_tag.dynamic_lock_areas; if (old == NULL) { - new = topaz_tag.dynamic_lock_areas = (dynamic_lock_area_t *)malloc(sizeof(dynamic_lock_area_t)); + new = topaz_tag.dynamic_lock_areas = (dynamic_lock_area_t *) calloc(sizeof(dynamic_lock_area_t) , sizeof(uint8_t)); } else { while(old->next != NULL) { old = old->next; } - new = old->next = (dynamic_lock_area_t *)malloc(sizeof(dynamic_lock_area_t)); + new = old->next = (dynamic_lock_area_t *) calloc(sizeof(dynamic_lock_area_t), sizeof(uint8_t)); } new->next = NULL; if (area_start <= next_lockable_byte) { diff --git a/client/cmdhw.c b/client/cmdhw.c index 49cb0025e..ec7b42a1a 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -74,7 +74,7 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) { if ( mem_avail > 0 ) mem_left = (mem_avail * 1024) - mem_used; - PrintAndLogEx(NORMAL, " --= Nonvolatile Program Memory Size: %uK bytes, Used: %u bytes (%2.0f\%) Free: %u bytes (%2.0f\%)", + PrintAndLogEx(NORMAL, " --= Nonvolatile Program Memory Size: %uK bytes, Used: %u bytes (%2.0f%%) Free: %u bytes (%2.0f%%)", mem_avail, mem_used, mem_avail == 0 ? 0.0f : (float)mem_used/(mem_avail*1024)*100, @@ -257,9 +257,9 @@ int CmdVersion(const char *Cmd) { SendCommand(&c); if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { #ifdef __WIN32 - PrintAndLogEx(NORMAL, "\nProxmark3 RFID instrument\n"); + PrintAndLogEx(NORMAL, "\n [ Proxmark3 RFID instrument ]\n"); #else - PrintAndLogEx(NORMAL, "\n\e[34mProxmark3 RFID instrument\e[0m\n"); + PrintAndLogEx(NORMAL, "\n\e[34m [ Proxmark3 RFID instrument ]\e[0m\n"); #endif char s[50] = {0}; #if defined(WITH_FLASH) || defined(WITH_SMARTCARD) || defined(WITH_FPC) @@ -275,7 +275,7 @@ int CmdVersion(const char *Cmd) { strncat(s, "fpc; ", sizeof(s) - strlen(s) - 1); #endif PrintAndLogEx(NORMAL, "\n [ CLIENT ]"); - PrintAndLogEx(NORMAL, " client: iceman %s \n", s); + PrintAndLogEx(NORMAL, " client: iceman %s \n", s); PrintAndLogEx(NORMAL, (char*)resp.d.asBytes); lookupChipID(resp.arg[0], resp.arg[1]); diff --git a/client/cmdlf.c b/client/cmdlf.c index 50077add2..240a1d402 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -186,15 +186,21 @@ int CmdLFCommandRead(const char *Cmd) { } int CmdFlexdemod(const char *Cmd) { -#define LONG_WAIT 100 + + if ( GraphTraceLen < 0 ) + return 0; + +#ifndef LONG_WAIT +#define LONG_WAIT 100 +#endif int i, j, start, bit, sum, phase = 0; - uint8_t data[MAX_GRAPH_TRACE_LEN] = {0}; - size_t size = getFromGraphBuf(data); - if (size == 0) - return 0; + int data[GraphTraceLen]; + memcpy(data, GraphBuffer, GraphTraceLen); - for (i = 0; i < size; ++i) + size_t size = GraphTraceLen; + + for (i = 0; i < GraphTraceLen; ++i) data[i] = (data[i] < 0) ? -1 : 1; for (start = 0; start < size - LONG_WAIT; start++) { @@ -819,14 +825,16 @@ int CheckChipType(bool getDeviceData) { //check for em4x05/em4x69 chips first uint32_t word = 0; if (EM4x05IsBlock0(&word)) { - PrintAndLogEx(NORMAL, "\nValid EM4x05/EM4x69 Chip Found\nTry lf em 4x05... commands\n"); + PrintAndLogEx(SUCCESS, "\nValid EM4x05/EM4x69 Chip Found"); + PrintAndLogEx(SUCCESS, "Try " _YELLOW_(`lf em 4x05`) " commands"); save_restoreGB(GRAPH_RESTORE); return 1; } //check for t55xx chip... if (tryDetectP1(true)) { - PrintAndLogEx(NORMAL, "\nValid T55xx Chip Found\nTry `lf t55xx` commands\n"); + PrintAndLogEx(SUCCESS, "\nValid T55xx Chip Found"); + PrintAndLogEx(SUCCESS, "Try " _YELLOW_(`lf t55xx`)" commands"); save_restoreGB(GRAPH_RESTORE); return 1; } @@ -856,9 +864,10 @@ int CmdLFfind(const char *Cmd) { return 0; } - PrintAndLogEx(NORMAL, "NOTE: some demods output possible binary\n if it finds something that looks like a tag"); - PrintAndLogEx(NORMAL, "False Positives ARE possible\n"); - PrintAndLogEx(NORMAL, "\nChecking for known tags:\n"); + PrintAndLogEx(INFO, "NOTE: some demods output possible binary"); + PrintAndLogEx(INFO, "if it finds something that looks like a tag"); + PrintAndLogEx(INFO, "False Positives " _YELLOW_(ARE) "possible\n"); + PrintAndLogEx(INFO, "\nChecking for known tags:\n"); // only run these tests if device is online if (isOnline) { @@ -891,6 +900,7 @@ int CmdLFfind(const char *Cmd) { if (CmdLFNedapDemod("")) { PrintAndLogEx(SUCCESS, "\nValid NEDAP ID Found!"); goto out;} if (CmdNexWatchDemod("")) { PrintAndLogEx(SUCCESS, "\nValid NexWatch ID Found!"); goto out;} if (CmdNoralsyDemod("")) { PrintAndLogEx(SUCCESS, "\nValid Noralsy ID Found!"); goto out;} + if (CmdKeriDemod("")) { PrintAndLogEx(SUCCESS, "\nValid KERI ID Found!"); goto out;} if (CmdPacDemod("")) { PrintAndLogEx(SUCCESS, "\nValid PAC/Stanley ID Found!"); goto out;} if (CmdParadoxDemod("")) { PrintAndLogEx(SUCCESS, "\nValid Paradox ID Found!"); goto out;} if (CmdPrescoDemod("")) { PrintAndLogEx(SUCCESS, "\nValid Presco ID Found!"); goto out;} @@ -957,6 +967,7 @@ static command_t CommandTable[] = { {"indala", CmdLFINDALA, 1, "{ Indala RFIDs... }"}, {"io", CmdLFIO, 1, "{ ioProx RFIDs... }"}, {"jablotron", CmdLFJablotron, 1, "{ Jablotron RFIDs... }"}, + {"keri", CmdLFKeri, 1, "{ KERI RFIDs... }"}, {"nedap", CmdLFNedap, 1, "{ Nedap RFIDs... }"}, {"nexwatch", CmdLFNEXWATCH, 1, "{ NexWatch RFIDs... }"}, {"noralsy", CmdLFNoralsy, 1, "{ Noralsy RFIDs... }"}, diff --git a/client/cmdlf.h b/client/cmdlf.h index de216435f..04c7317a1 100644 --- a/client/cmdlf.h +++ b/client/cmdlf.h @@ -42,13 +42,14 @@ #include "cmdlfnoralsy.h" // for NORALSY meny #include "cmdlffdx.h" // for FDX-B meny #include "cmdlfcotag.h" // for COTAG meny -#include "cmdlfindala.h" // for indala menu -#include "cmdlfguard.h"// for gproxii menu -#include "cmdlffdx.h" // for fdx-b menu -#include "cmdlfparadox.h"// for paradox menu +#include "cmdlfindala.h" // for indala menu +#include "cmdlfguard.h" // for gproxii menu +#include "cmdlffdx.h" // for fdx-b menu +#include "cmdlfparadox.h" // for paradox menu #include "cmdlfnexwatch.h" //for nexwatch menu #include "cmdlfsecurakey.h" //for securakey menu #include "cmdlfpac.h" // for pac menu +#include "cmdlfkeri.h" // for keri menu #define T55XX_WRITE_TIMEOUT 1500 diff --git a/client/cmdlfawid.c b/client/cmdlfawid.c index b17864dcf..3cc56f56c 100644 --- a/client/cmdlfawid.c +++ b/client/cmdlfawid.c @@ -101,7 +101,7 @@ static bool sendPing(void){ static bool sendTry(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint32_t delay, uint8_t *bits, size_t bs_len, bool verbose){ if ( verbose ) - PrintAndLogEx(NORMAL, "Trying FC: %u; CN: %u", fc, cn); + PrintAndLogEx(INFO, "Trying FC: %u; CN: %u", fc, cn); if ( !getAWIDBits(fmtlen, fc, cn, bits)) { PrintAndLogEx(WARNING, "Error with tag bitstream generation."); @@ -171,7 +171,7 @@ int getAWIDBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *bits) { if (bitLen != 88) return 0; - PrintAndLogEx(NORMAL, "awid raw bits:\n %s \n", sprint_bin(bits, bitLen)); + PrintAndLogEx(SUCCESS, "awid raw bits:\n %s \n", sprint_bin(bits, bitLen)); return 1; } @@ -181,27 +181,27 @@ static void verify_values(uint8_t *fmtlen, uint32_t *fc, uint32_t *cn){ case 50: if ((*fc & 0xFFFF) != *fc) { *fc &= 0xFFFF; - PrintAndLogEx(NORMAL, "Facility-Code Truncated to 16-bits (AWID50): %u", *fc); + PrintAndLogEx(INFO, "Facility-Code Truncated to 16-bits (AWID50): %u", *fc); } break; case 37: if ((*fc & 0x1FFF) != *fc) { *fc &= 0x1FFF; - PrintAndLogEx(NORMAL, "Facility-Code Truncated to 13-bits (AWID37): %u", *fc); + PrintAndLogEx(INFO, "Facility-Code Truncated to 13-bits (AWID37): %u", *fc); } if ((*cn & 0x3FFFF) != *cn) { *cn &= 0x3FFFF; - PrintAndLogEx(NORMAL, "Card Number Truncated to 18-bits (AWID37): %u", *cn); + PrintAndLogEx(INFO, "Card Number Truncated to 18-bits (AWID37): %u", *cn); } break; case 34: if ((*fc & 0xFF) != *fc) { *fc &= 0xFF; - PrintAndLogEx(NORMAL, "Facility-Code Truncated to 8-bits (AWID34): %u", *fc); + PrintAndLogEx(INFO, "Facility-Code Truncated to 8-bits (AWID34): %u", *fc); } if ((*cn & 0xFFFFFF) != *cn) { *cn &= 0xFFFFFF; - PrintAndLogEx(NORMAL, "Card Number Truncated to 24-bits (AWID34): %u", *cn); + PrintAndLogEx(INFO, "Card Number Truncated to 24-bits (AWID34): %u", *cn); } break; case 26: @@ -209,11 +209,11 @@ static void verify_values(uint8_t *fmtlen, uint32_t *fc, uint32_t *cn){ *fmtlen = 26; if ((*fc & 0xFF) != *fc) { *fc &= 0xFF; - PrintAndLogEx(NORMAL, "Facility-Code Truncated to 8-bits (AWID26): %u", *fc); + PrintAndLogEx(INFO, "Facility-Code Truncated to 8-bits (AWID26): %u", *fc); } if ((*cn & 0xFFFF) != *cn) { *cn &= 0xFFFF; - PrintAndLogEx(NORMAL, "Card Number Truncated to 16-bits (AWID26): %u", *cn); + PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (AWID26): %u", *cn); } break; } @@ -290,7 +290,7 @@ int CmdAWIDDemod(const char *Cmd) { uint32_t rawHi2 = bytebits_to_byte(bits + idx, 32); size = removeParity(bits, idx+8, 4, 1, 88); - if (size != 66){ + if (size != 66) { PrintAndLogEx(DEBUG, "DEBUG: Error - AWID at parity check-tag size does not match AWID format"); return 0; } @@ -323,21 +323,21 @@ int CmdAWIDDemod(const char *Cmd) { fc = bytebits_to_byte(bits + 9, 8); cardnum = bytebits_to_byte(bits + 17, 16); code1 = bytebits_to_byte(bits + 8,fmtLen); - PrintAndLogEx(NORMAL, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, rawHi2, rawHi, rawLo); + PrintAndLogEx(SUCCESS, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, rawHi2, rawHi, rawLo); break; case 34: fc = bytebits_to_byte(bits + 9, 8); cardnum = bytebits_to_byte(bits + 17, 24); code1 = bytebits_to_byte(bits + 8, (fmtLen-32) ); code2 = bytebits_to_byte(bits + 8 + (fmtLen-32), 32); - PrintAndLogEx(NORMAL, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo); + PrintAndLogEx(SUCCESS, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo); break; case 37: fc = bytebits_to_byte(bits + 9, 13); cardnum = bytebits_to_byte(bits + 22, 18); code1 = bytebits_to_byte(bits + 8, (fmtLen-32) ); code2 = bytebits_to_byte(bits + 8 + (fmtLen-32), 32); - PrintAndLogEx(NORMAL, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo); + PrintAndLogEx(SUCCESS, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo); break; // case 40: // break; @@ -346,18 +346,18 @@ int CmdAWIDDemod(const char *Cmd) { cardnum = bytebits_to_byte(bits + 25, 32); code1 = bytebits_to_byte(bits + 8, (fmtLen-32) ); code2 = bytebits_to_byte(bits + 8 + (fmtLen-32), 32); - PrintAndLogEx(NORMAL, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo); + PrintAndLogEx(SUCCESS, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo); break; default: if (fmtLen > 32 ) { cardnum = bytebits_to_byte(bits + 8 + (fmtLen-17), 16); code1 = bytebits_to_byte(bits + 8, fmtLen-32); code2 = bytebits_to_byte(bits + 8 + (fmtLen-32), 32); - PrintAndLogEx(NORMAL, "AWID Found - BitLength: %d -unknown BitLength- (%u) - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo); + PrintAndLogEx(SUCCESS, "AWID Found - BitLength: %d -unknown BitLength- (%u) - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo); } else { cardnum = bytebits_to_byte(bits + 8 + (fmtLen-17), 16); code1 = bytebits_to_byte(bits + 8, fmtLen); - PrintAndLogEx(NORMAL, "AWID Found - BitLength: %d -unknown BitLength- (%u) - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo); + PrintAndLogEx(SUCCESS, "AWID Found - BitLength: %d -unknown BitLength- (%u) - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo); } break; } @@ -386,8 +386,8 @@ int CmdAWIDSim(const char *Cmd) { verify_values(&fmtlen, &fc, &cn); - PrintAndLogEx(NORMAL, "Emulating AWID %u -- FC: %u; CN: %u\n", fmtlen, fc, cn); - PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or run another command"); + PrintAndLogEx(SUCCESS, "Simulating AWID %u -- FC: %u; CN: %u\n", fmtlen, fc, cn); + PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command"); if (!getAWIDBits(fmtlen, fc, cn, bits)) { PrintAndLogEx(WARNING, "Error with tag bitstream generation."); @@ -417,8 +417,8 @@ int CmdAWIDClone(const char *Cmd) { uint8_t *bs=bits; memset(bs,0,sizeof(bits)); - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_awid_clone(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_awid_clone(); fmtlen = param_get8(Cmd, 0); fc = param_get32ex(Cmd, 1, 0, 10); @@ -426,7 +426,7 @@ int CmdAWIDClone(const char *Cmd) { if ( !fc || !cn) return usage_lf_awid_clone(); - if (param_getchar(Cmd, 3) == 'Q' || param_getchar(Cmd, 3) == 'q') + if (tolower(param_getchar(Cmd, 3)) == 'q') //t5555 (Q5) BITRATE = (RF-2)/2 (iceman) blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 3< maxErr ) { PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB no data or error found %d, clock: %d", errCnt, clk); return 0; } - errCnt = BiphaseRawDecode(BitStream, &size, &offset, 1); + errCnt = BiphaseRawDecode(bs, &size, &offset, 1); if (errCnt < 0 || errCnt > maxErr ) { PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB BiphaseRawDecode: %d", errCnt); return 0; } - int preambleIndex = detectFDXB(BitStream, &size); + int preambleIndex = detectFDXB(bs, &size); if (preambleIndex < 0){ PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB preamble not found :: %d",preambleIndex); return 0; @@ -188,44 +186,44 @@ int CmdFDXBdemodBI(const char *Cmd){ return 0; } - setDemodBuf(BitStream, 128, preambleIndex); + setDemodBuf(bs, 128, preambleIndex); // remove marker bits (1's every 9th digit after preamble) (pType = 2) - size = removeParity(BitStream, preambleIndex + 11, 9, 2, 117); + size = removeParity(bs, preambleIndex + 11, 9, 2, 117); if ( size != 104 ) { PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB error removeParity:: %d", size); return 0; } - PrintAndLogEx(NORMAL, "\nFDX-B / ISO 11784/5 Animal Tag ID Found:"); + PrintAndLogEx(SUCCESS, "\nFDX-B / ISO 11784/5 Animal Tag ID Found:"); //got a good demod - uint64_t NationalCode = ((uint64_t)(bytebits_to_byteLSBF(BitStream+32,6)) << 32) | bytebits_to_byteLSBF(BitStream,32); - uint32_t countryCode = bytebits_to_byteLSBF(BitStream+38,10); - uint8_t dataBlockBit = BitStream[48]; - uint32_t reservedCode = bytebits_to_byteLSBF(BitStream+49,14); - uint8_t animalBit = BitStream[63]; - uint32_t crc16 = bytebits_to_byteLSBF(BitStream+64,16); - uint32_t extended = bytebits_to_byteLSBF(BitStream+80,24); + uint64_t NationalCode = ((uint64_t)(bytebits_to_byteLSBF(bs+32, 6)) << 32) | bytebits_to_byteLSBF(bs, 32); + uint32_t countryCode = bytebits_to_byteLSBF(bs+38, 10); + uint8_t dataBlockBit = bs[48]; + uint32_t reservedCode = bytebits_to_byteLSBF(bs+49, 14); + uint8_t animalBit = bs[63]; + uint32_t crc16 = bytebits_to_byteLSBF(bs+64, 16); + uint32_t extended = bytebits_to_byteLSBF(bs+80, 24); - uint64_t rawid = ((uint64_t)bytebits_to_byte(BitStream,32)<<32) | bytebits_to_byte(BitStream+32,32); + uint64_t rawid = ((uint64_t)bytebits_to_byte(bs, 32) << 32) | bytebits_to_byte(bs+32, 32); uint8_t raw[8]; num_to_bytes(rawid, 8, raw); - PrintAndLogEx(NORMAL, "Raw ID Hex: %s", sprint_hex(raw,8)); + PrintAndLogEx(SUCCESS, "Raw ID Hex: %s", sprint_hex(raw,8)); uint16_t calcCrc = crc16_kermit(raw, 8); - PrintAndLogEx(NORMAL, "Animal ID: %04u-%012" PRIu64, countryCode, NationalCode); - PrintAndLogEx(NORMAL, "National Code: %012" PRIu64, NationalCode); - PrintAndLogEx(NORMAL, "CountryCode: %04u", countryCode); + PrintAndLogEx(SUCCESS, "Animal ID: %04u-%012" PRIu64, countryCode, NationalCode); + PrintAndLogEx(SUCCESS, "National Code: %012" PRIu64, NationalCode); + PrintAndLogEx(SUCCESS, "CountryCode: %04u", countryCode); - PrintAndLogEx(NORMAL, "Reserved/RFU: %u", reservedCode); - PrintAndLogEx(NORMAL, "Animal Tag: %s", animalBit ? "True" : "False"); - PrintAndLogEx(NORMAL, "Has extended data: %s [0x%X]", dataBlockBit ? "True" : "False", extended); - PrintAndLogEx(NORMAL, "CRC: 0x%04X - [%04X] - %s", crc16, calcCrc, (calcCrc == crc16) ? "Passed" : "Failed"); + PrintAndLogEx(SUCCESS, "Reserved/RFU: %u", reservedCode); + PrintAndLogEx(SUCCESS, "Animal Tag: %s", animalBit ? _YELLOW_(True) : "False"); + PrintAndLogEx(SUCCESS, "Has extended data: %s [0x%X]", dataBlockBit ? _YELLOW_(True) : "False", extended); + PrintAndLogEx(SUCCESS, "CRC: 0x%04X - [%04X] - %s", crc16, calcCrc, (calcCrc == crc16) ? _GREEN_(Passed) : "Failed"); if (g_debugMode) { PrintAndLogEx(DEBUG, "Start marker %d; Size %d", preambleIndex, size); - char *bin = sprint_bin_break(BitStream,size,16); + char *bin = sprint_bin_break(bs, size, 16); PrintAndLogEx(DEBUG, "DEBUG BinStream:\n%s",bin); } return 1; @@ -282,14 +280,14 @@ int CmdFdxDemod(const char *Cmd) { uint16_t calcCrc = crc16_kermit(raw, 8); - PrintAndLogEx(NORMAL, "\nFDX-B / ISO 11784/5 Animal Tag ID Found: Raw : %s", sprint_hex(raw, 8)); - PrintAndLogEx(NORMAL, "Animal ID %04u-%012" PRIu64, countryCode, NationalCode); - PrintAndLogEx(NORMAL, "National Code %012" PRIu64 " (0x%" PRIx64 ")", NationalCode, NationalCode); - PrintAndLogEx(NORMAL, "Country Code %04u", countryCode); - PrintAndLogEx(NORMAL, "Reserved/RFU %u (0x04%X)", reservedCode, reservedCode); - PrintAndLogEx(NORMAL, "Animal Tag %s", animalBit ? "True" : "False"); - PrintAndLogEx(NORMAL, "Has extended data %s [0x%X]", dataBlockBit ? "True" : "False", extended); - PrintAndLogEx(NORMAL, "CRC-16 0x%04X - 0x%04X [%s]", crc16, calcCrc, (calcCrc == crc16) ? "Ok" : "Failed"); + PrintAndLogEx(SUCCESS, "\nFDX-B / ISO 11784/5 Animal Tag ID Found: Raw : %s", sprint_hex(raw, 8)); + PrintAndLogEx(SUCCESS, "Animal ID %04u-%012" PRIu64, countryCode, NationalCode); + PrintAndLogEx(SUCCESS, "National Code %012" PRIu64 " (0x%" PRIx64 ")", NationalCode, NationalCode); + PrintAndLogEx(SUCCESS, "Country Code %04u", countryCode); + PrintAndLogEx(SUCCESS, "Reserved/RFU %u (0x04%X)", reservedCode, reservedCode); + PrintAndLogEx(SUCCESS, "Animal Tag %s", animalBit ? _YELLOW_(True) : "False"); + PrintAndLogEx(SUCCESS, "Has extended data %s [0x%X]", dataBlockBit ? _YELLOW_(True) : "False", extended); + PrintAndLogEx(SUCCESS, "CRC-16 0x%04X - 0x%04X [%s]", crc16, calcCrc, (calcCrc == crc16) ? _GREEN_(Ok) : "Failed"); if (g_debugMode) { PrintAndLogEx(DEBUG, "Start marker %d; Size %d", preambleIndex, size); @@ -341,7 +339,7 @@ int CmdFdxClone(const char *Cmd) { blocks[3] = bytebits_to_byte(bs + 64, 32); blocks[4] = bytebits_to_byte(bs + 96, 32); - PrintAndLogEx(NORMAL, "Preparing to clone FDX-B to T55x7 with animal ID: %04u-%"PRIu64, countryid, animalid); + PrintAndLogEx(INFO, "Preparing to clone FDX-B to T55x7 with animal ID: %04u-%"PRIu64, countryid, animalid); print_blocks(blocks, 5); UsbCommand resp; @@ -379,7 +377,7 @@ int CmdFdxSim(const char *Cmd) { arg1 = clk << 8 | encoding; arg2 = invert << 8 | separator; - PrintAndLogEx(NORMAL, "Simulating FDX-B animal ID: %04u-%"PRIu64, countryid, animalid); + PrintAndLogEx(SUCCESS, "Simulating FDX-B animal ID: %04u-%"PRIu64, countryid, animalid); UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; diff --git a/client/cmdlfguard.c b/client/cmdlfguard.c index ea97d6f77..5707c78fb 100644 --- a/client/cmdlfguard.c +++ b/client/cmdlfguard.c @@ -107,21 +107,21 @@ int GetGuardBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits) { for (i = 0; i < 4; ++i) rawbytes[i+4] = bytebits_to_byte( pre + (i*8), 8); - if (g_debugMode) PrintAndLogEx(NORMAL, " WIE | %s\n", sprint_hex(rawbytes, sizeof(rawbytes))); + PrintAndLogEx(DEBUG, " WIE | %s\n", sprint_hex(rawbytes, sizeof(rawbytes))); // XOR (only works on wiegand stuff) for (i = 1; i < 12; ++i) rawbytes[i] ^= xorKey ; - if (g_debugMode) PrintAndLogEx(NORMAL, " XOR | %s \n", sprint_hex(rawbytes, sizeof(rawbytes))); + PrintAndLogEx(DEBUG, " XOR | %s \n", sprint_hex(rawbytes, sizeof(rawbytes))); // convert rawbytes to bits in pre for (i = 0; i < 12; ++i) num_to_bytebitsLSBF( rawbytes[i], 8, pre + (i*8)); - if (g_debugMode) PrintAndLogEx(NORMAL, "\n Raw | %s \n", sprint_hex(rawbytes, sizeof(rawbytes))); - if (g_debugMode) PrintAndLogEx(NORMAL, " Raw | %s\n", sprint_bin(pre, 64) ); + PrintAndLogEx(DEBUG, "\n Raw | %s \n", sprint_hex(rawbytes, sizeof(rawbytes))); + PrintAndLogEx(DEBUG, " Raw | %s\n", sprint_bin(pre, 64) ); // add spacer bit 0 every 4 bits, starting with index 0, // 12 bytes, 24 nibbles. 24+1 extra bites. 3bytes. ie 9bytes | 1byte xorkey, 8bytes rawdata (64bits, should be enough for a 40bit wiegand) @@ -135,7 +135,7 @@ int GetGuardBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits) { guardBits[4] = 1; guardBits[5] = 0; - if (g_debugMode) PrintAndLogEx(NORMAL, " FIN | %s\n", sprint_bin(guardBits, 96) ); + PrintAndLogEx(DEBUG, " FIN | %s\n", sprint_bin(guardBits, 96) ); return 1; } @@ -192,7 +192,7 @@ int CmdGuardDemod(const char *Cmd) { PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII preamble not found"); else if (preambleIndex == -3) PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII size not correct: %d", size); - else if (preambleIndex == -3) + else if (preambleIndex == -5) PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII wrong spacerbits"); else PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII ans: %d", preambleIndex); @@ -246,9 +246,9 @@ int CmdGuardDemod(const char *Cmd) { break; } if ( !unknown) - PrintAndLogEx(NORMAL, "G-Prox-II Found: Format Len: %ubit - FC: %u - Card: %u, Raw: %08x%08x%08x", fmtLen, FC, Card, raw1, raw2, raw3); + PrintAndLogEx(SUCCESS, "G-Prox-II Found: Format Len: %ubit - FC: %u - Card: %u, Raw: %08x%08x%08x", fmtLen, FC, Card, raw1, raw2, raw3); else - PrintAndLogEx(NORMAL, "Unknown G-Prox-II Fmt Found: Format Len: %u, Raw: %08x%08x%08x", fmtLen, raw1, raw2, raw3); + PrintAndLogEx(SUCCESS, "Unknown G-Prox-II Fmt Found: Format Len: %u, Raw: %08x%08x%08x", fmtLen, raw1, raw2, raw3); return 1; } @@ -290,7 +290,7 @@ int CmdGuardClone(const char *Cmd) { blocks[2] = bytebits_to_byte(bs + 32, 32); blocks[3] = bytebits_to_byte(bs + 64, 32); - PrintAndLogEx(NORMAL, "Preparing to clone Guardall to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber); + PrintAndLogEx(INFO, "Preparing to clone Guardall to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber); print_blocks(blocks, 4); UsbCommand resp; @@ -333,7 +333,7 @@ int CmdGuardSim(const char *Cmd) { return 1; } - PrintAndLogEx(NORMAL, "Simulating Guardall - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber ); + PrintAndLogEx(SUCCESS, "Simulating Guardall - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber ); uint64_t arg1, arg2; arg1 = (clock << 8) | encoding; diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index 7bc3bb9e9..7d1bda95c 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -106,7 +106,7 @@ static bool sendTry(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint32_t delay, ui // this should be optional. if ( verbose ) - PrintAndLogEx(NORMAL, "Trying FC: %u; CN: %u", fc, cn); + PrintAndLogEx(INFO, "Trying FC: %u; CN: %u", fc, cn); calcWiegand( fmtlen, fc, cn, bits); @@ -164,7 +164,7 @@ int CmdHIDDemod(const char *Cmd) { } if (hi2 != 0){ //extra large HID tags - PrintAndLogEx(NORMAL, "HID Prox TAG ID: %x%08x%08x (%u)", hi2, hi, lo, (lo>>1) & 0xFFFF); + PrintAndLogEx(SUCCESS, "HID Prox TAG ID: %x%08x%08x (%u)", hi2, hi, lo, (lo>>1) & 0xFFFF); } else { //standard HID tags <38 bits uint8_t fmtLen = 0; uint32_t cc = 0; @@ -209,9 +209,9 @@ int CmdHIDDemod(const char *Cmd) { } } if(fmtLen==32 && (lo & 0x40000000)){//if 32 bit and Kastle bit set - PrintAndLogEx(NORMAL, "HID Prox TAG (Kastle format) ID: %08x (%u) - Format Len: 32bit - CC: %u - FC: %u - Card: %u", lo, (lo >> 1) & 0xFFFF, cc, fc, cardnum); + PrintAndLogEx(SUCCESS, "HID Prox TAG (Kastle format) ID: %08x (%u) - Format Len: 32bit - CC: %u - FC: %u - Card: %u", lo, (lo >> 1) & 0xFFFF, cc, fc, cardnum); }else{ - PrintAndLogEx(NORMAL, "HID Prox TAG ID: %x%08x (%u) - Format Len: %ubit - FC: %u - Card: %u", hi, lo, (lo >> 1) & 0xFFFF, fmtLen, fc, cardnum); + PrintAndLogEx(SUCCESS, "HID Prox TAG ID: %x%08x (%u) - Format Len: %ubit - FC: %u - Card: %u", hi, lo, (lo >> 1) & 0xFFFF, fmtLen, fc, cardnum); } } @@ -244,16 +244,16 @@ int CmdHIDSim(const char *Cmd) { uint32_t hi = 0, lo = 0; uint32_t n = 0, i = 0; - uint8_t ctmp = param_getchar(Cmd, 0); - if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_hid_sim(); + uint8_t ctmp = tolower(param_getchar(Cmd, 0)); + if ( strlen(Cmd) == 0 || ctmp == 'h' ) return usage_lf_hid_sim(); while (sscanf(&Cmd[i++], "%1x", &n ) == 1) { hi = (hi << 4) | (lo >> 28); lo = (lo << 4) | (n & 0xf); } - PrintAndLogEx(NORMAL, "Emulating tag with ID %x%08x", hi, lo); - PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation"); + PrintAndLogEx(SUCCESS, "Simulating HID tag with ID %x%08x", hi, lo); + PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation"); UsbCommand c = {CMD_HID_SIM_TAG, {hi, lo, 0}}; clearCommandBuffer(); @@ -277,7 +277,7 @@ int CmdHIDClone(const char *Cmd) { lo = (lo << 4) | (n & 0xf); } - PrintAndLogEx(NORMAL, "Cloning tag with long ID %x%08x%08x", hi2, hi, lo); + PrintAndLogEx(INFO, "Preparing to clone HID tag with long ID %x%08x%08x", hi2, hi, lo); c.d.asBytes[0] = 1; } else { @@ -285,7 +285,7 @@ int CmdHIDClone(const char *Cmd) { hi = (hi << 4) | (lo >> 28); lo = (lo << 4) | (n & 0xf); } - PrintAndLogEx(NORMAL, "Cloning tag with ID %x%08x", hi, lo); + PrintAndLogEx(INFO, "Preparing to clone HID tag with ID %x%08x", hi, lo); hi2 = 0; c.d.asBytes[0] = 0; } @@ -492,33 +492,28 @@ int CmdHIDBrute(const char *Cmd){ memset(bits, 0, sizeof(bits)); uint8_t cmdp = 0; - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': - case 'H': return usage_lf_hid_brute(); case 'f': - case 'F': fc = param_get32ex(Cmd ,cmdp+1, 0, 10); if ( !fc ) errors = true; cmdp += 2; break; case 'd': - case 'D': // delay between attemps, defaults to 1000ms. delay = param_get32ex(Cmd, cmdp+1, 1000, 10); cmdp += 2; break; case 'c': - case 'C': cn = param_get32ex(Cmd, cmdp+1, 0, 10); // truncate cardnumber. cn &= 0xFFFF; cmdp += 2; break; case 'a': - case 'A': fmtlen = param_get8(Cmd, cmdp+1); cmdp += 2; bool is_ftm_ok = false; @@ -532,7 +527,6 @@ int CmdHIDBrute(const char *Cmd){ errors = !is_ftm_ok; break; case 'v': - case 'V': verbose = true; cmdp++; break; @@ -545,8 +539,8 @@ int CmdHIDBrute(const char *Cmd){ if ( fc == 0 ) errors = true; if ( errors ) return usage_lf_hid_brute(); - PrintAndLogEx(NORMAL, "Brute-forcing HID reader"); - PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or run another command"); + PrintAndLogEx(INFO, "Brute-forcing HID reader"); + PrintAndLogEx(INFO, "Press pm3-button to abort simulation or run another command"); uint16_t up = cn; uint16_t down = cn; diff --git a/client/cmdlfindala.c b/client/cmdlfindala.c index dd262e0dc..1707895b0 100644 --- a/client/cmdlfindala.c +++ b/client/cmdlfindala.c @@ -136,7 +136,7 @@ int CmdIndalaDemod(const char *Cmd) { idx = indala224decode(DemodBuffer, &size, &invert); if (idx < 0 || size != 224) { PrintAndLogEx(DEBUG, "DEBUG: Error - Indala wrong size, expected [64|224] got: %d (startindex %i)", size, idx); - return -1; + return 0; } } @@ -231,8 +231,8 @@ int CmdIndalaDemodAlt(const char *Cmd) { } if (rawbit > 0){ - PrintAndLogEx(NORMAL, "Recovered %d raw bits, expected: %d", rawbit, GraphTraceLen/32); - PrintAndLogEx(NORMAL, "worst metric (0=best..7=worst): %d at pos %d", worst, worstPos); + PrintAndLogEx(INFO, "Recovered %d raw bits, expected: %d", rawbit, GraphTraceLen/32); + PrintAndLogEx(INFO, "worst metric (0=best..7=worst): %d at pos %d", worst, worstPos); } else { return 0; } @@ -262,7 +262,7 @@ int CmdIndalaDemodAlt(const char *Cmd) { } if (start == rawbit - uidlen + 1) { - PrintAndLogEx(NORMAL, "nothing to wait for"); + PrintAndLogEx(FAILED, "nothing to wait for"); return 0; } @@ -288,7 +288,7 @@ int CmdIndalaDemodAlt(const char *Cmd) { showbits[bit] = '.' + bits[bit]; } showbits[bit+1]='\0'; - PrintAndLogEx(NORMAL, "Partial UID=%s", showbits); + PrintAndLogEx(SUCCESS, "Partial UID | %s", showbits); return 0; } else { for (bit = 0; bit < uidlen; bit++) { @@ -313,7 +313,7 @@ int CmdIndalaDemodAlt(const char *Cmd) { uid2 = (uid2<<1) | 1; } } - PrintAndLogEx(NORMAL, "UID=%s (%x%08x)", showbits, uid1, uid2); + PrintAndLogEx(SUCCESS, "UID | %s (%x%08x)", showbits, uid1, uid2); } else { uid3 = uid4 = uid5 = uid6 = uid7 = 0; @@ -331,7 +331,7 @@ int CmdIndalaDemodAlt(const char *Cmd) { else uid7 = (uid7<<1) | 1; } - PrintAndLogEx(NORMAL, "UID=%s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7); + PrintAndLogEx(SUCCESS, "UID | %s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7); } // Checking UID against next occurrences @@ -350,7 +350,7 @@ int CmdIndalaDemodAlt(const char *Cmd) { times += 1; } - PrintAndLogEx(NORMAL, "Occurrences: %d (expected %d)", times, (rawbit - start) / uidlen); + PrintAndLogEx(DEBUG, "Occurrences: %d (expected %d)", times, (rawbit - start) / uidlen); // Remodulating for tag cloning // HACK: 2015-01-04 this will have an impact on our new way of seening lf commands (demod) @@ -377,8 +377,8 @@ int CmdIndalaDemodAlt(const char *Cmd) { int CmdIndalaSim(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_indala_sim(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_indala_sim(); uint8_t bits[224]; size_t size = sizeof(bits); @@ -392,9 +392,9 @@ int CmdIndalaSim(const char *Cmd) { return usage_lf_indala_sim(); // convert to binarray - uint8_t counter = 224; - for (uint8_t i=0; i< len; i++) { - for(uint8_t j=0; j<8; j++) { + uint8_t counter = 223; + for (uint8_t i = 0; i < len; i++) { + for(uint8_t j = 0; j < 8; j++) { bits[counter--] = hexuid[i] & 1; hexuid[i] >>= 1; } @@ -409,8 +409,8 @@ int CmdIndalaSim(const char *Cmd) { // It has to send either 64bits (8bytes) or 224bits (28bytes). Zero padding needed if not. // lf simpsk 1 c 32 r 2 d 0102030405060708 -// PrintAndLogEx(NORMAL, "Emulating Indala UID: %u \n", cn); -// PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or run another command"); + PrintAndLogEx(SUCCESS, "Simulating Indala UID: %s", sprint_hex(hexuid, len)); + PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command"); UsbCommand c = {CMD_PSK_SIM_TAG, {arg1, arg2, size}}; memcpy(c.d.asBytes, bits, size); @@ -427,6 +427,7 @@ int CmdIndalaClone(const char *Cmd) { uint32_t n = 0, i = 0; if (strchr(Cmd,'l') != 0) { + while (sscanf(&Cmd[i++], "%1x", &n ) == 1) { uid1 = (uid1 << 4) | (uid2 >> 28); uid2 = (uid2 << 4) | (uid3 >> 28); @@ -436,7 +437,8 @@ int CmdIndalaClone(const char *Cmd) { uid6 = (uid6 << 4) | (uid7 >> 28); uid7 = (uid7 << 4) | (n & 0xf); } - PrintAndLogEx(NORMAL, "Cloning 224bit tag with UID %x%08x%08x%08x%08x%08x%08x", uid1, uid2, uid3, uid4, uid5, uid6, uid7); + + PrintAndLogEx(INFO, "Preparing to clone Indala 224bit tag with UID %x%08x%08x%08x%08x%08x%08x", uid1, uid2, uid3, uid4, uid5, uid6, uid7); c.cmd = CMD_INDALA_CLONE_TAG_L; c.d.asDwords[0] = uid1; c.d.asDwords[1] = uid2; @@ -450,7 +452,7 @@ int CmdIndalaClone(const char *Cmd) { uid1 = (uid1 << 4) | (uid2 >> 28); uid2 = (uid2 << 4) | (n & 0xf); } - PrintAndLogEx(NORMAL, "Cloning 64bit tag with UID %x%08x", uid1, uid2); + PrintAndLogEx(INFO, "Preparing to clone Indala 64bit tag with UID %x%08x", uid1, uid2); c.cmd = CMD_INDALA_CLONE_TAG; c.arg[0] = uid1; c.arg[1] = uid2; diff --git a/client/cmdlfio.c b/client/cmdlfio.c index d2cecec4b..61fe9d00d 100644 --- a/client/cmdlfio.c +++ b/client/cmdlfio.c @@ -86,15 +86,15 @@ int CmdIOProxDemod(const char *Cmd) { uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0}; size_t size = getFromGraphBuf(bits); if (size < 65) { - if (g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox not enough samples in GraphBuffer"); + PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox not enough samples in GraphBuffer"); return 0; } //get binary from fsk wave int waveIdx = 0; idx = detectIOProx(bits, &size, &waveIdx); - if (idx < 0){ - if (g_debugMode){ - if (idx == -1){ + if (idx < 0) { + if (g_debugMode) { + if (idx == -1) { PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox not enough samples"); } else if (idx == -2) { PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox just noise detected"); @@ -115,10 +115,10 @@ int CmdIOProxDemod(const char *Cmd) { setDemodBuf(bits, size, idx); setClockGrid(64, waveIdx + (idx*64)); - if (idx==0){ - if (g_debugMode){ + if (idx == 0) { + if (g_debugMode) { PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox data not found - FSK Bits: %d", size); - if (size > 92) PrintAndLogEx(NORMAL, "%s", sprint_bin_break(bits, 92, 16)); + if (size > 92) PrintAndLogEx(DEBUG, "%s", sprint_bin_break(bits, 92, 16)); } return retval; } @@ -132,15 +132,13 @@ int CmdIOProxDemod(const char *Cmd) { // //XSF(version)facility:codeone+codetwo (raw) - if (g_debugMode) { - PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d", bits[idx], bits[idx+1], bits[idx+2], bits[idx+3], bits[idx+4], bits[idx+5], bits[idx+6], bits[idx+7], bits[idx+8]); - PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d", bits[idx+9], bits[idx+10], bits[idx+11],bits[idx+12],bits[idx+13],bits[idx+14],bits[idx+15],bits[idx+16],bits[idx+17]); - PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d facility", bits[idx+18], bits[idx+19], bits[idx+20],bits[idx+21],bits[idx+22],bits[idx+23],bits[idx+24],bits[idx+25],bits[idx+26]); - PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d version", bits[idx+27], bits[idx+28], bits[idx+29],bits[idx+30],bits[idx+31],bits[idx+32],bits[idx+33],bits[idx+34],bits[idx+35]); - PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d code1", bits[idx+36], bits[idx+37], bits[idx+38],bits[idx+39],bits[idx+40],bits[idx+41],bits[idx+42],bits[idx+43],bits[idx+44]); - PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d code2", bits[idx+45], bits[idx+46], bits[idx+47],bits[idx+48],bits[idx+49],bits[idx+50],bits[idx+51],bits[idx+52],bits[idx+53]); - PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d%d checksum", bits[idx+54],bits[idx+55],bits[idx+56],bits[idx+57],bits[idx+58],bits[idx+59],bits[idx+60],bits[idx+61],bits[idx+62],bits[idx+63]); - } + PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d", bits[idx], bits[idx+1], bits[idx+2], bits[idx+3], bits[idx+4], bits[idx+5], bits[idx+6], bits[idx+7], bits[idx+8]); + PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d", bits[idx+9], bits[idx+10], bits[idx+11],bits[idx+12],bits[idx+13],bits[idx+14],bits[idx+15],bits[idx+16],bits[idx+17]); + PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d facility", bits[idx+18], bits[idx+19], bits[idx+20],bits[idx+21],bits[idx+22],bits[idx+23],bits[idx+24],bits[idx+25],bits[idx+26]); + PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d version", bits[idx+27], bits[idx+28], bits[idx+29],bits[idx+30],bits[idx+31],bits[idx+32],bits[idx+33],bits[idx+34],bits[idx+35]); + PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d code1", bits[idx+36], bits[idx+37], bits[idx+38],bits[idx+39],bits[idx+40],bits[idx+41],bits[idx+42],bits[idx+43],bits[idx+44]); + PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d code2", bits[idx+45], bits[idx+46], bits[idx+47],bits[idx+48],bits[idx+49],bits[idx+50],bits[idx+51],bits[idx+52],bits[idx+53]); + PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d%d checksum", bits[idx+54],bits[idx+55],bits[idx+56],bits[idx+57],bits[idx+58],bits[idx+59],bits[idx+60],bits[idx+61],bits[idx+62],bits[idx+63]); uint32_t code = bytebits_to_byte(bits+idx,32); uint32_t code2 = bytebits_to_byte(bits+idx+32,32); @@ -163,13 +161,13 @@ int CmdIOProxDemod(const char *Cmd) { snprintf(crcStr, 3, "ok"); retval = 1; } else { - if (g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox crc failed"); + PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox crc failed"); snprintf(crcStr, sizeof(crcStr), "failed 0x%02X != 0x%02X", crc, calccrc); retval = 0; } - PrintAndLogEx(NORMAL, "IO Prox XSF(%02d)%02x:%05d (%08x%08x) [crc %s]", version, facilitycode, number, code, code2, crcStr); + PrintAndLogEx(SUCCESS, "IO Prox XSF(%02d)%02x:%05d (%08x%08x) [crc %s]", version, facilitycode, number, code, code2, crcStr); if (g_debugMode){ PrintAndLogEx(DEBUG, "DEBUG: IO prox idx: %d, Len: %d, Printing demod buffer:", idx, size); @@ -241,7 +239,7 @@ int getIOProxBits(uint8_t version, uint8_t fc, uint16_t cn, uint8_t *bits) { memcpy(bits, pre, sizeof(pre)); - PrintAndLogEx(NORMAL, "IO raw bits:\n %s \n", sprint_bin(bits, 64)); + PrintAndLogEx(SUCCESS, "IO raw bits:\n %s \n", sprint_bin(bits, 64)); return 1; } @@ -252,8 +250,8 @@ int CmdIOProxSim(const char *Cmd) { size_t size = sizeof(bits); memset(bits, 0x00, size); - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_io_sim(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_io_sim(); version = param_get8(Cmd, 0); fc = param_get8(Cmd, 1); @@ -263,7 +261,7 @@ int CmdIOProxSim(const char *Cmd) { if ((cn & 0xFFFF) != cn) { cn &= 0xFFFF; - PrintAndLogEx(NORMAL, "Card Number Truncated to 16-bits (IOProx): %u", cn); + PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (IOProx): %u", cn); } // clock 64, FSK2a fcHIGH 10 | fcLOW 8 @@ -272,8 +270,8 @@ int CmdIOProxSim(const char *Cmd) { arg1 = high << 8 | low; arg2 = invert << 8 | clk; - PrintAndLogEx(NORMAL, "Emulating IOProx Version: %u FC: %u; CN: %u\n", version, fc, cn); - PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or run another command"); + PrintAndLogEx(SUCCESS, "Simulating IOProx version: %u FC: %u; CN: %u\n", version, fc, cn); + PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command"); if ( !getIOProxBits(version, fc, cn, bits)) { PrintAndLogEx(WARNING, "Error with tag bitstream generation."); @@ -309,7 +307,7 @@ int CmdIOProxClone(const char *Cmd) { if ((cn & 0xFFFF) != cn) { cn &= 0xFFFF; - PrintAndLogEx(NORMAL, "Card Number Truncated to 16-bits (IOProx): %u", cn); + PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (IOProx): %u", cn); } if ( !getIOProxBits(version, fc, cn, bits)) { @@ -323,7 +321,7 @@ int CmdIOProxClone(const char *Cmd) { blocks[1] = bytebits_to_byte(bits, 32); blocks[2] = bytebits_to_byte(bits + 32, 32); - PrintAndLogEx(NORMAL, "Preparing to clone IOProx to T55x7 with Version: %u FC: %u, CN: %u", version, fc, cn); + PrintAndLogEx(INFO, "Preparing to clone IOProx to T55x7 with Version: %u FC: %u, CN: %u", version, fc, cn); print_blocks(blocks, 3); //UsbCommand c = {CMD_T55XX_WRITE_BLOCK, {0,0,0}}; diff --git a/client/cmdlfjablotron.c b/client/cmdlfjablotron.c index 39cbc0651..541e7b31b 100644 --- a/client/cmdlfjablotron.c +++ b/client/cmdlfjablotron.c @@ -130,14 +130,14 @@ int CmdJablotronDemod(const char *Cmd) { PrintAndLogEx(SUCCESS, "Jablotron Tag Found: Card ID: %"PRIx64" :: Raw: %08X%08X", id, raw1, raw2); uint8_t chksum = raw2 & 0xFF; - PrintAndLogEx(NORMAL, "Checksum: %02X [%s]", + PrintAndLogEx(INFO, "Checksum: %02X [%s]", chksum, - (chksum == jablontron_chksum(DemodBuffer)) ? "OK":"FAIL" + (chksum == jablontron_chksum(DemodBuffer)) ? _GREEN_(OK) : _RED_(FAIL) ); id = DEC2BCD(id); // Printed format: 1410-nn-nnnn-nnnn - PrintAndLogEx(NORMAL, "Printed: 1410-%02X-%04X-%04X", + PrintAndLogEx(SUCCESS, "Printed: 1410-%02X-%04X-%04X", (uint8_t)(id >> 32) & 0xFF, (uint16_t)(id >> 16) & 0xFFFF, (uint16_t)id & 0xFFFF @@ -158,8 +158,8 @@ int CmdJablotronClone(const char *Cmd) { uint8_t bits[64]; memset(bits, 0, sizeof(bits)); - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_jablotron_clone(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_jablotron_clone(); fullcode = param_get64ex(Cmd, 0, 0, 16); @@ -170,7 +170,7 @@ int CmdJablotronClone(const char *Cmd) { // clearing the topbit needed for the preambl detection. if ((fullcode & 0x7FFFFFFFFF) != fullcode) { fullcode &= 0x7FFFFFFFFF; - PrintAndLogEx(NORMAL, "Card Number Truncated to 39bits: %"PRIx64, fullcode); + PrintAndLogEx(INFO, "Card Number Truncated to 39bits: %"PRIx64, fullcode); } if ( !getJablotronBits(fullcode, bits)) { @@ -181,13 +181,13 @@ int CmdJablotronClone(const char *Cmd) { blocks[1] = bytebits_to_byte(bits, 32); blocks[2] = bytebits_to_byte(bits + 32, 32); - PrintAndLogEx(NORMAL, "Preparing to clone Jablotron to T55x7 with FullCode: %"PRIx64, fullcode); + PrintAndLogEx(INFO, "Preparing to clone Jablotron to T55x7 with FullCode: %"PRIx64, fullcode); print_blocks(blocks, 3); UsbCommand resp; UsbCommand c = {CMD_T55XX_WRITE_BLOCK, {0,0,0}}; - for (uint8_t i=0; i<4; i++) { + for (uint8_t i=0; i<3; i++) { c.arg[0] = blocks[i]; c.arg[1] = i; clearCommandBuffer(); @@ -203,15 +203,15 @@ int CmdJablotronClone(const char *Cmd) { int CmdJablotronSim(const char *Cmd) { uint64_t fullcode = 0; - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_jablotron_sim(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_jablotron_sim(); fullcode = param_get64ex(Cmd, 0, 0, 16); // clearing the topbit needed for the preambl detection. if ((fullcode & 0x7FFFFFFFFF) != fullcode) { fullcode &= 0x7FFFFFFFFF; - PrintAndLogEx(NORMAL, "Card Number Truncated to 39bits: %"PRIx64, fullcode); + PrintAndLogEx(INFO, "Card Number Truncated to 39bits: %"PRIx64, fullcode); } uint8_t clk = 64, encoding = 2, separator = 0, invert = 1; @@ -220,7 +220,7 @@ int CmdJablotronSim(const char *Cmd) { arg1 = clk << 8 | encoding; arg2 = invert << 8 | separator; - PrintAndLogEx(NORMAL, "Simulating Jablotron - FullCode: %"PRIx64, fullcode); + PrintAndLogEx(SUCCESS, "Simulating Jablotron - FullCode: %"PRIx64, fullcode); UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; getJablotronBits(fullcode, c.d.asBytes); diff --git a/client/cmdlfkeri.c b/client/cmdlfkeri.c new file mode 100644 index 000000000..560cd5c96 --- /dev/null +++ b/client/cmdlfkeri.c @@ -0,0 +1,243 @@ +//----------------------------------------------------------------------------- +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency KERI tag commands +// PSK1, RF/128, RF/2, 64 bits long +//----------------------------------------------------------------------------- +#include "cmdlfkeri.h" + +static int CmdHelp(const char *Cmd); + +int usage_lf_keri_clone(void){ + PrintAndLogEx(NORMAL, "clone a KERI tag to a T55x7 tag."); + PrintAndLogEx(NORMAL, "Usage: lf keri clone [h] "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h : This help"); + PrintAndLogEx(NORMAL, " : Keri Internal ID"); + PrintAndLogEx(NORMAL, " : specify write to Q5 (t5555 instead of t55x7)"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " lf keri clone 112233"); + return 0; +} + +int usage_lf_keri_sim(void) { + PrintAndLogEx(NORMAL, "Enables simulation of KERI card with specified card number."); + PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf keri sim [h] "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h : This help"); + PrintAndLogEx(NORMAL, " : Keri Internal ID"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " lf keri sim 112233"); + return 0; +} + +// find KERI preamble in already demoded data +int detectKeri(uint8_t *dest, size_t *size, bool *invert) { + + uint8_t preamble[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; + uint8_t preamble_i[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0}; + + // sanity check. + if ( *size < sizeof(preamble) + 100) return -1; + + size_t startIdx = 0; + + if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) { + + // if didn't find preamble try again inverting + if (!preambleSearch(DemodBuffer, preamble_i, sizeof(preamble_i), size, &startIdx)) + return -2; + + *invert ^= 1; + } + + if (*size != 64) return -3; //wrong demoded size + + return (int)startIdx; +} + +int CmdKeriDemod(const char *Cmd) { + + if (!PSKDemod("", false)) { + PrintAndLogEx(DEBUG, "DEBUG: Error - KERI: PSK1 Demod failed"); + return 0; + } + bool invert = false; + size_t size = DemodBufferLen; + int idx = detectKeri(DemodBuffer, &size, &invert); + if (idx < 0) { + if (idx == -1) + PrintAndLogEx(DEBUG, "DEBUG: Error - KERI: too few bits found"); + else if (idx == -2) + PrintAndLogEx(DEBUG, "DEBUG: Error - KERI: preamble not found"); + else if (idx == -3) + PrintAndLogEx(DEBUG, "DEBUG: Error - KERI: Size not correct: 64 != %d", size); + else + PrintAndLogEx(DEBUG, "DEBUG: Error - KERI: ans: %d", idx); + + return 0; + } + setDemodBuf(DemodBuffer, size, idx); + setClockGrid(g_DemodClock, g_DemodStartIdx + (idx * g_DemodClock)); + + //got a good demod + uint32_t raw1 = bytebits_to_byte(DemodBuffer , 32); + uint32_t raw2 = bytebits_to_byte(DemodBuffer+32, 32); + + //get internal id + uint32_t ID = bytebits_to_byte(DemodBuffer+29, 32); + ID &= 0x7FFFFFFF; + + /* + 000000000000000000000000000001XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX111 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^1###############################^^^ + Preamble block 29 bits of ZEROS + 32 bit Internal ID (First bit always 1) + 3 bit of 1s in the end + + How this is decoded to Facility ID, Card number is unknown + Facility ID = 0-31 (indicates 5 bits) + Card number = up to 10 digits + + Might be a hash of FC & CN to generate Internal ID + */ + + PrintAndLogEx(SUCCESS, "KERI Tag Found -- Internal ID: %u", ID); + PrintAndLogEx(SUCCESS, "Raw: %08X%08X", raw1 ,raw2); + + if (invert){ + PrintAndLogEx(INFO, "Had to Invert - probably KERI"); + for (size_t i = 0; i < size; i++) + DemodBuffer[i] ^= 1; + + CmdPrintDemodBuff("x"); + } + return 1; +} + +int CmdKeriRead(const char *Cmd) { + lf_read(true, 10000); + return CmdKeriDemod(Cmd); +} + +int CmdKeriClone(const char *Cmd) { + + uint32_t internalid = 0; + uint32_t blocks[3] = { + T55x7_TESTMODE_DISABLED | + T55x7_X_MODE | + T55x7_MODULATION_PSK1 | + T55x7_PSKCF_RF_2 | + 2 << T55x7_MAXBLOCK_SHIFT, + 0, + 0}; + + // dynamic bitrate used + blocks[0] |= 0xF << 18; + + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_keri_clone(); + + internalid = param_get32ex(Cmd, 0, 0, 10); + + //Q5 + if (tolower(param_getchar(Cmd, 1)) == 'q') { + blocks[0] = + T5555_MODULATION_PSK1 | + T5555_SET_BITRATE(128) | + T5555_PSK_RF_2 | + 2 << T5555_MAXBLOCK_SHIFT; + } + + + // MSB is ONE + internalid |= 0x80000000; + + // 3 LSB is ONE + uint64_t data = ((uint64_t)internalid << 3 ) + 7; + + // + blocks[1] = data >> 32; + blocks[2] = data & 0xFFFFFFFF; + + PrintAndLogEx(INFO, "Preparing to clone KERI to T55x7 with Internal Id: %u", internalid); + print_blocks(blocks, 3); + + + UsbCommand resp; + UsbCommand c = {CMD_T55XX_WRITE_BLOCK, {0,0,0}}; + + + for (uint8_t i = 0; i < 3; i++) { + c.arg[0] = blocks[i]; + c.arg[1] = i; + clearCommandBuffer(); + SendCommand(&c); + if (!WaitForResponseTimeout(CMD_ACK, &resp, T55XX_WRITE_TIMEOUT)){ + PrintAndLogEx(WARNING, "Error occurred, device did not respond during write operation."); + return -1; + } + } + + return 0; +} + +int CmdKeriSim(const char *Cmd) { + + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_keri_sim(); + + uint64_t internalid = param_get32ex(Cmd, 0, 0, 10); + internalid |= 0x80000000; + internalid <<= 3; + internalid += 7; + + uint8_t bits[64] = {0x00}; + // loop to bits + uint8_t j = 0; + for ( int8_t i = 63; i >= 0; --i) { + bits[j++] = ((internalid >> i) & 1 ); + } + + uint8_t clk = 32, carrier = 2, invert = 0; + uint16_t arg1, arg2; + size_t size = 64; + arg1 = clk << 8 | carrier; + arg2 = invert; + + PrintAndLogEx(SUCCESS, "Simulating KERI - Internal Id: %u", internalid); + + UsbCommand c = {CMD_PSK_SIM_TAG, {arg1, arg2, size}}; + memcpy(c.d.asBytes, bits, size); + clearCommandBuffer(); + SendCommand(&c); + + return 0; +} + +static command_t CommandTable[] = { + {"help", CmdHelp, 1, "This help"}, + {"demod", CmdKeriDemod, 1, "Demodulate an KERI tag from the GraphBuffer"}, + {"read", CmdKeriRead, 0, "Attempt to read and extract tag data from the antenna"}, + {"clone", CmdKeriClone, 0, "clone KERI to T55x7"}, + {"sim", CmdKeriSim, 0, "simulate KERI tag"}, + {NULL, NULL, 0, NULL} +}; + +int CmdLFKeri(const char *Cmd) { + clearCommandBuffer(); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdlfkeri.h b/client/cmdlfkeri.h new file mode 100644 index 000000000..ed0629b37 --- /dev/null +++ b/client/cmdlfkeri.h @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency Stanley/PAC tag commands +//----------------------------------------------------------------------------- +#ifndef CMDLFKERI_H__ +#define CMDLFKERI_H__ + +#include +#include +#include "proxmark3.h" +#include "ui.h" +#include "util.h" +#include "graph.h" +#include "cmdparser.h" +#include "cmddata.h" +#include "cmdmain.h" +#include "cmdlf.h" +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // preamble test + +extern int CmdLFKeri(const char *Cmd); +extern int CmdKeriRead(const char *Cmd); +extern int CmdKeriDemod(const char *Cmd); +extern int CmdKeriClone(const char *Cmd); +extern int CmdKeriSim(const char *Cmd); + +extern int detectKeri(uint8_t *dest, size_t *size, bool *invert); + +extern int usage_lf_keri_clone(void); +extern int usage_lf_keri_sim(void); +#endif + diff --git a/client/cmdlfnedap.c b/client/cmdlfnedap.c index 19e83d3cc..25f9b624b 100644 --- a/client/cmdlfnedap.c +++ b/client/cmdlfnedap.c @@ -194,15 +194,15 @@ int CmdLFNedapDemod(const char *Cmd) { chksum2 = bytebits_to_byte(DemodBuffer+110, 8); chksum2 |= bytebits_to_byte(DemodBuffer+119, 8) << 8; - PrintAndLogEx(NORMAL, "NEDAP ID Found - Raw: %08x%08x%08x%08x", raw[3], raw[2], raw[1], raw[0]); - PrintAndLogEx(NORMAL, " - UID: %06X", uid); - PrintAndLogEx(NORMAL, " - i: %04X", two); - PrintAndLogEx(NORMAL, " - Checksum2 %04X", chksum2); + PrintAndLogEx(SUCCESS, "NEDAP ID Found - Raw: %08x%08x%08x%08x", raw[3], raw[2], raw[1], raw[0]); + PrintAndLogEx(SUCCESS, " - UID: %06X", uid); + PrintAndLogEx(SUCCESS, " - i: %04X", two); + PrintAndLogEx(SUCCESS, " - Checksum2 %04X", chksum2); if (g_debugMode){ PrintAndLogEx(DEBUG, "DEBUG: idx: %d, Len: %d, Printing Demod Buffer:", idx, 128); printDemodBuff(); - PrintAndLogEx(NORMAL, "BIN:\n%s", sprint_bin_break( DemodBuffer, 128, 64) ); + PrintAndLogEx(DEBUG, "BIN:\n%s", sprint_bin_break( DemodBuffer, 128, 64) ); } return 1; @@ -268,7 +268,7 @@ int CmdLFNedapClone(const char *Cmd) { blocks[3] = bytebits_to_byte(bits + 64, 32); blocks[4] = bytebits_to_byte(bits + 96, 32); - PrintAndLogEx(NORMAL, "Preparing to clone NEDAP to T55x7 with card number: %u", cardnumber); + PrintAndLogEx(INFO, "Preparing to clone NEDAP to T55x7 with card number: %u", cardnumber); print_blocks(blocks, 5); UsbCommand resp; @@ -314,8 +314,8 @@ int CmdLFNedapSim(const char *Cmd) { return 1; } - PrintAndLogEx(NORMAL, "bin %s", sprint_bin_break(bs, 128, 32)); - PrintAndLogEx(NORMAL, "Simulating Nedap - CardNumber: %u", cardnumber ); + PrintAndLogEx(SUCCESS, "bin %s", sprint_bin_break(bs, 128, 32)); + PrintAndLogEx(SUCCESS, "Simulating Nedap - CardNumber: %u", cardnumber ); UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; memcpy(c.d.asBytes, bs, size); @@ -332,7 +332,7 @@ int CmdLFNedapChk(const char *Cmd){ len = ( len == 0 ) ? 5 : len>>1; - PrintAndLogEx(NORMAL, "Input: [%d] %s", len, sprint_hex(data, len)); + PrintAndLogEx(SUCCESS, "Input: [%d] %s", len, sprint_hex(data, len)); //uint8_t last = GetParity(data, EVEN, 62); //PrintAndLogEx(NORMAL, "TEST PARITY:: %d | %d ", DemodBuffer[62], last); @@ -367,7 +367,7 @@ int CmdLFNedapChk(const char *Cmd){ } } - PrintAndLogEx(NORMAL, "Nedap checksum: 0x%X", ((ch << 8) | cl) ); + PrintAndLogEx(SUCCESS, "Nedap checksum: 0x%X", ((ch << 8) | cl) ); return 0; } diff --git a/client/cmdlfnexwatch.c b/client/cmdlfnexwatch.c index c90557665..4057fe452 100644 --- a/client/cmdlfnexwatch.c +++ b/client/cmdlfnexwatch.c @@ -34,14 +34,13 @@ int detectNexWatch(uint8_t *dest, size_t *size, bool *invert) { int CmdNexWatchDemod(const char *Cmd) { if (!PSKDemod("", false)) { - if (g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch can't demod signal"); + PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch can't demod signal"); return 0; } bool invert = false; size_t size = DemodBufferLen; int idx = detectNexWatch(DemodBuffer, &size, &invert); - if (idx <= 0){ - if (g_debugMode){ + if (idx <= 0) { if (idx == -1) PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch not enough samples"); // else if (idx == -2) @@ -54,7 +53,7 @@ int CmdNexWatchDemod(const char *Cmd) { // PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch size not correct: %d", size); else PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch error %d",idx); - } + return 0; } @@ -101,6 +100,7 @@ static command_t CommandTable[] = { }; int CmdLFNEXWATCH(const char *Cmd) { + clearCommandBuffer(); CmdsParse(CommandTable, Cmd); return 0; } diff --git a/client/cmdlfnoralsy.c b/client/cmdlfnoralsy.c index bb28ad5e5..0f61e26ea 100644 --- a/client/cmdlfnoralsy.c +++ b/client/cmdlfnoralsy.c @@ -161,10 +161,10 @@ int CmdNoralsyDemod(const char *Cmd) { return 0; } - PrintAndLogEx(NORMAL, "Noralsy Tag Found: Card ID %u, Year: %u Raw: %08X%08X%08X", cardid, year, raw1 ,raw2, raw3); + PrintAndLogEx(SUCCESS, "Noralsy Tag Found: Card ID %u, Year: %u Raw: %08X%08X%08X", cardid, year, raw1 ,raw2, raw3); if (raw1 != 0xBB0214FF) { - PrintAndLogEx(NORMAL, "Unknown bits set in first block! Expected 0xBB0214FF, Found: 0x%08X", raw1); - PrintAndLogEx(NORMAL, "Please post this output in forum to further research on this format"); + PrintAndLogEx(WARNING, "Unknown bits set in first block! Expected 0xBB0214FF, Found: 0x%08X", raw1); + PrintAndLogEx(WARNING, "Please post this output in forum to further research on this format"); } return 1; } @@ -202,7 +202,7 @@ int CmdNoralsyClone(const char *Cmd) { blocks[2] = bytebits_to_byte(bits + 32, 32); blocks[3] = bytebits_to_byte(bits + 64, 32); - PrintAndLogEx(NORMAL, "Preparing to clone Noralsy to T55x7 with CardId: %u", id); + PrintAndLogEx(INFO, "Preparing to clone Noralsy to T55x7 with CardId: %u", id); print_blocks(blocks, 4); UsbCommand resp; @@ -247,7 +247,7 @@ int CmdNoralsySim(const char *Cmd) { return 1; } - PrintAndLogEx(NORMAL, "Simulating Noralsy - CardId: %u", id); + PrintAndLogEx(SUCCESS, "Simulating Noralsy - CardId: %u", id); UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; memcpy(c.d.asBytes, bs, size); diff --git a/client/cmdlfpresco.c b/client/cmdlfpresco.c index 9c8037457..98df02fe5 100644 --- a/client/cmdlfpresco.c +++ b/client/cmdlfpresco.c @@ -12,11 +12,11 @@ static int CmdHelp(const char *Cmd); int usage_lf_presco_clone(void){ PrintAndLogEx(NORMAL, "clone a Presco tag to a T55x7 tag."); - PrintAndLogEx(NORMAL, "Usage: lf presco clone [h] d H "); + PrintAndLogEx(NORMAL, "Usage: lf presco clone [h] d c "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " d : 9 digit presco card ID"); - PrintAndLogEx(NORMAL, " H : 8 digit hex card number"); + PrintAndLogEx(NORMAL, " c : 8 digit hex card number"); PrintAndLogEx(NORMAL, " : specify write to Q5 (t5555 instead of t55x7)"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); @@ -29,11 +29,11 @@ int usage_lf_presco_sim(void) { PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); PrintAndLogEx(NORMAL, "Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated."); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf presco sim [h] d or H "); + PrintAndLogEx(NORMAL, "Usage: lf presco sim [h] d or c "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " d : 9 digit presco card number"); - PrintAndLogEx(NORMAL, " H : 8 digit hex card number"); + PrintAndLogEx(NORMAL, " c : 8 digit hex card number"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf presco sim d 123456789"); @@ -62,24 +62,22 @@ int GetWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode int stringlen = 0; memset(id, 0x00, sizeof(id)); - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return -1; - case 'H': + case 'c': hex = true; //get hex *fullcode = param_get32ex(Cmd, cmdp+1, 0, 16); cmdp+=2; break; - case 'D': case 'd': //param get string int param_getstr(const char *line, int paramnum, char * str) stringlen = param_getstr(Cmd, cmdp+1, id, sizeof(id)); if (stringlen < 2) return -1; cmdp += 2; break; - case 'Q': case 'q': *Q5 = true; cmdp++; @@ -136,7 +134,6 @@ int CmdPrescoDemod(const char *Cmd) { size_t size = DemodBufferLen; int ans = detectPresco(DemodBuffer, &size); if (ans < 0) { - if (ans == -1) PrintAndLogEx(DEBUG, "DEBUG: Error - Presco: too few bits found"); else if (ans == -2) @@ -163,7 +160,7 @@ int CmdPrescoDemod(const char *Cmd) { char cmd[12] = {0}; sprintf(cmd, "H %08X", cardid); GetWiegandFromPresco(cmd, &sitecode, &usercode, &fullcode, &Q5); - PrintAndLogEx(NORMAL, "SiteCode %u, UserCode %u, FullCode, %08X", sitecode, usercode, fullcode); + PrintAndLogEx(SUCCESS, "SiteCode %u, UserCode %u, FullCode, %08X", sitecode, usercode, fullcode); return 1; } @@ -190,12 +187,12 @@ int CmdPrescoClone(const char *Cmd) { if ((sitecode & 0xFF) != sitecode) { sitecode &= 0xFF; - PrintAndLogEx(NORMAL, "Facility-Code Truncated to 8-bits (Presco): %u", sitecode); + PrintAndLogEx(INFO, "Facility-Code Truncated to 8-bits (Presco): %u", sitecode); } if ((usercode & 0xFFFF) != usercode) { usercode &= 0xFFFF; - PrintAndLogEx(NORMAL, "Card Number Truncated to 16-bits (Presco): %u", usercode); + PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (Presco): %u", usercode); } blocks[1] = 0x10D00000; //preamble @@ -203,7 +200,7 @@ int CmdPrescoClone(const char *Cmd) { blocks[3] = 0x00000000; blocks[4] = fullcode; - PrintAndLogEx(NORMAL, "Preparing to clone Presco to T55x7 with SiteCode: %u, UserCode: %u, FullCode: %08x", sitecode, usercode, fullcode); + PrintAndLogEx(INFO, "Preparing to clone Presco to T55x7 with SiteCode: %u, UserCode: %u, FullCode: %08x", sitecode, usercode, fullcode); print_blocks(blocks, 5); UsbCommand resp; @@ -236,7 +233,7 @@ int CmdPrescoSim(const char *Cmd) { arg1 = clk << 8 | encoding; arg2 = invert << 8 | separator; - PrintAndLogEx(NORMAL, "Simulating Presco - SiteCode: %u, UserCode: %u, FullCode: %08X",sitecode, usercode, fullcode); + PrintAndLogEx(SUCCESS, "Simulating Presco - SiteCode: %u, UserCode: %u, FullCode: %08X",sitecode, usercode, fullcode); UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; GetPrescoBits(fullcode, c.d.asBytes); diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index 8e7dbd57f..1153fccc3 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -285,7 +285,7 @@ int CmdPyramidClone(const char *Cmd) { blocks[3] = bytebits_to_byte(bs + 64, 32); blocks[4] = bytebits_to_byte(bs + 96, 32); - PrintAndLogEx(NORMAL, "Preparing to clone Farpointe/Pyramid to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber); + PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber); print_blocks(blocks, 5); UsbCommand resp; @@ -331,7 +331,7 @@ int CmdPyramidSim(const char *Cmd) { return 1; } - PrintAndLogEx(NORMAL, "Simulating Farpointe/Pyramid - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber ); + PrintAndLogEx(SUCCESS, "Simulating Farpointe/Pyramid - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber ); UsbCommand c = {CMD_FSK_SIM_TAG, {arg1, arg2, size}}; memcpy(c.d.asBytes, bs, size); diff --git a/client/cmdlfsecurakey.c b/client/cmdlfsecurakey.c index 793c30fce..64e491d7f 100644 --- a/client/cmdlfsecurakey.c +++ b/client/cmdlfsecurakey.c @@ -97,12 +97,12 @@ int CmdSecurakeyDemod(const char *Cmd) { // test parities - evenparity32 looks to add an even parity returns 0 if already even... bool parity = !evenparity32(lWiegand) && !oddparity32(rWiegand); - PrintAndLogEx(NORMAL, "Securakey Tag Found--BitLen: %u, Card ID: %u, FC: 0x%X, Raw: %08X%08X%08X", bitLen, cardid, fc, raw1 ,raw2, raw3); + PrintAndLogEx(SUCCESS, "Securakey Tag Found--BitLen: %u, Card ID: %u, FC: 0x%X, Raw: %08X%08X%08X", bitLen, cardid, fc, raw1 ,raw2, raw3); if (bitLen <= 32) - PrintAndLogEx(NORMAL, "Wiegand: %08X, Parity: %s", (lWiegand<<(bitLen/2)) | rWiegand, parity ? "Passed" : "Failed"); - PrintAndLogEx(NORMAL, "\nHow the FC translates to printed FC is unknown"); - PrintAndLogEx(NORMAL, "How the checksum is calculated is unknown"); - PrintAndLogEx(NORMAL, "Help the community identify this format further\n by sharing your tag on the pm3 forum or with forum members"); + PrintAndLogEx(SUCCESS, "Wiegand: %08X, Parity: %s", (lWiegand<<(bitLen/2)) | rWiegand, parity ? "Passed" : "Failed"); + PrintAndLogEx(INFO, "\nHow the FC translates to printed FC is unknown"); + PrintAndLogEx(INFO, "How the checksum is calculated is unknown"); + PrintAndLogEx(INFO, "Help the community identify this format further\n by sharing your tag on the pm3 forum or with forum members"); return 1; } diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index ed8c0464e..3c7547e34 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -141,21 +141,33 @@ int usage_t55xx_wakup(){ PrintAndLogEx(NORMAL, " lf t55xx wakeup p 11223344 - send wakeup password"); return 0; } -int usage_t55xx_bruteforce(){ - PrintAndLogEx(NORMAL, "This command uses A) bruteforce to scan a number range"); - PrintAndLogEx(NORMAL, " B) a dictionary attack"); +int usage_t55xx_chk(){ + PrintAndLogEx(NORMAL, "This command uses a dictionary attack"); PrintAndLogEx(NORMAL, "press 'enter' to cancel the command"); - PrintAndLogEx(NORMAL, "Usage: lf t55xx bruteforce [h] [i <*.dic>]"); + PrintAndLogEx(NORMAL, "Usage: lf t55xx bruteforce [h] [i <*.dic>]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " m - use dictionary from flashmemory\n"); + PrintAndLogEx(NORMAL, " i <*.dic> - loads a default keys dictionary file <*.dic>"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " lf t55xx bruteforce m"); + PrintAndLogEx(NORMAL, " lf t55xx bruteforce i default_pwd.dic"); + PrintAndLogEx(NORMAL, ""); + return 0; +} +int usage_t55xx_bruteforce(){ + PrintAndLogEx(NORMAL, "This command uses bruteforce to scan a number range"); + PrintAndLogEx(NORMAL, "press 'enter' to cancel the command"); + PrintAndLogEx(NORMAL, "Usage: lf t55xx bruteforce [h] "); PrintAndLogEx(NORMAL, " password must be 4 bytes (8 hex symbols)"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " - 4 byte hex value to start pwd search at"); PrintAndLogEx(NORMAL, " - 4 byte hex value to end pwd search at"); - PrintAndLogEx(NORMAL, " i <*.dic> - loads a default keys dictionary file <*.dic>"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf t55xx bruteforce aaaaaaaa bbbbbbbb"); - PrintAndLogEx(NORMAL, " lf t55xx bruteforce i default_pwd.dic"); PrintAndLogEx(NORMAL, ""); return 0; } @@ -224,10 +236,9 @@ int CmdT55xxSetConfig(const char *Cmd) { uint8_t cmdp = 0; bool errors = false; while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - tmp = param_getchar(Cmd, cmdp); + tmp = tolower(param_getchar(Cmd, cmdp)); switch(tmp) { case 'h': - case 'H': return usage_t55xx_config(); case 'b': errors |= param_getdec(Cmd, cmdp+1, &bitRate); @@ -292,12 +303,10 @@ int CmdT55xxSetConfig(const char *Cmd) { config.offset = offset; cmdp+=2; break; - case 'Q': case 'q': config.Q5 = true; cmdp++; break; - case 'S': case 's': config.ST = true; cmdp++; @@ -343,8 +352,8 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32 if (!AquireData(page1, block, usepwd, password) ) return 0; if (!DecodeT55xxBlock()) return 0; - char blk[10]={0}; - sprintf(blk,"%02d", block); + char blk[10] = {0}; + sprintf(blk, "%02d", block); printT55xxBlock(blk); return 1; } @@ -358,22 +367,18 @@ int CmdT55xxReadBlock(const char *Cmd) { bool errors = false; uint8_t cmdp = 0; while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { + switch ( tolower(param_getchar(Cmd, cmdp))) { case 'h': - case 'H': return usage_t55xx_read(); case 'b': - case 'B': errors |= param_getdec(Cmd, cmdp+1, &block); cmdp += 2; break; case 'o': - case 'O': override = true; cmdp++; break; case 'p': - case 'P': password = param_get32ex(Cmd, cmdp+1, 0, 16); usepwd = true; cmdp += 2; @@ -686,7 +691,7 @@ bool tryDetectModulation(){ bool retval = false; if ( hits > 1) { - PrintAndLogEx(NORMAL, "Found [%d] possible matches for modulation.",hits); + PrintAndLogEx(SUCCESS, "Found [%d] possible matches for modulation.", hits); for(int i=0; i>28==6 || b.block0>>28==9))) ); - PrintAndLogEx(NORMAL, "Inverted : %s", (b.inverted) ? "Yes" : "No" ); + PrintAndLogEx(NORMAL, "Inverted : %s", (b.inverted) ? _GREEN_(Yes) : "No" ); PrintAndLogEx(NORMAL, "Offset : %d", b.offset); - PrintAndLogEx(NORMAL, "Seq. Term. : %s", (b.ST) ? "Yes" : "No" ); + PrintAndLogEx(NORMAL, "Seq. Term. : %s", (b.ST) ? _GREEN_(Yes) : "No" ); PrintAndLogEx(NORMAL, "Block0 : 0x%08X", b.block0); PrintAndLogEx(NORMAL, ""); return 0; @@ -949,13 +954,11 @@ int CmdT55xxWakeUp(const char *Cmd) { uint32_t password = 0; uint8_t cmdp = 0; bool errors = false; - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': - case 'H': return usage_t55xx_wakup(); case 'p': - case 'P': password = param_get32ex(Cmd, cmdp+1, 0, 16); cmdp += 2; errors = false; @@ -971,7 +974,7 @@ int CmdT55xxWakeUp(const char *Cmd) { UsbCommand c = {CMD_T55XX_WAKEUP, {password, 0, 0}}; clearCommandBuffer(); SendCommand(&c); - PrintAndLogEx(NORMAL, "Wake up command sent. Try read now"); + PrintAndLogEx(SUCCESS, "Wake up command sent. Try read now"); return 0; } @@ -985,30 +988,25 @@ int CmdT55xxWriteBlock(const char *Cmd) { bool testMode = false; bool errors = false; uint8_t cmdp = 0; - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': - case 'H': return usage_t55xx_write(); case 'b': - case 'B': errors |= param_getdec(Cmd, cmdp+1, &block); cmdp += 2; break; case 'd': - case 'D': data = param_get32ex(Cmd, cmdp+1, 0, 16); gotdata = true; cmdp += 2; break; case 'p': - case 'P': password = param_get32ex(Cmd, cmdp+1, 0, 16); usepwd = true; cmdp += 2; break; case 't': - case 'T': testMode = true; cmdp++; break; @@ -1025,7 +1023,7 @@ int CmdT55xxWriteBlock(const char *Cmd) { if (errors || !gotdata) return usage_t55xx_write(); if (block > 7) { - PrintAndLogEx(NORMAL, "Block number must be between 0 and 7"); + PrintAndLogEx(WARNING, "Block number must be between 0 and 7"); return 0; } @@ -1037,7 +1035,7 @@ int CmdT55xxWriteBlock(const char *Cmd) { char pwdStr[16] = {0}; snprintf(pwdStr, sizeof(pwdStr), "pwd: 0x%08X", password); - PrintAndLogEx(NORMAL, "Writing page %d block: %02d data: 0x%08X %s", page1, block, data, (usepwd) ? pwdStr : "" ); + PrintAndLogEx(INFO, "Writing page %d block: %02d data: 0x%08X %s", page1, block, data, (usepwd) ? pwdStr : "" ); //Password mode if (usepwd) { @@ -1054,12 +1052,13 @@ int CmdT55xxWriteBlock(const char *Cmd) { } int CmdT55xxReadTrace(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - bool pwdmode = false; - uint32_t password = 0; - if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') return usage_t55xx_trace(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) > 1 || cmdp == 'h') return usage_t55xx_trace(); - if (strlen(Cmd)==0) { + bool pwdmode = false; + uint32_t password = 0; + + if (strlen(Cmd) == 0) { // sanity check. if (!SanityOfflineCheck(false)) return 1; @@ -1086,7 +1085,7 @@ int CmdT55xxReadTrace(const char *Cmd) { uint32_t hdr = PackBits(si, 9, DemodBuffer); si += 9; if (hdr != 0x1FF) { - PrintAndLogEx(NORMAL, "Invalid Q5 Trace data header (expected 0x1FF, found %X)", hdr); + PrintAndLogEx(FAILED, "Invalid Q5 Trace data header (expected 0x1FF, found %X)", hdr); return 1; } @@ -1125,7 +1124,7 @@ int CmdT55xxReadTrace(const char *Cmd) { data.acl = PackBits(si, 8, DemodBuffer); si += 8; if ( data.acl != 0xE0 ) { - PrintAndLogEx(NORMAL, "The modulation is most likely wrong since the ACL is not 0xE0. "); + PrintAndLogEx(FAILED, "The modulation is most likely wrong since the ACL is not 0xE0. "); return 1; } @@ -1222,11 +1221,11 @@ int CmdT55xxInfo(const char *Cmd){ */ bool pwdmode = false; uint32_t password = 0; - char cmdp = param_getchar(Cmd, 0); + char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') return usage_t55xx_info(); + if (strlen(Cmd) > 1 || cmdp == 'h') return usage_t55xx_info(); - if (strlen(Cmd)==0){ + if (strlen(Cmd) == 0) { // sanity check. if (!SanityOfflineCheck(false)) return 1; @@ -1259,24 +1258,26 @@ int CmdT55xxInfo(const char *Cmd){ uint32_t inv = PackBits(si, 1, DemodBuffer); si += 1; uint32_t por = PackBits(si, 1, DemodBuffer); si += 1; - if (config.Q5) PrintAndLogEx(NORMAL, "*** Warning *** Config Info read off a Q5 will not display as expected"); + if (config.Q5) + PrintAndLogEx(NORMAL, _RED_(*** Warning ***) " Config Info read off a Q5 will not display as expected"); + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "-- T55x7 Configuration & Tag Information --------------------"); PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(NORMAL, " Safer key : %s", GetSaferStr(safer)); PrintAndLogEx(NORMAL, " reserved : %d", resv); PrintAndLogEx(NORMAL, " Data bit rate : %s", GetBitRateStr(dbr, extend)); - PrintAndLogEx(NORMAL, " eXtended mode : %s", (extend) ? "Yes - Warning":"No"); + PrintAndLogEx(NORMAL, " eXtended mode : %s", (extend) ? _YELLOW_(Yes - Warning) : "No"); PrintAndLogEx(NORMAL, " Modulation : %s", GetModulationStr(datamod)); PrintAndLogEx(NORMAL, " PSK clock frequency : %d", pskcf); - PrintAndLogEx(NORMAL, " AOR - Answer on Request : %s", (aor) ? "Yes":"No"); - PrintAndLogEx(NORMAL, " OTP - One Time Pad : %s", (otp) ? "Yes - Warning":"No" ); + PrintAndLogEx(NORMAL, " AOR - Answer on Request : %s", (aor) ? _GREEN_(Yes) : "No"); + PrintAndLogEx(NORMAL, " OTP - One Time Pad : %s", (otp) ? _YELLOW_(Yes - Warning) : "No" ); PrintAndLogEx(NORMAL, " Max block : %d", maxblk); - PrintAndLogEx(NORMAL, " Password mode : %s", (pwd) ? "Yes":"No"); - PrintAndLogEx(NORMAL, " Sequence Start Terminator : %s", (sst) ? "Yes":"No"); - PrintAndLogEx(NORMAL, " Fast Write : %s", (fw) ? "Yes":"No"); - PrintAndLogEx(NORMAL, " Inverse data : %s", (inv) ? "Yes":"No"); - PrintAndLogEx(NORMAL, " POR-Delay : %s", (por) ? "Yes":"No"); + PrintAndLogEx(NORMAL, " Password mode : %s", (pwd) ? _GREEN_(Yes) : "No"); + PrintAndLogEx(NORMAL, " Sequence Start Terminator : %s", (sst) ? _GREEN_(Yes) : "No"); + PrintAndLogEx(NORMAL, " Fast Write : %s", (fw) ? _GREEN_(Yes) : "No"); + PrintAndLogEx(NORMAL, " Inverse data : %s", (inv) ? _GREEN_(Yes) : "No"); + PrintAndLogEx(NORMAL, " POR-Delay : %s", (por) ? _GREEN_(Yes) : "No"); PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(NORMAL, " Raw Data - Page 0"); PrintAndLogEx(NORMAL, " Block 0 : 0x%08X %s", block0, sprint_bin(DemodBuffer + config.offset, 32) ); @@ -1288,8 +1289,8 @@ int CmdT55xxDump(const char *Cmd){ uint32_t password = 0; bool override = false; - char cmdp = param_getchar(Cmd, 0); - if ( cmdp == 'h' || cmdp == 'H') return usage_t55xx_dump(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if ( cmdp == 'h') return usage_t55xx_dump(); bool usepwd = ( strlen(Cmd) > 0); if ( usepwd ){ @@ -1474,7 +1475,7 @@ int CmdT55xxWipe(const char *Cmd) { // Try with the default password to reset block 0 // With a pwd should work even if pwd bit not set - PrintAndLogEx(NORMAL, "\nBeginning Wipe of a T55xx tag (assuming the tag is not password protected)\n"); + PrintAndLogEx(INFO, "\nBeginning Wipe of a T55xx tag (assuming the tag is not password protected)\n"); if ( Q5 ) snprintf(ptrData,sizeof(writeData),"b 0 d 6001F004 p 0"); @@ -1489,7 +1490,7 @@ int CmdT55xxWipe(const char *Cmd) { if (!CmdT55xxWriteBlock(ptrData)) PrintAndLogEx(WARNING, "Error writing blk %d", blk); - memset(writeData,0x00, sizeof(writeData)); + memset(writeData, 0x00, sizeof(writeData)); } return 0; } @@ -1503,23 +1504,68 @@ bool IsCancelled(void) { return false; } -int CmdT55xxBruteForce(const char *Cmd) { - +int CmdT55xxChkPwds(const char *Cmd) { // load a default pwd file. char line[9]; char filename[FILE_PATH_SIZE] = {0}; int keycnt = 0; uint8_t stKeyBlock = 20; uint8_t *keyBlock = NULL, *p = NULL; - uint32_t start_password = 0x00000000; //start password - uint32_t end_password = 0xFFFFFFFF; //end password bool found = false; + uint8_t timeout = 0; memset(line, 0, sizeof(line)); char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_t55xx_bruteforce(); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_t55xx_chk(); + + /* + if ( T55xxReadBlock(7, 0, 0, 0, 0) ) { + + // now try to validate it.. + PrintAndLogEx(WARNING, "\n Block 7 was readable"); + return 1; + } + */ + + uint64_t t1 = msclock(); + if ( cmdp == 'm' ) { + UsbCommand c = {CMD_T55XX_CHKPWDS, {0,0,0} }; + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + + while ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { + timeout++; + printf("."); fflush(stdout); + if (timeout > 180) { + PrintAndLogEx(WARNING, "\nno response from Proxmark. Aborting..."); + return 2; + } + } + + if ( resp.arg[0] ) { + PrintAndLogEx(SUCCESS, "\nFound a candidate [ %08X ]. Trying to validate", resp.arg[1]); + + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, resp.arg[1])) { + PrintAndLogEx(INFO, "Aquireing data from device failed. Quitting"); + return 2; + } + + found = tryDetectModulation(); + if (found) { + PrintAndLogEx(SUCCESS, "Found valid password: [ %08X ]", resp.arg[1]); + } else { + PrintAndLogEx(WARNING, "Password NOT found."); + } + } else { + PrintAndLogEx(WARNING, "Password NOT found."); + } + + goto out; + } + keyBlock = calloc(stKeyBlock, 4); if (keyBlock == NULL) return 1; @@ -1531,7 +1577,7 @@ int CmdT55xxBruteForce(const char *Cmd) { FILE * f = fopen( filename , "r"); if ( !f ) { - PrintAndLogEx(NORMAL, "File: %s: not found or locked.", filename); + PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename); free(keyBlock); return 1; } @@ -1546,7 +1592,7 @@ int CmdT55xxBruteForce(const char *Cmd) { if( line[0]=='#' ) continue; if (!isxdigit(line[0])) { - PrintAndLogEx(NORMAL, "File content error. '%s' must include 8 HEX symbols", line); + PrintAndLogEx(WARNING, "File content error. '%s' must include 8 HEX symbols", line); continue; } @@ -1569,19 +1615,20 @@ int CmdT55xxBruteForce(const char *Cmd) { num_to_bytes( strtoll(line, NULL, 16), 4, keyBlock + 4*keycnt); - PrintAndLogEx(NORMAL, "chk custom pwd[%2d] %08X", keycnt, bytes_to_num(keyBlock + 4 * keycnt, 4) ); +// PrintAndLogEx(NORMAL, "chk custom pwd[%2d] %08X", keycnt, bytes_to_num(keyBlock + 4 * keycnt, 4) ); keycnt++; memset(line, 0, sizeof(line)); - } + } + if (f) fclose(f); if (keycnt == 0) { - PrintAndLogEx(NORMAL, "No keys found in file"); + PrintAndLogEx(WARNING, "No keys found in file"); free(keyBlock); return 1; } - PrintAndLogEx(NORMAL, "Loaded %d keys", keycnt); + PrintAndLogEx(SUCCESS, "Loaded %d keys", keycnt); // loop uint64_t testpwd = 0x00; @@ -1600,74 +1647,92 @@ int CmdT55xxBruteForce(const char *Cmd) { testpwd = bytes_to_num(keyBlock + 4*c, 4); - PrintAndLogEx(NORMAL, "Testing %08X", testpwd); + PrintAndLogEx(INFO, "Testing %08X", testpwd); if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd)) { - PrintAndLogEx(NORMAL, "Aquireing data from device failed. Quitting"); + PrintAndLogEx(INFO, "Aquireing data from device failed. Quitting"); free(keyBlock); return 0; } found = tryDetectModulation(); - if ( found ) { - PrintAndLogEx(NORMAL, "Found valid password: [%08X]", testpwd); - //free(keyBlock); - //return 0; - } + if ( found ) + break; + } - PrintAndLogEx(NORMAL, "Password NOT found."); - free(keyBlock); - return 0; + if ( found ) + PrintAndLogEx(SUCCESS, "Found valid password: [ %08X ]", testpwd); + else + PrintAndLogEx(WARNING, "Password NOT found."); } + free(keyBlock); + +out: + t1 = msclock() - t1; + PrintAndLogEx(SUCCESS, "\nTime in bruteforce: %.0f seconds\n", (float)t1/1000.0); + return 0; +} + +int CmdT55xxBruteForce(const char *Cmd) { + + uint32_t start_password = 0x00000000; //start password + uint32_t end_password = 0xFFFFFFFF; //end password + uint32_t curr = 0; + bool found = false; + + + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_t55xx_bruteforce(); + + uint64_t t1 = msclock(); + // Try to read Block 7, first :) // incremental pwd range search start_password = param_get32ex(Cmd, 0, 0, 16); end_password = param_get32ex(Cmd, 1, 0, 16); + curr = start_password; + if ( start_password >= end_password ) { - free(keyBlock); return usage_t55xx_bruteforce(); } - PrintAndLogEx(NORMAL, "Search password range [%08X -> %08X]", start_password, end_password); - - uint32_t i = start_password; + PrintAndLogEx(INFO, "Search password range [%08X -> %08X]", start_password, end_password); - while ((!found) && (i <= end_password)){ + while ( !found || (curr <= end_password)){ printf("."); fflush(stdout); if (IsCancelled()) { - free(keyBlock); return 0; } - if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i)) { - PrintAndLogEx(NORMAL, "Aquireing data from device failed. Quitting"); - free(keyBlock); + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, curr)) { + PrintAndLogEx(WARNING, "Aquireing data from device failed. Quitting"); return 0; } + found = tryDetectModulation(); - - if (found) break; - i++; + + ++curr; } PrintAndLogEx(NORMAL, ""); if (found) - PrintAndLogEx(NORMAL, "Found valid password: [%08x]", i); + PrintAndLogEx(SUCCESS, "Found valid password: [ %08X ]", curr); else - PrintAndLogEx(NORMAL, "Password NOT found. Last tried: [%08x]", --i); + PrintAndLogEx(WARNING, "Password NOT found. Last tried: [ %08X ]", --curr); - free(keyBlock); + t1 = msclock() - t1; + PrintAndLogEx(SUCCESS, "\nTime in bruteforce: %.0f seconds\n", (float)t1/1000.0); return 0; } int tryOnePassword(uint32_t password) { - PrintAndLogEx(NORMAL, "Trying password %08x", password); + PrintAndLogEx(INFO, "Trying password %08x", password); if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, password)) { PrintAndLogEx(NORMAL, "Acquire data from device failed. Quitting"); return -1; @@ -1686,8 +1751,8 @@ int CmdT55xxRecoverPW(const char *Cmd) { uint32_t prev_password = 0xffffffff; uint32_t mask = 0x0; int found = 0; - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_t55xx_recoverpw(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h' ) return usage_t55xx_recoverpw(); orig_password = param_get32ex(Cmd, 0, 0x51243648, 16); //password used by handheld cloners @@ -1746,9 +1811,9 @@ int CmdT55xxRecoverPW(const char *Cmd) { PrintAndLogEx(NORMAL, ""); if (found == 1) - PrintAndLogEx(NORMAL, "Found valid password: [%08x]", curr_password); + PrintAndLogEx(SUCCESS, "Found valid password: [%08x]", curr_password); else - PrintAndLogEx(NORMAL, "Password NOT found."); + PrintAndLogEx(WARNING, "Password NOT found."); return 0; } @@ -1870,13 +1935,11 @@ int CmdT55xxDetectPage1(const char *Cmd){ uint32_t password = 0; uint8_t cmdp = 0; - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': - case 'H': return usage_t55xx_detectP1(); case 'p': - case 'P': password = param_get32ex(Cmd, cmdp+1, 0, 16); usepwd = true; cmdp += 2; @@ -1899,7 +1962,7 @@ int CmdT55xxDetectPage1(const char *Cmd){ return false; } bool success = tryDetectP1(false); - if (success) PrintAndLogEx(NORMAL, "T55xx chip found!"); + if (success) PrintAndLogEx(SUCCESS, "T55xx chip found!"); return success; } @@ -1959,6 +2022,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"bruteforce", CmdT55xxBruteForce,0, " [i <*.dic>] Simple bruteforce attack to find password"}, {"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, + {"chk", CmdT55xxChkPwds, 1, "Check passwords"}, {"detect", CmdT55xxDetect, 1, "[1] Try detecting the tag modulation from reading the configuration block."}, {"deviceconfig", CmdT55xxSetDeviceConfig, 1, "Set/Get T55XX device configuration (startgap, writegap, write0, write1, readgap"}, {"p1detect", CmdT55xxDetectPage1,1, "[1] Try detecting if this is a t55xx tag by reading page 1"}, diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index 15adab0b6..46de0c359 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -133,6 +133,7 @@ t55xx_conf_block_t Get_t55xx_Config(void); void Set_t55xx_Config(t55xx_conf_block_t conf); extern int CmdLFT55XX(const char *Cmd); +extern int CmdT55xxChk(const char *Cmd); extern int CmdT55xxBruteForce(const char *Cmd); extern int CmdT55xxSetConfig(const char *Cmd); extern int CmdT55xxReadBlock(const char *Cmd); diff --git a/client/cmdlfviking.c b/client/cmdlfviking.c index 984e5ec83..33a5588d3 100644 --- a/client/cmdlfviking.c +++ b/client/cmdlfviking.c @@ -118,7 +118,7 @@ int CmdVikingClone(const char *Cmd) { rawID = getVikingBits(id); - PrintAndLogEx(NORMAL, "Cloning - ID: %08X, Raw: %08X%08X",id,(uint32_t)(rawID >> 32),(uint32_t) (rawID & 0xFFFFFFFF)); + PrintAndLogEx(INFO, "Preparing to clone Viking tag - ID: %08X, Raw: %08X%08X",id,(uint32_t)(rawID >> 32),(uint32_t) (rawID & 0xFFFFFFFF)); UsbCommand c = {CMD_VIKING_CLONE_TAG, {rawID >> 32, rawID & 0xFFFFFFFF, Q5}}; clearCommandBuffer(); @@ -149,7 +149,7 @@ int CmdVikingSim(const char *Cmd) { arg1 = clk << 8 | encoding; arg2 = invert << 8 | separator; - PrintAndLogEx(NORMAL, "Simulating Viking - ID: %08X, Raw: %08X%08X",id,(uint32_t)(rawID >> 32),(uint32_t) (rawID & 0xFFFFFFFF)); + PrintAndLogEx(SUCCESS, "Simulating Viking - ID: %08X, Raw: %08X%08X",id,(uint32_t)(rawID >> 32),(uint32_t) (rawID & 0xFFFFFFFF)); UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; num_to_bytebits(rawID, size, c.d.asBytes); diff --git a/client/cmdlfvisa2000.c b/client/cmdlfvisa2000.c index 2736934af..02cd5392e 100644 --- a/client/cmdlfvisa2000.c +++ b/client/cmdlfvisa2000.c @@ -165,8 +165,8 @@ int CmdVisa2kClone(const char *Cmd) { uint64_t id = 0; uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_64 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, BL0CK1, 0}; - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_visa2k_clone(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_visa2k_clone(); id = param_get32ex(Cmd, 0, 0, 10); @@ -210,7 +210,7 @@ int CmdVisa2kSim(const char *Cmd) { arg1 = clk << 8 | encoding; arg2 = invert << 8 | separator; - PrintAndLogEx(NORMAL, "Simulating Visa2000 - CardId: %u", id); + PrintAndLogEx(SUCCESS, "Simulating Visa2000 - CardId: %u", id); UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; diff --git a/client/cmdmain.c b/client/cmdmain.c index 5b147e76a..9b71df21d 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -24,14 +24,14 @@ static command_t CommandTable[] = { {"lf", CmdLF, 1, "{ Low Frequency commands... }"}, {"emv", CmdEMV, 1, "{ EMV iso14443 and iso7816... }"}, {"rem", CmdRem, 1, "{ Add text to row in log file }"}, - {"reveng", CmdRev, 1, "{ Crc calculations from the software reveng 1.53... }"}, + {"reveng", CmdRev, 1, "{ Crc calculations from the RevEng software... }"}, {"script", CmdScript, 1, "{ Scripting commands }"}, {"trace", CmdTrace, 1, "{ Trace manipulation... }"}, #ifdef WITH_FLASH - {"mem", CmdFlashMem, 1, "{ RDV40, Flash Memory manipulation... }"}, + {"mem", CmdFlashMem, 1, "{ Flash Memory manipulation... }"}, #endif #ifdef WITH_SMARTCARD - {"sc", CmdSmartcard, 1, "{ RDV40, Smart card ISO7816 commands... }"}, + {"sc", CmdSmartcard, 1, "{ Smart card ISO7816 commands... }"}, #endif {"quit", CmdQuit, 1, ""}, {"exit", CmdQuit, 1, "Exit program"}, diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index 8408b03ce..8b10dc6fe 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -8,6 +8,7 @@ // Proxmark3 RDV40 Smartcard module commands //----------------------------------------------------------------------------- #include "cmdsmartcard.h" +#include "../emv/emvjson.h" static int CmdHelp(const char *Cmd); @@ -15,14 +16,18 @@ int usage_sm_raw(void) { PrintAndLogEx(NORMAL, "Usage: sc raw [h|r|c] d <0A 0B 0C ... hex>"); PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " r : do not read response"); - PrintAndLogEx(NORMAL, " a : active smartcard without select"); - PrintAndLogEx(NORMAL, " s : active smartcard with select"); + PrintAndLogEx(NORMAL, " a : active smartcard without select (reset sc module)"); + PrintAndLogEx(NORMAL, " s : active smartcard with select (get ATR)"); PrintAndLogEx(NORMAL, " t : executes TLV decoder if it possible"); + PrintAndLogEx(NORMAL, " 0 : use protocol T=0"); PrintAndLogEx(NORMAL, " d : bytes to send"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " sc raw d 00a404000e315041592e5359532e444446303100 - `1PAY.SYS.DDF01` PPSE directory"); - PrintAndLogEx(NORMAL, " sc raw d 00a404000e325041592e5359532e444446303100 - `2PAY.SYS.DDF01` PPSE directory"); + PrintAndLogEx(NORMAL, " sc raw s 0 d 00a404000e315041592e5359532e4444463031 - `1PAY.SYS.DDF01` PPSE directory with get ATR"); + PrintAndLogEx(NORMAL, " sc raw 0 d 00a404000e325041592e5359532e4444463031 - `2PAY.SYS.DDF01` PPSE directory"); + PrintAndLogEx(NORMAL, " sc raw 0 t d 00a4040007a0000000041010 - Mastercard"); + PrintAndLogEx(NORMAL, " sc raw 0 t d 00a4040007a0000000031010 - Visa"); + return 0; } int usage_sm_reader(void) { @@ -63,15 +68,48 @@ int usage_sm_setclock(void) { return 0; } int usage_sm_brute(void) { - PrintAndLogEx(NORMAL, "Tries to bruteforce SFI, "); + PrintAndLogEx(NORMAL, "Tries to bruteforce SFI, using a known list of AID's "); PrintAndLogEx(NORMAL, "Usage: sc brute [h]"); PrintAndLogEx(NORMAL, " h : this help"); + PrintAndLogEx(NORMAL, " t : executes TLV decoder if it possible"); +// PrintAndLogEx(NORMAL, " 0 : use protocol T=0"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " sc brute"); + PrintAndLogEx(NORMAL, " sc brute t"); return 0; } +static int smart_loadjson(const char *preferredName, const char *suffix, json_t **root) { + + json_error_t error; + + if ( preferredName == NULL ) return 1; + if ( suffix == NULL ) return 1; + + int retval = 0; + int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10); + char * fileName = calloc(size, sizeof(char)); + sprintf(fileName, "%s.%s", preferredName, suffix); + + *root = json_load_file(fileName, 0, &error); + if (!*root) { + PrintAndLogEx(ERR, "json (%s) error on line %d: %s", fileName, error.line, error.text); + retval = 2; + goto out; + } + + if (!json_is_array(*root)) { + PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", fileName); + retval = 3; + goto out; + } + + PrintAndLogEx(SUCCESS, "Loaded file (%s) OK.", fileName); +out: + free(fileName); + return retval; +} + uint8_t GetATRTA1(uint8_t *atr, size_t atrlen) { if (atrlen > 2) { uint8_t T0 = atr[1]; @@ -79,7 +117,7 @@ uint8_t GetATRTA1(uint8_t *atr, size_t atrlen) { return atr[2]; } - return 0x11; // default value is ‘0x11’, corresponding to fmax=5 MHz, Fi=372, Di=1. + return 0x11; // default value is ‘0x11’, corresponding to fmax=5 MHz, Fi=372, Di=1. } int DiArray[] = { @@ -141,75 +179,60 @@ float FArray[] = { int GetATRDi(uint8_t *atr, size_t atrlen) { uint8_t TA1 = GetATRTA1(atr, atrlen); - - return DiArray[TA1 & 0x0f]; // The 4 low-order bits of TA1 (4th MSbit to 1st LSbit) encode Di + return DiArray[TA1 & 0x0F]; // The 4 low-order bits of TA1 (4th MSbit to 1st LSbit) encode Di } int GetATRFi(uint8_t *atr, size_t atrlen) { uint8_t TA1 = GetATRTA1(atr, atrlen); - return FiArray[TA1 >> 4]; // The 4 high-order bits of TA1 (8th MSbit to 5th LSbit) encode fmax and Fi } float GetATRF(uint8_t *atr, size_t atrlen) { uint8_t TA1 = GetATRTA1(atr, atrlen); - return FArray[TA1 >> 4]; // The 4 high-order bits of TA1 (8th MSbit to 5th LSbit) encode fmax and Fi } static int PrintATR(uint8_t *atr, size_t atrlen) { - uint8_t vxor = 0; - for (int i = 1; i < atrlen; i++) - vxor ^= atr[i]; - - if (vxor) - PrintAndLogEx(WARNING, "Check summ error. Must be 0 but: 0x%02x", vxor); - else - PrintAndLogEx(INFO, "Check summ OK."); - - if (atr[0] != 0x3b) - PrintAndLogEx(WARNING, "Not a direct convention: 0x%02x", atr[0]); uint8_t T0 = atr[1]; uint8_t K = T0 & 0x0F; - uint8_t TD1 = 0; - - uint8_t T1len = 0; - uint8_t TD1len = 0; - uint8_t TDilen = 0; + uint8_t TD1 = 0, T1len = 0, TD1len = 0, TDilen = 0; if (T0 & 0x10) { - PrintAndLog("TA1 (Maximum clock frequency, proposed bit duration): 0x%02x", atr[2 + T1len]); + PrintAndLog("\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]); T1len++; } + if (T0 & 0x20) { - PrintAndLog("TB1 (Deprecated: VPP requirements): 0x%02x", atr[2 + T1len]); + PrintAndLog("\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]); T1len++; } + if (T0 & 0x40) { - PrintAndLog("TC1 (Extra delay between bytes required by card): 0x%02x", atr[2 + T1len]); + PrintAndLog("\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]); T1len++; } + if (T0 & 0x80) { TD1 = atr[2 + T1len]; - PrintAndLog("TD1 (First offered transmission protocol, presence of TA2..TD2): 0x%02x. Protocol T=%d", TD1, TD1 & 0x0f); + PrintAndLog("\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f); T1len++; if (TD1 & 0x10) { - PrintAndLog("TA2 (Specific protocol and parameters to be used after the ATR): 0x%02x", atr[2 + T1len + TD1len]); + PrintAndLog("\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]); TD1len++; } if (TD1 & 0x20) { - PrintAndLog("TB2 (Deprecated: VPP precise voltage requirement): 0x%02x", atr[2 + T1len + TD1len]); + PrintAndLog("\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]); TD1len++; } if (TD1 & 0x40) { - PrintAndLog("TC2 (Maximum waiting time for protocol T=0): 0x%02x", atr[2 + T1len + TD1len]); + PrintAndLog("\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]); TD1len++; } if (TD1 & 0x80) { uint8_t TDi = atr[2 + T1len + TD1len]; - PrintAndLog("TD2 (A supported protocol or more global parameters, presence of TA3..TD3): 0x%02x. Protocol T=%d", TDi, TDi & 0x0f); + PrintAndLog("\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f); TD1len++; bool nextCycle = true; @@ -217,20 +240,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { while (nextCycle) { nextCycle = false; if (TDi & 0x10) { - PrintAndLog("TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); + PrintAndLog("\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); TDilen++; } if (TDi & 0x20) { - PrintAndLog("TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); + PrintAndLog("\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); TDilen++; } if (TDi & 0x40) { - PrintAndLog("TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); + PrintAndLog("\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); TDilen++; } if (TDi & 0x80) { TDi = atr[2 + T1len + TD1len + TDilen]; - PrintAndLog("TD%d: 0x%02x. Protocol T=%d", vi, TDi, TDi & 0x0f); + PrintAndLog("\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f); TDilen++; nextCycle = true; @@ -239,27 +262,40 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { } } } + + uint8_t vxor = 0; + for (int i = 1; i < atrlen; i++) + vxor ^= atr[i]; + + if (vxor) + PrintAndLogEx(WARNING, "Check summ error. Must be 0 got 0x%02X", vxor); + else + PrintAndLogEx(INFO, "Check summ OK."); + + if (atr[0] != 0x3b) + PrintAndLogEx(WARNING, "Not a direct convention [ 0x%02x ]", atr[0]); + uint8_t calen = 2 + T1len + TD1len + TDilen + K; if (atrlen != calen && atrlen != calen + 1) // may be CRC PrintAndLogEx(ERR, "ATR length error. len: %d, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K); - else - PrintAndLogEx(INFO, "ATR length OK."); - PrintAndLog("Historical bytes len: 0x%02x", K); if (K > 0) - PrintAndLog("The format of historical bytes: %02x", atr[2 + T1len + TD1len + TDilen]); + PrintAndLogEx(INFO, "\nHistorical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]); + if (K > 1) { - PrintAndLog("Historical bytes:"); + PrintAndLogEx(INFO, "\tHistorical bytes"); dump_buffer(&atr[2 + T1len + TD1len + TDilen], K, NULL, 1); } return 0; } +bool smart_select(bool silent, smart_card_atr_t *atr) { + if (atr) + memset(atr, 0, sizeof(smart_card_atr_t)); -static bool smart_select(bool silent) { UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}}; clearCommandBuffer(); SendCommand(&c); @@ -275,40 +311,43 @@ static bool smart_select(bool silent) { return false; } - if (!silent) { - smart_card_atr_t card; - memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); - + smart_card_atr_t card; + memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); + + if (atr) + memcpy(atr, &card, sizeof(smart_card_atr_t)); + + if (!silent) PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); - } return true; } -static int smart_wait(uint8_t *data) { +static int smart_wait(uint8_t *data, bool silent) { UsbCommand resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { - PrintAndLogEx(WARNING, "smart card response failed"); + if (!silent) PrintAndLogEx(WARNING, "smart card response timeout"); return -1; } uint32_t len = resp.arg[0]; if ( !len ) { - PrintAndLogEx(WARNING, "smart card response failed"); + if (!silent) PrintAndLogEx(WARNING, "smart card response failed"); return -2; } memcpy(data, resp.d.asBytes, len); - PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 32)); - if (len >= 2) { - PrintAndLogEx(SUCCESS, "%02X%02X | %s", data[len - 2], data[len - 1], GetAPDUCodeDescription(data[len - 2], data[len - 1])); + if (!silent) PrintAndLogEx(SUCCESS, "%02X%02X | %s", data[len - 2], data[len - 1], GetAPDUCodeDescription(data[len - 2], data[len - 1])); + } else { + if (!silent) PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 8)); } + return len; } -static int smart_response(uint8_t *data) { +static int smart_responseEx(uint8_t *data, bool silent) { - int datalen = smart_wait(data); + int datalen = smart_wait(data, silent); bool needGetData = false; if (datalen < 2 ) { @@ -321,14 +360,14 @@ static int smart_response(uint8_t *data) { if (needGetData) { int len = data[datalen - 1]; - PrintAndLogEx(INFO, "Requesting response. len=0x%x", len); - uint8_t getstatus[] = {0x00, ISO7816_GETSTATUS, 0x00, 0x00, len}; + if (!silent) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len); + uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len}; UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}}; memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) ); clearCommandBuffer(); SendCommand(&cStatus); - datalen = smart_wait(data); + datalen = smart_wait(data, silent); if (datalen < 2 ) { goto out; @@ -338,8 +377,10 @@ static int smart_response(uint8_t *data) { if (datalen != len + 2) { // data with ACK if (datalen == len + 2 + 1) { // 2 - response, 1 - ACK - if (data[0] != ISO7816_GETSTATUS) { - PrintAndLogEx(ERR, "GetResponse ACK error. len=0x%x data[0]=%02x", len, data[0]); + if (data[0] != ISO7816_GET_RESPONSE) { + if (!silent) { + PrintAndLogEx(ERR, "GetResponse ACK error. len 0x%x | data[0] %02X", len, data[0]); + } datalen = 0; goto out; } @@ -348,7 +389,9 @@ static int smart_response(uint8_t *data) { memmove(data, &data[1], datalen); } else { // wrong length - PrintAndLogEx(WARNING, "GetResponse wrong length. Must be: 0x%02x but: 0x%02x", len, datalen - 3); + if (!silent) { + PrintAndLogEx(WARNING, "GetResponse wrong length. Must be 0x%02X got 0x%02X", len, datalen - 3); + } } } } @@ -357,11 +400,16 @@ out: return datalen; } +static int smart_response(uint8_t *data) { + return smart_responseEx(data, false); +} + int CmdSmartRaw(const char *Cmd) { int hexlen = 0; bool active = false; bool active_select = false; + bool useT0 = false; uint8_t cmdp = 0; bool errors = false, reply = true, decodeTLV = false, breakloop = false; uint8_t data[USB_CMD_DATA_SIZE] = {0x00}; @@ -385,6 +433,10 @@ int CmdSmartRaw(const char *Cmd) { decodeTLV = true; cmdp++; break; + case '0': + useT0 = true; + cmdp++; + break; case 'd': { switch (param_gethex_to_eol(Cmd, cmdp+1, data, sizeof(data), &hexlen)) { case 1: @@ -425,7 +477,10 @@ int CmdSmartRaw(const char *Cmd) { } if (hexlen > 0) { - c.arg[0] |= SC_RAW; + if (useT0) + c.arg[0] |= SC_RAW_T0; + else + c.arg[0] |= SC_RAW; } memcpy(c.d.asBytes, data, hexlen ); @@ -457,7 +512,7 @@ int CmdSmartRaw(const char *Cmd) { } if (decodeTLV && len > 4) - TLVPrintFromBuffer(buf+1, len-3); + TLVPrintFromBuffer(buf, len-2); free(buf); } @@ -468,8 +523,9 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave *dataoutlen = 0; if (activateCard) - smart_select(false); - printf("* APDU SC\n"); + smart_select(false, NULL); + + PrintAndLogEx(DEBUG, "APDU SC"); UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, datainlen, 0}}; if (activateCard) { @@ -479,10 +535,10 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave clearCommandBuffer(); SendCommand(&c); - int len = smart_response(dataout); + int len = smart_responseEx(dataout, true); if ( len < 0 ) { - return 2; + return 1; } // retry @@ -496,15 +552,13 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave clearCommandBuffer(); SendCommand(&c2); - len = smart_response(dataout); + len = smart_responseEx(dataout, true); } *dataoutlen = len; - return 0; } - int CmdSmartUpgrade(const char *Cmd) { PrintAndLogEx(WARNING, "WARNING - Smartcard socket firmware upgrade."); @@ -541,7 +595,7 @@ int CmdSmartUpgrade(const char *Cmd) { // load file f = fopen(filename, "rb"); if ( !f ){ - PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename); + PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename); return 1; } @@ -652,33 +706,37 @@ int CmdSmartInfo(const char *Cmd){ memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); // print header - PrintAndLogEx(INFO, "\n--- Smartcard Information ---------"); + PrintAndLogEx(INFO, "--- Smartcard Information ---------"); PrintAndLogEx(INFO, "-------------------------------------------------------------"); - PrintAndLogEx(INFO, "ISO76183 ATR : %s", sprint_hex(card.atr, card.atr_len)); - PrintAndLogEx(INFO, "look up ATR"); - PrintAndLogEx(INFO, "http://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) ); + PrintAndLogEx(INFO, "ISO7618-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); + PrintAndLogEx(INFO, "\nhttp://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) ); // print ATR PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "* ATR:"); + PrintAndLogEx(INFO, "ATR"); PrintATR(card.atr, card.atr_len); // print D/F (brom byte TA1 or defaults) PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "* D/F (TA1):"); + PrintAndLogEx(INFO, "D/F (TA1)"); int Di = GetATRDi(card.atr, card.atr_len); int Fi = GetATRFi(card.atr, card.atr_len); float F = GetATRF(card.atr, card.atr_len); if (GetATRTA1(card.atr, card.atr_len) == 0x11) PrintAndLogEx(INFO, "Using default values..."); - PrintAndLogEx(NORMAL, "Di=%d", Di); - PrintAndLogEx(NORMAL, "Fi=%d", Fi); - PrintAndLogEx(NORMAL, "F=%.1f MHz", F); - PrintAndLogEx(NORMAL, "Cycles/ETU=%d", Fi/Di); - PrintAndLogEx(NORMAL, "%.1f bits/sec at 4MHz", (float)4000000 / (Fi/Di)); - PrintAndLogEx(NORMAL, "%.1f bits/sec at Fmax=%.1fMHz", (F * 1000000) / (Fi/Di), F); - + PrintAndLogEx(NORMAL, "\t- Di %d", Di); + PrintAndLogEx(NORMAL, "\t- Fi %d", Fi); + PrintAndLogEx(NORMAL, "\t- F %.1f MHz", F); + + if (Di && Fi) { + PrintAndLogEx(NORMAL, "\t- Cycles/ETU %d", Fi/Di); + PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at 4MHz", (float)4000000 / (Fi/Di)); + PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at Fmax (%.1fMHz)", (F * 1000000) / (Fi/Di), F); + } else { + PrintAndLogEx(WARNING, "\t- Di or Fi is RFU."); + }; + return 0; } @@ -784,63 +842,279 @@ int CmdSmartList(const char *Cmd) { return 0; } -int CmdSmartBruteforceSFI(const char *Cmd) { +static void smart_brute_prim(){ - char ctmp = tolower(param_getchar(Cmd, 0)); - if (ctmp == 'h') return usage_sm_brute(); + uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t)); + if ( !buf ) + return; - uint8_t data[5] = {0x00, 0xB2, 0x00, 0x00, 0x00}; + int len = 0; + uint8_t get_card_data[] = { + 0x80, 0xCA, 0x9F, 0x13, 0x00, + 0x80, 0xCA, 0x9F, 0x17, 0x00, + 0x80, 0xCA, 0x9F, 0x36, 0x00, + 0x80, 0xCA, 0x9F, 0x4f, 0x00 + }; + + UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, 5, 0}}; + + PrintAndLogEx(INFO, "Reading primitives"); - PrintAndLogEx(INFO, "Selecting card"); - if ( !smart_select(false) ) { - return 1; - } - - PrintAndLogEx(INFO, "Selecting PPSE aid"); - CmdSmartRaw("d 00a404000e325041592e5359532e444446303100"); - CmdSmartRaw("d 00a4040007a000000004101000"); - - PrintAndLogEx(INFO, "starting"); - - UsbCommand c = {CMD_SMART_RAW, {SC_RAW, sizeof(data), 0}}; - uint8_t* buf = malloc(USB_CMD_DATA_SIZE); - if ( !buf ) - return 1; + for (int i = 0; i < sizeof(get_card_data); i += 5) { - for (uint8_t i=1; i < 4; i++) { - for (int p1=1; p1 < 5; p1++) { - - data[2] = p1; - data[3] = (i << 3) + 4; + memcpy(c.d.asBytes, get_card_data+i, 5 ); + clearCommandBuffer(); + SendCommand(&c); + + len = smart_responseEx(buf, true); - memcpy(c.d.asBytes, data, sizeof(data) ); + if ( len > 2 ) { + + //if ( decodeTLV ) { + //if (!TLVPrintFromBuffer(buf, len-2)) { + PrintAndLogEx(SUCCESS, "\tHEX %d |: %s", len, sprint_hex(buf, len)); + //} + //} + } + len = 0; + } + free(buf); +} + +static int smart_brute_sfi(bool decodeTLV){ + + uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t)); + if ( !buf ) + return 1; + + int len = 0; + // READ RECORD + uint8_t READ_RECORD[] = {0x00, 0xB2, 0x00, 0x00, 0x00}; + UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, sizeof(READ_RECORD), 0}}; + + PrintAndLogEx(INFO, "Start SFI brute forcing"); + + for (uint8_t sfi=1; sfi <= 31; sfi++) { + + printf("."); fflush(stdout); + + for (uint16_t rec=1; rec <= 255; rec++) { + + if (ukbhit()) { + int gc = getchar(); (void)gc; + PrintAndLogEx(NORMAL, "\naborted via keyboard!\n"); + free(buf); + return 1; + } + + READ_RECORD[2] = rec; + READ_RECORD[3] = (sfi << 3) | 4; + + memcpy(c.d.asBytes, READ_RECORD, sizeof(READ_RECORD) ); clearCommandBuffer(); SendCommand(&c); - smart_response(buf); + len = smart_responseEx(buf, true); - // if 0x6C if ( buf[0] == 0x6C ) { - data[4] = buf[1]; + READ_RECORD[4] = buf[1]; - memcpy(c.d.asBytes, data, sizeof(data) ); + memcpy(c.d.asBytes, READ_RECORD, sizeof(READ_RECORD) ); clearCommandBuffer(); SendCommand(&c); - uint8_t len = smart_response(buf); + len = smart_responseEx(buf, true); - // TLV decoder - if (len > 4) - TLVPrintFromBuffer(buf+1, len-3); - - data[4] = 0; + READ_RECORD[4] = 0; } + + if ( len > 4 ) { + + PrintAndLogEx(SUCCESS, "\n\t file %02d, record %02d found", sfi, rec); + + uint8_t modifier = (buf[0] == 0xC0) ? 1 : 0; + + if ( decodeTLV ) { + if (!TLVPrintFromBuffer(buf + modifier, len-2-modifier)) { + PrintAndLogEx(SUCCESS, "\tHEX: %s", sprint_hex(buf, len)); + } + } + } memset(buf, 0x00, USB_CMD_DATA_SIZE); } - } + } free(buf); return 0; } +static void smart_brute_options(bool decodeTLV) { + + uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t)); + if ( !buf ) + return; + + uint8_t GET_PROCESSING_OPTIONS[] = {0x80, 0xA8, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00}; + + // Get processing options command + UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, sizeof(GET_PROCESSING_OPTIONS), 0}}; + memcpy(c.d.asBytes, GET_PROCESSING_OPTIONS, sizeof(GET_PROCESSING_OPTIONS) ); + clearCommandBuffer(); + SendCommand(&c); + + int len = smart_responseEx(buf, true); + if ( len > 4 ) { + PrintAndLogEx(SUCCESS, "Got processing options"); + if ( decodeTLV ) { + TLVPrintFromBuffer(buf, len-2); + } + } else { + PrintAndLogEx(FAILED, "Getting processing options failed"); + } + + free(buf); +} + +int CmdSmartBruteforceSFI(const char *Cmd) { + + uint8_t cmdp = 0; + bool errors = false, decodeTLV = false; //, useT0 = false; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': return usage_sm_brute(); + case 't': + decodeTLV = true; + cmdp++; + break; +/* + case '0': + useT0 = true; + cmdp++; + break; +*/ + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors) return usage_sm_brute(); + + const char *SELECT = "00a40400%02x%s"; + +// uint8_t GENERATE_AC[] = {0x80, 0xAE}; +// uint8_t GET_CHALLENGE[] = {0x00, 0x84, 0x00}; +// uint8_t GET_DATA[] = {0x80, 0xCA, 0x00, 0x00, 0x00}; +// uint8_t SELECT[] = {0x00, 0xA4, 0x04, 0x00}; +// uint8_t UNBLOCK_PIN[] = {0x84, 0x24, 0x00, 0x00, 0x00}; +// uint8_t VERIFY[] = {0x00, 0x20, 0x00, 0x80}; + + // Select AID command + UsbCommand cAid = {CMD_SMART_RAW, {SC_RAW_T0, 0, 0}}; + + PrintAndLogEx(INFO, "Importing AID list"); + json_t *root = NULL; + smart_loadjson("aidlist", "json", &root); + + uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t)); + if ( !buf ) + return 1; + + PrintAndLogEx(INFO, "Selecting card"); + if ( !smart_select(false, NULL) ) { + free(buf); + return 1; + } + + char* caid = NULL; + + for (int i = 0; i < json_array_size(root); i++) { + + printf("+"); fflush(stdout); + + if (caid) + free(caid); + + json_t *data, *jaid; + + data = json_array_get(root, i); + if (!json_is_object(data)) { + PrintAndLogEx(ERR, "data %d is not an object\n", i + 1); + json_decref(root); + return 1; + } + + jaid = json_object_get(data, "AID"); + if (!json_is_string(jaid)) { + PrintAndLogEx(ERR, "AID data [%d] is not a string", i + 1); + json_decref(root); + return 1; + } + + const char* aid = json_string_value(jaid); + if ( !aid ) + continue; + + size_t aidlen = strlen(aid); + caid = calloc( 8+2+aidlen+1, sizeof(uint8_t)); + snprintf(caid, 8+2+aidlen+1, SELECT, aidlen >> 1, aid); + + int hexlen = 0; + int res = param_gethex_to_eol(caid, 0, cAid.d.asBytes, sizeof(cAid.d.asBytes), &hexlen); + if ( res ) + continue; + + cAid.arg[1] = hexlen; + + clearCommandBuffer(); + SendCommand(&cAid); + + int len = smart_responseEx(buf, true); + if ( len < 3 ) + continue; + + json_t *jvendor, *jname; + jvendor = json_object_get(data, "Vendor"); + if (!json_is_string(jvendor)) { + PrintAndLogEx(ERR, "Vendor data [%d] is not a string", i + 1); + continue; + } + + const char* vendor = json_string_value(jvendor); + if ( !vendor ) + continue; + + jname = json_object_get(data, "Name"); + if (!json_is_string(jname)) { + PrintAndLogEx(ERR, "Name data [%d] is not a string", i + 1); + continue; + } + const char* name = json_string_value(jname); + if ( !name ) + continue; + + PrintAndLogEx(SUCCESS, "\nAID %s | %s | %s", aid, vendor, name); + + smart_brute_options(decodeTLV); + + smart_brute_prim(); + + smart_brute_sfi(decodeTLV); + + PrintAndLogEx(SUCCESS, "\nSFI brute force done\n"); + } + + if (caid) + free(caid); + + free(buf); + json_decref(root); + + PrintAndLogEx(SUCCESS, "\nSearch completed."); + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"list", CmdSmartList, 0, "List ISO 7816 history"}, diff --git a/client/cmdsmartcard.h b/client/cmdsmartcard.h index cffaeff98..00bc41ff4 100644 --- a/client/cmdsmartcard.h +++ b/client/cmdsmartcard.h @@ -33,6 +33,7 @@ extern int CmdSmartUpgrade(const char* cmd); extern int CmdSmartInfo(const char* cmd); extern int CmdSmartReader(const char *Cmd); +extern bool smart_select(bool silent, smart_card_atr_t *atr); extern int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); extern int usage_sm_raw(void); diff --git a/client/cmdtrace.c b/client/cmdtrace.c index 90c08459f..cf55970b0 100644 --- a/client/cmdtrace.c +++ b/client/cmdtrace.c @@ -14,7 +14,6 @@ static int CmdHelp(const char *Cmd); // trace pointer static uint8_t *trace; long traceLen = 0; -bool preRDV40 = true; int usage_trace_list(){ PrintAndLogEx(NORMAL, "List protocol data in trace buffer."); @@ -166,7 +165,8 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui crcStatus = iso14443B_CRC_check(frame, data_len); break; case PROTO_MIFARE: - crcStatus = mifare_CRC_check(isResponse, frame, data_len); + crcStatus = mifare_CRC_check(isResponse, frame, data_len); + break; case ISO_14443A: case MFDES: crcStatus = iso14443A_CRC_check(isResponse, frame, data_len); @@ -289,6 +289,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui void printFelica(uint16_t traceLen, uint8_t *trace) { + PrintAndLogEx(NORMAL, "ISO18092 / FeliCa - Timings are not as accurate"); PrintAndLogEx(NORMAL, " Gap | Src | Data | CRC | Annotation |"); PrintAndLogEx(NORMAL, "--------|-----|---------------------------------|----------|-------------------|"); uint16_t tracepos = 0; @@ -297,8 +298,9 @@ void printFelica(uint16_t traceLen, uint8_t *trace) { if (tracepos + 3 >= traceLen) break; - uint16_t gap = (uint16_t)trace[tracepos+1] + ((uint16_t)trace[tracepos] >> 8); - uint16_t crc_ok = trace[tracepos+2]; + + uint16_t gap = *((uint16_t *)(trace + tracepos)); + uint8_t crc_ok = trace[tracepos+2]; tracepos += 3; if (tracepos + 3 >= traceLen) break; @@ -511,8 +513,8 @@ int CmdTraceList(const char *Cmd) { } } - PrintAndLogEx(NORMAL, "Recorded Activity (TraceLen = %d bytes)", traceLen); - PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Recorded Activity (TraceLen = %d bytes)", traceLen); + PrintAndLogEx(INFO, ""); if (protocol == FELICA) { printFelica(traceLen, trace); } else { @@ -526,8 +528,6 @@ int CmdTraceList(const char *Cmd) { " Tag Mode: Timings are in sub carrier periods (1/212 kHz == 4.7us)"); if ( protocol == ISO_15693 ) PrintAndLogEx(NORMAL, "ISO15693 - Timings are not as accurate"); - if ( protocol == FELICA ) - PrintAndLogEx(NORMAL, "ISO18092 / FeliCa - Timings are not as accurate"); if ( protocol == ISO_7816_4 ) PrintAndLogEx(NORMAL, "ISO7816-4 / Smartcard - Timings N/A yet"); diff --git a/client/comms.c b/client/comms.c index 97af830df..5beaa0adb 100644 --- a/client/comms.c +++ b/client/comms.c @@ -154,42 +154,31 @@ static void UsbCommandReceived(UsbCommand* c) { char s[USB_CMD_DATA_SIZE+1]; memset(s, 0x00, sizeof(s)); size_t len = MIN(c->arg[0], USB_CMD_DATA_SIZE); - memcpy(s, c->d.asBytes, len); - - - //#define FLAG_RAWPRINT 0x0111 - //#define FLAG_NOOPT 0x0000 - //#define FLAG_NOLOG 0x0001 - //#define FLAG_NONEWLINE 0x0010 - //#define FLAG_NOPROMPT 0x0100 + memcpy(s, c->d.asBytes, len); uint64_t flag = c->arg[1]; - if (flag > 0) { // FLAG_RAWPRINT) { - switch (flag) { - case FLAG_RAWPRINT: - printf("%s", s); - return; - case FLAG_NONEWLINE: - printf("%s\r", s); - return; - case FLAG_NOLOG: - printf("%s\r\n", s); - return; - } - fflush(stdout); - return; - } - - // print debug line on same row. escape seq \r - if ( c->arg[1] == CMD_MEASURE_ANTENNA_TUNING_HF) { - PrintAndLogEx(NORMAL, "\r#db# %s", s); - } else { - PrintAndLogEx(NORMAL, "#db# %s", s); + + switch (flag) { + case FLAG_RAWPRINT: + printf("%s", s); + break; + case FLAG_NONEWLINE: + printf("\r%s", s); + break; + case FLAG_NOLOG: + printf("%s\r\n", s); + break; + //case FLAG_NOPROMPT: + // break; + case FLAG_NOOPT: + default: + PrintAndLogEx(NORMAL, "#db# %s", s); + break; } fflush(stdout); break; } case CMD_DEBUG_PRINT_INTEGERS: { - PrintAndLogEx(NORMAL, "#db# %08x, %08x, %08x", c->arg[0], c->arg[1], c->arg[2]); + PrintAndLogEx(NORMAL, "#db# %" PRIx64 ", %" PRIx64 ", %" PRIx64 "", c->arg[0], c->arg[1], c->arg[2]); break; } // iceman: hw status - down the path on device, runs printusbspeed which starts sending a lot of diff --git a/client/crypto/asn1dump.c b/client/crypto/asn1dump.c index 34f4a9fa4..a0abdf3cf 100644 --- a/client/crypto/asn1dump.c +++ b/client/crypto/asn1dump.c @@ -24,7 +24,9 @@ #include "util.h" #include "proxmark3.h" -#define PRINT_INDENT(level) {for (int i = 0; i < (level); i++) fprintf(f, " ");} +#ifndef PRINT_INDENT +# define PRINT_INDENT(level) {for (int i = 0; i < (level); i++) fprintf(f, " ");} +#endif enum asn1_tag_t { ASN1_TAG_GENERIC, @@ -235,10 +237,13 @@ static char *asn1_oid_description(const char *oid, bool with_group_desc) { static char res[300]; memset(res, 0x00, sizeof(res)); - strcpy(fname, get_my_executable_directory()); + size_t len = strlen(get_my_executable_directory()); + if ( len > 300 ) len = 299; + + strncpy(fname, get_my_executable_directory(), len); strcat(fname, "crypto/oids.json"); if (access(fname, F_OK) < 0) { - strcpy(fname, get_my_executable_directory()); + strncpy(fname, get_my_executable_directory(), len); strcat(fname, "oids.json"); if (access(fname, F_OK) < 0) { goto error; // file not found diff --git a/client/default_iclass_keys.dic b/client/default_iclass_keys.dic index 0f7ec2d2c..829ba521e 100644 --- a/client/default_iclass_keys.dic +++ b/client/default_iclass_keys.dic @@ -8,3 +8,4 @@ AEA684A6DAB23278 -- AA1 5b7c62c491c11b39 -- from loclass demo file. F0E1D2C3B4A59687 -- Kd from PicoPass 2k documentation 5CBCF1DA45D5FB4F -- PicoPass Default Exchange Key +31ad7ebd2f282168 -- From HID multiclassSE reader diff --git a/client/default_keys.dic b/client/default_keys.dic index f764596ce..cd23d9a0d 100644 --- a/client/default_keys.dic +++ b/client/default_keys.dic @@ -98,6 +98,7 @@ fc00018778f7,--VästtrafikenKeyA, RKFÖstgötaTrafikenKeyA 314B49474956,--VIGIK1KeyA 564c505f4d41,--VIGIK1KeyB ba5b895da162,--VIGIK1KeyB +4143414F5250, # # Data from: http://irq5.io/2013/04/13/decoding-bcard-conference-badges/ f4a9ef2afc6d,--BCARD KeyB @@ -708,4 +709,50 @@ E56AC127DD45, EA0FD73CB149, FC0001877BF7, FD8705E721B0, -00ada2cd516d, \ No newline at end of file +00ada2cd516d, +# +# +D3F7D3F7D3F7 +## +237a4d0d9119, +0ed7846c2bc9, +FFFFD06F83E3, +FFFFAE82366C, +F89C86B2A961, +F83466888612, +ED3A7EFBFF56, +E96246531342, +E1DD284379D4, +DFED39FFBB76, +DB5181C92CBE, +CFC738403AB0, +BCFE01BCFE01, +BA28CFD15EE8, +B0699AD03D17, +AABBCC660429, +A4EF6C3BB692, +A2B2C9D187FB, +9B1DD7C030A1, +9AEDF9931EC1, +8F9B229047AC, +872B71F9D15A, +833FBD3CFE51, +5D293AFC8D7E, +5554AAA96321, +474249437569, +435330666666, +1A2B3C4D5E6F, +123456ABCDEF, +83BAB5ACAD62, +64E2283FCF5E, +64A2EE93B12B, +46868F6D5677, +40E5EA1EFC00, +37D4DCA92451, +2012053082AD, +2011092119F1, +200306202033, +1795902DBAF9, +17505586EF02, +022FE48B3072, +013940233313, diff --git a/client/default_pwd.dic b/client/default_pwd.dic index dd1364385..87423478b 100644 --- a/client/default_pwd.dic +++ b/client/default_pwd.dic @@ -96,6 +96,7 @@ FABADA11, //china? 69696969, 12121212, 12344321, +1234ABCD, 11112222, 13131313, 10041004, @@ -104,8 +105,8 @@ FABADA11, //china? abcd1234, 20002000, 19721972, -aa55aa55, //amiboo -55aa55aa, //rev amiboo +aa55aa55, // amiboo +55aa55aa, // rev amiboo 4f271149, // seeds ul-ev1 07d7bb0b, // seeds ul-ev1 9636ef8f, // seeds ul-ev1 @@ -113,4 +114,4 @@ b5f44686, // seeds ul-ev1 9E3779B9, // TEA C6EF3720, // TEA 7854794A, // xbox tea constant :) -F1EA5EED, //burtle +F1EA5EED, // burtle diff --git a/client/dictionaries/bmp_sort_keys.dic b/client/dictionaries/bmp_sort_keys.dic new file mode 100644 index 000000000..0f8acdcf3 --- /dev/null +++ b/client/dictionaries/bmp_sort_keys.dic @@ -0,0 +1,1000 @@ +002DE0301481, +004173272D18, +0058A4884CA5, +00BAC32761D8, +00BB79731B00, +00E8C85DB172, +02096124DA70, +024988BC4D5E, +0271B7C4B015, +028137A705DB, +02827C286AB4, +02C10DA600D0, +0340643D5E27, +037A5DA4682B, +037AC43CBD9D, +037B9B8AA219, +037EE3DE21B7, +0380A9A3CBDE, +03D10A75B56A, +03E8CD22E691, +04109ED8EA79, +04361330B35C, +043D8B66D569, +045E5588845C, +048DE5148DE7, +0490921D0194, +04B717BD92EB, +04D49C76623B, +051518B3301E, +0529E8827A52, +052B16064085, +05DC4016B500, +06124317A9A6, +06147D199266, +0670AEB833CE, +0686A9E6D6E0, +06A34E5E6639, +06B78AD0C4BB, +0710E7818AB8, +07121B8C633A, +07176713C0ED, +0793533A5087, +081D1B1C3110, +0849495E1CCA, +09429512046E, +0966C3B28E04, +098A92C3660A, +098B48278122, +099672009EEA, +0A7632943926, +0AEE126549DA, +0B3B8C2833BC, +0B733C13E2C9, +0B764247D00E, +0BE811559D69, +0C208AD4E4B3, +0C270BC0BDDC, +0C5D782CB183, +0C82C94EB11B, +0CCDE948878A, +0CCE39820AAE, +0CDE3E716B32, +0CE06C96DB4C, +0CE87813E389, +0D3385CEA152, +0D5C5B8BCC5B, +0DB0A87AB882, +0DE247593B93, +0E0AD1796003, +0E62E6CAC3D3, +106E2D6E55E6, +1096A7830C82, +11549C141AD9, +116A92C793D6, +116C31526819, +11C68052AAE9, +1234B5BE8E78, +1268C7D104E1, +12A21B5671A8, +13359D5AE9A5, +1426EC62BB6C, +144489B1056E, +14A22C112090, +14C9BBB5361B, +14EB6286AC57, +14EE72B27223, +153BB53ACE71, +157B03405B38, +15A45083D24E, +15DACCE8D5EC, +16124677BBC5, +16373A44D5D7, +1663659384DC, +167828B6105C, +16B25A453093, +1706B1BE25C7, +171B15888483, +17BC8EED9A0C, +17C6299D5A37, +17E9C4C416EB, +1804087C7166, +1841CC4E3E79, +18AB05761CC5, +18ADAAC2B08B, +18E566417E5C, +191390328752, +1A47959E7DB4, +1A9A970CC370, +1B095E78BB33, +1B1717043D2B, +1B1A054566D9, +1B4654AE9454, +1B9CD1ED3420, +1B9E00780953, +1BB6A9CE71E2, +1C1250A36A13, +1C2316079532, +1C2855ED7A10, +1CD1AE73CA8C, +1CD3D4E690B7, +1D0322005969, +1D09B23EB116, +1D67A32045ED, +1D89D900968A, +1DAE8D2CEA5C, +1E1873799CD7, +1E60CE7C5179, +1E6A67909B8D, +1E8516585792, +1EB0864E9134, +1ECE3D04A020, +2009828E4A21, +200A6A3AA65D, +20188A599582, +20267CB20256, +20628CA7D92D, +2077C980EB2E, +2089B5D68B27, +209481EC6256, +20B6691C64B1, +20CC5A00C677, +211473555436, +2170E9D0D448, +219529A90EDD, +21A5B6481B7D, +224A308017D1, +227D16EA455A, +22A1245CA266, +22A95CB798DC, +230E26964171, +231173B68E46, +2332BB9A2452, +234323BC2992, +234E50256146, +235C9338D5B6, +23789D9ADD0D, +23997DD240AB, +23A5BA53AD4D, +23BB58853461, +24CAD4153036, +24CE79506842, +25228ED714BC, +257377227B34, +2584287A0174, +2616192EEB22, +265C03B50877, +26D641E834DC, +27073B57132B, +279060E3DEE9, +284BA0A0A29C, +285C6604C5B4, +28B20331245A, +28D042242A83, +28DDD4C3E9C4, +292C2CCD157E, +299ABB519354, +2A41BE015C1D, +2A4A55052A51, +2A94CBCD7A6E, +2AB6536187C7, +2B2D2DC3D319, +2BD607CA70B2, +2C6C7957EB3E, +2C9E9E4D0895, +2D2A97DD45E3, +2D41850A8AA6, +2DAC030D1AB9, +2E12426D8847, +2E25AD1D6D8D, +2E2E85E0E6C9, +2E4340CC1C63, +2E6803BE2E11, +2EB24B573DCD, +2EC6450A47C7, +2ECDA9A5EA96, +2EDE1C155023, +302D5D37342B, +303645E47667, +303B30A460E8, +3048EBB8A18E, +30BD652BED24, +30CCE5ECB397, +310241E1CB36, +312670228372, +319E8895EAB5, +31E3A933BC4A, +3250D2E661DA, +32560224418D, +32589E221D10, +326657A8E9C0, +329AC7C59311, +32A091B89995, +3312C094BD20, +336C8CBA5AE2, +34240649314A, +3493D84E6317, +349A347186D7, +349BEAC5210E, +34A939B49EDC, +34CC7E36C8C4, +34D71347877E, +34DC25B4D0CE, +35895EB472C4, +358A6A398211, +360A08C66042, +36306A9CA571, +37284428A250, +377EC8A78B8D, +37BD90A68613, +37E602347133, +382DE6AB2D1A, +385D498B5390, +38B67589E47D, +393CCCCCDA4A, +39682B3E10B5, +397619525709, +39A83A32909B, +3A5834C46513, +3A70C7A4BCE4, +3A818D01E093, +3AA5AC1CDC21, +3AAE07339954, +3B4497052B42, +3B784087DB2D, +3B86A20C16EA, +3B8E321AB1B4, +3BC4A3099B0D, +3BC741376E71, +3C4C95D0A0C7, +3C84B55A5E54, +3C888A88C59D, +3D5C8240B2D2, +3DB004172BE7, +3E23271C1C15, +3E3188294ED1, +3E84144A770E, +3EA227893101, +3EB914E70076, +3EE6D4A85643, +40DABA780B41, +4119340759A2, +415210E0C6BB, +416D21717779, +41B1839829A9, +4201A36DE766, +4261A795D5A7, +42AA0B29626E, +430265958BEB, +4317C5C16EAD, +431D799E0C89, +4342794AD7BB, +4387ADE263DB, +43982124C310, +4436CB060568, +44449507B736, +44E858C82975, +459BC12982B1, +45AE5DDA9830, +45C414CDC347, +45CE4E504C06, +461744C8EABD, +46D012CA3BEC, +47170BD112B6, +47C43D5DD234, +47CD4AC26271, +47D410D1C7C4, +4808C5AD0115, +485BEEDBC293, +486001404A80, +488CCC60B70A, +49204E3CA169, +495657C78147, +4970714D53D9, +4AA715A0BBB4, +4B9901AEC16E, +4BE0B912A5A3, +4CBC34D10D83, +4CD3ACABC6A3, +4CE00134DE1E, +4CEB27151C49, +4D02A3D7CE48, +4D13683C7960, +4D1A263BA48B, +4D23919463A3, +4D9763C083D9, +4DAC8EE52C68, +4DCB89C7B2E6, +4DD9D9B637C4, +4DE6CB63A920, +4DEBA10CC85D, +4E232A8C2E30, +4E2879A411E7, +4EA7B0BED74B, +4EB8761372EA, +4EC2B23135AB, +4EC71DB088DE, +4EC9AB4B5519, +50179E461EE6, +50265ED9D468, +5047DC2975BE, +508357498162, +508BE54D326E, +510A8C52AAC4, +511335CC92CD, +518229589A81, +5184D04315D7, +51B4AE31B246, +526EDB918BEE, +529CE44BEBCC, +52A843082BB3, +52AE9A909674, +5313E9079489, +532DE5E7E0E9, +535508AA6C91, +53691569B669, +540A5B789761, +547B86E57596, +54C649075B57, +552249203848, +55430B5318E9, +5570D22DC66B, +55710879E113, +55D2E4AC0446, +56207539825A, +564664475726, +566441C5C28C, +56A7930913C3, +56C944B04618, +56D455A8BBEA, +5726991C8C28, +5726AA3BE37B, +573314090BA5, +577C31903867, +577C528E786C, +57AD9604ED24, +580C377283C7, +587329CE3EBE, +587C34557B36, +58B11E803B58, +5902E4DCC95D, +5A060A64C535, +5A36898CA7C5, +5A4740D952EC, +5A6ED7966868, +5A99578CAA13, +5AAD6814E68B, +5B065568048A, +5B6CE0B3AD0A, +5B70E0B11758, +5B926E3751EB, +5B9CA63C4267, +5BDC1391B289, +5C1D3898D537, +5C34B8E4A456, +5C36456EA1E5, +5C43A75C65A0, +5C5752328A47, +5C9D20250D74, +5CBA3CEE351A, +5CD5E98A2864, +5CE0EB9C01B6, +5D384E6A4145, +5D9DB8445155, +5DE8717BB640, +5E1A4EE98748, +5E45A227B391, +5E8E50B3048B, +5EB0EA0A9412, +6032C47B7676, +60E0C84ADDEE, +612A447A2149, +612D81821854, +616B820EAD01, +616D75A4A022, +61DE2B085AC9, +62312EC272A0, +6232C5262CC6, +62B7C7C9B0D0, +62C531C6E29C, +63E6AAAB4433, +644ABCC3DD12, +64AE7BEA1784, +6515B38077D6, +65972038CC25, +65E120DE5E55, +66141DDE8320, +66718BD91332, +668082242328, +668920AEE063, +6696C4332D46, +66C9880D1DC2, +67150CB11E95, +671737BA0054, +673551D0A99E, +676D682C4336, +678B98AA2E86, +6847808E63EE, +6887A122AA62, +6888C514DEAD, +688BD5B7B4E9, +68A99E258692, +68C312391560, +68C9D33E3735, +6900A069E3D7, +690155BE8D8E, +69174742042D, +69B9CE233517, +6A0B123D7595, +6AB8E2B49E25, +6ABD4C4A72D9, +6B1CC539A1B2, +6B30B6B0925D, +6B638C1C950D, +6BAAAB1D4589, +6BAD01EBE736, +6BB4ED5E1682, +6CA178E036DA, +6CE210B529C4, +6D23D505D2B1, +6D3CBD12BC6D, +6D83563EB521, +6D98AB9CCC71, +6E3D7366E78C, +6E5582237608, +6E6602904925, +6E77B8EB6444, +6E978A7B16C6, +6EEC05EB651C, +70284824B26C, +702CDACE0C14, +704E1B85BED8, +70BB123776D6, +70CCC3A2D7C0, +716A747CB931, +7173E199A420, +71BC9C9E31E4, +71CAEEA3B771, +71D8BA423D55, +72253C7DD951, +7260377CD286, +7280858E8B20, +72913BDAB647, +72B5B87BBC6E, +72C83B1D098A, +72DA8050A38E, +735C2AB60A97, +736B602A93D9, +738D7833E7DE, +73E7B22D6E54, +74133B1E2DED, +74A929877793, +74E3670C045A, +7531E3E2A41C, +7542A9B65EB4, +7564993C91C7, +760ED0AB626E, +762E0E021E38, +763D7E6BB40E, +764B38E2903D, +768016001C8D, +76A616C3D42C, +76AE99D9A294, +76BAAA710D25, +76E3B23696BC, +77322DD2E184, +77B40902B6D9, +77C0AC14972D, +77C1CE0E7674, +77D7B7E2C8BA, +78279397A68E, +7836593AB838, +783859EB51A6, +78CCDB50C193, +7932684154AE, +79604362370E, +796630ED27B3, +799E4E270953, +79A00573947A, +79B798D66B01, +7A0455D0A7EC, +7A33D19B7248, +7B0A8AE18817, +7B0BA045AB35, +7B0DE8504D57, +7B21781EC649, +7B7224C1AB79, +7B90C2BA9B23, +7BB90D382672, +7BBC9DC92836, +7C09DC408C47, +7C418B493454, +7C491D518242, +7C7A86CC727C, +7CE836EBD228, +7D49042C530D, +7E5744EC286C, +7E680A48C383, +7EC45CCEC35A, +7EDADA19EB57, +8005BD088847, +8022E705B640, +8031E3565825, +80499BAA5959, +807466CCBAB5, +810518578380, +810D24CB13CC, +812B02C34A64, +8163A5DDE1CD, +8186CE2B363E, +81DE6062B9D7, +822017D8929A, +8247C78188C5, +8270D538D5E8, +82D8E8DDE296, +831207CA6E8A, +83378A077357, +83A05B477535, +840160379EEE, +84044BAB78A7, +84366C6D7781, +8442CC9AA777, +8470AAD30447, +8498740493BB, +84A35A698E93, +84ABDE484425, +84B24DBB9A67, +84B723B2A237, +852BEB133D74, +854501E98239, +854A0ED2E77D, +85A066D39785, +8619557091AA, +86228C3742A4, +8637BB3BA795, +8642D9310B46, +86538085966D, +86EE9C410811, +870A042C1B34, +873B47C457E6, +873CE44DDC6B, +874D123262E7, +87513C960770, +877641436923, +878A091B74B7, +87927467808B, +88C2E39B5990, +88D252AC1A8A, +891EDA20BDEA, +89267DEE07ED, +892CB89ACCC6, +8A2423E9D100, +8A6BC2E3811B, +8A8EB5771EE9, +8A906B4B3211, +8AB21B524C5C, +8AB823BDC2AE, +8AC3B2ADE77B, +8AC4317D049B, +8ACD6B86EC44, +8AD966CA3B4D, +8B0A3B3DCDD4, +8B1B6C705C1A, +8B1C75E27153, +8B2A5E0332A1, +8B6216E412DB, +8B7CCA9DB004, +8B9999AE9703, +8BABAD9A65C6, +8C32D0AE3DB7, +8C99807368A5, +8CC1133D7D5B, +8CD2C872187A, +8D0563B86DD4, +8D43D81E37B4, +8D96A800B21A, +8D97B475C957, +8DA62EC0C524, +8DACA1BC0636, +8DE3B131D728, +8E55316D3B3D, +8EE497C9A869, +90210DDAB57D, +9026977EB8A6, +903AA4305025, +9083158A49A1, +9092D12E7967, +90D8713352D1, +911E097A27A9, +9140EC087241, +918A67D05479, +919B1D357E91, +9210BBA2AB26, +9224B6555E30, +9226D4D1236A, +922E7955CC67, +929CC86B1B26, +929E1556110E, +9302DEB79C5A, +9384841B4702, +93B4BD1CB47C, +93D985D55712, +940B37939AC6, +94673AE73823, +947A8147E0AE, +94CD6A4B6391, +94CEEAC5A8D7, +95ABD3A7C631, +95E1C233EDE2, +9607AE17AD09, +960C98566E52, +96435BD1D29B, +965D66E19245, +965D72659982, +9695167B4149, +96D0C3996714, +97274C21BD6C, +973186B345BB, +973A28C983A3, +979686C51AB6, +97992CE2DD31, +97E9D0C89DA8, +97EB8A44C49D, +98314DC363C5, +9860DC044565, +988D023C15A5, +9917BDA7B4D7, +9996A233442A, +9A2132B5B625, +9A694755A978, +9A7911ECC275, +9AA1E6CE588C, +9ABCCD2AE7C7, +9B39A60D3841, +9C0630361CC5, +9C4E19AB64B1, +9CE96BADE4D8, +9D442B28BD11, +9D4C35AE1A08, +9E02910C691A, +9E46407C9024, +9E74D104ACEA, +9EDD416A7912, +A026642D13AD, +A12908B38536, +A16EE9666D5A, +A199132A4043, +A1AEC2B58BBA, +A1BE42A15EDE, +A1D0844C2C63, +A1E0103A1879, +A253602B9445, +A2B019B46CB9, +A2BBCC3B546C, +A2C325A73A9C, +A2CB60E815A0, +A314B97C1A6A, +A3647146C335, +A3A580799BB4, +A3D30CC8EB97, +A402B5137D86, +A42158CC74B5, +A435DD64AD17, +A4693D21013B, +A479A91EED49, +A4B30D146A01, +A5142D626200, +A54056E87CBB, +A57DBD287491, +A588C918E327, +A593071D4758, +A5CC0EE7B9E3, +A6375E98A5B5, +A666347B3B4B, +A6A203994202, +A6BAE1A1520D, +A6E9885AA49D, +A705087E89A8, +A7072D4324C7, +A745AD7D6789, +A750456E7C5E, +A783A8774651, +A787C822020C, +A78BB575EAC5, +A7905680A254, +A805534D84E9, +A86C2595A1C3, +A89903B6ADDB, +A9182707A219, +A9391782A846, +A96B08E3A50B, +A98DEB0733C9, +A9C37CE71D23, +AA2D69C757D9, +AA4E4558A9EE, +AA6C835C9124, +AAC0C35C43EB, +AB30CB2CB354, +AB6191DB240A, +AB8953D3560C, +ABBB521319E6, +AC47461358D7, +AC58C25A1559, +AC7D4B201D92, +AD061A23287D, +AD105D52DB36, +AD4EA84D7185, +AD5038D15490, +AD97523144B2, +ADB24E78784B, +ADCBD453B232, +AE516A187825, +AE52116C234C, +AE817239CAB5, +AEA5A5A0E46B, +AECC93678543, +B0452769A83C, +B04D71906C60, +B0805C191424, +B09172DDBE43, +B13AE369390C, +B14080E570D1, +B1419B62772C, +B14775DEA2E2, +B188BA649EA1, +B1BB0DB95C67, +B1BB19BDD424, +B1E8B5054DAD, +B1EBB537CC0D, +B2174092CDC5, +B2554CC8AD6E, +B2C5A2E88304, +B312E56ED250, +B37B48D8C1C5, +B39C699CD208, +B3B121208E34, +B3C3C6E4395B, +B410B958C3B8, +B4204546A74E, +B45171C5A67D, +B4B103E693ED, +B4DACABCAB07, +B506567A2B84, +B51083D5C2BD, +B54D7674CB90, +B570E5EA1DA3, +B598984AD584, +B5D7E1135821, +B60D053A36D9, +B63957593E23, +B64558CAC0C9, +B68175BCA864, +B6CD1A3EC5BC, +B72468A7710D, +B75176C82A8B, +B7AA0CA5D94A, +B7B9D7E523B8, +B808D87AB75C, +B93A6432E51A, +B941A9D99B6C, +B9DA40920237, +BA6C2E10086A, +BA7384AB949E, +BA8DEEE045E8, +BADC2149EC42, +BB1924266B36, +BB41640E6340, +BBB475DB2B03, +BBD4C4699719, +BC0B2C897267, +BC7BEE6B71C4, +BC8B21AD8802, +BCA2D8118631, +BCB7A7006400, +BCBC6637499B, +BCBD2B8BE4B3, +BD213E28C568, +BD32E4EC7080, +BD401D63C3E9, +BD463C3693A4, +BD749E85586A, +BD7CA11B9551, +BD96355CBE36, +BD9E6EB7B524, +BDADE6111218, +BDB576D1E88C, +BDB5DC09C522, +BE19C75D6B7E, +BE5B3ED935AC, +BEA20C972E70, +BEEB4A159B37, +C01E8740DE38, +C0411C28857D, +C045544AD1E4, +C04660B76831, +C0C4CA21B876, +C0E0E092C8B4, +C0EE394D3D95, +C14601C6B411, +C16EBAE928B2, +C189A791A85B, +C1ACDB8C1890, +C1C55A7A99EA, +C1D72A47755A, +C1D8B91D65AA, +C1E6149B386D, +C22D8E2B1E37, +C23E999B6298, +C314E31A670D, +C3D275A9B8C7, +C3EE19B61C89, +C427B93DC2ED, +C443EEC4330D, +C477B966D328, +C4C6CAE4784C, +C55875BCB82C, +C581CA998910, +C5ABC0A455C5, +C5BE33E6B1E2, +C629E0D34581, +C65194543D6B, +C67B8E869D90, +C6BC3B9CCB41, +C7034BC581A6, +C748500B6947, +C757C15E9E0D, +C798A8465ACB, +C7B6702AC17B, +C849133B7CCC, +C870C98A4E91, +C90B7AD266D3, +C90D996C3A2D, +C953797CCE61, +C9639352EEC8, +C983685AA86B, +C9CCA6D095A3, +C9CE81D47EDB, +C9D449AD9970, +CA0D9CCC4C38, +CA277AC09859, +CA56EB045188, +CAB92B865BAD, +CAE8572C2657, +CB1CE185575C, +CB2ECC3D9C22, +CB642A081A89, +CBBAD2DA0EC5, +CC1B5BD45315, +CC2C02300D34, +CC559969D0CC, +CC5646BD7AEB, +CC6A93BD93D1, +CC726DD08765, +CCBBAB6504A4, +CCC1EA3E27B8, +CD16EAB946E9, +CDB4EEE02E14, +CDC21E1E1EC7, +CE09B3870EA2, +CE5AA0C8B5A8, +CE63DE29E069, +D0368B24CA49, +D0489010A72C, +D075379A21A6, +D09893B4EE04, +D0A7A2787570, +D0B8C06C02E4, +D106E94A4C3B, +D11E7D1BBEEA, +D12B25B8DDE2, +D1972D6CE2C3, +D1B91D224946, +D2752E53679D, +D35B2B75CC52, +D40E935117A2, +D4C37528DC05, +D4C818A5455E, +D4CD56DB8AEB, +D5190BD5CED6, +D55E5AA3406D, +D576E9D856D9, +D5E444E9D82D, +D61A3231790D, +D669B3AE1E11, +D6C075899D06, +D6C3503456C4, +D7AC70A05A0C, +D80A37B6D7ED, +D82E6938C58C, +D85E51344EB6, +D8809EB9BA7D, +D8913C2D48E9, +D9109460D912, +D94E36427E20, +D97E55B1816A, +D99425130C1A, +D99C3222A190, +D9A207103ED7, +D9C70CC5818A, +DA3379D12773, +DA705702248C, +DA818C56CE43, +DAE1888DCC0B, +DBA0A2DCA8E0, +DBD9799E15B1, +DC242193D7E3, +DCB5AC62946C, +DCB75AEC61A0, +DD6E0587A821, +DD7B1A7C6A82, +DDA22A189095, +DDDAE53AA711, +DDE7304E78B6, +DE1B4DA681B9, +DEAC67E2D7C1, +DEB7D7E4C62B, +E127434AB3B7, +E1ACC6742AB7, +E1E59574ADBC, +E1EA6BAA03D9, +E222553A59A2, +E2230B8E84C9, +E33E807EC3BA, +E341574B2E32, +E42868808B70, +E43562C624B0, +E43D54DC3511, +E466090D2123, +E47069DA0C44, +E49DD6062901, +E4ACA0ADBA0D, +E4B976AD6687, +E526BB7888DB, +E53354B71B10, +E57581CE8617, +E61A1DA5A60E, +E6293BDA5EDC, +E64C2A07CA9B, +E6600C4D6A44, +E6655B6425DC, +E6BADC631036, +E70143BE0091, +E75E07A010D1, +E76962E3B8B4, +E8028A6DCC90, +E80C5E3E8227, +E8779E40450E, +E8A9E2D87D36, +E8B5A0BDD993, +E933DA9735C4, +E93A2E63189D, +E9447637E40D, +E94836269887, +E94D82A564BA, +E98DC3B561B5, +E9EB2DE57AE9, +EA490920877D, +EA4C494C9353, +EA9B1695DD91, +EAD0E31A6834, +EB16B6462B66, +EB276C9AB68D, +EB3C9732C3BA, +EB44DDC408CE, +EB8536C958B2, +EBC825C186B3, +EC1A55BB58EB, +EC2B12107313, +EC8CB5758097, +ECD4C42EA3D1, +ED22B7115435, +ED2CE17A590C, +ED65A9B6469C, +ED6748113E0D, +ED8CEB8B7102, +EDCE0890472D, +EDD4A2EA7493, +EE17C426D25E, +EE487A4C806E, +EE5931913A8D, +EED56840AEBA, diff --git a/client/dictionaries/icbpm_sort_keys.dic b/client/dictionaries/icbpm_sort_keys.dic new file mode 100644 index 000000000..b4a635d44 --- /dev/null +++ b/client/dictionaries/icbpm_sort_keys.dic @@ -0,0 +1,1001 @@ + +00383D96411D, +005307DB7853, +009A4C4C6C49, +00C447B8A2D2, +01124119AB54, +0117BAE4D8D9, +018861488381, +0267B4922681, +02974B9786C9, +02A46AC9233A, +02BED876BD48, +02D8A7729ED3, +02EB32B92D30, +03C34821DE9A, +03D87397E9A8, +042CDEE5D0BA, +044ED79417E1, +04524659496E, +04602A40C037, +048451A79DA1, +0490AD0C9283, +04E16965C142, +05138E278443, +052B99EC186E, +056D4B5D2915, +0578E317C419, +05865124E5CA, +0599E014139E, +05DB68DB9364, +066C127C208D, +06966B31A285, +06B577E0E480, +071B57D258CE, +072B300309C9, +0759955331EE, +0769855EEC13, +079B8DA54DB1, +082B68A67491, +0832E4783600, +08506533E741, +0853A982D793, +08629D1DD0D6, +087C0CDA3B46, +08AE4ECD7CE3, +0965220D2ECE, +09A14A80754E, +09ACEA48DD0D, +09DB8EE5458C, +09E6CB76C080, +0A44A754B592, +0A7328887DC2, +0A906663EE1C, +0AB08938E3DA, +0AD8AD0739A6, +0B00220EAE75, +0B1960681E79, +0B31815E6A7C, +0B3690D4B122, +0BB8414CB6EA, +0BEC525E3463, +0C296648344D, +0CB6CC83AC45, +0CCAD03DDBC6, +0D6C26AB25CD, +0DC9143735D1, +0DE8A36CBBCC, +0E175033BD77, +0E6478123917, +0E7D4AC83133, +0E8420B04083, +0EA607E1C4E3, +105743704432, +107A6AB6B305, +110BB6D5539D, +1114A47CC39A, +116AA873ACC8, +120616C6208E, +120C83C06317, +12343D71106C, +123A082E2AEA, +12E50BE60524, +133DC845505E, +138153A4351A, +1395C108B6B6, +1428C04BAAD1, +147D93848C70, +14A353C60820, +1504C1846399, +1523A1E39D03, +1532A2511A8B, +157308368E8E, +16065CC411E0, +1637D8ACA71E, +1639134699C7, +167358BB268E, +168DE72B3B5A, +16A05D5C31C3, +16B4442EAE97, +17197B247A4A, +1774DB1A8CA1, +17820DAA47B2, +1782BEDBD347, +17B561AA82B4, +17C548CBC3A6, +17DA5C873BC5, +18025130661E, +184B95B4E3C6, +18A3196D364B, +18A97BD26818, +18BE810A83DD, +18C3AC2A7E90, +194D4E1DE89D, +196E279BE9A9, +1A2C8D855336, +1A3A76ED470A, +1A55D4849951, +1A9872D00EC9, +1ACD5433BBDD, +1ADC527D5BDA, +1AE29C8CD672, +1B14CAC3D0C2, +1B20A6E1D06B, +1B30A7825B23, +1B3E45AEE657, +1B75E7B007DB, +1B9DABDEBAE0, +1BAB19D01495, +1BD3119E0363, +1BDA0D87A575, +1CD38D77090B, +1D12BBB575B1, +1E1A0DB8729C, +1E2DE60A477A, +1E3C71643766, +1E6ED46CE258, +1EE60A4A8D22, +200D45263629, +2013899194BB, +206CE78E0C6C, +20B51C977E54, +2142B57D369D, +2172D827D3E2, +2178ED80D581, +21B4BE97AE07, +21B91A26133A, +21C7650673CD, +220D815D366A, +22C2176E1CD6, +22C3AB41B123, +233D7B324CEE, +2340CBD61A71, +2348251AD23E, +2381B8214025, +23BAE8DA1AC5, +23C317B8D6DA, +243A41574A39, +248EA5E91987, +2491457885A7, +255A9E590BCC, +257192699E32, +25892216C620, +2595E5B1DE76, +25AE69DED1B4, +25BA8775B3C4, +25D967D4DD35, +25DB996D56ED, +25EE21CDE4B9, +2625E408276B, +26B744C673DB, +26C6D38B8257, +26D787613684, +27689527E201, +27743B5A5736, +27D1635ED1B3, +27D5B8D2642E, +28035CA5B300, +2812EB6A427C, +28133B46730A, +281499DD16A0, +281DD9E6C98E, +2870E08CEDBA, +28B8685B1B22, +28C3D17E4DEC, +2953C63E9E58, +295D3C9A8B28, +297B74853CAA, +29ACACC2828E, +29EA97BC4A6B, +29EB3CA1C0DE, +2A079CC2AD37, +2A27E0602400, +2A45A0D8D6EE, +2A47CDD3A322, +2A4C4DB1D71D, +2AA82B4B6711, +2ABD68BDC5A3, +2AE7BDB10CB4, +2B051C90BE82, +2B490231E063, +2BAB94372644, +2C03252C10E7, +2C3EE5E98804, +2CB671E6365D, +2CC55B46705B, +2CD09D3C0A1B, +2CECBC323E31, +2D302827C9B4, +2D716C9C467B, +2D8856109732, +2E15681A4355, +2E79209B9519, +2EEE063290C1, +301C9AA3DECA, +30C520D6A2B9, +30D6324910AB, +3113AADC9D6B, +3124ACA5491C, +315AD0D6E6D2, +31A16DAC864D, +31EC44581294, +32DE3CD81C24, +32E532232C29, +33256E443128, +33293485AD61, +33305B0365AA, +3343B72BAA71, +3372C9C5D4AE, +33754E0D1687, +33A444334869, +33B54345C32E, +34002AAEE45D, +343C556CEE59, +3444DDE6D7E5, +345B62452538, +3495A04A9270, +34EB673C863B, +35123500C1EA, +353A7167576B, +3599856810B2, +35E7DE9899EE, +35EDABB506D8, +36C54912D10E, +36CA0101B6DC, +36D268442846, +373E5827E0B8, +376D6C446746, +37E2EAE635B5, +381B0A70E135, +3862B259DC71, +386676C44A13, +3905679DEEC4, +39070618BB17, +394181105544, +395D38815892, +39A00E856381, +39C0E2ED99B5, +3A1E82E2CDB7, +3A5D13E05B6A, +3A6DE2081CDD, +3A8498924010, +3A9D49E8BEB2, +3AD0EE1031A9, +3B052E65D40A, +3B4986981212, +3B4C51ACC53D, +3B99486097C6, +3BB36BC22CE4, +3BB4B3025B79, +3BBB7BD8D7B7, +3C09C971D835, +3C4A12E7A107, +3C633B3474DD, +3CB9E31D6022, +3CD344A7EB21, +3CD8C6705954, +3CE887B9D091, +3D5EA1C71953, +3D89120EB993, +3D9C3245AE76, +3DED9D496478, +3E0913A96E74, +3E34909990B5, +3E7DD7953DDD, +3EEB33434C1A, +4015D16B5C1C, +401C81A72C56, +40E7B8D60242, +41016C0CB8DE, +4124864B0D40, +415BAA0CAB15, +418184DBB4A0, +419513740558, +4195EE7238CC, +41B727883B27, +41BC44A8C3C6, +41DDC3A48EEA, +420445087613, +42068108DE36, +4245921D73CA, +42A959953C45, +430E67734C18, +4314D9D03B95, +43166BCA83EB, +43400A093A7E, +434CE764DE91, +43595AC786EE, +438099331C1E, +43814087A7B5, +438C3CD95B58, +43B3E895B281, +44074C461042, +444D37149B20, +44A04DAA30CB, +4537282554C5, +4584EACB6087, +45DB3799C150, +45E599AE38EA, +462305611C4A, +4636195CDA2D, +46752993E2E9, +4684316440D6, +46C7246C1958, +4751A5274848, +4761E34CB054, +476388408D8E, +478947735B45, +47AD81972D5B, +47C23398EA52, +47E9D4D4BE35, +4812AEC4B01A, +48276645A4EA, +48644467A214, +489C783B3514, +48C860AA4B74, +495C6639575B, +49681C20A00D, +49E8249DD677, +49E93C110AA1, +4A24470C19C5, +4A4755BC4A2A, +4A4D5E3A9011, +4A65D627625C, +4A6B36C5BCCC, +4AB725ED89B5, +4B39E3923D0D, +4B59316C10E0, +4C275C8BB2DA, +4C2E9455D296, +4C44DB1D0C3A, +4C67059B0006, +4CA30E1A298A, +4CA74DAC7C01, +4CB212D72D57, +4CD3B228EBB4, +4CE1972E090C, +4CEE1794E0EA, +4D06DBCA167E, +4D2CC85EB338, +4D40BC7A44DB, +4D769DA515D3, +4D79C95DAD2D, +4DBAC8ECE167, +4E3CB839E87D, +4E3D548E1267, +4E8250E29617, +4E94C7962769, +5038884E4178, +505B5A8EB20A, +50642C36DA00, +5083664D8C09, +50B77DA96DE2, +511E269A9BAE, +51798AEAAE9E, +51ED5833AB6D, +525335E4CD34, +5261CDDA279E, +526E55542A54, +529C16A720AB, +52A230B1C50E, +52AADA374811, +52D20D6E3E35, +534BB4A6984E, +5352CCC3DCD2, +540B15E8019D, +54AA2915E815, +558DB8891A90, +55A691710B48, +55D1E91B1D35, +55D95774E9A0, +563C6B96D59D, +567032E13B54, +56741B108D22, +57029D991123, +5714E9D33034, +5734CD8A65DA, +5785EE00049E, +57B8B111491D, +57CC9D0AA32B, +57D7D4D746DA, +583C936DCB4B, +586B470A43B3, +5876E1D34183, +58B6AE62DB88, +58C35C8BC9AB, +597E98000ED4, +59DB4DBB5D7A, +5A150653E624, +5A211CE57C4B, +5A6272CDBE9C, +5ACB8043C10C, +5B41CEBC2213, +5B59BCC4321E, +5BA03479BB8C, +5BC64C42281C, +5C9B1A8E31CD, +5C9BD0AC1DB1, +5D223E990AD8, +5D8C3A5C5761, +5DA57EACA38C, +5E41DD5D1154, +5E6ABB51EC75, +5E7CC04C3A58, +5E810C48C8D8, +5E8943D9A836, +5ED616273468, +60100DD0E023, +6033A1C0E431, +6088A566CC60, +60B20ADA0471, +60B8411D876E, +60C742D8D9C0, +6135433CC5EA, +6153ADD80A15, +61718ED2C94D, +6175241B035A, +61780BCB0C57, +61B701698050, +61C4E56629A3, +61D59C284952, +61E57B490A55, +622E5E0812D7, +6251CE7E547A, +62953A89B137, +62D6EAA06CD6, +630228659A47, +632931BE8EC7, +63539BB89DEE, +636CB69BB10C, +63783393E20D, +639DB16995B7, +63AA2A5B076C, +63B636458E94, +6443E64DCC4B, +64695084C575, +6493D06D5710, +649B302A97C5, +64B8632B54D4, +654BACB21C3B, +65A3D5823819, +65DEDABD1B34, +6608944EE186, +665B8B24C20D, +6685D0BE19E0, +66933A9E7982, +674C7BB59A16, +675E35EE359E, +67AA98E362C9, +67D47C1B6425, +67DE22850162, +67E8B986B2A7, +681EA28BA6CD, +6828B52B6507, +6874E54471E8, +6879B1CA44A3, +68C00A810D41, +68C9E8AA5C3E, +697A8ED07418, +69B5357A617A, +6A7B3A7B6735, +6AA40421D23C, +6AB676B4DB9D, +6B00420BE41C, +6B0B7B967871, +6B9D041136B4, +6BB1A14768A8, +6BCAE24D9700, +6C0458728774, +6C57CBD51995, +6C5E10B86CDE, +6CA491A8C7B8, +6CBC25C1DA2E, +6CD430D99958, +6CEC27647CC0, +6D4D29CEB9B5, +6D6E9A6B725D, +6D801AC74572, +6D97408C6D60, +6DDE6E871C64, +6DEA848B6195, +6E05B5C44A54, +6E751666AE9A, +6E7DBCDA05B3, +7004BA1763ED, +7016ECD01559, +7076D48D5E49, +7091621EA016, +709311997549, +70984C14D3DB, +70D73BE22CDD, +70D9461C5E90, +712BC18422CB, +712E6CAA74A4, +7164042BA89E, +7175E14A4D62, +718B39561350, +718BDA352E28, +719B1418323E, +71A8D54D82B3, +71DC30168C27, +7221E016597B, +7234CC6BD65D, +727A80DD5296, +72B393D6E8A9, +732C9BE4DDBA, +736B4A835B2B, +73EA81968900, +740AB5126199, +741A31054E6B, +74498C1D4B3D, +745276053CB6, +74684B0B4B1D, +74772915E24C, +74A24BE33BE2, +74A778236D5A, +74AA58008A31, +74C27A96CB3A, +754AD5773746, +756C15E54212, +759403A563D8, +759D2130312B, +75A0E10D8C84, +75A807E46B96, +75E454785C6C, +76078A25C088, +76140285B768, +763D835BD5ED, +767C33468C72, +76962C07EC9E, +76984E62CCE4, +769AE4646931, +76E5DA67A1EC, +7708D5CAD58B, +77383BAA4D90, +7789E646A556, +779A248E098C, +77DB71037644, +77E0A57DD456, +7853D464E2A4, +78EA6EB04463, +7909427EC8B9, +7910A31ECD19, +79271963B6E8, +793D98517D33, +79B7A4C58DE0, +79B9148761B3, +7A2893B75AD1, +7A4C61A1B48D, +7A7469B69C6A, +7AA84B1A527D, +7B00211CA416, +7B118EABC7BB, +7B1D9A2E22AA, +7B583D350740, +7B9D3A6BD061, +7C2DAC2CC775, +7C4CBBD2DDE1, +7CD52B5B8E77, +7D412100532B, +7D46C149DAD9, +7D4CA630E229, +7DAC0E83D335, +7DC935E220A0, +7DCA66BACA13, +7E30778792D2, +7E43C3BAB3CB, +7E475BA186E6, +7EE2A624851A, +80CED5362B2C, +80D2CC78E10B, +80D62251E20C, +816875D55ED1, +81950D0517AC, +81B519418C3E, +8211571B9D16, +823C7CC6E06A, +826DD63B9032, +827303C574B5, +82C5ADED4B81, +82E344329D34, +83588E140165, +835D33B48113, +8384148AE52D, +8394B57153D6, +83A0184757C0, +83D86835B48B, +8502EE9A7E85, +852C2B72659D, +8534A6CE0911, +85ABD94CD7A9, +85DA8099CD7E, +85E0B6B26945, +864CA2A6BE93, +868A33A44447, +86EDEABCC357, +87DDD5A188EE, +8830379B50B7, +883803A3360C, +883DA78EC87D, +88482A12C2C6, +888EBD3DB945, +88D026793359, +88DD4B7C5991, +8931DC3733D4, +894D8E2DCDEE, +897B845C2680, +89B638BD909E, +89D2C28BE578, +8A1869848D1A, +8A39D09508C9, +8ACCC7290C8C, +8AD8B41EC218, +8B028B7E6D60, +8B6A95C7D2E2, +8BA1226EBA21, +8BD586B21ABC, +8C0EA504B635, +8CA939DC6DE4, +8CAE5D688443, +8CEC639E64DC, +8DECE0DD29DE, +8E0EC762E883, +8E958D8B8C52, +8EB64D710C88, +8ED4A17717D9, +8EE9D9C03A0D, +9014E1430AEB, +90965DEBC8B9, +90E56E616DDD, +912CD8E04437, +912E33563E1B, +918048032247, +919402EC39CB, +91D28E2B126D, +9216EEE5B677, +9232215296B2, +925A070E9096, +925A5521D48D, +92CC200886A2, +932035869655, +937144459949, +93B260DBC70A, +94552B863E37, +95327A0A3600, +954275CDD7E0, +957E6EE3EB55, +95B920CACC84, +96382E1C8E12, +964E8E5338BD, +96706C8D6ECC, +96759A0D5566, +96D5213C5DDB, +97300764797A, +973BDDBE7434, +974838AE17A0, +9752A6B316D5, +97926543783B, +97EB373096CA, +982D6054B83D, +989D127BD496, +98A54AD58A43, +98A92128364C, +98CD5AA2A4DB, +98E8C543688E, +99207A00AA4A, +99243E754CB8, +9925893ABAC7, +9937553A965E, +9976E6ADE0C9, +9982E3E6A4A0, +9984C1A3229E, +99C487AB85EC, +99E2A19C9673, +9A05EBE41D7D, +9A138D1A5CB7, +9A179148B824, +9A6EC0A9ECB8, +9A720CBD7BB1, +9AB22BBDDD87, +9AC43B5A06D8, +9AD8150BE648, +9AD97423190D, +9B4ADDDEB749, +9B7603341727, +9C45237377BE, +9D090AE1A15E, +9D59641E40A5, +9DA4528CEB8C, +9DA728164176, +9DAC62A346B7, +9E0E9D983B9A, +9E5271763D3D, +9EE95586D024, +9EEE39E00CBB, +A04671256EE2, +A091485B4B5D, +A1B5577ED36E, +A1EB280E3901, +A2789E1DD888, +A293A90AE72C, +A309E3AEBDB9, +A3196E77B072, +A31E72DCC826, +A34DEA01690E, +A36031D6ECB2, +A38044A3E18E, +A421D7A04C4B, +A424C686CA39, +A44590A779A5, +A47AD3895C63, +A5041E8B8E22, +A50DC0830AA5, +A52B8929D665, +A5BCBA6BE592, +A61D5137E6B3, +A6344C0418DC, +A690A817B9D9, +A7E3B3459240, +A81E6D3C8E11, +A8C0BE436685, +A8DE205120A8, +A91E2BE6C308, +A9258D6B06B5, +A992B5E070C1, +AAC6E3205D48, +AB101546634E, +AB6EE0761ACA, +AB9BCA200547, +AC4BC5B2D3C0, +AC7A0B47B03E, +AC88B26AC1D0, +ACAEB3456AD9, +ACB906631D8A, +ACE07B45C0C5, +AD1992AE37CA, +AD5586744A60, +AD674E4ADB79, +ADA093B06831, +AE7C3AE5334A, +AE9EB8CAB2C3, +AEAE9E5CE65D, +B002D1BDC29B, +B0463E703098, +B063B209BB20, +B0788BE3BAA4, +B0C3B3299090, +B128298D9073, +B160677E7035, +B19D3D57176A, +B1CCDB7999B9, +B231AA398B90, +B250E9590215, +B28BE0D819ED, +B292C9554CBA, +B2D8485C2460, +B31763D9D0DE, +B328014DDD6A, +B378C424C9E2, +B3D8C03C78E0, +B41D18E3B980, +B46824B972E9, +B50383A32302, +B509D631967C, +B56CA847A7C3, +B56EC9A20D28, +B5B763215C82, +B6550EAC573A, +B66060201705, +B6614EBEAAA2, +B6A18CBD4DA6, +B6ABB62E437E, +B6C6558E58CA, +B7009204D512, +B71D5B22B1C2, +B7392DD1E497, +B7709ED7CE60, +B7A26320A491, +B7A9DA22E9C6, +B7DEC863369D, +B7E9A91174CB, +B8178A34E2DC, +B83092098A7D, +B84C50E56DEC, +B89BD135E935, +B8E87380D361, +B9485A9648C6, +B9ED829C22AE, +BA227EE91818, +BA7BBD9683B1, +BA8224EA7A80, +BA84C974B356, +BAD293A45C8A, +BB850C7E4934, +BBC1256810A4, +BC1CD369549E, +BC5C76E5909C, +BC66E9270049, +BC6AB08B03CC, +BC74CA2C2B06, +BC7C64828C1D, +BCCC3A719013, +BD06E96EB7D7, +BD196D0A74E0, +BE02790E84AC, +BE1266314B9D, +BE518C742B74, +BE5695316117, +BE5D8EBA120D, +BE8286DA7D12, +BE9CE00EE4DD, +C003962B3462, +C0067E095049, +C015A21E0146, +C03BC03AD437, +C06CE7D57A0D, +C07EE1E10B56, +C0885A29251E, +C198163ABECE, +C1EB7337A035, +C225479C7064, +C2740E1665A8, +C27924128A00, +C2A701656B8B, +C2C30D21C53E, +C2CBB2ACD38D, +C38D19A9C8D1, +C3B1BB7E7492, +C3BA2438A981, +C3CD74758DE2, +C4033B3BB1D7, +C404D280640E, +C4467DE80B2D, +C46A048C88DD, +C52877867C05, +C56D005E258E, +C56D052D5533, +C5BB2CCCB9C3, +C5C272694A1E, +C6121BC4A29C, +C65EEAE02433, +C661C4AE1DD1, +C76C94B495CA, +C7BD49777A79, +C7CD131E9B60, +C7E35D6294BA, +C8E173DB04CC, +C95855AE08E8, +C98147E69033, +C99A004E6133, +C9E893C4090B, +CA119C79A197, +CA309D2CBC41, +CA4BAA390BC4, +CA92DD257E21, +CA968EBEB9C7, +CADED0C50AC4, +CB18774EA550, +CB1999D19E10, +CB75C1BAE669, +CC2517AB2346, +CC2AC1AD29CA, +CD11359C7A90, +CD14C8553CB9, +CD333295BBE2, +CD3DB8C27E5C, +CDA811AD5055, +CDABDCA23986, +CDCA8BD7B002, +CE0456AB0DCE, +CE58AE1C51E9, +CE76E8A600DC, +CE95875316C8, +CEB105E65289, +CEB651752D4C, +CEE02D97E5BD, +D023DB35ED05, +D0BE546CC06B, +D0CE7EB0D379, +D10329D366C8, +D15C004DBC8D, +D16E6B668254, +D1CEEC977644, +D1DC0E1CC09E, +D2550925679B, +D28B2D42DE1A, +D2926519AC09, +D313116A45B4, +D3DC10453857, +D431C8C73BDC, +D4C67846791C, +D5629384CE7D, +D5ABE7180600, +D62A4A0E57C2, +D660CE9E3080, +D66AE9282140, +D6A91C14AC47, +D6E23B4E75C6, +D726C4979654, +D76DE12943B4, +D7A405AD9E4E, +D7BD3AE48E93, +D7D49700BBCC, +D7E8A5089E7A, +D84C81EE910D, +D8545199A949, +D86243C1380E, +D88A12EB3622, +D89B5EA419C1, +D8A3690B0115, +D94646A4C65B, +D982B4846A96, +DA303BADB013, +DAD9A48A8C33, +DAEB5D63920B, +DB01A99DD94C, +DB22BB7D6818, +DB37160CBB4B, +DB7E3687E450, +DC7697E37A9B, +DCC44C4E9269, +DCCE477E785E, +DD68DE9CDA5A, +DE1B08C6D94B, +DE41BBD7E68D, +DE6E04AE4475, +DE8CD4277A9E, +DEA8098D6E51, +DEB2BEE8858A, +DEB550958AD9, +E045E6309471, +E0E21213C611, +E0E457054B62, +E1097C69DA4A, +E1EA831EA514, +E20716902884, +E2C9CB14C06C, +E33B66EA2705, +E34C5B12BABA, +E38A1C654E82, +E3905BA54194, +E3E3919444CA, +E4450EC1010C, +E49A03306224, +E5100AC4C6C3, +E5124DB665A6, +E5491B5E3DD6, +E5BE9C989A29, +E5C3A9A27D3E, +E65111EB1E40, +E65792427D4C, +E7004C5EA94A, +E705087DECBB, +E7CB93E68155, +E81512343BAD, +E8428C8B0740, +E859EBC22318, +E87267A508DB, +E886AE7D1BE0, +E8B008239600, +E8C4B4A4E482, +E8D53410B736, +E902964DA28D, +E9203D5BD2DA, +E9526CACA8B2, +E9C11D763BEC, +EA3BDAA4E498, +EA61AC8B4969, +EA8E8ADC26B9, +EB5588EAE5E8, +EBA964C07075, +EC71B679D3AA, +ECB4019ADD97, +ED14D0A14B0C, +ED296C79266C, +EDBA3C943EA8, +EDC7CEBD4000, +EDE2747DA6C3, +EE3029556CEB, +EE49610E6121, +EEB704D69BCA, +EED69A391464, diff --git a/client/dictionaries/mrzd_sort_keys.dic b/client/dictionaries/mrzd_sort_keys.dic new file mode 100644 index 000000000..025f1b995 --- /dev/null +++ b/client/dictionaries/mrzd_sort_keys.dic @@ -0,0 +1,57 @@ +010203040506, +013940233313, +022FE48B3072, +123456789ABC, +123456ABCDEF, +17505586EF02, +1795902DBAF9, +1A2B3C4D5E6F, +1A982C7E459A, +200306202033, +2011092119F1, +2012053082AD, +37D4DCA92451, +40E5EA1EFC00, +435330666666, +46868F6D5677, +474249437569, +4D3A99C351DD, +533CB6C723F6, +5554AAA96321, +587EE5F9350F, +5A1B85FCE20A, +5D293AFC8D7E, +64A2EE93B12B, +64E2283FCF5E, +714C5C886E97, +833FBD3CFE51, +83BAB5ACAD62, +872B71F9D15A, +8F9B229047AC, +8FD0A4F256E9, +9AEDF9931EC1, +9B1DD7C030A1, +A0478CC39091, +A0A1A2A3A4A5, +A2B2C9D187FB, +A4EF6C3BB692, +AABBCC660429, +AABBCCDDEEFF, +ABCDEF123456, +B0699AD03D17, +B0B1B2B3B4B5, +BA28CFD15EE8, +BCFE01BCFE01, +C0C1C2C3C4C5, +CFC738403AB0, +D0D1D2D3D4D5, +D3F7D3F7D3F7, +DB5181C92CBE, +DFED39FFBB76, +E1DD284379D4, +E96246531342, +ED3A7EFBFF56, +F83466888612, +F89C86B2A961, +FFFFAE82366C, +FFFFD06F83E3, diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 647123faf..f14d23f2d 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -38,6 +38,20 @@ void ParamLoadDefaults(struct tlvdb *tlvRoot) { TLV_ADD(0x9F6A, "\x01\x02\x03\x04"); //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4 TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC + //95:(Terminal Verification Results) len:5 + // all OK TVR + TLV_ADD(0x95, "\x00\x00\x00\x00\x00"); +} + +void PrintChannel(EMVCommandChannel channel) { + switch(channel) { + case ECC_CONTACTLESS: + PrintAndLogEx(INFO, "Channel: CONTACTLESS"); + break; + case ECC_CONTACT: + PrintAndLogEx(INFO, "Channel: CONTACT"); + break; + } } int CmdEMVSelect(const char *cmd) { @@ -67,6 +81,7 @@ int CmdEMVSelect(const char *cmd) { EMVCommandChannel channel = ECC_CONTACTLESS; if (arg_get_lit(5)) channel = ECC_CONTACT; + PrintChannel(channel); CLIGetHexWithReturn(6, data, &datalen); CLIParserFree(); @@ -114,6 +129,7 @@ int CmdEMVSearch(const char *cmd) { EMVCommandChannel channel = ECC_CONTACTLESS; if (arg_get_lit(5)) channel = ECC_CONTACT; + PrintChannel(channel); CLIParserFree(); SetAPDULogging(APDULogging); @@ -170,6 +186,7 @@ int CmdEMVPPSE(const char *cmd) { EMVCommandChannel channel = ECC_CONTACTLESS; if (arg_get_lit(7)) channel = ECC_CONTACT; + PrintChannel(channel); CLIParserFree(); SetAPDULogging(APDULogging); @@ -224,6 +241,7 @@ int CmdEMVGPO(const char *cmd) { EMVCommandChannel channel = ECC_CONTACTLESS; if (arg_get_lit(6)) channel = ECC_CONTACT; + PrintChannel(channel); CLIGetHexWithReturn(7, data, &datalen); CLIParserFree(); @@ -235,6 +253,7 @@ int CmdEMVGPO(const char *cmd) { // calc PDOL struct tlv *pdol_data_tlv = NULL; + struct tlvdb *tmp_ext = NULL; struct tlv data_tlv = { .tag = 0x83, .len = datalen, @@ -248,9 +267,11 @@ int CmdEMVGPO(const char *cmd) { ParamLoadFromJson(tlvRoot); }; - pdol_data_tlv = dol_process((const struct tlv *)tlvdb_external(0x9f38, datalen, data), tlvRoot, 0x83); + tmp_ext = tlvdb_external(0x9f38, datalen, data); + pdol_data_tlv = dol_process((const struct tlv *)tmp_ext, tlvRoot, 0x83); if (!pdol_data_tlv){ PrintAndLogEx(ERR, "Can't create PDOL TLV."); + tlvdb_free(tmp_ext); tlvdb_free(tlvRoot); return 4; } @@ -265,6 +286,7 @@ int CmdEMVGPO(const char *cmd) { unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len); if (!pdol_data_tlv_data) { PrintAndLogEx(ERR, "Can't create PDOL data."); + tlvdb_free(tmp_ext); tlvdb_free(tlvRoot); return 4; } @@ -278,6 +300,8 @@ int CmdEMVGPO(const char *cmd) { if (pdol_data_tlv != &data_tlv) free(pdol_data_tlv); + + tlvdb_free(tmp_ext); tlvdb_free(tlvRoot); if (sw) @@ -306,7 +330,7 @@ int CmdEMVReadRecord(const char *cmd) { arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("tT", "tlv", "TLV decode results of selected applets"), arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), - arg_strx1(NULL, NULL, "", NULL), + arg_strx1(NULL, NULL, "", NULL), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -317,6 +341,7 @@ int CmdEMVReadRecord(const char *cmd) { EMVCommandChannel channel = ECC_CONTACTLESS; if (arg_get_lit(4)) channel = ECC_CONTACT; + PrintChannel(channel); CLIGetHexWithReturn(5, data, &datalen); CLIParserFree(); @@ -399,6 +424,7 @@ int CmdEMVAC(const char *cmd) { EMVCommandChannel channel = ECC_CONTACTLESS; if (arg_get_lit(8)) channel = ECC_CONTACT; + PrintChannel(channel); CLIGetHexWithReturn(9, data, &datalen); CLIParserFree(); @@ -410,6 +436,7 @@ int CmdEMVAC(const char *cmd) { // calc CDOL struct tlv *cdol_data_tlv = NULL; + struct tlvdb *tmp_ext = NULL; struct tlv data_tlv = { .tag = 0x01, .len = datalen, @@ -424,9 +451,11 @@ int CmdEMVAC(const char *cmd) { ParamLoadFromJson(tlvRoot); }; - cdol_data_tlv = dol_process((const struct tlv *)tlvdb_external(0x8c, datalen, data), tlvRoot, 0x01); // 0x01 - dummy tag + tmp_ext = tlvdb_external(0x8c, datalen, data); + cdol_data_tlv = dol_process((const struct tlv *)tmp_ext, tlvRoot, 0x01); // 0x01 - dummy tag if (!cdol_data_tlv){ PrintAndLogEx(ERR, "Can't create CDOL TLV."); + tlvdb_free(tmp_ext); tlvdb_free(tlvRoot); return 4; } @@ -447,6 +476,8 @@ int CmdEMVAC(const char *cmd) { if (cdol_data_tlv != &data_tlv) free(cdol_data_tlv); + + tlvdb_free(tmp_ext); tlvdb_free(tlvRoot); if (sw) @@ -481,6 +512,7 @@ int CmdEMVGenerateChallenge(const char *cmd) { EMVCommandChannel channel = ECC_CONTACTLESS; if (arg_get_lit(3)) channel = ECC_CONTACT; + PrintChannel(channel); CLIParserFree(); SetAPDULogging(APDULogging); @@ -510,8 +542,11 @@ int CmdEMVInternalAuthenticate(const char *cmd) { int datalen = 0; CLIParserInit("emv intauth", - "Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\nNeeds a EMV applet to be selected and GPO to be executed.", - "Usage:\n\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n" + "Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\n" + "Needs a EMV applet to be selected and GPO to be executed.", + + "Usage:\n" + "\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n" "\temv intauth -t 01020304 -> execute Internal Authenticate with 4-byte DDOL data, show result in TLV\n" "\temv intauth -pmt 9F 37 04 -> load params from file, make DDOL data from DDOL, Internal Authenticate with DDOL, show result in TLV"); @@ -536,6 +571,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) { EMVCommandChannel channel = ECC_CONTACTLESS; if (arg_get_lit(6)) channel = ECC_CONTACT; + PrintChannel(channel); CLIGetHexWithReturn(7, data, &datalen); CLIParserFree(); @@ -547,6 +583,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) { // calc DDOL struct tlv *ddol_data_tlv = NULL; + struct tlvdb *tmp_ext = NULL; struct tlv data_tlv = { .tag = 0x01, .len = datalen, @@ -561,9 +598,11 @@ int CmdEMVInternalAuthenticate(const char *cmd) { ParamLoadFromJson(tlvRoot); }; - ddol_data_tlv = dol_process((const struct tlv *)tlvdb_external(0x9f49, datalen, data), tlvRoot, 0x01); // 0x01 - dummy tag + tmp_ext = tlvdb_external(0x9f49, datalen, data); + ddol_data_tlv = dol_process((const struct tlv *)tmp_ext, tlvRoot, 0x01); // 0x01 - dummy tag if (!ddol_data_tlv){ PrintAndLogEx(ERR, "Can't create DDOL TLV."); + tlvdb_free(tmp_ext); tlvdb_free(tlvRoot); return 4; } @@ -584,6 +623,8 @@ int CmdEMVInternalAuthenticate(const char *cmd) { if (ddol_data_tlv != &data_tlv) free(ddol_data_tlv); + + tlvdb_free(tmp_ext); tlvdb_free(tlvRoot); if (sw) @@ -598,7 +639,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) { return 0; } -#define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;} +#define dreturn(n) {free(pdol_data_tlv); tlvdb_free(tlvSelect); tlvdb_free(tlvRoot); DropFieldEx( channel ); return n;} void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum TransactionType TrType, bool GenACGPO) { @@ -663,6 +704,50 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, } } +void ProcessACResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV) { + if (buf[0] == 0x80) { + if (decodeTLV){ + PrintAndLog("GPO response format1:"); + TLVPrintFromBuffer(buf, len); + } + + uint8_t elmlen = len - 2; // wo 0x80XX + + if (len < 4 + 2 || (elmlen - 2) % 4 || elmlen != buf[1]) { + PrintAndLogEx(ERR, "GPO response format1 parsing error. length=%d", len); + } else { + struct tlvdb *tlvElm = NULL; + if (decodeTLV) + PrintAndLog("\n------------ Format1 decoded ------------"); + + // CID (Cryptogram Information Data) + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f27, 1, &buf[2], &tlvElm); + if (decodeTLV) + TLVPrintFromTLV(tlvElm); + + // ATC (Application Transaction Counter) + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f36, 2, &buf[3], &tlvElm); + if (decodeTLV) + TLVPrintFromTLV(tlvElm); + + // AC (Application Cryptogram) + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f26, MIN(8, elmlen - 3), &buf[5], &tlvElm); + if (decodeTLV) + TLVPrintFromTLV(tlvElm); + + // IAD (Issuer Application Data) - optional + if (len > 11 + 2) { + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f10, elmlen - 11, &buf[13], &tlvElm); + if (decodeTLV) + TLVPrintFromTLV(tlvElm); + } + } + } else { + if (decodeTLV) + TLVPrintFromBuffer(buf, len); + } +} + int CmdEMVExec(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; @@ -680,7 +765,8 @@ int CmdEMVExec(const char *cmd) { CLIParserInit("emv exec", "Executes EMV contactless transaction", - "Usage:\n\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n" + "Usage:\n" + "\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n" "\temv exec -satc -> select card, execute CDA transaction, show APDU and TLV\n"); void* argtable[] = { @@ -708,9 +794,9 @@ int CmdEMVExec(const char *cmd) { enum TransactionType TrType = TT_MSD; if (arg_get_lit(7)) - TrType = TT_QVSDCMCHIP; + TrType = TT_QVSDCMCHIP; if (arg_get_lit(8)) - TrType = TT_CDA; + TrType = TT_CDA; if (arg_get_lit(9)) TrType = TT_VSDC; @@ -718,8 +804,18 @@ int CmdEMVExec(const char *cmd) { EMVCommandChannel channel = ECC_CONTACTLESS; if (arg_get_lit(11)) channel = ECC_CONTACT; + PrintChannel(channel); + uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; CLIParserFree(); +#ifndef WITH_SMARTCARD + // not compiled with smartcard functionality, we need to exit + if ( channel == ECC_CONTACT ) { + PrintAndLogEx(WARNING, "PM3 Client is not compiled with support for SMARTCARD. Exiting."); + return 0; + } +#endif + SetAPDULogging(showAPDU); // init applets list tree @@ -732,7 +828,7 @@ int CmdEMVExec(const char *cmd) { // PPSE PrintAndLogEx(NORMAL, "\n* PPSE."); SetAPDULogging(showAPDU); - res = EMVSearchPSE(channel, activateField, true, decodeTLV, tlvSelect); + res = EMVSearchPSE(channel, activateField, true, psenum, decodeTLV, tlvSelect); // check PPSE and select application id if (!res) { @@ -845,7 +941,7 @@ int CmdEMVExec(const char *cmd) { uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIoffline = AFL->value[i * 4 + 3]; - PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); + PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline count:%02x", SFI, SFIstart, SFIend, SFIoffline); if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { PrintAndLogEx(NORMAL, "SFI ERROR! Skipped..."); continue; @@ -867,7 +963,7 @@ int CmdEMVExec(const char *cmd) { // Build Input list for Offline Data Authentication // EMV 4.3 book3 10.3, page 96 - if (SFIoffline) { + if (SFIoffline > 0) { if (SFI < 11) { const unsigned char *abuf = buf; size_t elmlen = len; @@ -882,6 +978,8 @@ int CmdEMVExec(const char *cmd) { memcpy(&ODAiList[ODAiListLen], buf, len); ODAiListLen += len; } + + SFIoffline--; } } } @@ -921,7 +1019,7 @@ int CmdEMVExec(const char *cmd) { // transaction check // qVSDC - if (TrType == TT_QVSDCMCHIP|| TrType == TT_CDA){ + if (TrType == TT_QVSDCMCHIP || TrType == TT_CDA){ // 9F26: Application Cryptogram const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL); if (AC) { @@ -938,7 +1036,7 @@ int CmdEMVExec(const char *cmd) { // print AC data PrintAndLogEx(NORMAL, "ATC: %s", sprint_hex(ATC->value, ATC->len)); PrintAndLogEx(NORMAL, "AC: %s", sprint_hex(AC->value, AC->len)); - if (IAD){ + if (IAD) { PrintAndLogEx(NORMAL, "IAD: %s", sprint_hex(IAD->value, IAD->len)); if (IAD->len >= IAD->value[0] + 1) { @@ -978,17 +1076,18 @@ int CmdEMVExec(const char *cmd) { // ICC Dynamic Number struct tlvdb * ICCDynN = tlvdb_fixed(0x9f4c, len, buf); tlvdb_add(tlvRoot, ICCDynN); - if (decodeTLV){ + if (decodeTLV) { PrintAndLogEx(NORMAL, "\n* * ICC Dynamic Number:"); TLVPrintFromTLV(ICCDynN); } PrintAndLogEx(NORMAL, "* * Calc CDOL1"); struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag - if (!cdol_data_tlv){ + if (!cdol_data_tlv) { PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV."); dreturn(6); } + PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len)); PrintAndLogEx(NORMAL, "* * AC1"); @@ -1010,6 +1109,7 @@ int CmdEMVExec(const char *cmd) { if (res) { PrintAndLogEx(NORMAL, "CDA error (%d)", res); } + free(ac_tlv); free(cdol_data_tlv); @@ -1073,7 +1173,7 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(NORMAL, "Use default UDOL."); struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag - if (!udol_data_tlv){ + if (!udol_data_tlv) { PrintAndLogEx(WARNING, "Error: can't create UDOL TLV."); dreturn(8); } @@ -1101,7 +1201,140 @@ int CmdEMVExec(const char *cmd) { } } - DropField(); + // VSDC + if (GetCardPSVendor(AID, AIDlen) == CV_VISA && (TrType == TT_VSDC || TrType == TT_CDA)){ + PrintAndLogEx(NORMAL, "\n--> VSDC transaction."); + + PrintAndLogEx(NORMAL, "* * Calc CDOL1"); + struct tlv *cdol1_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag + if (!cdol1_data_tlv) { + PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV."); + dreturn(6); + } + + PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol1_data_tlv->len, sprint_hex(cdol1_data_tlv->value, cdol1_data_tlv->len)); + + PrintAndLogEx(NORMAL, "* * AC1"); + // EMVAC_TC + EMVAC_CDAREQ --- to get SDAD + res = EMVAC(channel, true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol1_data_tlv->value, cdol1_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); + + if (res) { + PrintAndLogEx(NORMAL, "AC1 error(%d): %4x. Exit...", res, sw); + free(cdol1_data_tlv); + dreturn(7); + } + + // process Format1 (0x80) and print Format2 (0x77) + ProcessACResponseFormat1(tlvRoot, buf, len, decodeTLV); + + uint8_t CID = 0; + tlvdb_get_uint8(tlvRoot, 0x9f27, &CID); + + // AC1 print result + PrintAndLog(""); + if ((CID & EMVAC_AC_MASK) == EMVAC_AAC) PrintAndLogEx(INFO, "AC1 result: AAC (Transaction declined)"); + if ((CID & EMVAC_AC_MASK) == EMVAC_TC) PrintAndLogEx(INFO, "AC1 result: TC (Transaction approved)"); + if ((CID & EMVAC_AC_MASK) == EMVAC_ARQC) PrintAndLogEx(INFO, "AC1 result: ARQC (Online authorisation requested)"); + if ((CID & EMVAC_AC_MASK) == EMVAC_AC_MASK) PrintAndLogEx(INFO, "AC1 result: RFU"); + + // decode Issuer Application Data (IAD) + uint8_t CryptoVersion = 0; + const struct tlv *IAD = tlvdb_get(tlvRoot, 0x9f10, NULL); + if (IAD && (IAD->len > 1)) { + PrintAndLogEx(NORMAL, "\n* * Issuer Application Data (IAD):"); + uint8_t VDDlen = IAD->value[0]; // Visa discretionary data length + uint8_t IDDlen = 0; // Issuer discretionary data length + PrintAndLogEx(NORMAL, "IAD length: %d", IAD->len); + PrintAndLogEx(NORMAL, "VDDlen: %d", VDDlen); + if (VDDlen < IAD->len - 1) + IDDlen = IAD->value[VDDlen + 1]; + PrintAndLogEx(NORMAL, "IDDlen: %d", IDDlen); + + uint8_t DerivKeyIndex = IAD->value[1]; + CryptoVersion = IAD->value[2]; + + PrintAndLogEx(NORMAL, "CryptoVersion: %d", CryptoVersion); + PrintAndLogEx(NORMAL, "DerivKeyIndex: %d", DerivKeyIndex); + + // Card Verification Results (CVR) decode + if ((VDDlen - 2) > 0) { + uint8_t CVRlen = IAD->value[3]; + if (CVRlen == (VDDlen - 2 - 1)) { + PrintAndLogEx(NORMAL, "CVR length: %d", CVRlen); + PrintAndLogEx(NORMAL, "CVR: %s", sprint_hex(&IAD->value[4], CVRlen)); + } else { + PrintAndLogEx(NORMAL, "Wrong CVR length! CVR: %s", sprint_hex(&IAD->value[3], VDDlen - 2)); + } + } + if (IDDlen) + PrintAndLogEx(NORMAL, "IDD: %s", sprint_hex(&IAD->value[VDDlen + 1], IDDlen)); + } else { + PrintAndLogEx(NORMAL, "Issuer Application Data (IAD) not found."); + } + + PrintAndLogEx(NORMAL, "\n* * Processing online request"); + + // authorization response code from acquirer + const char HostResponse[] = "00"; // 0x3030 + size_t HostResponseLen = sizeof(HostResponse) - 1; + PrintAndLogEx(NORMAL, "Host Response: `%s`", HostResponse); + tlvdb_change_or_add_node(tlvRoot, 0x8a, HostResponseLen, (const unsigned char *)HostResponse); + + if (CryptoVersion == 10) { + PrintAndLogEx(NORMAL, "\n* * Generate ARPC"); + + // Application Cryptogram (AC) + const struct tlv *AC = tlvdb_get(tlvRoot, 0x9f26, NULL); + if (AC && (AC->len > 0)) { + PrintAndLogEx(NORMAL, "AC: %s", sprint_hex(AC->value, AC->len)); + + size_t rawARPClen = AC->len; + uint8_t rawARPC[rawARPClen]; + memcpy(rawARPC, AC->value, AC->len); + for (int i = 0; (i < HostResponseLen) && (i < rawARPClen); i++) + rawARPC[i] ^= HostResponse[i]; + PrintAndLogEx(NORMAL, "raw ARPC: %s", sprint_hex(rawARPC, rawARPClen)); + + // here must be calculation of ARPC, but we dont know a bank keys. + PrintAndLogEx(NORMAL, "ARPC: n/a"); + + } else { + PrintAndLogEx(NORMAL, "Application Cryptogram (AC) not found."); + } + + // here must be external authenticate, but we dont know ARPC + + } + + + // needs to send AC2 command (res == ARQC) + if ((CID & EMVAC_AC_MASK) == EMVAC_ARQC) { + PrintAndLogEx(NORMAL, "\n* * Calc CDOL2"); + struct tlv *cdol2_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8d, NULL), tlvRoot, 0x01); // 0x01 - dummy tag + if (!cdol2_data_tlv) { + PrintAndLogEx(WARNING, "Error: can't create CDOL2 TLV."); + dreturn(6); + } + + PrintAndLogEx(NORMAL, "CDOL2 data[%d]: %s", cdol2_data_tlv->len, sprint_hex(cdol2_data_tlv->value, cdol2_data_tlv->len)); + + //PrintAndLogEx(NORMAL, "* * AC2"); + + + // here must be AC2, but we dont make external authenticate ( + +/* // AC2 + PRINT_INDENT(level); + if ((CID & EMVAC_AC2_MASK) == EMVAC_AAC2) fprintf(f, "\tAC2: AAC (Transaction declined)\n"); + if ((CID & EMVAC_AC2_MASK) == EMVAC_TC2) fprintf(f, "\tAC2: TC (Transaction approved)\n"); + if ((CID & EMVAC_AC2_MASK) == EMVAC_ARQC2) fprintf(f, "\tAC2: not requested (ARQC)\n"); + if ((CID & EMVAC_AC2_MASK) == EMVAC_AC2_MASK) fprintf(f, "\tAC2: RFU\n"); +*/ + } + + } + + DropFieldEx( channel ); // Destroy TLV's free(pdol_data_tlv); @@ -1164,19 +1397,23 @@ int CmdEMVScan(const char *cmd) { EMVCommandChannel channel = ECC_CONTACTLESS; if (arg_get_lit(11)) channel = ECC_CONTACT; + PrintChannel(channel); + uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; uint8_t relfname[250] ={0}; char *crelfname = (char *)relfname; int relfnamelen = 0; CLIGetStrWithReturn(12, relfname, &relfnamelen); CLIParserFree(); - SetAPDULogging(showAPDU); - - // TODO - if (channel == ECC_CONTACT) { - PrintAndLogEx(ERR, "Do not use contact interface. Exit."); - return 1; +#ifndef WITH_SMARTCARD + // not compiled with smartcard functionality, we need to exit + if ( channel == ECC_CONTACT ) { + PrintAndLogEx(WARNING, "PM3 Client is not compiled with support for SMARTCARD. Exiting."); + return 0; } +#endif + + SetAPDULogging(showAPDU); // current path + file name if (!strstr(crelfname, ".json")) @@ -1201,23 +1438,37 @@ int CmdEMVScan(const char *cmd) { } // drop field at start - DropField(); - - // iso 14443 select - PrintAndLogEx(NORMAL, "--> GET UID, ATS."); - - iso14a_card_select_t card; - if (Hf14443_4aGetCardData(&card)) { - return 2; - } + DropFieldEx( channel ); JsonSaveStr(root, "$.File.Created", "proxmark3 `emv scan`"); - JsonSaveStr(root, "$.Card.Communication", "iso14443-4a"); - JsonSaveBufAsHex(root, "$.Card.UID", (uint8_t *)&card.uid, card.uidlen); - JsonSaveHex(root, "$.Card.ATQA", card.atqa[0] + (card.atqa[1] << 2), 2); - JsonSaveHex(root, "$.Card.SAK", card.sak, 0); - JsonSaveBufAsHex(root, "$.Card.ATS", (uint8_t *)card.ats, card.ats_len); + if (channel == ECC_CONTACTLESS) { + // iso 14443 select + PrintAndLogEx(NORMAL, "--> GET UID, ATS."); + + iso14a_card_select_t card; + if (Hf14443_4aGetCardData(&card)) { + return 2; + } + + JsonSaveStr(root, "$.Card.Contactless.Communication", "iso14443-4a"); + JsonSaveBufAsHex(root, "$.Card.Contactless.UID", (uint8_t *)&card.uid, card.uidlen); + JsonSaveHex(root, "$.Card.Contactless.ATQA", card.atqa[0] + (card.atqa[1] << 2), 2); + JsonSaveHex(root, "$.Card.Contactless.SAK", card.sak, 0); + JsonSaveBufAsHex(root, "$.Card.Contactless.ATS", (uint8_t *)card.ats, card.ats_len); + } else { + PrintAndLogEx(NORMAL, "--> GET ATR."); + + smart_card_atr_t card; + smart_select(true, &card); + if (!card.atr_len) { + PrintAndLogEx(ERR, "Can't get ATR from a smart card."); + return 1; + } + + JsonSaveStr(root, "$.Card.Contact.Communication", "iso7816"); + JsonSaveBufAsHex(root, "$.Card.Contact.ATR", (uint8_t *)card.atr, card.atr_len); + } // init applets list tree const char *al = "Applets list"; @@ -1242,7 +1493,7 @@ int CmdEMVScan(const char *cmd) { tlvdb_free(fci); } - res = EMVSearchPSE(channel, false, true, decodeTLV, tlvSelect); + res = EMVSearchPSE(channel, false, true, psenum, decodeTLV, tlvSelect); // check PPSE and select application id if (!res) { @@ -1254,7 +1505,7 @@ int CmdEMVScan(const char *cmd) { if (EMVSearch(channel, false, true, decodeTLV, tlvSelect)) { PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit..."); tlvdb_free(tlvSelect); - DropField(); + DropFieldEx( channel ); return 3; } @@ -1270,7 +1521,7 @@ int CmdEMVScan(const char *cmd) { if (!AIDlen) { PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit..."); - DropField(); + DropFieldEx( channel ); return 4; } @@ -1289,7 +1540,7 @@ int CmdEMVScan(const char *cmd) { if (res) { PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res); tlvdb_free(tlvRoot); - DropField(); + DropFieldEx( channel ); return 5; } @@ -1317,7 +1568,7 @@ int CmdEMVScan(const char *cmd) { if (!pdol_data_tlv){ PrintAndLogEx(ERR, "Can't create PDOL TLV."); tlvdb_free(tlvRoot); - DropField(); + DropFieldEx( channel ); return 6; } @@ -1326,7 +1577,7 @@ int CmdEMVScan(const char *cmd) { if (!pdol_data_tlv_data) { PrintAndLogEx(ERR, "Can't create PDOL data."); tlvdb_free(tlvRoot); - DropField(); + DropFieldEx( channel ); return 6; } PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); @@ -1340,7 +1591,7 @@ int CmdEMVScan(const char *cmd) { if (res) { PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw); tlvdb_free(tlvRoot); - DropField(); + DropFieldEx( channel ); return 7; } ProcessGPOResponseFormat1(tlvRoot, buf, len, decodeTLV); @@ -1382,7 +1633,7 @@ int CmdEMVScan(const char *cmd) { uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIoffline = AFL->value[i * 4 + 3]; - PrintAndLog("--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); + PrintAndLogEx(INFO, "--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { PrintAndLogEx(ERR, "SFI ERROR! Skipped..."); continue; @@ -1432,8 +1683,7 @@ int CmdEMVScan(const char *cmd) { // free tlv object tlvdb_free(tlvRoot); - // DropField - DropField(); + DropFieldEx( channel ); res = json_dump_file(root, fname, JSON_INDENT(2)); if (res) { @@ -1448,25 +1698,6 @@ int CmdEMVScan(const char *cmd) { return 0; } -int usage_emv_getrnd(void){ - PrintAndLogEx(NORMAL, "retrieve the UN number from a terminal"); - PrintAndLogEx(NORMAL, "Usage: emv getrnd [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " emv getrnd"); - return 0; -} - -//retrieve the UN number from a terminal -int CmdEMVGetrng(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if ( cmdp == 'h' || cmdp == 'H') return usage_emv_getrnd(); - - return 0; -} - int CmdEMVList(const char *Cmd) { return CmdTraceList("7816"); } @@ -1475,6 +1706,237 @@ int CmdEMVTest(const char *cmd) { return ExecuteCryptoTests(true); } +int CmdEMVRoca(const char *cmd) { + uint8_t AID[APDU_AID_LEN] = {0}; + size_t AIDlen = 0; + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + int res; + + CLIParserInit("emv roca", + "Tries to extract public keys and run the ROCA test against them.\n", + "Usage:\n" + "\temv roca -w -> select --CONTACT-- card and run test\n" + "\temv roca -> select --CONTACTLESS-- card and run test\n" + ); + + void* argtable[] = { + arg_param_begin, + arg_lit0("tT", "selftest", "self test"), + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(1)) + return roca_self_test(); + + if (arg_get_lit(2)) + channel = ECC_CONTACT; + PrintChannel(channel); + CLIParserFree(); + +#ifndef WITH_SMARTCARD + // not compiled with smartcard functionality, we need to exit + if ( channel == ECC_CONTACT ) { + PrintAndLogEx(WARNING, "PM3 Client is not compiled with support for SMARTCARD. Exiting."); + return 0; + } +#endif + + // select card + uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; + + SetAPDULogging(false); + + // init applets list tree + const char *al = "Applets list"; + struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); + + // EMV PPSE + PrintAndLogEx(NORMAL, "--> PPSE."); + res = EMVSearchPSE(channel, false, true, psenum, false, tlvSelect); + + // check PPSE and select application id + if (!res) { + TLVPrintAIDlistFromSelectTLV(tlvSelect); + } else { + // EMV SEARCH with AID list + PrintAndLogEx(NORMAL, "--> AID search."); + if (EMVSearch(channel, false, true, false, tlvSelect)) { + PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit..."); + tlvdb_free(tlvSelect); + DropFieldEx( channel ); + return 3; + } + + // check search and select application id + TLVPrintAIDlistFromSelectTLV(tlvSelect); + } + + // EMV SELECT application + SetAPDULogging(false); + EMVSelectApplication(tlvSelect, AID, &AIDlen); + + tlvdb_free(tlvSelect); + + if (!AIDlen) { + PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit..."); + DropFieldEx( channel ); + return 4; + } + + // Init TLV tree + const char *alr = "Root terminal TLV tree"; + struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr); + + // EMV SELECT applet + PrintAndLogEx(NORMAL, "\n-->Selecting AID:%s.", sprint_hex_inrow(AID, AIDlen)); + res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); + + if (res) { + PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res); + tlvdb_free(tlvRoot); + DropFieldEx( channel ); + return 5; + } + + PrintAndLog("\n* Init transaction parameters."); + InitTransactionParameters(tlvRoot, true, TT_QVSDCMCHIP, false); + + PrintAndLogEx(NORMAL, "-->Calc PDOL."); + struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83); + if (!pdol_data_tlv){ + PrintAndLogEx(ERR, "Can't create PDOL TLV."); + tlvdb_free(tlvRoot); + DropFieldEx( channel ); + return 6; + } + + size_t pdol_data_tlv_data_len; + unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len); + if (!pdol_data_tlv_data) { + PrintAndLogEx(ERR, "Can't create PDOL data."); + tlvdb_free(tlvRoot); + DropFieldEx( channel ); + free(pdol_data_tlv); + return 6; + } + PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); + + PrintAndLogEx(INFO, "-->GPO."); + res = EMVGPO(channel, true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); + + free(pdol_data_tlv_data); + free(pdol_data_tlv); + + if (res) { + PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw); + tlvdb_free(tlvRoot); + DropFieldEx( channel ); + return 7; + } + ProcessGPOResponseFormat1(tlvRoot, buf, len, false); + + PrintAndLogEx(INFO, "-->Read records from AFL."); + const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL); + + while(AFL && AFL->len) { + if (AFL->len % 4) { + PrintAndLogEx(ERR, "Wrong AFL length: %d", AFL->len); + break; + } + + for (int i = 0; i < AFL->len / 4; i++) { + uint8_t SFI = AFL->value[i * 4 + 0] >> 3; + uint8_t SFIstart = AFL->value[i * 4 + 1]; + uint8_t SFIend = AFL->value[i * 4 + 2]; + uint8_t SFIoffline = AFL->value[i * 4 + 3]; + + PrintAndLogEx(INFO, "--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); + if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { + PrintAndLogEx(ERR, "SFI ERROR! Skipped..."); + continue; + } + + for(int n = SFIstart; n <= SFIend; n++) { + PrintAndLogEx(INFO, "---->SFI[%02x] %d", SFI, n); + + res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); + if (res) { + PrintAndLogEx(ERR, "SFI[%02x]. APDU error %4x", SFI, sw); + continue; + } + } + } + + break; + } + + // getting certificates + if (tlvdb_get(tlvRoot, 0x90, NULL)) { + PrintAndLogEx(INFO, "-->Recovering certificates."); + PKISetStrictExecution(false); + + struct emv_pk *pk = get_ca_pk(tlvRoot); + if (!pk) { + PrintAndLogEx(ERR, "ERROR: Key not found. Exit."); + goto out; + } + + struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlvRoot); + if (!issuer_pk) { + emv_pk_free(pk); + PrintAndLogEx(WARNING, "WARNING: Issuer certificate not found. Exit."); + goto out; + } + + PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %s IDX %02hhx CSN %s", + sprint_hex(issuer_pk->rid, 5), + issuer_pk->index, + sprint_hex(issuer_pk->serial, 3) + ); + + + struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlvRoot, NULL); + if (!icc_pk) { + emv_pk_free(pk); + emv_pk_free(issuer_pk); + PrintAndLogEx(WARNING, "WARNING: ICC certificate not found. Exit."); + goto out; + } + PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %s IDX %02hhx CSN %s\n", + sprint_hex(icc_pk->rid, 5), + icc_pk->index, + sprint_hex(icc_pk->serial, 3) + ); + + PrintAndLogEx(INFO, "ICC pk modulus: %s", sprint_hex_inrow(icc_pk->modulus, icc_pk->mlen)); + + // icc_pk->exp, icc_pk->elen + // icc_pk->modulus, icc_pk->mlen + if (icc_pk->elen > 0 && icc_pk->mlen > 0) { + if (emv_rocacheck(icc_pk->modulus, icc_pk->mlen, true)) { + PrintAndLogEx(INFO, "ICC pk is a subject to ROCA vulnerability, insecure.."); + } else { + PrintAndLogEx(INFO, "ICC pk is OK("); + } + } + + PKISetStrictExecution(true); + } + +out: + + // free tlv object + tlvdb_free(tlvRoot); + + DropFieldEx( channel ); + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"exec", CmdEMVExec, 0, "Executes EMV contactless transaction."}, @@ -1489,13 +1951,14 @@ static command_t CommandTable[] = { {"scan", CmdEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."}, {"test", CmdEMVTest, 0, "Crypto logic test."}, /* - {"getrng", CmdEMVGetrng, 0, "get random number from terminal"}, - {"eload", CmdEmvELoad, 0, "load EMV tag into device"}, - {"dump", CmdEmvDump, 0, "dump EMV tag values"}, - {"sim", CmdEmvSim, 0, "simulate EMV tag"}, - {"clone", CmdEmvClone, 0, "clone an EMV tag"}, + {"getrng", CmdEMVGetrng, 0, "get random number from terminal"}, + {"eload", CmdEmvELoad, 0, "load EMV tag into device"}, + {"dump", CmdEmvDump, 0, "dump EMV tag values"}, + {"sim", CmdEmvSim, 0, "simulate EMV tag"}, + {"clone", CmdEmvClone, 0, "clone an EMV tag"}, */ - {"list", CmdEMVList, 0, "[Deprecated] List ISO7816 history"}, + {"list", CmdEMVList, 0, "[Deprecated] List ISO7816 history"}, + {"roca", CmdEMVRoca, 0, "Extract public keys and run ROCA test"}, {NULL, NULL, 0, NULL} }; diff --git a/client/emv/cmdemv.h b/client/emv/cmdemv.h index b4397fd15..c91f75606 100644 --- a/client/emv/cmdemv.h +++ b/client/emv/cmdemv.h @@ -25,6 +25,7 @@ #include "cmdmain.h" #include "emvcore.h" #include "apduinfo.h" +#include "emv_roca.h" int CmdEMV(const char *Cmd); @@ -34,5 +35,6 @@ extern int CmdEMVPPSE(const char *cmd); extern int CmdEMVExec(const char *cmd); extern int CmdEMVGetrng(const char *Cmd); extern int CmdEMVList(const char *Cmd); +extern int CmdEMVRoca(const char *Cmd); #endif diff --git a/client/emv/emv_pk.c b/client/emv/emv_pk.c index b577855e0..091ab8062 100644 --- a/client/emv/emv_pk.c +++ b/client/emv/emv_pk.c @@ -429,9 +429,6 @@ char *emv_pk_get_ca_pk_file(const char *dirname, const unsigned char *rid, unsig if (!dirname) dirname = ".";//openemv_config_get_str("capk.dir", NULL); - if (!dirname) - return NULL; - char *filename; int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx_%02hhx.0", dirname, @@ -453,9 +450,6 @@ char *emv_pk_get_ca_pk_rid_file(const char *dirname, const unsigned char *rid) if (!dirname) dirname = "."; //openemv_config_get_str("capk.dir", NULL); - if (!dirname) - return NULL; - char *filename; int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx.pks", dirname, diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index be4dfa0a7..84224a957 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -41,7 +41,8 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, uint8_t msgtype, size_t *len, const struct tlv *cert_tlv, - ... /* A list of tlv pointers, end with NULL */ + int tlv_count, + ... /* A list of tlv pointers */ ) { struct crypto_pk *kcp; @@ -99,20 +100,23 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, size_t hash_len = crypto_hash_get_size(ch); crypto_hash_write(ch, data + 1, data_len - 2 - hash_len); - va_start(vl, cert_tlv); - while (true) { + va_start(vl, tlv_count); + for (int i = 0; i < tlv_count; i++) { const struct tlv *add_tlv = va_arg(vl, const struct tlv *); if (!add_tlv) - break; + continue; crypto_hash_write(ch, add_tlv->value, add_tlv->len); } va_end(vl); - if (memcmp(data + data_len - 1 - hash_len, crypto_hash_read(ch), hash_len)) { + uint8_t hash[hash_len]; + memset(hash, 0, hash_len); + memcpy(hash, crypto_hash_read(ch), hash_len); + if (memcmp(data + data_len - 1 - hash_len, hash, hash_len)) { printf("ERROR: Calculated wrong hash\n"); printf("decoded: %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len)); - printf("calculated: %s\n",sprint_hex(crypto_hash_read(ch), hash_len)); + printf("calculated: %s\n",sprint_hex(hash, hash_len)); if (strictExecution) { crypto_hash_close(ch); @@ -165,6 +169,7 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk, const struct tlv *exp_tlv, const struct tlv *rem_tlv, const struct tlv *add_tlv, + const struct tlv *sdatl_tlv, bool showData ) { @@ -190,9 +195,11 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk, data = emv_pki_decode_message(enc_pk, msgtype, &data_len, cert_tlv, + 5, rem_tlv, exp_tlv, add_tlv, + sdatl_tlv, NULL); if (!data || data_len < 11 + pan_length) { printf("ERROR: Can't decode message\n"); @@ -275,9 +282,10 @@ static struct emv_pk *emv_pki_decode_key(const struct emv_pk *enc_pk, const struct tlv *cert_tlv, const struct tlv *exp_tlv, const struct tlv *rem_tlv, - const struct tlv *add_tlv + const struct tlv *add_tlv, + const struct tlv *sdatl_tlv ) { - return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, false); + return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, sdatl_tlv, false); } struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db) @@ -287,17 +295,30 @@ struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb tlvdb_get(db, 0x90, NULL), tlvdb_get(db, 0x9f32, NULL), tlvdb_get(db, 0x92, NULL), + NULL, NULL); } struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv) { - return emv_pki_decode_key(pk, 4, + size_t sdatl_len; + unsigned char *sdatl = emv_pki_sdatl_fill(db, &sdatl_len); + struct tlv sda_tdata = { + .tag = 0x00, // dummy tag + .len = sdatl_len, + .value = sdatl + }; + + struct emv_pk *res = emv_pki_decode_key(pk, 4, tlvdb_get(db, 0x5a, NULL), tlvdb_get(db, 0x9f46, NULL), tlvdb_get(db, 0x9f47, NULL), tlvdb_get(db, 0x9f48, NULL), - sda_tlv); + sda_tlv, + &sda_tdata); + + free(sdatl); // malloc here: emv_pki_sdatl_fill + return res; } struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db) @@ -307,17 +328,62 @@ struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb tlvdb_get(db, 0x9f2d, NULL), tlvdb_get(db, 0x9f2e, NULL), tlvdb_get(db, 0x9f2f, NULL), + NULL, NULL); } +unsigned char *emv_pki_sdatl_fill(const struct tlvdb *db, size_t *sdatl_len) { + uint8_t buf[2048] = {0}; + size_t len = 0; + + *sdatl_len = 0; + + const struct tlv *sda_tl = tlvdb_get(db, 0x9f4a, NULL); + if (!sda_tl || sda_tl->len <= 0) + return NULL; + + for (int i = 0; i < sda_tl->len; i++) { + uint32_t tag = sda_tl->value[i]; // here may be multibyte, but now not + const struct tlv *elm = tlvdb_get(db, tag, NULL); + if (elm) { + memcpy(&buf[len], elm->value, elm->len); + len += elm->len; + } + } + + if (len) { + *sdatl_len = len; + unsigned char *value = malloc(len); + memcpy(value, buf, len); + return value; + } + + return NULL; +} + + struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData) { size_t data_len; + + // Static Data Authentication Tag List + size_t sdatl_len; + unsigned char *sdatl = emv_pki_sdatl_fill(db, &sdatl_len); + struct tlv sda_tdata = { + .tag = 0x00, // dummy tag + .len = sdatl_len, + .value = sdatl + }; + unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len, tlvdb_get(db, 0x93, NULL), + 3, sda_tlv, + &sda_tdata, NULL); + free(sdatl); // malloc here: emv_pki_sdatl_fill + if (!data || data_len < 5) return NULL; @@ -345,6 +411,7 @@ struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct t size_t data_len; unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len, tlvdb_get(db, 0x9f4b, NULL), + 2, dyn_tlv, NULL); @@ -380,6 +447,7 @@ struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct t size_t data_len; unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len, tlvdb_get(db, 0x9f4b, NULL), + 5, tlvdb_get(db, 0x9f37, NULL), tlvdb_get(db, 0x9f02, NULL), tlvdb_get(db, 0x5f2a, NULL), @@ -456,6 +524,7 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t size_t data_len = 0; unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len, tlvdb_get(this_db, 0x9f4b, NULL), + 2, un_tlv, NULL); if (!data || data_len < 3) { diff --git a/client/emv/emv_pki.h b/client/emv/emv_pki.h index 6fa7b12e9..f5d80bd6d 100644 --- a/client/emv/emv_pki.h +++ b/client/emv/emv_pki.h @@ -23,6 +23,7 @@ extern void PKISetStrictExecution(bool se); +unsigned char *emv_pki_sdatl_fill(const struct tlvdb *db, size_t *sdatl_len); struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db); struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv); struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db); diff --git a/client/emv/emv_roca.c b/client/emv/emv_roca.c new file mode 100644 index 000000000..6f90f11b5 --- /dev/null +++ b/client/emv/emv_roca.c @@ -0,0 +1,175 @@ +/* roca.c - ROCA (CVE-2017-15361) fingerprint checker. + * Written by Rob Stradling (based on https://github.com/crocs-muni/roca/blob/master/roca/detect.py) + * Copyright (C) 2017-2018 Sectigo Limited + * modified 2018 iceman (dropped openssl bignum, now use mbedtls lib) + * modified 2018 merlok + * + * This program 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. + * + * This program 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 this program. If not, see . + */ +//----------------------------------------------------------------------------- +// EMV roca commands +//----------------------------------------------------------------------------- + +#include "emv_roca.h" + +static uint8_t g_primes[ROCA_PRINTS_LENGTH] = { + 11, 13, 17, 19, 37, 53, 61, 71, 73, 79, 97, 103, 107, 109, 127, 151, 157 +}; + +mbedtls_mpi g_prints[ROCA_PRINTS_LENGTH]; + +void rocacheck_init(void) { + + for (int i = 0; i < ROCA_PRINTS_LENGTH; i++) + mbedtls_mpi_init(&g_prints[i]); + + mbedtls_mpi_read_string(&g_prints[0], 10, "1026"); + mbedtls_mpi_read_string(&g_prints[1], 10, "5658"); + mbedtls_mpi_read_string(&g_prints[2], 10, "107286"); + mbedtls_mpi_read_string(&g_prints[3], 10, "199410"); + mbedtls_mpi_read_string(&g_prints[4], 10, "67109890"); + mbedtls_mpi_read_string(&g_prints[5], 10, "5310023542746834"); + mbedtls_mpi_read_string(&g_prints[6], 10, "1455791217086302986"); + mbedtls_mpi_read_string(&g_prints[7], 10, "20052041432995567486"); + mbedtls_mpi_read_string(&g_prints[8], 10, "6041388139249378920330"); + mbedtls_mpi_read_string(&g_prints[9], 10, "207530445072488465666"); + mbedtls_mpi_read_string(&g_prints[10], 10, "79228162521181866724264247298"); + mbedtls_mpi_read_string(&g_prints[11], 10, "1760368345969468176824550810518"); + mbedtls_mpi_read_string(&g_prints[12], 10, "50079290986288516948354744811034"); + mbedtls_mpi_read_string(&g_prints[13], 10, "473022961816146413042658758988474"); + mbedtls_mpi_read_string(&g_prints[14], 10, "144390480366845522447407333004847678774"); + mbedtls_mpi_read_string(&g_prints[15], 10, "1800793591454480341970779146165214289059119882"); + mbedtls_mpi_read_string(&g_prints[16], 10, "126304807362733370595828809000324029340048915994"); +} + +void rocacheck_cleanup(void) { + for (int i = 0; i < ROCA_PRINTS_LENGTH; i++) + mbedtls_mpi_free(&g_prints[i]); +} + +int bitand_is_zero( mbedtls_mpi* a, mbedtls_mpi* b ) { + + for (int i = 0; i < mbedtls_mpi_bitlen(a); i++) { + + if (mbedtls_mpi_get_bit(a, i) && mbedtls_mpi_get_bit(b, i)) + return 0; + } + return 1; +} + + +mbedtls_mpi_uint mpi_get_uint(const mbedtls_mpi *X) { + + if (X->n == 1 && X->s > 0) { + return X->p[0]; + } + printf("ZERRRRO!!!\n"); + return 0; +} + +void print_mpi(const char *msg, int radix, const mbedtls_mpi *X) { + + char Xchar[400] = {0}; + size_t len = 0; + + mbedtls_mpi_write_string(X, radix, Xchar, sizeof(Xchar), &len); + printf("%s[%d] %s\n", msg, len, Xchar); +} + +bool emv_rocacheck(const unsigned char *buf, size_t buflen, bool verbose) { + + mbedtls_mpi t_modulus; + mbedtls_mpi_init(&t_modulus); + + bool ret = false; + + rocacheck_init(); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary(&t_modulus, buf, buflen) ); + + for (int i = 0; i < ROCA_PRINTS_LENGTH; i++) { + + mbedtls_mpi t_temp; + mbedtls_mpi t_prime; + mbedtls_mpi g_one; + + mbedtls_mpi_init(&t_temp); + mbedtls_mpi_init(&t_prime); + mbedtls_mpi_init(&g_one); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string(&g_one, 10, "1") ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int(&t_prime, &t_prime, g_primes[i]) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi(&t_temp, &t_modulus, &t_prime) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l(&g_one, mpi_get_uint(&t_temp)) ); + + if (bitand_is_zero(&g_one, &g_prints[i])) { + if (verbose) + PrintAndLogEx(FAILED, "No fingerprint found.\n"); + goto cleanup; + } + + mbedtls_mpi_free(&g_one); + mbedtls_mpi_free(&t_temp); + mbedtls_mpi_free(&t_prime); + } + + ret = true; + if (verbose) + PrintAndLogEx(SUCCESS, "Fingerprint found!\n"); + +cleanup: + mbedtls_mpi_free(&t_modulus); + + rocacheck_cleanup(); + return ret; +} + +int roca_self_test(void) { + int ret = 0; + + PrintAndLogEx(INFO, "ROCA check vulnerability tests" ); + + // positive + uint8_t keyp[] = "\x94\x4e\x13\x20\x8a\x28\x0c\x37\xef\xc3\x1c\x31\x14\x48\x5e\x59"\ + "\x01\x92\xad\xbb\x8e\x11\xc8\x7c\xad\x60\xcd\xef\x00\x37\xce\x99"\ + "\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\ + "\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7"; + + + if (emv_rocacheck(keyp, 64, false)) { + PrintAndLogEx(SUCCESS, "Weak modulus [ %s]", _GREEN_(PASS) ); + } + else { + ret++; + PrintAndLogEx(FAILED, "Weak modulus [ %s]", _RED_(FAIL) ); + } + + // negative + uint8_t keyn[] = "\x84\x4e\x13\x20\x8a\x28\x0c\x37\xef\xc3\x1c\x31\x14\x48\x5e\x59"\ + "\x01\x92\xad\xbb\x8e\x11\xc8\x7c\xad\x60\xcd\xef\x00\x37\xce\x99"\ + "\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\ + "\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7"; + + if (emv_rocacheck(keyn, 64, false)) { + ret++; + PrintAndLogEx(FAILED, "Strong modulus [ %s]", _RED_(FAIL) ); + } else { + PrintAndLogEx(SUCCESS, "Strong modulus [ %s]", _GREEN_(PASS) ); + } + + return ret; +} diff --git a/client/emv/emv_roca.h b/client/emv/emv_roca.h new file mode 100644 index 000000000..9e12e4256 --- /dev/null +++ b/client/emv/emv_roca.h @@ -0,0 +1,38 @@ +/* roca.c - ROCA (CVE-2017-15361) fingerprint checker. + * Written by Rob Stradling (based on https://github.com/crocs-muni/roca/blob/master/roca/detect.py) + * Copyright (C) 2017-2018 Sectigo Limited + * modified 2018 iceman (dropped openssl bignum, now use mbedtls lib) + * modified 2018 merlok + * + * This program 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. + * + * This program 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 this program. If not, see . + */ +//----------------------------------------------------------------------------- +// EMV roca commands +//----------------------------------------------------------------------------- + +#ifndef EMV_ROCA_H__ +#define EMV_ROCA_H__ + +#include +#include +#include "mbedtls/bignum.h" +#include "util.h" + +#define ROCA_PRINTS_LENGTH 17 + +extern bool emv_rocacheck( const unsigned char *buf, size_t buflen, bool verbose ); +extern int roca_self_test( void ); + +#endif + diff --git a/client/emv/emv_tags.c b/client/emv/emv_tags.c index cc2897127..521598b67 100644 --- a/client/emv/emv_tags.c +++ b/client/emv/emv_tags.c @@ -175,7 +175,8 @@ static const struct emv_tag emv_tags[] = { // internal { 0x00 , "Unknown ???" }, { 0x01 , "", EMV_TAG_STRING }, // string for headers - { 0x02 , "Raw data", }, // data + { 0x02 , "Raw data" }, // data + { 0x06 , "Object Identifier (OID)" }, { 0x20 , "Cardholder Verification Results (CVR)", EMV_TAG_CVR }, // not standard! { 0x21 , "Input list for Offline Data Authentication" }, // not standard! data for "Offline Data Authentication" come from "read records" command. (EMV book3 10.3) @@ -184,6 +185,9 @@ static const struct emv_tag emv_tags[] = { { 0x42 , "Issuer Identification Number (IIN)" }, { 0x4f , "Application Dedicated File (ADF) Name" }, { 0x50 , "Application Label", EMV_TAG_STRING }, + { 0x51 , "File reference data element" }, + { 0x52 , "Command APDU" }, + { 0x53 , "Discretionary data (or template)" }, { 0x56 , "Track 1 Data" }, { 0x57 , "Track 2 Equivalent Data" }, { 0x5a , "Application Primary Account Number (PAN)" }, @@ -195,16 +199,29 @@ static const struct emv_tag emv_tags[] = { { 0x5f2d, "Language Preference", EMV_TAG_STRING }, { 0x5f30, "Service Code", EMV_TAG_NUMERIC }, { 0x5f34, "Application Primary Account Number (PAN) Sequence Number", EMV_TAG_NUMERIC }, + { 0x5f36, "Transaction Currency Exponent", EMV_TAG_NUMERIC }, + { 0x5f50, "Issuer URL", EMV_TAG_STRING }, + { 0x5f53, "International Bank Account Number (IBAN)" }, + { 0x5f54, "Bank Identifier Code (BIC)" }, + { 0x5f55, "Issuer Country Code (alpha2 format)", EMV_TAG_STRING }, + { 0x5f56, "Issuer Country Code (alpha3 format)", EMV_TAG_STRING }, + { 0x61 , "Application Template" }, { 0x6f , "File Control Information (FCI) Template" }, { 0x70 , "READ RECORD Response Message Template" }, + { 0x71 , "Issues Script Template 1" }, + { 0x72 , "Issues Script Template 2" }, + { 0x73 , "Directory Discretionary Template" }, { 0x77 , "Response Message Template Format 2" }, { 0x80 , "Response Message Template Format 1" }, + { 0x81 , "Amount, Authorised (Binary)" }, { 0x82 , "Application Interchange Profile", EMV_TAG_BITMASK, &EMV_AIP }, { 0x83 , "Command Template" }, { 0x84 , "Dedicated File (DF) Name" }, + { 0x86 , "Issuer Script Command" }, { 0x87 , "Application Priority Indicator" }, { 0x88 , "Short File Identifier (SFI)" }, + { 0x89 , "Authorisation Code" }, { 0x8a , "Authorisation Response Code" }, { 0x8c , "Card Risk Management Data Object List 1 (CDOL1)", EMV_TAG_DOL }, { 0x8d , "Card Risk Management Data Object List 2 (CDOL2)", EMV_TAG_DOL }, @@ -216,14 +233,25 @@ static const struct emv_tag emv_tags[] = { { 0x93 , "Signed Static Application Data" }, { 0x94 , "Application File Locator (AFL)", EMV_TAG_AFL }, { 0x95 , "Terminal Verification Results" }, + { 0x97 , "Transaction Certificate Data Object List (TDOL)" }, + { 0x98 , "Transaction Certificate (TC) Hash Value" }, + { 0x99 , "Transaction Personal Identification Number (PIN) Data" }, { 0x9a , "Transaction Date", EMV_TAG_YYMMDD }, - { 0x9c , "Transaction Type" }, + { 0x9b , "Transaction Status Information" }, + { 0x9c , "Transaction Type", EMV_TAG_NUMERIC }, + { 0x9d , "Directory Definition File (DDF) Name" }, + + { 0x9f01, "Acquirer Identifier", EMV_TAG_NUMERIC }, { 0x9f02, "Amount, Authorised (Numeric)", EMV_TAG_NUMERIC }, - { 0x9f03, "Amount, Other (Numeric)", EMV_TAG_NUMERIC, }, + { 0x9f03, "Amount, Other (Numeric)", EMV_TAG_NUMERIC }, + { 0x9f04, "Amount, Other (Binary)", EMV_TAG_NUMERIC }, + { 0x9f05, "Application Discretionary Data" }, { 0x9f06, "Application Identifier (AID), Terminal. ISO 7816-5" }, { 0x9f07, "Application Usage Control", EMV_TAG_BITMASK, &EMV_AUC }, { 0x9f08, "Application Version Number" }, + { 0x9f09, "Application Version Number - terminal" }, { 0x9f0a, "Application Selection Registered Proprietary Data" }, // https://blog.ul-ts.com/posts/electronic-card-identifier-one-more-step-for-mif-compliance/ + { 0x9f0b, "Cardholder Name Extended", EMV_TAG_STRING }, { 0x9f0d, "Issuer Action Code - Default", EMV_TAG_BITMASK, &EMV_TVR }, { 0x9f0e, "Issuer Action Code - Denial", EMV_TAG_BITMASK, &EMV_TVR }, { 0x9f0f, "Issuer Action Code - Online", EMV_TAG_BITMASK, &EMV_TVR }, @@ -231,10 +259,21 @@ static const struct emv_tag emv_tags[] = { { 0x9f11, "Issuer Code Table Index", EMV_TAG_NUMERIC }, { 0x9f12, "Application Preferred Name", EMV_TAG_STRING }, { 0x9f13, "Last Online Application Transaction Counter (ATC) Register" }, + { 0x9f14, "Lower Consecutive Offline Limit" }, + { 0x9f15, "Merchant Category Code", EMV_TAG_NUMERIC }, + { 0x9f16, "Merchant Identifier", EMV_TAG_STRING }, { 0x9f17, "Personal Identification Number (PIN) Try Counter" }, + { 0x9f18, "Issuer Script Identifier" }, { 0x9f1a, "Terminal Country Code" }, + { 0x9f1b, "Terminal Floor Limit" }, + { 0x9f1c, "Terminal Identification", EMV_TAG_STRING }, + { 0x9f1d, "Terminal Risk Management Data" }, + { 0x9f1e, "Interface Device (IFD) Serial Number", EMV_TAG_STRING }, { 0x9f1f, "Track 1 Discretionary Data", EMV_TAG_STRING }, - { 0x9f21, "Transaction Time" }, + { 0x9f20, "Track 2 Discretionary Data", EMV_TAG_STRING }, + { 0x9f21, "Transaction Time" }, + { 0x9f22, "Certification Authority Public Key Index - Terminal" }, + { 0x9f23, "Upper Consecutive Offline Limit" }, { 0x9f26, "Application Cryptogram" }, { 0x9f27, "Cryptogram Information Data", EMV_TAG_CID }, { 0x9f2a, "Kernel Identifier" }, @@ -242,12 +281,21 @@ static const struct emv_tag emv_tags[] = { { 0x9f2e, "ICC PIN Encipherment Public Key Exponent" }, { 0x9f2f, "ICC PIN Encipherment Public Key Remainder" }, { 0x9f32, "Issuer Public Key Exponent" }, + { 0x9f33, "Terminal Capabilities" }, { 0x9f34, "Cardholder Verification Method (CVM) Results" }, { 0x9f35, "Terminal Type" }, { 0x9f36, "Application Transaction Counter (ATC)" }, { 0x9f37, "Unpredictable Number" }, { 0x9f38, "Processing Options Data Object List (PDOL)", EMV_TAG_DOL }, + { 0x9f39, "Point-of-Service (POS) Entry Mode", EMV_TAG_NUMERIC }, + { 0x9f3a, "Amount, Reference Currency" }, + { 0x9f3b, "Application Reference Currency", EMV_TAG_NUMERIC }, + { 0x9f3c, "Transaction Reference Currency Code", EMV_TAG_NUMERIC }, + { 0x9f3d, "Transaction Reference Currency Exponent", EMV_TAG_NUMERIC }, + { 0x9f40, "Additional Terminal Capabilities" }, + { 0x9f41, "Transaction Sequence Counter", EMV_TAG_NUMERIC }, { 0x9f42, "Application Currency Code", EMV_TAG_NUMERIC }, + { 0x9f43, "Application Reference Currency Exponent", EMV_TAG_NUMERIC }, { 0x9f44, "Application Currency Exponent", EMV_TAG_NUMERIC }, { 0x9f45, "Data Authentication Code" }, { 0x9f46, "ICC Public Key Certificate" }, @@ -258,41 +306,136 @@ static const struct emv_tag emv_tags[] = { { 0x9f4b, "Signed Dynamic Application Data" }, { 0x9f4c, "ICC Dynamic Number" }, { 0x9f4d, "Log Entry" }, + { 0x9f4e, "Merchant Name and Location", EMV_TAG_STRING }, { 0x9f4f, "Log Format", EMV_TAG_DOL }, + + { 0x9f50, "Offline Accumulator Balance" }, + { 0x9f51, "Application Currency Code" }, + { 0x9f51, "DRDOL" }, + + { 0x9f52, "Application Default Action (ADA)" }, + { 0x9f52, "Terminal Compatibility Indicator" }, + + { 0x9f53, "Transaction Category Code" }, + { 0x9f54, "DS ODS Card" }, + + { 0x9f55, "Mobile Support Indicator" }, + { 0x9f55, "Issuer Authentication Flags" }, + + { 0x9f56, "Issuer Authentication Indicator" }, + { 0x9f57, "Issuer Country Code" }, + { 0x9f58, "Consecutive Transaction Counter Limit (CTCL)" }, + { 0x9f59, "Consecutive Transaction Counter Upper Limit (CTCUL)" }, + { 0x9f5A, "Application Program Identifier" }, + { 0x9f5b, "Issuer Script Results" }, + { 0x9f5c, "Cumulative Total Transaction Amount Upper Limit (CTTAUL)" }, + { 0x9f5d, "Application Capabilities Information" }, + { 0x9f5e, "Data Storage Identifier" }, + { 0x9f5f, "DS Slot Availability" }, + { 0x9f60, "CVC3 (Track1)" }, { 0x9f61, "CVC3 (Track2)" }, - { 0x9f62, "PCVC3(Track1)" }, - { 0x9f63, "PUNATC(Track1)" }, - { 0x9f64, "NATC(Track1)" }, - { 0x9f65, "PCVC3(Track2)" }, - { 0x9f66, "PUNATC(Track2) / Terminal Transaction Qualifiers (TTQ)", EMV_TAG_BITMASK, &EMV_TTQ }, - { 0x9f67, "NATC(Track2) / MSD Offset" }, + { 0x9f62, "PCVC3 (Track1)" }, + { 0x9f63, "PUNATC (Track1)" }, + { 0x9f64, "NATC (Track1)" }, + { 0x9f65, "PCVC3 (Track2)" }, + { 0x9f66, "PUNATC (Track2) / Terminal Transaction Qualifiers (TTQ)", EMV_TAG_BITMASK, &EMV_TTQ }, + { 0x9f67, "NATC (Track2) / MSD Offset" }, { 0x9f68, "Cardholder verification method list (PayPass)" }, - { 0x9f69, "Card Authentication Related Data" }, + { 0x9f69, "Card Authentication Related Data (UDOL)" }, { 0x9f6a, "Unpredictable Number", EMV_TAG_NUMERIC }, { 0x9f6b, "Track 2 Data" }, { 0x9f6c, "Card Transaction Qualifiers (CTQ)", EMV_TAG_BITMASK, &EMV_CTQ }, + { 0x9f6d, "Mag-stripe Application Version Number (Reader)" }, { 0x9f6e, "Form Factor Indicator" }, + { 0x9f6f, "DS Slot Management Control" }, + + { 0x9f70, "Protected Data Envelope 1" }, + { 0x9f71, "Protected Data Envelope 2" }, + { 0x9f72, "Protected Data Envelope 3" }, + { 0x9f73, "Protected Data Envelope 4" }, + { 0x9f74, "Protected Data Envelope 5" }, + { 0x9f75, "Unprotected Data Envelope 1" }, + { 0x9f76, "Unprotected Data Envelope 2" }, + { 0x9f77, "Unprotected Data Envelope 3" }, + { 0x9f78, "Unprotected Data Envelope 4" }, + { 0x9f79, "Unprotected Data Envelope 5" }, + { 0x9f7c, "Merchant Custom Data / Customer Exclusive Data (CED)" }, + { 0x9f7d, "DS Summary 1" }, + { 0x9f7f, "DS Unpredictable Number" }, + { 0xa5 , "File Control Information (FCI) Proprietary Template" }, { 0xbf0c, "File Control Information (FCI) Issuer Discretionary Data" }, { 0xdf20, "Issuer Proprietary Bitmap (IPB)" }, + { 0xdf4b, "POS Cardholder Interaction Information" }, + { 0xdf60, "VISA Log Entry" }, + { 0xdf61, "DS Digest H" }, + { 0xdf62, "DS ODS Info" }, + { 0xdf63, "DS ODS Term" }, + + { 0xdf8104, "Balance Read Before Gen AC" }, + { 0xdf8105, "Balance Read After Gen AC" }, + { 0xdf8106, "Data Needed" }, + { 0xdf8107, "CDOL1 Related Data" }, + { 0xdf8108, "DS AC Type" }, + { 0xdf8109, "DS Input (Term)" }, + { 0xdf810a, "DS ODS Info For Reader" }, + { 0xdf810b, "DS Summary Status" }, + { 0xdf810c, "Kernel ID" }, + { 0xdf810d, "DSVN Term" }, + { 0xdf810e, "Post-Gen AC Put Data Status" }, + { 0xdf810f, "Pre-Gen AC Put Data Status" }, + { 0xdf8110, "Proceed To First Write Flag" }, + { 0xdf8111, "PDOL Related Data" }, + { 0xdf8112, "Tags To Read" }, + { 0xdf8113, "DRDOL Related Data" }, + { 0xdf8114, "Reference Control Parameter" }, + { 0xdf8115, "Error Indication" }, + { 0xdf8116, "User Interface Request Data" }, + { 0xdf8117, "Card Data Input Capability" }, + { 0xdf8118, "CVM Capability - CVM Required" }, + { 0xdf8119, "CVM Capability - No CVM Required" }, + { 0xdf811a, "Default UDOL" }, + { 0xdf811b, "Kernel Configuration" }, + { 0xdf811c, "Max Lifetime of Torn Transaction Log Record" }, + { 0xdf811d, "Max Number of Torn Transaction Log Records" }, + { 0xdf811e, "Mag-stripe CVM Capability – CVM Required" }, + { 0xdf811f, "Security Capability" }, + { 0xdf8120, "Terminal Action Code – Default" }, + { 0xdf8121, "Terminal Action Code – Denial" }, + { 0xdf8122, "Terminal Action Code – Online" }, + { 0xdf8123, "Reader Contactless Floor Limit" }, + { 0xdf8124, "Reader Contactless Transaction Limit (No On-device CVM)" }, + { 0xdf8125, "Reader Contactless Transaction Limit (On-device CVM)" }, + { 0xdf8126, "Reader CVM Required Limit" }, + { 0xdf8127, "TIME_OUT_VALUE" }, + { 0xdf8128, "IDS Status" }, + { 0xdf8129, "Outcome Parameter Set" }, + { 0xdf812a, "DD Card (Track1)" }, + { 0xdf812b, "DD Card (Track2)" }, + { 0xdf812c, "Mag-stripe CVM Capability – No CVM Required" }, + { 0xdf812d, "Message Hold Time" }, + + { 0xff8101, "Torn Record" }, + { 0xff8102, "Tags To Write Before Gen AC" }, + { 0xff8103, "Tags To Write After Gen AC" }, + { 0xff8104, "Data To Send" }, + { 0xff8105, "Data Record" }, + { 0xff8106, "Discretionary Data" }, }; -static int emv_sort_tag(tlv_tag_t tag) -{ +static int emv_sort_tag(tlv_tag_t tag) { return (int)(tag >= 0x100 ? tag : tag << 8); } -static int emv_tlv_compare(const void *a, const void *b) -{ +static int emv_tlv_compare(const void *a, const void *b) { const struct tlv *tlv = a; const struct emv_tag *tag = b; return emv_sort_tag(tlv->tag) - (emv_sort_tag(tag->tag)); } -static const struct emv_tag *emv_get_tag(const struct tlv *tlv) -{ +static const struct emv_tag *emv_get_tag(const struct tlv *tlv) { struct emv_tag *tag = bsearch(tlv, emv_tags, sizeof(emv_tags)/sizeof(emv_tags[0]), sizeof(emv_tags[0]), emv_tlv_compare); @@ -310,8 +453,7 @@ static const char *bitstrings[] = { "1.......", }; -static void emv_tag_dump_bitmask(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) -{ +static void emv_tag_dump_bitmask(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { const struct emv_tag_bit *bits = tag->data; unsigned bit, byte; @@ -331,8 +473,7 @@ static void emv_tag_dump_bitmask(const struct tlv *tlv, const struct emv_tag *ta } } -static void emv_tag_dump_dol(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) -{ +static void emv_tag_dump_dol(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { const unsigned char *buf = tlv->value; size_t left = tlv->len; @@ -353,7 +494,7 @@ static void emv_tag_dump_dol(const struct tlv *tlv, const struct emv_tag *tag, F } } -static void emv_tag_dump_string(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level){ +static void emv_tag_dump_string(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { fprintf(f, "\tString value '"); fwrite(tlv->value, 1, tlv->len, f); fprintf(f, "'\n"); @@ -468,8 +609,6 @@ static void emv_tag_dump_cvr(const struct tlv *tlv, const struct emv_tag *tag, F if (data[0] || data[1] || data[2] || data[3]) emv_tag_dump_bitmask(&bit_tlv, &bit_tag, f, level); - - return; } // EMV Book 3 @@ -512,12 +651,9 @@ static void emv_tag_dump_cid(const struct tlv *tlv, const struct emv_tag *tag, F break; } } - - return; } -static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) -{ +static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { uint32_t X, Y; int i; @@ -615,7 +751,7 @@ static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *t } } -static void emv_tag_dump_afl(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level){ +static void emv_tag_dump_afl(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { if (tlv->len < 4 || tlv->len % 4) { PRINT_INDENT(level); fprintf(f, "\tINVALID!\n"); @@ -628,8 +764,7 @@ static void emv_tag_dump_afl(const struct tlv *tlv, const struct emv_tag *tag, F } } -bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level) -{ +bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level) { if (!tlv) { fprintf(f, "NULL\n"); return false; @@ -682,8 +817,7 @@ bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level) return true; } -char *emv_get_tag_name(const struct tlv *tlv) -{ +char *emv_get_tag_name(const struct tlv *tlv) { static char *defstr = ""; if (!tlv) diff --git a/client/emv/emv_tags.h b/client/emv/emv_tags.h index 246fc72d7..f7d9a8476 100644 --- a/client/emv/emv_tags.h +++ b/client/emv/emv_tags.h @@ -25,6 +25,10 @@ # define EMVAC_TC 0x40 # define EMVAC_ARQC 0x80 # define EMVAC_CDAREQ 0x10 +# define EMVAC_AC2_MASK 0x30 +# define EMVAC_AAC2 0x00 +# define EMVAC_TC2 0x10 +# define EMVAC_ARQC2 0x20 // CID # define EMVCID_ADVICE 0x08 diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 058aefe50..7af08690c 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -120,7 +120,7 @@ static bool print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf) return true; } -void TLVPrintFromBuffer(uint8_t *data, int datalen) { +bool TLVPrintFromBuffer(uint8_t *data, int datalen) { struct tlvdb *t = NULL; t = tlvdb_parse_multi(data, datalen); if (t) { @@ -128,9 +128,11 @@ void TLVPrintFromBuffer(uint8_t *data, int datalen) { tlvdb_visit(t, print_cb, NULL, 0); tlvdb_free(t); + return true; } else { PrintAndLogEx(WARNING, "TLV ERROR: Can't parse response as TLV tree."); } + return false; } void TLVPrintFromTLVLev(struct tlvdb *tlv, int level) { @@ -239,7 +241,7 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField int res = 0; if (ActivateField) { - DropField(); + DropFieldEx( channel ); msleep(50); } @@ -260,8 +262,11 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField } break; case ECC_CONTACT: - //int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +#ifdef WITH_SMARTCARD res = ExchangeAPDUSC(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); +#else + res = 1; +#endif if (res) { return res; } @@ -330,60 +335,145 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO return res; } -int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { +int EMVSelectWithRetry(EMVCommandChannel channel, 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) { + int retrycnt = 0; + int res = 0; + do { + res = EMVSelect(channel, false, true, AID, AIDLen, Result, MaxResultLen, ResultLen, sw, tlv); + + // retry if error and not returned sw error + if (res && res != 5) { + if (++retrycnt < 3){ + continue; + } else { + // card select error, proxmark error + if (res == 1) { + PrintAndLogEx(WARNING, "Exit..."); + return 1; + } + + retrycnt = 0; + PrintAndLogEx(NORMAL, "Retry failed [%s]. Skiped...", sprint_hex_inrow(AID, AIDLen)); + return res; + } + } + } while (res && res != 5); + + return res; +} + +int EMVCheckAID(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlvdbelm, struct tlvdb *tlv){ uint8_t data[APDU_RES_LEN] = {0}; size_t datalen = 0; + int res = 0; + uint16_t sw = 0; + + while (tlvdbelm) { + const struct tlv *tgAID = tlvdb_get_inchild(tlvdbelm, 0x4f, NULL); + if (tgAID) { + res = EMVSelectWithRetry(channel, false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv); + + // if returned sw error + if (res == 5) { + // next element + tlvdbelm = tlvdb_find_next(tlvdbelm, 0x61); + continue; + } + + if (res) + break; + + // all is ok + if (decodeTLV){ + PrintAndLogEx(NORMAL, "%s:", sprint_hex_inrow(tgAID->value, tgAID->len)); + TLVPrintFromBuffer(data, datalen); + } + } + tlvdbelm = tlvdb_find_next(tlvdbelm, 0x61); + } + return res; +} + +int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) { + uint8_t data[APDU_RES_LEN] = {0}; + size_t datalen = 0; + uint8_t sfidata[0x11][APDU_RES_LEN]; + size_t sfidatalen[0x11] = {0}; uint16_t sw = 0; int res; + bool fileFound = false; // select PPSE - res = EMVSelectPSE(channel, ActivateField, true, 2, data, sizeof(data), &datalen, &sw); + res = EMVSelectPSE(channel, ActivateField, true, PSENum, data, sizeof(data), &datalen, &sw); if (!res){ + if (sw != 0x9000) { + PrintAndLogEx(FAILED, "Select PSE error. APDU error: %04x.", sw); + return 1; + } + struct tlvdb *t = NULL; t = tlvdb_parse_multi(data, datalen); if (t) { - int retrycnt = 0; - struct tlvdb *ttmp = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0xbf0c, 0x61, 0x00}); - if (!ttmp) - PrintAndLogEx(FAILED, "PPSE don't have records."); - - while (ttmp) { - const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x4f, NULL); - if (tgAID) { - res = EMVSelect(channel, false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv); - - // retry if error and not returned sw error - if (res && res != 5) { - if (++retrycnt < 3){ - continue; - } else { - // card select error, proxmark error - if (res == 1) { - PrintAndLogEx(WARNING, "Exit..."); - return 1; - } - - retrycnt = 0; - PrintAndLogEx(NORMAL, "Retry failed [%s]. Skiped...", sprint_hex_inrow(tgAID->value, tgAID->len)); - } - - // next element - ttmp = tlvdb_find_next(ttmp, 0x61); - continue; + // PSE/PPSE with SFI + struct tlvdb *tsfi = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0x88, 0x00}); + if (tsfi) { + uint8_t sfin = 0; + tlv_get_uint8(tlvdb_get_tlv(tsfi), &sfin); + PrintAndLogEx(INFO, "* PPSE get SFI: 0x%02x.", sfin); + + for (uint8_t ui = 0x01; ui <= 0x10; ui++) { + PrintAndLogEx(INFO, "* * Get SFI: 0x%02x. num: 0x%02x", sfin, ui); + res = EMVReadRecord(channel, true, sfin, ui, sfidata[ui], APDU_RES_LEN, &sfidatalen[ui], &sw, NULL); + + // end of records + if (sw == 0x6a83) { + sfidatalen[ui] = 0; + PrintAndLogEx(INFO, "* * PPSE get SFI. End of records."); + break; + } + + // error catch! + if (sw != 0x9000) { + sfidatalen[ui] = 0; + PrintAndLogEx(FAILED, "PPSE get Error. APDU error: %04x.", sw); + break; } - retrycnt = 0; - // all is ok if (decodeTLV){ - PrintAndLogEx(NORMAL, "%s:", sprint_hex_inrow(tgAID->value, tgAID->len)); - TLVPrintFromBuffer(data, datalen); + TLVPrintFromBuffer(sfidata[ui], sfidatalen[ui]); + } + } + + for (uint8_t ui = 0x01; ui <= 0x10; ui++) { + if (sfidatalen[ui]) { + struct tlvdb *tsfi = NULL; + tsfi = tlvdb_parse_multi(sfidata[ui], sfidatalen[ui]); + if (tsfi) { + struct tlvdb *tsfitmp = tlvdb_find_path(tsfi, (tlv_tag_t[]){0x70, 0x61, 0x00}); + if (!tsfitmp) { + PrintAndLogEx(FAILED, "SFI 0x%02d don't have records.", sfidatalen[ui]); + continue; + } + res = EMVCheckAID(channel, decodeTLV, tsfitmp, tlv); + fileFound = true; + } + tlvdb_free(tsfi); } } - - ttmp = tlvdb_find_next(ttmp, 0x61); } + + // PSE/PPSE plain (wo SFI) + struct tlvdb *ttmp = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0xbf0c, 0x61, 0x00}); + if (ttmp) { + res = EMVCheckAID(channel, decodeTLV, ttmp, tlv); + fileFound = true; + } + + if (!fileFound) + PrintAndLogEx(FAILED, "PPSE don't have records."); + tlvdb_free(t); } else { PrintAndLogEx(WARNING, "PPSE ERROR: Can't get TLV from response."); @@ -393,7 +483,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO } if(!LeaveFieldON) - DropField(); + DropFieldEx( channel ); return res; } @@ -509,7 +599,7 @@ int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t * } int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv); + return EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, true, Result, MaxResultLen, ResultLen, sw, tlv); } int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { @@ -517,7 +607,7 @@ int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8 } // Authentication -static struct emv_pk *get_ca_pk(struct tlvdb *db) { +struct emv_pk *get_ca_pk(struct tlvdb *db) { const struct tlv *df_tlv = tlvdb_get(db, 0x84, NULL); const struct tlv *caidx_tlv = tlvdb_get(db, 0x8f, NULL); @@ -566,7 +656,7 @@ int trSDA(struct tlvdb *tlv) { struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); if (dac_db) { const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); - PrintAndLogEx(NORMAL, "SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); + PrintAndLogEx(NORMAL, "SDA verified OK. (Data Authentication Code: %02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); tlvdb_add(tlv, dac_db); } else { emv_pk_free(issuer_pk); @@ -595,12 +685,12 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { } const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL); - if (!sda_tlv || sda_tlv->len < 1) { +/* if (!sda_tlv || sda_tlv->len < 1) { it may be 0!!!! emv_pk_free(pk); PrintAndLogEx(WARNING, "Error: Can't find input list for Offline Data Authentication. Exit."); return 3; } - +*/ struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv); if (!issuer_pk) { emv_pk_free(pk); @@ -623,7 +713,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { if (!icc_pk) { emv_pk_free(pk); emv_pk_free(issuer_pk); - PrintAndLogEx(WARNING, "Error: ICC setrificate not found. Exit."); + PrintAndLogEx(WARNING, "Error: ICC certificate not found. Exit."); return 2; } PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", @@ -638,21 +728,25 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { icc_pk->serial[2] ); - struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv); - if (!icc_pe_pk) { - PrintAndLogEx(WARNING, "WARNING: ICC PE PK recover error. "); + if (tlvdb_get(tlv, 0x9f2d, NULL)) { + struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv); + if (!icc_pe_pk) { + PrintAndLogEx(WARNING, "WARNING: ICC PE PK recover error. "); + } else { + PrintAndLogEx(SUCCESS, "ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + icc_pe_pk->rid[0], + icc_pe_pk->rid[1], + icc_pe_pk->rid[2], + icc_pe_pk->rid[3], + icc_pe_pk->rid[4], + icc_pe_pk->index, + icc_pe_pk->serial[0], + icc_pe_pk->serial[1], + icc_pe_pk->serial[2] + ); + } } else { - PrintAndLogEx(SUCCESS, "ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", - icc_pe_pk->rid[0], - icc_pe_pk->rid[1], - icc_pe_pk->rid[2], - icc_pe_pk->rid[3], - icc_pe_pk->rid[4], - icc_pe_pk->index, - icc_pe_pk->serial[0], - icc_pe_pk->serial[1], - icc_pe_pk->serial[2] - ); + PrintAndLogEx(INFO, "ICC PE PK (PIN Encipherment Public Key Certificate) not found.\n"); } // 9F4B: Signed Dynamic Application Data @@ -694,7 +788,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); if (dac_db) { const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); - PrintAndLogEx(NORMAL, "SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); + PrintAndLogEx(NORMAL, "SDAD verified OK. (Data Authentication Code: %02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); tlvdb_add(tlv, dac_db); } else { PrintAndLogEx(WARNING, "Error: SSAD verify error"); @@ -704,7 +798,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { return 4; } - PrintAndLogEx(NORMAL, "\n* Calc DDOL"); + PrintAndLogEx(NORMAL, "\n* * Calc DDOL"); const struct tlv *ddol_tlv = tlvdb_get(tlv, 0x9f49, NULL); if (!ddol_tlv) { ddol_tlv = &default_ddol_tlv; @@ -722,7 +816,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { PrintAndLogEx(NORMAL, "DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); - PrintAndLogEx(NORMAL, "\n* Internal Authenticate"); + PrintAndLogEx(NORMAL, "\n* * Internal Authenticate"); int res = EMVInternalAuthenticate(channel, true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL); if (res) { PrintAndLogEx(WARNING, "Internal Authenticate error(%d): %4x. Exit...", res, sw); @@ -738,11 +832,18 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { if (len < 3 ) { PrintAndLogEx(WARNING, "Error: Internal Authenticate format1 parsing error. length=%d", len); } else { + // parse response 0x80 + struct tlvdb *t80 = tlvdb_parse_multi(buf, len); + const struct tlv * t80tlv = tlvdb_get_tlv(t80); + // 9f4b Signed Dynamic Application Data - dda_db = tlvdb_fixed(0x9f4b, len - 2, buf + 2); + dda_db = tlvdb_fixed(0x9f4b, t80tlv->len, t80tlv->value); tlvdb_add(tlv, dda_db); + + tlvdb_free(t80); + if (decodeTLV){ - PrintAndLogEx(NORMAL, "* * Decode response format 1:"); + PrintAndLogEx(NORMAL, "* * * Decode response format 1:"); TLVPrintFromTLV(dda_db); } } @@ -777,12 +878,12 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { // 9f4c ICC Dynamic Number const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL); if(idn_tlv) { - PrintAndLogEx(NORMAL, "\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len)); - PrintAndLogEx(NORMAL, "DDA verified OK."); + PrintAndLogEx(INFO, "\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len)); + PrintAndLogEx(INFO, "DDA verified OK."); tlvdb_add(tlv, idn_db); tlvdb_free(idn_db); } else { - PrintAndLogEx(NORMAL, "\nERROR: DDA verify error"); + PrintAndLogEx(ERR, "\nDDA verify error"); tlvdb_free(idn_db); emv_pk_free(pk); @@ -898,7 +999,7 @@ int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) { PrintAndLog("WARNING: Issuer certificate not found. Exit."); return 2; } - PrintAndLog("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx", + PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx", issuer_pk->rid[0], issuer_pk->rid[1], issuer_pk->rid[2], @@ -921,10 +1022,10 @@ int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) { if (!icc_pk) { emv_pk_free(pk); emv_pk_free(issuer_pk); - PrintAndLog("WARNING: ICC certificate not found. Exit."); + PrintAndLogEx(WARNING, "WARNING: ICC certificate not found. Exit."); return 2; } - printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", icc_pk->rid[0], icc_pk->rid[1], icc_pk->rid[2], diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index c2b1746e1..9aaaf2e6f 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -39,7 +39,7 @@ typedef enum { enum TransactionType { TT_MSD, - TT_VSDC, // not standart for contactless!!!! + TT_VSDC, // contact only. not standart for contactless TT_QVSDCMCHIP, TT_CDA, }; @@ -65,7 +65,7 @@ enum CardPSVendor { }; extern enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen); -extern void TLVPrintFromBuffer(uint8_t *data, int datalen); +extern bool TLVPrintFromBuffer(uint8_t *data, int datalen); extern void TLVPrintFromTLV(struct tlvdb *tlv); extern void TLVPrintFromTLVLev(struct tlvdb *tlv, int level); extern void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv); @@ -79,7 +79,7 @@ extern void SetAPDULogging(bool logging); extern int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // search application -extern int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); +extern int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv); extern int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); extern int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); extern int EMVSelect(EMVCommandChannel channel, 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); @@ -102,6 +102,7 @@ extern int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_ extern int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root); +extern struct emv_pk *get_ca_pk(struct tlvdb *db); #endif diff --git a/client/emv/emvjson.c b/client/emv/emvjson.c index 116e16da1..dc409a2a5 100644 --- a/client/emv/emvjson.c +++ b/client/emv/emvjson.c @@ -242,24 +242,25 @@ int JsonSaveTLVTree(json_t *root, json_t *elm, char *path, struct tlvdb *tlvdbel bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t * buffer, size_t maxbufferlen, size_t *bufferlen) { int buflen = 0; - switch(param_gethex_to_eol(hexvalue, 0, buffer, maxbufferlen, &buflen)) { - case 1: - PrintAndLog("%s Invalid HEX value.", errormsg); - return false; - case 2: - PrintAndLog("%s Hex value too large.", errormsg); - return false; - case 3: - PrintAndLog("%s Hex value must have even number of digits.", errormsg); - return false; + switch (param_gethex_to_eol(hexvalue, 0, buffer, maxbufferlen, &buflen)) { + case 1: + PrintAndLog("%s Invalid HEX value.", errormsg); + return false; + case 2: + PrintAndLog("%s Hex value too large.", errormsg); + return false; + case 3: + PrintAndLog("%s Hex value must have even number of digits.", errormsg); + return false; } if (buflen > maxbufferlen) { - PrintAndLog("%s HEX length (%d) more than %d", errormsg, *bufferlen, maxbufferlen); + PrintAndLog("%s HEX length (%d) more than %d", errormsg, (bufferlen) ? *bufferlen : -1, maxbufferlen); return false; } - *bufferlen = buflen; + if ( bufferlen ) + *bufferlen = buflen; return true; } @@ -371,14 +372,13 @@ bool ParamLoadFromJson(struct tlvdb *tlv) { uint8_t buf[251] = {0}; size_t buflen = 0; - // here max length must be 4, but now tlv_tag_t is 2-byte var. so let it be 2 by now... TODO: needs refactoring tlv_tag_t... - if (!HexToBuffer("TLV Error type:", tlvTag, buf, 2, &buflen)) { + if (!HexToBuffer("TLV Error type:", tlvTag, buf, 4, &buflen)) { json_decref(root); return false; } tlv_tag_t tag = 0; for (int i = 0; i < buflen; i++) { - tag = (tag << 8) + buf[i]; + tag = (tag << 8) | buf[i]; } if (!HexToBuffer("TLV Error value:", tlvValue, buf, sizeof(buf) - 1, &buflen)) { diff --git a/client/emv/test/cryptotest.c b/client/emv/test/cryptotest.c index 1d5891fe0..4e8df1a25 100644 --- a/client/emv/test/cryptotest.c +++ b/client/emv/test/cryptotest.c @@ -31,6 +31,7 @@ #include "dda_test.h" #include "cda_test.h" #include "crypto/libpcrypto.h" +#include "emv/emv_roca.h" int ExecuteCryptoTests(bool verbose) { int res; @@ -90,11 +91,15 @@ int ExecuteCryptoTests(bool verbose) { res = exec_crypto_test(verbose); if (res) TestFail = true; + res = roca_self_test(); + if (res) TestFail = true; + PrintAndLog("\n--------------------------"); + if (TestFail) - PrintAndLog("Test(s) [ERROR]."); + PrintAndLogEx(FAILED, "\tTest(s) [ %s ]", _RED_(FAIL) ); else - PrintAndLog("Tests [OK]."); + PrintAndLogEx(SUCCESS, "\tTest(s) [ %s ]", _GREEN_(OK) ); return TestFail; } diff --git a/client/emv/tlv.c b/client/emv/tlv.c index 35bdb5d4c..a309d0659 100644 --- a/client/emv/tlv.c +++ b/client/emv/tlv.c @@ -352,19 +352,28 @@ struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[]) { void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other) { + if (tlvdb == other) + return; + while (tlvdb->next) { + if (tlvdb->next == other) + return; + tlvdb = tlvdb->next; } tlvdb->next = other; } -void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value) +void tlvdb_change_or_add_node_ex(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value, struct tlvdb **tlvdb_elm) { struct tlvdb *telm = tlvdb_find_full(tlvdb, tag); if (telm == NULL) { // new tlv element - tlvdb_add(tlvdb, tlvdb_fixed(tag, len, value)); + struct tlvdb *elm = tlvdb_fixed(tag, len, value); + tlvdb_add(tlvdb, elm); + if (tlvdb_elm) + *tlvdb_elm = elm; } else { // the same tlv structure if (telm->tag.tag == tag && telm->tag.len == len && !memcmp(telm->tag.value, value, len)) @@ -400,11 +409,19 @@ void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, co // free old element with childrens telm->next = NULL; tlvdb_free(telm); + + if (tlvdb_elm) + *tlvdb_elm = tnewelm; } return; } +void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value) +{ + tlvdb_change_or_add_node_ex(tlvdb, tag, len, value, NULL); +} + void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level) { struct tlvdb *next = NULL; @@ -458,7 +475,10 @@ const struct tlv *tlvdb_get_inchild(const struct tlvdb *tlvdb, tlv_tag_t tag, co } const struct tlv *tlvdb_get_tlv(const struct tlvdb *tlvdb) { - return &tlvdb->tag; + if (tlvdb) + return &tlvdb->tag; + else + return NULL; } unsigned char *tlv_encode(const struct tlv *tlv, size_t *len) @@ -534,3 +554,46 @@ struct tlvdb *tlvdb_elm_get_parent(struct tlvdb *tlvdb) { return tlvdb->parent; } + +bool tlvdb_get_uint8(struct tlvdb *tlvRoot, tlv_tag_t tag, uint8_t *value) +{ + const struct tlv *tlvelm = tlvdb_get(tlvRoot, tag, NULL); + return tlv_get_uint8(tlvelm, value); +} + +bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value) +{ + *value = 0; + if (etlv) + { + if (etlv->len == 0) + return true; + + if (etlv->len == 1) + { + *value = etlv->value[0]; + return true; + } + } + return false; +} + +bool tlv_get_int(const struct tlv *etlv, int *value) +{ + *value = 0; + if (etlv) + { + if (etlv->len == 0) + return true; + + if (etlv->len <= 4) + { + for (int i = 0; i < etlv->len; i++) + { + *value += etlv->value[i] * (1 << (i * 8)); + } + return true; + } + } + return false; +} diff --git a/client/emv/tlv.h b/client/emv/tlv.h index b25b51de2..e75bbf986 100644 --- a/client/emv/tlv.h +++ b/client/emv/tlv.h @@ -22,7 +22,7 @@ #include #include -typedef uint16_t tlv_tag_t; +typedef uint32_t tlv_tag_t; struct tlv { tlv_tag_t tag; @@ -50,6 +50,7 @@ struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[]); void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other); void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value); +void tlvdb_change_or_add_node_ex(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value, struct tlvdb **tlvdb_elm); void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level); const struct tlv *tlvdb_get(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev); @@ -61,4 +62,9 @@ unsigned char *tlv_encode(const struct tlv *tlv, size_t *len); bool tlv_is_constructed(const struct tlv *tlv); bool tlv_equal(const struct tlv *a, const struct tlv *b); +bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value); +bool tlv_get_int(const struct tlv *etlv, int *value); + +bool tlvdb_get_uint8(struct tlvdb *tlvRoot, tlv_tag_t tag, uint8_t *value); + #endif diff --git a/client/fido/additional_ca.c b/client/fido/additional_ca.c index f529e99b5..564eda2ae 100644 --- a/client/fido/additional_ca.c +++ b/client/fido/additional_ca.c @@ -58,6 +58,23 @@ "U9psmyPzK+Vsgw2jeRQ5JlKDyqE0hebfC1tvFu0CCrJFcw==\r\n" \ "-----END CERTIFICATE-----\r\n" +// Name: SoloKey U2F Root CA Serial 14143382635911888524 (0xc44763928ff4be8c) +// Issued: 2018-11-11 +#define SOLOKEY_CA \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIIB9DCCAZoCCQDER2OSj/S+jDAKBggqhkjOPQQDAjCBgDELMAkGA1UEBhMCVVMx\r\n" \ +"ETAPBgNVBAgMCE1hcnlsYW5kMRIwEAYDVQQKDAlTb2xvIEtleXMxEDAOBgNVBAsM\r\n" \ +"B1Jvb3QgQ0ExFTATBgNVBAMMDHNvbG9rZXlzLmNvbTEhMB8GCSqGSIb3DQEJARYS\r\n" \ +"aGVsbG9Ac29sb2tleXMuY29tMCAXDTE4MTExMTEyNTE0MloYDzIwNjgxMDI5MTI1\r\n" \ +"MTQyWjCBgDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRIwEAYDVQQK\r\n" \ +"DAlTb2xvIEtleXMxEDAOBgNVBAsMB1Jvb3QgQ0ExFTATBgNVBAMMDHNvbG9rZXlz\r\n" \ +"LmNvbTEhMB8GCSqGSIb3DQEJARYSaGVsbG9Ac29sb2tleXMuY29tMFkwEwYHKoZI\r\n" \ +"zj0CAQYIKoZIzj0DAQcDQgAEWHAN0CCJVZdMs0oktZ5m93uxmB1iyq8ELRLtqVFL\r\n" \ +"SOiHQEab56qRTB/QzrpGAY++Y2mw+vRuQMNhBiU0KzwjBjAKBggqhkjOPQQDAgNI\r\n" \ +"ADBFAiEAz9SlrAXIlEu87vra54rICPs+4b0qhp3PdzcTg7rvnP0CIGjxzlteQQx+\r\n" \ +"jQGd7rwSZuE5RWUPVygYhUstQO9zNUOs\r\n" \ +"-----END CERTIFICATE-----\r\n" + /* Concatenation of all additional CA certificates in PEM format if available */ -const char additional_ca_pem[] = GLOBALSIGN_CA YUBICO_CA; +const char additional_ca_pem[] = GLOBALSIGN_CA YUBICO_CA SOLOKEY_CA; const size_t additional_ca_pem_len = sizeof(additional_ca_pem); diff --git a/client/fido/fidocore.c b/client/fido/fidocore.c index ee39fbbe9..49088ec28 100644 --- a/client/fido/fidocore.c +++ b/client/fido/fidocore.c @@ -250,9 +250,9 @@ int FIDOCheckDERAndGetKey(uint8_t *der, size_t derLen, bool verbose, uint8_t *pu uint32_t verifyflags = 0; res = mbedtls_x509_crt_verify(&cert, &cacert, NULL, NULL, &verifyflags, NULL, NULL); if (res) { - PrintAndLog("ERROR: DER verify returned 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res)); + PrintAndLog("ERROR: DER verify returned 0x%x - %s\n", (res<0)?-res:res, ecdsa_get_error(res)); } else { - PrintAndLog("Certificate OK."); + PrintAndLog("Certificate OK.\n"); } if (verbose) { @@ -347,8 +347,10 @@ bool CheckrpIdHash(json_t *json, uint8_t *hash) { uint8_t hash2[32] = {0}; JsonLoadStr(json, "$.RelyingPartyEntity.id", hashval); - sha256hash((uint8_t *)hashval, strlen(hashval), hash2); - + int res = sha256hash((uint8_t *)hashval, strlen(hashval), hash2); + if (res) + return false; + return !memcmp(hash, hash2, 32); } diff --git a/client/flash.c b/client/flash.c index de6fdf7e6..2c06311c3 100644 --- a/client/flash.c +++ b/client/flash.c @@ -38,7 +38,7 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs, flash_seg_t *seg; uint32_t last_end = 0; - ctx->segments = malloc(sizeof(flash_seg_t) * num_phdrs); + ctx->segments = calloc(sizeof(flash_seg_t) * num_phdrs, sizeof(uint8_t)); if (!ctx->segments) { fprintf(stderr, "Out of memory\n"); return -1; @@ -88,7 +88,7 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs, uint8_t *data; // make extra space if we need to move the data forward - data = malloc(filesz + BLOCK_SIZE); + data = calloc(filesz + BLOCK_SIZE, sizeof(uint8_t)); if (!data) { fprintf(stderr, "Error: Out of memory\n"); return -1; @@ -111,7 +111,7 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs, uint32_t new_length = this_end - prev_seg->start; uint32_t this_offset = paddr - prev_seg->start; uint32_t hole = this_offset - prev_seg->length; - uint8_t *new_data = malloc(new_length); + uint8_t *new_data = calloc(new_length, sizeof(uint8_t)); if (!new_data) { fprintf(stderr, "Error: Out of memory\n"); free(data); @@ -223,7 +223,7 @@ int flash_load(flash_file_t *ctx, const char *name, int can_write_bl) { } num_phdrs = le16(ehdr.e_phnum); - phdrs = malloc(le16(ehdr.e_phnum) * sizeof(Elf32_Phdr)); + phdrs = calloc(le16(ehdr.e_phnum) * sizeof(Elf32_Phdr), sizeof(uint8_t)); if (!phdrs) { fprintf(stderr, "Out of memory\n"); goto fail; diff --git a/client/fpga_compress.c b/client/fpga_compress.c index ceba6ac64..6e6e67be4 100644 --- a/client/fpga_compress.c +++ b/client/fpga_compress.c @@ -59,7 +59,7 @@ static void usage(void) static voidpf fpga_deflate_malloc(voidpf opaque, uInt items, uInt size) { - return malloc(items*size); + return calloc(items*size, sizeof(uint8_t)); } @@ -89,9 +89,9 @@ int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile, bool hardn z_stream compressed_fpga_stream; if (hardnested_mode) { - fpga_config = malloc(num_infiles * HARDNESTED_TABLE_SIZE); + fpga_config = calloc(num_infiles * HARDNESTED_TABLE_SIZE, sizeof(uint8_t)); } else { - fpga_config = malloc(num_infiles * FPGA_CONFIG_SIZE); + fpga_config = calloc(num_infiles * FPGA_CONFIG_SIZE, sizeof(uint8_t)); } // read the input files. Interleave them into fpga_config[] i = 0; diff --git a/client/graph.c b/client/graph.c index 4346a8040..42bb79c84 100644 --- a/client/graph.c +++ b/client/graph.c @@ -115,10 +115,13 @@ int GetAskClock(const char *str, bool printAns) { if (st == false) { idx = DetectASKClock(bits, size, &clock, 20); } - setClockGrid(clock, idx); + + if ( clock > 0 ) { + setClockGrid(clock, idx); + } // Only print this message if we're not looping something if (printAns || g_debugMode) - PrintAndLogEx(NORMAL, "Auto-detected clock rate: %d, Best Starting Position: %d", clock, idx); + PrintAndLogEx(SUCCESS, "Auto-detected clock rate: %d, Best Starting Position: %d", clock, idx); return clock; } @@ -137,7 +140,7 @@ uint8_t GetPskCarrier(const char *str, bool printAns) { if (( fc >> 8) == 10 && carrier == 8) return 0; // Only print this message if we're not looping something if (printAns) - PrintAndLogEx(NORMAL, "Auto-detected PSK carrier rate: %d", carrier); + PrintAndLogEx(SUCCESS, "Auto-detected PSK carrier rate: %d", carrier); return carrier; } @@ -159,7 +162,7 @@ int GetPskClock(const char* str, bool printAns) { setClockGrid(clock, firstPhaseShiftLoc); // Only print this message if we're not looping something if (printAns) - PrintAndLogEx(NORMAL, "Auto-detected clock rate: %d", clock); + PrintAndLogEx(SUCCESS, "Auto-detected clock rate: %d", clock); return clock; } @@ -181,7 +184,7 @@ int GetNrzClock(const char* str, bool printAns) { setClockGrid(clock, clkStartIdx); // Only print this message if we're not looping something if (printAns) - PrintAndLogEx(NORMAL, "Auto-detected clock rate: %d", clock); + PrintAndLogEx(SUCCESS, "Auto-detected clock rate: %d", clock); return clock; } //by marshmellow @@ -200,7 +203,7 @@ int GetFskClock(const char* str, bool printAns) { if ((fc1==10 && fc2==8) || (fc1==8 && fc2==5)){ if (printAns) - PrintAndLogEx(NORMAL, "Detected Field Clocks: FC/%d, FC/%d - Bit Clock: RF/%d", fc1, fc2, rf1); + PrintAndLogEx(SUCCESS, "Detected Field Clocks: FC/%d, FC/%d - Bit Clock: RF/%d", fc1, fc2, rf1); setClockGrid(rf1, firstClockEdge); return rf1; } diff --git a/client/hardnested/hardnested_bf_core.c b/client/hardnested/hardnested_bf_core.c index c00434a52..6bf29b795 100644 --- a/client/hardnested/hardnested_bf_core.c +++ b/client/hardnested/hardnested_bf_core.c @@ -59,6 +59,7 @@ THE SOFTWARE. #include #include "crapto1/crapto1.h" #include "parity.h" +#include "util.h" // bitslice type // while AVX supports 256 bit vector floating point operations, we need integer operations for boolean logic @@ -99,9 +100,6 @@ typedef union { // size of nonce to be decrypted #define KEYSTREAM_SIZE 24 -// endianness conversion -#define rev32(word) ((((word) & 0xff) << 24) | ((((word) >> 8) & 0xff) << 16) | ((((word) >> 16) & 0xff) << 8) | ((((word) >> 24) & 0xff))) - // this needs to be compiled several times for each instruction set. // For each instruction set, define a dedicated function name: #if defined (__AVX512F__) @@ -184,7 +182,7 @@ void BITSLICE_TEST_NONCES(uint32_t nonces_to_bruteforce, uint32_t *bf_test_nonce // bitslice nonces' 2nd to 4th byte for (uint32_t i = 0; i < nonces_to_bruteforce; i++) { for(uint32_t bit_idx = 0; bit_idx < KEYSTREAM_SIZE; bit_idx++){ - bool bit = get_bit(KEYSTREAM_SIZE-1-bit_idx, rev32(bf_test_nonce[i] << 8)); + bool bit = get_bit(KEYSTREAM_SIZE-1-bit_idx, BSWAP_32(bf_test_nonce[i] << 8)); if(bit){ bitsliced_encrypted_nonces[i][bit_idx].value = bs_ones.value; } else { diff --git a/client/hardnested/hardnested_bruteforce.c b/client/hardnested/hardnested_bruteforce.c index 55d6bbfbf..1a09d7a49 100644 --- a/client/hardnested/hardnested_bruteforce.c +++ b/client/hardnested/hardnested_bruteforce.c @@ -170,7 +170,9 @@ crack_states_thread(void* x){ __atomic_fetch_add(&found_bs_key, key, __ATOMIC_SEQ_CST); char progress_text[80]; - sprintf(progress_text, "Brute force phase completed. Key found: %012" PRIx64, key); + char keystr[18]; + sprintf(keystr, "%012" PRIx64 " ", key); + sprintf(progress_text, "Brute force phase completed. Key found: " _YELLOW_(%s), keystr); hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0); break; } else if(keys_found){ @@ -311,6 +313,11 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint uint64_t start_time = msclock(); +#if defined(__linux__) || defined(__APPLE__) + if ( NUM_BRUTE_FORCE_THREADS < 0 ) + return false; +#endif + pthread_t threads[NUM_BRUTE_FORCE_THREADS]; struct args { bool silent; @@ -322,7 +329,7 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint uint8_t *best_first_bytes; } thread_args[NUM_BRUTE_FORCE_THREADS]; - for(uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++){ + for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++){ thread_args[i].thread_ID = i; thread_args[i].silent = silent; thread_args[i].cuid = cuid; @@ -332,7 +339,7 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint thread_args[i].best_first_bytes = best_first_bytes; pthread_create(&threads[i], NULL, crack_states_thread, (void*)&thread_args[i]); } - for(uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++){ + for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++){ pthread_join(threads[i], 0); } diff --git a/client/hid-flasher/flash.c b/client/hid-flasher/flash.c index e74f4ed49..c53e560d5 100644 --- a/client/hid-flasher/flash.c +++ b/client/hid-flasher/flash.c @@ -40,7 +40,7 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs, flash_seg_t *seg; uint32_t last_end = 0; - ctx->segments = malloc(sizeof(flash_seg_t) * num_phdrs); + ctx->segments = calloc(sizeof(flash_seg_t) * num_phdrs, sizeof(uint8_t)); if (!ctx->segments) { fprintf(stderr, "Out of memory\n"); return -1; @@ -90,7 +90,7 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs, uint8_t *data; // make extra space if we need to move the data forward - data = malloc(filesz + BLOCK_SIZE); + data = calloc(filesz + BLOCK_SIZE, sizeof(uint8_t)); if (!data) { fprintf(stderr, "Out of memory\n"); return -1; @@ -226,7 +226,7 @@ int flash_load(flash_file_t *ctx, const char *name, int can_write_bl) } num_phdrs = le16(ehdr.e_phnum); - phdrs = malloc(le16(ehdr.e_phnum) * sizeof(Elf32_Phdr)); + phdrs = calloc(le16(ehdr.e_phnum) * sizeof(Elf32_Phdr), sizeof(uint8_t)); if (!phdrs) { fprintf(stderr, "Out of memory\n"); goto fail; diff --git a/client/jansson/Makefile b/client/jansson/Makefile index 7657e35f3..596c1778c 100644 --- a/client/jansson/Makefile +++ b/client/jansson/Makefile @@ -32,7 +32,7 @@ CMDOBJS = $(CFILES:%.c=%.o) CLEAN = $(CMDOBJS) CC= gcc -CFLAGS= -O2 -Wall -Wno-unused-variable -Wno-unused-function +CFLAGS= -O2 -Wall -Wno-unused-variable -Wno-unused-function -Wno-format-truncation LDFLAGS= $(SYSLDFLAGS) $(libjansson_la_LDFLAGS) LIBS= $(SYSLIBS) $(MYLIBS) DEFAULT_INCLUDES = -I. diff --git a/client/jansson/error.c b/client/jansson/error.c index f5da6b9b0..96b3b3fac 100644 --- a/client/jansson/error.c +++ b/client/jansson/error.c @@ -3,8 +3,7 @@ void jsonp_error_init(json_error_t *error, const char *source) { - if(error) - { + if (error) { error->text[0] = '\0'; error->line = -1; error->column = -1; @@ -20,13 +19,13 @@ void jsonp_error_set_source(json_error_t *error, const char *source) { size_t length; - if(!error || !source) + if (!error || !source) return; length = strlen(source); - if(length < JSON_ERROR_SOURCE_LENGTH) - strncpy(error->source, source, length + 1); - else { + if (length < JSON_ERROR_SOURCE_LENGTH) { + strncpy(error->source, source, length); + } else { size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4; memcpy(error->source, "...", 3); strncpy(error->source + 3, source + extra, length - extra + 1); @@ -38,7 +37,6 @@ void jsonp_error_set(json_error_t *error, int line, int column, const char *msg, ...) { va_list ap; - va_start(ap, msg); jsonp_error_vset(error, line, column, position, code, msg, ap); va_end(ap); @@ -48,10 +46,10 @@ void jsonp_error_vset(json_error_t *error, int line, int column, size_t position, enum json_error_code code, const char *msg, va_list ap) { - if(!error) + if (!error) return; - if(error->text[0] != '\0') { + if (error->text[0] != '\0') { /* error already set */ return; } diff --git a/client/jansson/load.c b/client/jansson/load.c index 8700919fd..2f123724e 100644 --- a/client/jansson/load.c +++ b/client/jansson/load.c @@ -114,8 +114,7 @@ static void error_set(json_error_t *error, const lex_t *lex, if(saved_text && saved_text[0]) { if(lex->saved_text.length <= 20) { - snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, - "%s near '%s'", msg_text, saved_text); + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, "%s near '%s'", msg_text, saved_text); msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; result = msg_with_context; } @@ -131,8 +130,7 @@ static void error_set(json_error_t *error, const lex_t *lex, result = msg_text; } else { - snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, - "%s near end of file", msg_text); + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, "%s near end of file", msg_text); msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; result = msg_with_context; } diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c index af11ce4cc..e8553ba6c 100644 --- a/client/loclass/cipher.c +++ b/client/loclass/cipher.c @@ -224,7 +224,7 @@ void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) { uint8_t cc_nr[13] = { 0 }; uint8_t div_key[8]; - //cc_nr=(uint8_t*)malloc(length+1); + //cc_nr=(uint8_t*) calloc(length+1, sizeof(uint8_t)); memcpy(cc_nr, cc_nr_p, 12); memcpy(div_key, div_key_p, 8); @@ -244,7 +244,7 @@ void doMAC_N(uint8_t *address_data_p, uint8_t address_data_size, uint8_t *div_ke { uint8_t *address_data; uint8_t div_key[8]; - address_data = (uint8_t*) malloc(address_data_size); + address_data = (uint8_t*) calloc(address_data_size, sizeof(uint8_t)); memcpy(address_data, address_data_p, address_data_size); memcpy(div_key, div_key_p, 8); diff --git a/client/loclass/cipherutils.h b/client/loclass/cipherutils.h index 568671791..21d11aac0 100644 --- a/client/loclass/cipherutils.h +++ b/client/loclass/cipherutils.h @@ -52,7 +52,7 @@ typedef struct { uint8_t * buffer; uint8_t numbits; uint8_t position; -}BitstreamOut; +} BitstreamOut; bool headBit( BitstreamIn *stream); bool tailBit( BitstreamIn *stream); diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index 2002e348f..630fa72a6 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -493,7 +493,7 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) { uint64_t t1 = msclock(); - dumpdata* attack = (dumpdata* ) malloc(itemsize); + dumpdata* attack = (dumpdata* ) calloc(itemsize, sizeof(uint8_t)); for (i = 0 ; i * itemsize < dumpsize ; i++ ) { memcpy(attack, dump + i * itemsize, itemsize); @@ -538,18 +538,19 @@ int bruteforceFile(const char *filename, uint16_t keytable[]) { if (fsize < 0) { PrintAndLogDevice(WARNING, "Error, when getting filesize"); - if (f) fclose(f); + fclose(f); return 1; } uint8_t *dump = calloc(fsize, sizeof(uint8_t)); if ( !dump ) { PrintAndLogDevice(WARNING, "Failed to allocate memory"); + fclose(f); return 2; } size_t bytes_read = fread(dump, 1, fsize, f); - if (f) fclose(f); + fclose(f); if (bytes_read < fsize) { PrintAndLogDevice(WARNING, "Error, could only read %d bytes (should be %d)", bytes_read, fsize ); diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c index b099d6a35..6f6f1a5a4 100644 --- a/client/loclass/fileutils.c +++ b/client/loclass/fileutils.c @@ -71,14 +71,14 @@ int saveFile(const char *preferredName, const char *suffix, const void* data, si /*Opening file for writing in binary mode*/ FILE *f = fopen(fileName, "wb"); if (!f) { - PrintAndLogDevice(WARNING, "file not found or locked. '%s'", fileName); + PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName); free(fileName); return 1; } fwrite(data, 1, datalen, f); fflush(f); fclose(f); - PrintAndLogDevice(SUCCESS, "saved %u bytes to binary file %s", datalen, fileName); + PrintAndLogDevice(SUCCESS, "saved %u bytes to binary file " _YELLOW_(%s), datalen, fileName); free(fileName); return 0; } @@ -106,8 +106,8 @@ int saveFileEML(const char *preferredName, const char *suffix, uint8_t* data, si /*Opening file for writing in text mode*/ FILE *f = fopen(fileName, "w+"); - if (!f) { - PrintAndLogDevice(WARNING, "file not found or locked. '%s'", fileName); + if (!f) { + PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName); retval = 1; goto out; } @@ -130,7 +130,7 @@ int saveFileEML(const char *preferredName, const char *suffix, uint8_t* data, si } fflush(f); fclose(f); - PrintAndLogDevice(SUCCESS, "saved %d blocks to text file %s", blocks, fileName); + PrintAndLogDevice(SUCCESS, "saved %d blocks to text file " _YELLOW_(%s), blocks, fileName); out: free(fileName); @@ -240,13 +240,12 @@ int saveFileJSON(const char *preferredName, const char *suffix, JSONFileType fty int res = json_dump_file(root, fileName, JSON_INDENT(2)); if (res) { - PrintAndLogDevice(FAILED, "error: can't save the file: %s", fileName); + PrintAndLogDevice(FAILED, "error: can't save the file: " _YELLOW_(%s), fileName); json_decref(root); retval = 200; goto out; } - PrintAndLogDevice(SUCCESS, "File `%s` saved.", fileName); - + PrintAndLogDevice(SUCCESS, "saved to json file " _YELLOW_(%s), fileName); json_decref(root); out: @@ -266,9 +265,9 @@ int loadFile(const char *preferredName, const char *suffix, void* data, size_t* FILE *f = fopen(fileName, "rb"); if ( !f ) { - PrintAndLogDevice(FAILED, "file: %s: not found or locked.", fileName); - retval = 1; - goto out; + PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName); + free(fileName); + return 1; } // get filesize in order to malloc memory @@ -305,13 +304,18 @@ int loadFile(const char *preferredName, const char *suffix, void* data, size_t* memcpy( (data), dump, bytes_read); free(dump); - PrintAndLogDevice(SUCCESS, "loaded %d bytes from binary file %s", bytes_read, fileName); + PrintAndLogDevice(SUCCESS, "loaded %d bytes from binary file " _YELLOW_(%s), bytes_read, fileName); *datalen = bytes_read; out: fclose(f); + + if (data) + free(data); + free(fileName); + return retval; } @@ -319,6 +323,7 @@ int loadFileEML(const char *preferredName, const char *suffix, void* data, size_ if ( preferredName == NULL ) return 1; if ( suffix == NULL ) return 1; + if ( data == NULL ) return 1; size_t counter = 0; int retval = 0, hexlen = 0; @@ -328,7 +333,7 @@ int loadFileEML(const char *preferredName, const char *suffix, void* data, size_ FILE *f = fopen(fileName, "r"); if ( !f ) { - PrintAndLogDevice(FAILED, "file: %s: not found or locked.", fileName); + PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName); retval = 1; goto out; } @@ -359,8 +364,10 @@ int loadFileEML(const char *preferredName, const char *suffix, void* data, size_ } } fclose(f); - PrintAndLogDevice(SUCCESS, "loaded %d bytes from text file %s", counter, fileName); - *datalen = counter; + PrintAndLogDevice(SUCCESS, "loaded %d bytes from text file " _YELLOW_(%s), counter, fileName); + + if ( datalen ) + *datalen = counter; out: free(fileName); @@ -368,12 +375,14 @@ out: } int loadFileJSON(const char *preferredName, const char *suffix, void* data, size_t maxdatalen, size_t* datalen) { - *datalen = 0; - json_t *root; - json_error_t error; if ( preferredName == NULL ) return 1; if ( suffix == NULL ) return 1; + if ( data == NULL ) return 1; + + *datalen = 0; + json_t *root; + json_error_t error; int retval = 0; int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10); @@ -382,13 +391,13 @@ int loadFileJSON(const char *preferredName, const char *suffix, void* data, size root = json_load_file(fileName, 0, &error); if (!root) { - PrintAndLog("ERROR: json (%s) error on line %d: %s", fileName, error.line, error.text); + PrintAndLog("ERROR: json " _YELLOW_(%s) " error on line %d: %s", fileName, error.line, error.text); retval = 2; goto out; } if (!json_is_object(root)) { - PrintAndLog("ERROR: Invalid json (%s) format. root must be an object.", fileName); + PrintAndLog("ERROR: Invalid json " _YELLOW_(%s) " format. root must be an object.", fileName); retval = 3; goto out; } @@ -446,13 +455,82 @@ int loadFileJSON(const char *preferredName, const char *suffix, void* data, size } - PrintAndLog("Loaded JSON: (%s) OK.", fileName); + PrintAndLog("loaded from JSON file " _YELLOW_(%s), fileName); out: json_decref(root); free(fileName); return retval; } +int loadFileDICTIONARY(const char *preferredName, const char *suffix, void* data, size_t* datalen, uint8_t keylen, uint16_t* keycnt ) { + + if ( preferredName == NULL ) return 1; + if ( suffix == NULL ) return 1; + if ( data == NULL ) return 1; + + // t5577 == 4bytes + // mifare == 6 bytes + // iclass == 8 bytes + // default to 6 bytes. + if (keylen != 4 && keylen != 6 && keylen != 8) { + keylen = 6; + } + + // double up since its chars + keylen <<= 1; + + char line[255]; + + size_t counter = 0; + int retval = 0; + int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10); + char * fileName = calloc(size, sizeof(char)); + sprintf(fileName,"%s.%s", preferredName, suffix); + + FILE *f = fopen(fileName, "r"); + if ( !f ) { + PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName); + retval = 1; + goto out; + } + + // read file + while ( fgets(line, sizeof(line), f) ) { + + // add null terminator + line[keylen] = 0; + + // smaller keys than expected is skipped + if (strlen(line) < keylen) + continue; + + + // The line start with # is comment, skip + if( line[0] == '#' ) + continue; + + if (!isxdigit(line[0])){ + PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_(%2d) "HEX symbols", line, keylen); + continue; + } + + uint64_t key = strtoull(line, NULL, 16); + + num_to_bytes(key, keylen >> 1, data + counter); + (*keycnt)++; + memset(line, 0, sizeof(line)); + counter += (keylen >> 1); + } + fclose(f); + PrintAndLogDevice(SUCCESS, "loaded " _GREEN_(%2d) "keys from dictionary file " _YELLOW_(%s), *keycnt, fileName); + + if ( datalen ) + *datalen = counter; +out: + free(fileName); + return retval; +} + #else //if we're on ARM #endif diff --git a/client/loclass/fileutils.h b/client/loclass/fileutils.h index b73f5fc30..9485707f1 100644 --- a/client/loclass/fileutils.h +++ b/client/loclass/fileutils.h @@ -48,7 +48,7 @@ #include #include "../ui.h" #include "../emv/emvjson.h" -#include "mifare4.h" +#include "mifare/mifare4.h" #include "cmdhfmfu.h" typedef enum { @@ -124,7 +124,7 @@ extern int loadFile(const char *preferredName, const char *suffix, void* data, s */ extern int loadFileEML(const char *preferredName, const char *suffix, void* data, size_t* datalen); -/** STUB +/** * @brief Utility function to load data from a JSON textfile. This method takes a preferred name. * E.g. dumpdata-15.json * @@ -137,6 +137,21 @@ extern int loadFileEML(const char *preferredName, const char *suffix, void* data */ extern int loadFileJSON(const char *preferredName, const char *suffix, void* data, size_t maxdatalen, size_t* datalen); + +/** + * @brief Utility function to load data from a DICTIONARY textfile. This method takes a preferred name. + * E.g. default_keys.dic + * + * @param preferredName + * @param suffix the file suffix. Leave out the ".". + * @param data The data array to store the loaded bytes from file + * @param maxdatalen maximum size of data array in bytes + * @param datalen the number of bytes loaded from file + * @param keylen the number of bytes a key per row is + * @return 0 for ok, 1 for failz +*/ +extern int loadFileDICTIONARY(const char *preferredName, const char *suffix, void* data, size_t* datalen, uint8_t keylen, uint16_t* keycnt ); + #define PrintAndLogDevice(level, format, args...) PrintAndLogEx(level, format , ## args) #else diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c index aefbbaf99..c1265dc4d 100644 --- a/client/loclass/ikeys.c +++ b/client/loclass/ikeys.c @@ -428,8 +428,8 @@ void testPermute() printarr("permuted", res, 8); } -//These testcases are -//{ UID , TEMP_KEY, DIV_KEY} using the specific key +// These testcases are +// { UID , TEMP_KEY, DIV_KEY} using the specific key typedef struct { uint8_t uid[8]; @@ -475,7 +475,7 @@ int testDES(Testcase testcase, mbedtls_des_context ctx_enc, mbedtls_des_context return retval; } bool des_getParityBitFromKey(uint8_t key) -{//The top 7 bits is used +{ // The top 7 bits is used bool parity = ((key & 0x80) >> 7) ^ ((key & 0x40) >> 6) ^ ((key & 0x20) >> 5) ^ ((key & 0x10) >> 4) ^ ((key & 0x08) >> 3) @@ -676,7 +676,8 @@ static bool readKeyFile(uint8_t key[8]) { bool retval = false; //Test a few variants - char filename[30]; + char filename[30] = {0}; + if (fileExists("iclass_key.bin")){ sprintf(filename, "%s.bin", "iclass_key"); } else if (fileExists("loclass/iclass_key.bin")){ @@ -685,6 +686,9 @@ static bool readKeyFile(uint8_t key[8]) { sprintf(filename, "%s.bin", "client/loclass/iclass_key"); } + if ( strlen(filename) == 0 ) + return retval; + FILE *f = fopen(filename, "rb"); if (!f) return retval; diff --git a/client/lualibs/taglib.lua b/client/lualibs/taglib.lua index f421ab22f..97194714c 100644 --- a/client/lualibs/taglib.lua +++ b/client/lualibs/taglib.lua @@ -1,72 +1,115 @@ -local manufacturer = {} -manufacturer[0x01]='Motorola [UK]' -manufacturer[0x02]='STMicroelectronics SA [France]' -manufacturer[0x03]='Hitachi, Ltd [Japan]' -manufacturer[0x04]='NXP Semiconductors [Germany]' -manufacturer[0x05]='Infineon Technologies AG [Germany]' -manufacturer[0x06]='Cylink [USA]' -manufacturer[0x07]='Texas Instrument [France]' -manufacturer[0x08]='Fujitsu Limited [Japan]' -manufacturer[0x09]='Matsushita Electronics Corporation, Semiconductor Company [Japan]' -manufacturer[0x0A]='NEC [Japan]' -manufacturer[0x0B]='Oki Electric Industry Co. Ltd [Japan]' -manufacturer[0x0C]='Toshiba Corp. [Japan]' -manufacturer[0x0D]='Mitsubishi Electric Corp. [Japan]' -manufacturer[0x0E]='Samsung Electronics Co. Ltd [Korea]' -manufacturer[0x0F]='Hynix [Korea]' -manufacturer[0x10]='LG-Semiconductors Co. Ltd [Korea]' -manufacturer[0x11]='Emosyn-EM Microelectronics [USA]' -manufacturer[0x12]='INSIDE Technology [France]' -manufacturer[0x13]='ORGA Kartensysteme GmbH [Germany]' -manufacturer[0x14]='SHARP Corporation [Japan]' -manufacturer[0x15]='ATMEL [France]' -manufacturer[0x16]='EM Microelectronic-Marin SA [Switzerland]' -manufacturer[0x17]='KSW Microtec GmbH [Germany]' -manufacturer[0x18]='ZMD AG [Germany]' -manufacturer[0x19]='XICOR, Inc. [USA]' -manufacturer[0x1A]='Sony Corporation [Japan]' -manufacturer[0x1B]='Malaysia Microelectronic Solutions Sdn. Bhd [Malaysia]' -manufacturer[0x1C]='Emosyn [USA]' -manufacturer[0x1D]='Shanghai Fudan Microelectronics Co. Ltd. P.R. [China]' -manufacturer[0x1E]='Magellan Technology Pty Limited [Australia]' -manufacturer[0x1F]='Melexis NV BO [Switzerland]' -manufacturer[0x20]='Renesas Technology Corp. [Japan]' -manufacturer[0x21]='TAGSYS [France]' -manufacturer[0x22]='Transcore [USA]' -manufacturer[0x23]='Shanghai belling corp., ltd. [China]' -manufacturer[0x24]='Masktech Germany Gmbh [Germany]' -manufacturer[0x25]='Innovision Research and Technology Plc [UK]' -manufacturer[0x26]='Hitachi ULSI Systems Co., Ltd. [Japan]' -manufacturer[0x27]='Cypak AB [Sweden]' -manufacturer[0x28]='Ricoh [Japan]' -manufacturer[0x29]='ASK [France]' -manufacturer[0x2A]='Unicore Microsystems, LLC [RussianFederation]' -manufacturer[0x2B]='Dallas Semiconductor/Maxim [USA]' -manufacturer[0x2C]='Impinj, Inc. [USA]' -manufacturer[0x2D]='RightPlug Alliance [USA]' -manufacturer[0x2E]='Broadcom Corporation [USA]' -manufacturer[0x2F]='MStar Semiconductor, Inc Taiwan, [ROC]' -manufacturer[0x30]='BeeDar Technology Inc. [USA]' -manufacturer[0x31]='RFIDsec [Denmark]' -manufacturer[0x32]='Schweizer Electronic AG [Germany]' -manufacturer[0x33]='AMIC Technology Corp [Taiwan]' -manufacturer[0x34]='Mikron JSC [Russia]' -manufacturer[0x35]='Fraunhofer Institute for Photonic Microsystems [Germany]' -manufacturer[0x36]='IDS Microchip AG [Switzerland]' -manufacturer[0x37]='Kovio [USA]' -manufacturer[0x38]='HMT Microelectronic Ltd [Switzerland]' -manufacturer[0x39]='Silicon Craft Technology [Thailand]' -manufacturer[0x3A]='Advanced Film Device Inc. [Japan]' -manufacturer[0x3B]='Nitecrest Ltd [UK]' -manufacturer[0x3C]='Verayo Inc. [USA]' -manufacturer[0x3D]='HID Global [USA]' -manufacturer[0x3E]='Productivity Engineering Gmbh [Germany]' -manufacturer[0x3F]='Austriamicrosystems AG (reserved) [Austria]' -manufacturer[0x40]='Gemalto SA [France]' -manufacturer[0x41]='Renesas Electronics Corporation [Japan]' -manufacturer[0x42]='3Alogics Inc [Korea]' -manufacturer[0x43]='Top TroniQ Asia Limited Hong [Kong]' -manufacturer[0x44]='Gentag Inc (USA) [USA]' +local m = {} +m[0x01]='Motorola UK' +m[0x02]='ST Microelectronics SA France' +m[0x03]='Hitachi, Ltd Japan' +m[0x04]='NXP Semiconductors Germany' +m[0x05]='Infineon Technologies AG Germany' +m[0x06]='Cylink USA' +m[0x07]='Texas Instrument France' +m[0x08]='Fujitsu Limited Japan' +m[0x09]='Matsushita Electronics Corporation, Semiconductor Company Japan' +m[0x0A]='NEC Japan' +m[0x0B]='Oki Electric Industry Co. Ltd Japan' +m[0x0C]='Toshiba Corp. Japan' +m[0x0D]='Mitsubishi Electric Corp. Japan' +m[0x0E]='Samsung Electronics Co. Ltd Korea' +m[0x0F]='Hynix / Hyundai, Korea' +m[0x10]='LG-Semiconductors Co. Ltd Korea' +m[0x11]='Emosyn-EM Microelectronics USA' +m[0x12]='INSIDE Technology France' +m[0x13]='ORGA Kartensysteme GmbH Germany' +m[0x14]='SHARP Corporation Japan' +m[0x15]='ATMEL France' +m[0x16]='EM Microelectronic-Marin SA Switzerland' +m[0x17]='KSW Microtec GmbH Germany' +m[0x18]='ZMD AG Germany' +m[0x19]='XICOR, Inc. USA' +m[0x1A]='Sony Corporation Japan' +m[0x1B]='Malaysia Microelectronic Solutions Sdn. Bhd Malaysia' +m[0x1C]='Emosyn USA' +m[0x1D]='Shanghai Fudan Microelectronics Co. Ltd. P.R. China' +m[0x1E]='Magellan Technology Pty Limited Australia' +m[0x1F]='Melexis NV BO Switzerland' +m[0x20]='Renesas Technology Corp. Japan' +m[0x21]='TAGSYS France' +m[0x22]='Transcore USA' +m[0x23]='Shanghai belling corp., ltd. China' +m[0x24]='Masktech Germany Gmbh Germany' +m[0x25]='Innovision Research and Technology Plc UK' +m[0x26]='Hitachi ULSI Systems Co., Ltd. Japan' +m[0x27]='Cypak AB Sweden' +m[0x28]='Ricoh Japan' +m[0x29]='ASK France' +m[0x2A]='Unicore Microsystems, LLC RussianFederation' +m[0x2B]='Dallas Semiconductor/Maxim USA' +m[0x2C]='Impinj, Inc. USA' +m[0x2D]='RightPlug Alliance USA' +m[0x2E]='Broadcom Corporation USA' +m[0x2F]='MStar Semiconductor, Inc Taiwan, ROC' +m[0x30]='BeeDar Technology Inc. USA' +m[0x31]='RFIDsec Denmark' +m[0x32]='Schweizer Electronic AG Germany' +m[0x33]='AMIC Technology Corp Taiwan' +m[0x34]='Mikron JSC Russia' +m[0x35]='Fraunhofer Institute for Photonic Microsystems Germany' +m[0x36]='IDS Microchip AG Switzerland' +m[0x37]='Kovio USA' +m[0x38]='HMT Microelectronic Ltd Switzerland' +m[0x39]='Silicon Craft Technology Thailand' +m[0x3A]='Advanced Film Device Inc. Japan' +m[0x3B]='Nitecrest Ltd UK' +m[0x3C]='Verayo Inc. USA' +m[0x3D]='HID Global USA' +m[0x3E]='Productivity Engineering Gmbh Germany' +m[0x3F]='Austriamicrosystems AG (reserved) Austria' +m[0x40]='Gemalto SA France' +m[0x41]='Renesas Electronics Corporation Japan' +m[0x42]='3Alogics Inc Korea' +m[0x43]='Top TroniQ Asia Limited Hong Kong' +m[0x44]='Gentag Inc USA' +m[0x45]='Invengo Information Technology Co.Ltd China' +m[0x46]='Guangzhou Sysur Microelectronics, Inc China' +m[0x47]='CEITEC S.A. Brazil' +m[0x48]='Shanghai Quanray Electronics Co. Ltd. China' +m[0x49]='MediaTek Inc Taiwan' +m[0x4A]='Angstrem PJSC Russia' +m[0x4B]='Celisic Semiconductor (Hong Kong) Limited China' +m[0x4C]='LEGIC Identsystems AG Switzerland' +m[0x4D]='Balluff GmbH Germany' +m[0x4E]='Oberthur Technologies France' +m[0x4F]='Silterra Malaysia Sdn. Bhd. Malaysia' +m[0x50]='DELTA Danish Electronics, Light & Acoustics Denmark' +m[0x51]='Giesecke & Devrient GmbH Germany' +m[0x52]='Shenzhen China Vision Microelectronics Co., Ltd. China' +m[0x53]='Shanghai Feiju Microelectronics Co. Ltd. China' +m[0x54]='Intel Corporation USA' +m[0x55]='Microsensys GmbH Germany' +m[0x56]='Sonix Technology Co., Ltd. Taiwan' +m[0x57]='Qualcomm Technologies Inc USA' +m[0x58]='Realtek Semiconductor Corp Taiwan' +m[0x59]='Freevision Technologies Co. Ltd China' +m[0x5A]='Giantec Semiconductor Inc. China' +m[0x5B]='JSC Angstrem-T Russia' +m[0x5C]='STARCHIP France' +m[0x5D]='SPIRTECH France' +m[0x5E]='GANTNER Electronic GmbH Austria' +m[0x5F]='Nordic Semiconductor Norway' +m[0x60]='Verisiti Inc USA' +m[0x61]='Wearlinks Technology Inc. China' +m[0x62]='Userstar Information Systems Co., Ltd Taiwan' +m[0x63]='Pragmatic Printing Ltd. UK' +m[0x64]='Associacao do Laboratorio de Sistemas Integraveis Tecnologico – LSI-TEC Brazil' +m[0x65]='Tendyron Corporation China' +m[0x66]='MUTO Smart Co., Ltd. Korea' +m[0x67]='ON Semiconductor USA' +m[0x68]='TUBITAK BILGEM Turkey' +m[0x69]='Huada Semiconductor Co., Ltd China' +m[0x6A]='SEVENEY France' +m[0x6B]='ISSM France' +m[0x6C]='Wisesec Ltd Israel' +m[0x7C]='DB HiTek Co Ltd Korea' +m[0x7D]='SATO Vicinity Australia' +m[0x7E]='Holtek Taiwan' return { lookupManufacturer = function (value) @@ -76,8 +119,6 @@ return { value = v end - return manufacturer[value] or "no tag-info available" + return m[value] or "no tag-info available" end, - - } \ No newline at end of file diff --git a/client/mifare/mad.c b/client/mifare/mad.c new file mode 100644 index 000000000..34ea50cfc --- /dev/null +++ b/client/mifare/mad.c @@ -0,0 +1,267 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// MIFARE Application Directory (MAD) functions +//----------------------------------------------------------------------------- + +#include "mad.h" +#include "ui.h" +#include "crc.h" +#include "util.h" + +// https://www.nxp.com/docs/en/application-note/AN10787.pdf +static madAIDDescr madKnownAIDs[] = { + {0x0000, "free"}, + {0x0001, "defect, e.g. access keys are destroyed or unknown"}, + {0x0002, "reserved"}, + {0x0003, "contains additional directory info"}, + {0x0004, "contains card holder information in ASCII format."}, + {0x0005, "not applicable (above memory size)"}, + + {0x03e1, "NDEF"}, +}; + +static madAIDDescr madKnownClusterCodes[] = { + {0x00, "cluster: card administration"}, + {0x01, "cluster: miscellaneous applications"}, + {0x02, "cluster: miscellaneous applications"}, + {0x03, "cluster: miscellaneous applications"}, + {0x04, "cluster: miscellaneous applications"}, + {0x05, "cluster: miscellaneous applications"}, + {0x06, "cluster: miscellaneous applications"}, + {0x07, "cluster: miscellaneous applications"}, + {0x08, "cluster: airlines"}, + {0x09, "cluster: ferry traffic"}, + {0x10, "cluster: railway services"}, + {0x11, "cluster: miscellaneous applications"}, + {0x12, "cluster: transport"}, + {0x14, "cluster: security solutions"}, + {0x18, "cluster: city traffic"}, + {0x19, "cluster: Czech Railways"}, + {0x20, "cluster: bus services"}, + {0x21, "cluster: multi modal transit"}, + {0x28, "cluster: taxi"}, + {0x30, "cluster: road toll"}, + {0x31, "cluster: generic transport"}, + {0x38, "cluster: company services"}, + {0x40, "cluster: city card services"}, + {0x47, "cluster: access control & security"}, + {0x48, "cluster: access control & security"}, + {0x49, "cluster: VIGIK"}, + {0x4A, "cluster: Ministry of Defence, Netherlands"}, + {0x4B, "cluster: Bosch Telecom, Germany"}, + {0x4C, "cluster: European Union Institutions"}, + {0x50, "cluster: ski ticketing"}, + {0x51, "cluster: access control & security"}, + {0x52, "cluster: access control & security"}, + {0x53, "cluster: access control & security"}, + {0x54, "cluster: access control & security"}, + {0x55, "cluster: SOAA standard for offline access standard"}, + {0x56, "cluster: access control & security"}, + {0x58, "cluster: academic services"}, + {0x60, "cluster: food"}, + {0x68, "cluster: non-food trade"}, + {0x70, "cluster: hotel"}, + {0x71, "cluster: loyalty"}, + {0x75, "cluster: airport services"}, + {0x78, "cluster: car rental"}, + {0x79, "cluster: Dutch government"}, + {0x80, "cluster: administration services"}, + {0x88, "cluster: electronic purse"}, + {0x90, "cluster: television"}, + {0x91, "cluster: cruise ship"}, + {0x95, "cluster: IOPTA"}, + {0x97, "cluster: metering"}, + {0x98, "cluster: telephone"}, + {0xA0, "cluster: health services"}, + {0xA8, "cluster: warehouse"}, + {0xB0, "cluster: electronic trade"}, + {0xB8, "cluster: banking"}, + {0xC0, "cluster: entertainment & sports"}, + {0xC8, "cluster: car parking"}, + {0xC9, "cluster: fleet management"}, + {0xD0, "cluster: fuel, gasoline"}, + {0xD8, "cluster: info services"}, + {0xE0, "cluster: press"}, + {0xE1, "cluster: NFC Forum"}, + {0xE8, "cluster: computer"}, + {0xF0, "cluster: mail"}, + {0xF8, "cluster: miscellaneous applications"}, +}; + +static const char unknownAID[] = ""; + +static const char *GetAIDDescription(uint16_t AID) { + for(int i = 0; i < ARRAYLEN(madKnownAIDs); i++) + if (madKnownAIDs[i].AID == AID) + return madKnownAIDs[i].Description; + + for(int i = 0; i < ARRAYLEN(madKnownClusterCodes); i++) + if (madKnownClusterCodes[i].AID == (AID >> 8)) // high byte - cluster code + return madKnownClusterCodes[i].Description; + + return unknownAID; +} + +int madCRCCheck(uint8_t *sector, bool verbose, int MADver) { + if (MADver == 1) { + uint8_t crc = CRC8Mad(§or[16 + 1], 15 + 16); + if (crc != sector[16]) { + if (verbose) + PrintAndLogEx(ERR, "Wrong MAD%d CRC. Calculated: 0x%02x, from card: 0x%02x", MADver, crc, sector[16]); + return 3; + }; + } else { + uint8_t crc = CRC8Mad(§or[1], 15 + 16 + 16); + if (crc != sector[0]) { + if (verbose) + PrintAndLogEx(ERR, "Wrong MAD%d CRC. Calculated: 0x%02x, from card: 0x%02x", MADver, crc, sector[16]); + return 3; + }; + } + + return 0; +} + +uint16_t madGetAID(uint8_t *sector, int MADver, int sectorNo) { + if (MADver == 1) + return (sector[16 + 2 + (sectorNo - 1) * 2] << 8) + (sector[16 + 2 + (sectorNo - 1) * 2 + 1]); + else + return (sector[2 + (sectorNo - 1) * 2] << 8) + (sector[2 + (sectorNo - 1) * 2 + 1]); +} + +int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2) { + if (!sector0) + return 1; + + uint8_t GPB = sector0[3 * 16 + 9]; + if (verbose) + PrintAndLogEx(NORMAL, "GPB: 0x%02x", GPB); + + // DA (MAD available) + if (!(GPB & 0x80)) { + PrintAndLogEx(ERR, "DA=0! MAD not available."); + return 1; + } + + // MA (multi-application card) + if (verbose) { + if (GPB & 0x40) + PrintAndLogEx(NORMAL, "Multi application card."); + else + PrintAndLogEx(NORMAL, "Single application card."); + } + + uint8_t MADVer = GPB & 0x03; + if (verbose) + PrintAndLogEx(NORMAL, "MAD version: %d", MADVer); + + // MAD version + if ((MADVer != 0x01) && (MADVer != 0x02)) { + PrintAndLogEx(ERR, "Wrong MAD version: 0x%02x", MADVer); + return 2; + }; + + if (haveMAD2) + *haveMAD2 = (MADVer == 2); + + int res = madCRCCheck(sector0, true, 1); + if (res) + return res; + + if (verbose) + PrintAndLogEx(NORMAL, "CRC8-MAD1 OK."); + + if (MADVer == 2 && sector10) { + int res = madCRCCheck(sector10, true, 2); + if (res) + return res; + + if (verbose) + PrintAndLogEx(NORMAL, "CRC8-MAD2 OK."); + } + + return 0; +} + +int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen) { + *madlen = 0; + bool haveMAD2 = false; + int res = MADCheck(sector0, sector10, false, &haveMAD2); + if (res) + return res; + + for (int i = 1; i < 16; i++) { + mad[*madlen] = madGetAID(sector0, 1, i); + (*madlen)++; + } + + if (haveMAD2) { + // mad2 sector (0x10 == 16dec) here + mad[*madlen] = 0x0005; + (*madlen)++; + + for (int i = 1; i < 24; i++) { + mad[*madlen] = madGetAID(sector10, 2, i); + (*madlen)++; + } + } + + return 0; +} + + +int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2) { + + // check MAD1 only + int res = MADCheck(sector, NULL, verbose, haveMAD2); + if (res) + return res; + + if (verbose) + PrintAndLogEx(NORMAL, "CRC8-MAD OK."); + + // info byte + uint8_t InfoByte = sector[16 + 1] & 0x3f; + if (InfoByte) { + PrintAndLogEx(NORMAL, "Card publisher sector: 0x%02x", InfoByte); + } else { + if (verbose) + PrintAndLogEx(NORMAL, "Card publisher sector not present."); + } + if (InfoByte == 0x10 || InfoByte >= 0x28) + PrintAndLogEx(WARNING, "Info byte error"); + + PrintAndLogEx(NORMAL, "00 MAD1"); + for(int i = 1; i < 16; i++) { + uint16_t AID = madGetAID(sector, 1, i); + PrintAndLogEx(NORMAL, "%02d [%04X] %s", i, AID, GetAIDDescription(AID)); + }; + + return 0; +}; + +int MAD2DecodeAndPrint(uint8_t *sector, bool verbose) { + PrintAndLogEx(NORMAL, "16 MAD2"); + + int res = madCRCCheck(sector, true, 2); + if (res) + return res; + + if (verbose) + PrintAndLogEx(NORMAL, "CRC8-MAD OK."); + + uint8_t InfoByte = sector[1] & 0x3f; + PrintAndLogEx(NORMAL, "MAD2 Card publisher sector: 0x%02x", InfoByte); + + for(int i = 1; i < 8 + 8 + 7 + 1; i++) { + uint16_t AID = madGetAID(sector, 2, i); + PrintAndLogEx(NORMAL, "%02d [%04X] %s", i + 16, AID, GetAIDDescription(AID)); + }; + + return 0; +}; diff --git a/client/mifare/mad.h b/client/mifare/mad.h new file mode 100644 index 000000000..6289982d9 --- /dev/null +++ b/client/mifare/mad.h @@ -0,0 +1,29 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// MIFARE Application Directory (MAD) functions +//----------------------------------------------------------------------------- + +#ifndef _MAD_H_ +#define _MAD_H_ + +#include +#include +#include + +typedef struct { + uint16_t AID; + const char *Description; +} madAIDDescr; + +extern int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2); +extern int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen); +extern int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2); +extern int MAD2DecodeAndPrint(uint8_t *sector, bool verbose); + + +#endif // _MAD_H_ diff --git a/client/mfkey.c b/client/mifare/mfkey.c similarity index 100% rename from client/mfkey.c rename to client/mifare/mfkey.c diff --git a/client/mfkey.h b/client/mifare/mfkey.h similarity index 100% rename from client/mfkey.h rename to client/mifare/mfkey.h diff --git a/client/mifare4.c b/client/mifare/mifare4.c similarity index 58% rename from client/mifare4.c rename to client/mifare/mifare4.c index 0c53a1f9b..c95529a84 100644 --- a/client/mifare4.c +++ b/client/mifare/mifare4.c @@ -17,6 +17,39 @@ #include "ui.h" #include "crypto/libpcrypto.h" +static bool VerboseMode = false; +void mfpSetVerboseMode(bool verbose) { + VerboseMode = verbose; +} + +typedef struct { + uint8_t Code; + const char *Description; +} PlusErrorsElm; + +static const PlusErrorsElm PlusErrors[] = { + {0xFF, ""}, + {0x00, "Transfer cannot be granted within the current authentication."}, + {0x06, "Access Conditions not fulfilled. Block does not exist, block is not a value block."}, + {0x07, "Too many read or write commands in the session or in the transaction."}, + {0x08, "Invalid MAC in command or response"}, + {0x09, "Block Number is not valid"}, + {0x0a, "Invalid block number, not existing block number"}, + {0x0b, "The current command code not available at the current card state."}, + {0x0c, "Length error"}, + {0x0f, "General Manipulation Error. Failure in the operation of the PICC (cannot write to the data block), etc."}, + {0x90, "OK"}, +}; +int PlusErrorsLen = sizeof(PlusErrors) / sizeof(PlusErrorsElm); + +const char * mfpGetErrorDescription(uint8_t errorCode) { + for(int i = 0; i < PlusErrorsLen; i++) + if (errorCode == PlusErrors[i].Code) + return PlusErrors[i].Description; + + return PlusErrors[0].Description; +} + AccessConditions_t MFAccessConditions[] = { {0x00, "rdAB wrAB incAB dectrAB"}, {0x01, "rdAB dectrAB"}, @@ -269,11 +302,136 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF memmove(session->Kmac, kmac, 16); } - PrintAndLogEx(INFO, "Authentication OK"); + if (verbose) + PrintAndLogEx(INFO, "Authentication OK"); return 0; } +int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + if(VerboseMode) + PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen)); + + int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); + + if(VerboseMode) + PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen)); + + return res; +} + +int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00}; + memmove(&rcmd[3], key, 16); + + return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); +} + +int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + uint8_t rcmd[1] = {0xaa}; + + return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); +} + +int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { + uint8_t rcmd[4 + 8] = {(plain?(0x37):(0x33)), blockNum, 0x00, blockCount}; + if (!plain && session) + CalculateMAC(session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode); + + int res = intExchangeRAW14aPlus(rcmd, plain?4:sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); + if(res) + return res; + + if (session) + session->R_Ctr++; + + if(session && mac && *dataoutlen > 11) + CalculateMAC(session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode); + + return 0; +} + +int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { + uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00}; + memmove(&rcmd[3], data, 16); + if (session) + CalculateMAC(session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode); + + int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); + if(res) + return res; + + if (session) + session->W_Ctr++; + + if(session && mac && *dataoutlen > 3) + CalculateMAC(session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode); + + return 0; +} + +int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose){ + uint8_t keyn[2] = {0}; + bool plain = false; + + uint16_t uKeyNum = 0x4000 + sectorNo * 2 + (keyType ? 1 : 0); + keyn[0] = uKeyNum >> 8; + keyn[1] = uKeyNum & 0xff; + if (verbose) + PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNo), sectorNo, uKeyNum); + + mf4Session session; + int res = MifareAuth4(&session, keyn, key, true, true, verbose); + if (res) { + PrintAndLogEx(ERR, "Sector %d authentication error: %d", sectorNo, res); + return res; + } + + uint8_t data[250] = {0}; + int datalen = 0; + uint8_t mac[8] = {0}; + uint8_t firstBlockNo = mfFirstBlockOfSector(sectorNo); + for(int n = firstBlockNo; n < firstBlockNo + mfNumBlocksPerSector(sectorNo); n++) { + res = MFPReadBlock(&session, plain, n & 0xff, 1, false, true, data, sizeof(data), &datalen, mac); + if (res) { + PrintAndLogEx(ERR, "Sector %d read error: %d", sectorNo, res); + DropField(); + return res; + } + + if (datalen && data[0] != 0x90) { + PrintAndLogEx(ERR, "Sector %d card read error: %02x %s", sectorNo, data[0], mfpGetErrorDescription(data[0])); + DropField(); + return 5; + } + if (datalen != 1 + 16 + 8 + 2) { + PrintAndLogEx(ERR, "Sector %d error returned data length:%d", sectorNo, datalen); + DropField(); + return 6; + } + + memcpy(&dataout[(n - firstBlockNo) * 16], &data[1], 16); + + if (verbose) + PrintAndLogEx(INFO, "data[%03d]: %s", n, sprint_hex(&data[1], 16)); + + if (memcmp(&data[1 + 16], mac, 8)) { + PrintAndLogEx(WARNING, "WARNING: mac on block %d not equal...", n); + PrintAndLogEx(WARNING, "MAC card: %s", sprint_hex(&data[1 + 16], 8)); + PrintAndLogEx(WARNING, "MAC reader: %s", sprint_hex(mac, 8)); + + if (!verbose) + return 7; + } else { + if(verbose) + PrintAndLogEx(INFO, "MAC: %s", sprint_hex(&data[1 + 16], 8)); + } + } + DropField(); + + return 0; +} + // Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards), // plus evtl. 8 sectors with 16 blocks each (4k cards) uint8_t mfNumBlocksPerSector(uint8_t sectorNo) { diff --git a/client/mifare4.h b/client/mifare/mifare4.h similarity index 65% rename from client/mifare4.h rename to client/mifare/mifare4.h index 011567a1e..e4bf6e386 100644 --- a/client/mifare4.h +++ b/client/mifare/mifare4.h @@ -43,9 +43,18 @@ typedef struct { char *description; } AccessConditions_t; +extern void mfpSetVerboseMode(bool verbose); +extern const char * mfpGetErrorDescription(uint8_t errorCode); + extern int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose); extern int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose); +extern int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +extern int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +extern int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac); +extern int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac); +extern int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose); + extern char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data); extern uint8_t mfNumBlocksPerSector(uint8_t sectorNo); diff --git a/client/mifaredefault.h b/client/mifare/mifaredefault.h similarity index 70% rename from client/mifaredefault.h rename to client/mifare/mifaredefault.h index 400463eaf..b12a57c03 100644 --- a/client/mifaredefault.h +++ b/client/mifare/mifaredefault.h @@ -31,7 +31,7 @@ static const uint64_t g_mifare_default_keys[] = 0xabcdef123456, 0x4d3a99c351dd, 0x1a982c7e459a, - 0xd3f7d3f7d3f7, + 0xd3f7d3f7d3f7, // NDEF public key 0x714c5c886e97, 0x587ee5f9350f, 0xa0478cc39091, @@ -42,4 +42,9 @@ static const uint64_t g_mifare_default_keys[] = 0x96a301bce267 }; +static const uint8_t g_mifare_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}; +static const uint8_t g_mifare_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; +static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7}; +static const uint8_t g_mifarep_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; + #endif diff --git a/client/mifarehost.c b/client/mifare/mifarehost.c similarity index 93% rename from client/mifarehost.c rename to client/mifare/mifarehost.c index fe2495938..eb89e0389 100644 --- a/client/mifarehost.c +++ b/client/mifare/mifarehost.c @@ -1,988 +1,1015 @@ -// Merlok, 2011, 2012 -// people from mifare@nethemba.com, 2010 -// -// 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. -//----------------------------------------------------------------------------- -// mifare commands -//----------------------------------------------------------------------------- -#include "mifarehost.h" -#include "cmdmain.h" - -int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) { - uint32_t uid = 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; - int16_t isOK = 0; - - UsbCommand c = {CMD_READER_MIFARE, {true, blockno, key_type}}; - - // message - PrintAndLogEx(NORMAL, "--------------------------------------------------------------------------------\n"); - PrintAndLogEx(NORMAL, "executing Darkside attack. Expected execution time: 25sec on average"); - PrintAndLogEx(NORMAL, "press pm3-button on the proxmark3 device to abort both proxmark3 and client."); - PrintAndLogEx(NORMAL, "--------------------------------------------------------------------------------\n"); - - while (true) { - clearCommandBuffer(); - SendCommand(&c); - - //flush queue - while (ukbhit()) { - int gc = getchar(); (void)gc; - return -5; - } - - // wait cycle - while (true) { - printf("."); fflush(stdout); - if (ukbhit()) { - int gc = getchar(); (void)gc; - return -5; - } - - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - isOK = resp.arg[0]; - if (isOK < 0) - return isOK; - - uid = (uint32_t)bytes_to_num(resp.d.asBytes + 0, 4); - 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 = (uint32_t)bytes_to_num(resp.d.asBytes + 24, 4); - ar = (uint32_t)bytes_to_num(resp.d.asBytes + 28, 4); - break; - } - } - PrintAndLogEx(NORMAL, "\n"); - - if (par_list == 0 && c.arg[0] == true) { - PrintAndLogEx(SUCCESS, "Parity is all zero. Most likely this card sends NACK on every authentication."); - } - c.arg[0] = false; - - keycount = nonce2key(uid, nt, nr, ar, par_list, ks_list, &keylist); - - if (keycount == 0) { - PrintAndLogEx(FAILED, "key not found (lfsr_common_prefix list is null). Nt=%08x", nt); - PrintAndLogEx(FAILED, "this is expected to happen in 25%% of all cases. Trying again with a different reader nonce..."); - continue; - } - - // only parity zero attack - 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; - PrintAndLogEx(FAILED, "no candidates found, trying again"); - continue; - } - } - - PrintAndLogEx(SUCCESS, "found %u candidate key%s\n", keycount, (keycount > 1) ? "s." : "."); - - *key = -1; - uint8_t keyBlock[USB_CMD_DATA_SIZE]; - int max_keys = USB_CMD_DATA_SIZE / 6; - 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 (par_list == 0) { - num_to_bytes(last_keylist[i*max_keys + j], 6, keyBlock+(j*6)); - } else { - num_to_bytes(keylist[i*max_keys + j], 6, keyBlock+(j*6)); - } - } - - if (!mfCheckKeys(blockno, key_type - 0x60, false, size, keyBlock, key)) { - break; - } - } - - if (*key != -1) { - break; - } else { - PrintAndLogEx(FAILED, "all candidate keys failed. Restarting darkside attack"); - free(last_keylist); - last_keylist = keylist; - c.arg[0] = true; - } - } - free(last_keylist); - free(keylist); - return 0; -} -int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){ - *key = -1; - UsbCommand c = {CMD_MIFARE_CHKKEYS, { (blockNo | (keyType << 8)), clear_trace, keycnt}}; - memcpy(c.d.asBytes, keyBlock, 6 * keycnt); - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) return 1; - if ((resp.arg[0] & 0xff) != 0x01) return 2; - *key = bytes_to_num(resp.d.asBytes, 6); - return 0; -} - -// Sends chunks of keys to device. -// 0 == ok all keys found -// 1 == -// 2 == Time-out, aborting -int mfCheckKeys_fast( uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, uint8_t strategy, - uint32_t size, uint8_t *keyBlock, sector_t *e_sector) { - - uint64_t t2 = msclock(); - uint32_t timeout = 0; - - // send keychunk - UsbCommand c = {CMD_MIFARE_CHKKEYS_FAST, { (sectorsCnt | (firstChunk << 8) | (lastChunk << 12) ), strategy, size}}; - memcpy(c.d.asBytes, keyBlock, 6 * size); - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - - while ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { - timeout++; - printf("."); fflush(stdout); - // max timeout for one chunk of 85keys, 60*3sec = 180seconds - // s70 with 40*2 keys to check, 80*85 = 6800 auth. - // takes about 97s, still some margin before abort - if (timeout > 180) { - PrintAndLogEx(WARNING, "\nno response from Proxmark. Aborting..."); - return 2; - } - } - t2 = msclock() - t2; - - // time to convert the returned data. - uint8_t curr_keys = resp.arg[0]; - - PrintAndLogEx(NORMAL, "\n[-] Chunk: %.1fs | found %u/%u keys (%u)", (float)(t2/1000.0), curr_keys, (sectorsCnt<<1), size); - - // all keys? - if ( curr_keys == sectorsCnt*2 || lastChunk ) { - - // success array. each byte is status of key - uint8_t arr[80]; - uint64_t foo = bytes_to_num(resp.d.asBytes+480, 8); - for (uint8_t i = 0; i < 64; ++i) { - arr[i] = (foo >> i) & 0x1; - } - foo = bytes_to_num(resp.d.asBytes+488, 2); - for (uint8_t i = 0; i < 16; ++i) { - arr[i+64] = (foo >> i) & 0x1; - } - - // initialize storage for found keys - icesector_t *tmp = NULL; - tmp = calloc(sectorsCnt, sizeof(icesector_t)); - if (tmp == NULL) - return 1; - memcpy(tmp, resp.d.asBytes, sectorsCnt * sizeof(icesector_t) ); - - for ( int i = 0; i < sectorsCnt; i++) { - // key A - if ( !e_sector[i].foundKey[0] ) { - e_sector[i].Key[0] = bytes_to_num( tmp[i].keyA, 6); - e_sector[i].foundKey[0] = arr[ (i*2) ]; - } - // key B - if ( !e_sector[i].foundKey[1] ) { - e_sector[i].Key[1] = bytes_to_num( tmp[i].keyB, 6); - e_sector[i].foundKey[1] = arr[ (i*2) + 1 ]; - } - } - free(tmp); - - if ( curr_keys == sectorsCnt*2 ) - return 0; - if ( lastChunk ) - return 1; - } - return 1; -} - -// PM3 imp of J-Run mf_key_brute (part 2) -// ref: https://github.com/J-Run/mf_key_brute -int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey){ - - #define KEYS_IN_BLOCK 85 - #define KEYBLOCK_SIZE 510 - #define CANDIDATE_SIZE 0xFFFF * 6 - uint8_t found = false; - uint64_t key64 = 0; - uint8_t candidates[CANDIDATE_SIZE] = {0x00}; - uint8_t keyBlock[KEYBLOCK_SIZE] = {0x00}; - - memset(candidates, 0, sizeof(candidates)); - memset(keyBlock, 0, sizeof(keyBlock)); - - // Generate all possible keys for the first two unknown bytes. - for (uint16_t i = 0; i < 0xFFFF; ++i) { - uint32_t j = i * 6; - candidates[0 + j] = i >> 8; - candidates[1 + j] = i; - candidates[2 + j] = key[2]; - candidates[3 + j] = key[3]; - candidates[4 + j] = key[4]; - candidates[5 + j] = key[5]; - } - uint32_t counter, i; - for ( i = 0, counter = 1; i < CANDIDATE_SIZE; i += KEYBLOCK_SIZE, ++counter){ - - key64 = 0; - - // copy candidatekeys to test key block - memcpy(keyBlock, candidates + i, KEYBLOCK_SIZE); - - // check a block of generated candidate keys. - if (!mfCheckKeys(blockNo, keyType, true, KEYS_IN_BLOCK, keyBlock, &key64)) { - *resultkey = key64; - found = true; - break; - } - - // progress - if ( counter % 20 == 0 ) - PrintAndLogEx(SUCCESS, "tried : %s.. \t %u keys", sprint_hex(candidates + i, 6), counter * KEYS_IN_BLOCK ); - } - return found; -} - -// Compare 16 Bits out of cryptostate -int Compare16Bits(const void * a, const void * b) { - if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0; - if ((*(uint64_t*)b & 0x00ff000000ff0000) > (*(uint64_t*)a & 0x00ff000000ff0000)) return 1; - return -1; -} - -// wrapper function for multi-threaded lfsr_recovery32 -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; - statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt ^ statelist->uid); - - for (p1 = statelist->head.slhead; *(uint64_t *)p1 != 0; p1++) {}; - - statelist->len = p1 - statelist->head.slhead; - statelist->tail.sltail = --p1; - qsort(statelist->head.slhead, statelist->len, sizeof(uint64_t), Compare16Bits); - - 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; - uint32_t uid; - UsbCommand resp; - StateList_t statelists[2]; - struct Crypto1State *p1, *p2, *p3, *p4; - - UsbCommand c = {CMD_MIFARE_NESTED, {blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, calibrate}}; - memcpy(c.d.asBytes, key, 6); - clearCommandBuffer(); - SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return -1; - - // error during nested - if (resp.arg[0]) return resp.arg[0]; - - memcpy(&uid, resp.d.asBytes, 4); - - for (i = 0; i < 2; i++) { - statelists[i].blockNo = resp.arg[2] & 0xff; - statelists[i].keyType = (resp.arg[2] >> 8) & 0xff; - statelists[i].uid = uid; - memcpy(&statelists[i].nt, (void *)(resp.d.asBytes + 4 + i * 8 + 0), 4); - memcpy(&statelists[i].ks1, (void *)(resp.d.asBytes + 4 + i * 8 + 4), 4); - } - - // calc keys - pthread_t thread_id[2]; - - // create and run worker threads - for (i = 0; i < 2; i++) - pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]); - - // wait for threads to terminate: - for (i = 0; i < 2; i++) - pthread_join(thread_id[i], (void*)&statelists[i].head.slhead); - - // the first 16 Bits of the cryptostate already contain part of our key. - // Create the intersection of the two lists based on these 16 Bits and - // roll back the cryptostate - p1 = p3 = statelists[0].head.slhead; - p2 = p4 = statelists[1].head.slhead; - - while (p1 <= statelists[0].tail.sltail && p2 <= statelists[1].tail.sltail) { - if (Compare16Bits(p1, p2) == 0) { - - struct Crypto1State savestate, *savep = &savestate; - savestate = *p1; - while(Compare16Bits(p1, savep) == 0 && p1 <= statelists[0].tail.sltail) { - *p3 = *p1; - lfsr_rollback_word(p3, statelists[0].nt ^ statelists[0].uid, 0); - p3++; - p1++; - } - savestate = *p2; - while(Compare16Bits(p2, savep) == 0 && p2 <= statelists[1].tail.sltail) { - *p4 = *p2; - lfsr_rollback_word(p4, statelists[1].nt ^ statelists[1].uid, 0); - p4++; - p2++; - } - } - else { - while (Compare16Bits(p1, p2) == -1) p1++; - while (Compare16Bits(p1, p2) == 1) p2++; - } - } - - *(uint64_t*)p3 = -1; - *(uint64_t*)p4 = -1; - statelists[0].len = p3 - statelists[0].head.slhead; - statelists[1].len = p4 - statelists[1].head.slhead; - statelists[0].tail.sltail = --p3; - statelists[1].tail.sltail = --p4; - - // the statelists now contain possible keys. The key we are searching for must be in the - // intersection of both lists - qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compare_uint64); - qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64); - // Create the intersection - statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead); - - //statelists[0].tail.keytail = --p7; - uint32_t keycnt = statelists[0].len; - if ( keycnt == 0 ) goto out; - - memset(resultKey, 0, 6); - uint64_t key64 = -1; - - // The list may still contain several key candidates. Test each of them with mfCheckKeys - uint32_t max_keys = keycnt > (USB_CMD_DATA_SIZE/6) ? (USB_CMD_DATA_SIZE/6) : keycnt; - uint8_t keyBlock[USB_CMD_DATA_SIZE] = {0x00}; - - for (int i = 0; i < keycnt; i += max_keys) { - - int size = keycnt - i > max_keys ? max_keys : keycnt - i; - - for (int j = 0; j < size; j++) { - crypto1_get_lfsr(statelists[0].head.slhead + i, &key64); - num_to_bytes(key64, 6, keyBlock + i * 6); - } - - if (!mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, size, keyBlock, &key64)) { - free(statelists[0].head.slhead); - free(statelists[1].head.slhead); - num_to_bytes(key64, 6, resultKey); - - PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [%012" PRIx64 "]", - (uint16_t)resp.arg[2] & 0xff, - (resp.arg[2] >> 8) ? 'B' : 'A', - key64 - ); - return -5; - } - } - -out: - PrintAndLogEx(SUCCESS, "target block:%3u key type: %c", - (uint16_t)resp.arg[2] & 0xff, - (resp.arg[2] >> 8) ? 'B' : 'A' - ); - - free(statelists[0].head.slhead); - free(statelists[1].head.slhead); - return -4; -} - -// EMULATOR -int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) { - UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return 1; - memcpy(data, resp.d.asBytes, blocksCount * 16); - return 0; -} - -int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount) { - return mfEmlSetMem_xt(data, blockNum, blocksCount, 16); -} - -int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth) { - UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNum, blocksCount, blockBtWidth}}; - memcpy(c.d.asBytes, data, blocksCount * blockBtWidth); - clearCommandBuffer(); - SendCommand(&c); - return 0; -} - -// "MAGIC" CARD -int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_t wipecard) { - - uint8_t params = MAGIC_SINGLE; - uint8_t block0[16]; - memset(block0, 0x00, sizeof(block0)); - - int old = mfCGetBlock(0, block0, params); - if (old == 0) - PrintAndLogEx(SUCCESS, "old block 0: %s", sprint_hex(block0, sizeof(block0))); - else - PrintAndLogEx(FAILED, "couldn't get old data. Will write over the last bytes of Block 0."); - - // fill in the new values - // UID - memcpy(block0, uid, 4); - // Mifare UID BCC - block0[4] = block0[0] ^ block0[1] ^ block0[2] ^ block0[3]; - // mifare classic SAK(byte 5) and ATQA(byte 6 and 7, reversed) - if ( sak != NULL ) - block0[5] = sak[0]; - - if ( atqa != NULL ) { - block0[6] = atqa[1]; - block0[7] = atqa[0]; - } - PrintAndLogEx(SUCCESS, "new block 0: %s", sprint_hex(block0,16)); - - if ( wipecard ) params |= MAGIC_WIPE; - if ( oldUID == NULL) params |= MAGIC_UID; - - return mfCSetBlock(0, block0, oldUID, params); -} - -int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params) { - - uint8_t isOK = 0; - UsbCommand c = {CMD_MIFARE_CSETBLOCK, {params, blockNo, 0}}; - memcpy(c.d.asBytes, data, 16); - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - isOK = resp.arg[0] & 0xff; - if (uid != NULL) - memcpy(uid, resp.d.asBytes, 4); - if (!isOK) - return 2; - } else { - PrintAndLogEx(WARNING, "command execute timeout"); - return 1; - } - return 0; -} - -int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) { - uint8_t isOK = 0; - UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, blockNo, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - isOK = resp.arg[0] & 0xff; - if (!isOK) - return 2; - memcpy(data, resp.d.asBytes, 16); - } else { - PrintAndLogEx(WARNING, "command execute timeout"); - return 1; - } - return 0; -} - -// SNIFFER -// [iceman] so many global variables.... - -// constants -static uint8_t trailerAccessBytes[4] = {0x08, 0x77, 0x8F, 0x00}; - -// variables -char logHexFileName[FILE_PATH_SIZE] = {0x00}; -static uint8_t traceCard[4096] = {0x00}; -static char traceFileName[FILE_PATH_SIZE] = {0x00}; -static int traceState = TRACE_IDLE; -static uint8_t traceCurBlock = 0; -static uint8_t traceCurKey = 0; - -struct Crypto1State *traceCrypto1 = NULL; -struct Crypto1State *revstate = NULL; -uint64_t key = 0; -uint32_t ks2 = 0; -uint32_t ks3 = 0; - -uint32_t cuid = 0; // uid part used for crypto1. -uint32_t nt = 0; // tag challenge -uint32_t nr_enc = 0; // encrypted reader challenge -uint32_t ar_enc = 0; // encrypted reader response -uint32_t at_enc = 0; // encrypted tag response - -int isTraceCardEmpty(void) { - return ((traceCard[0] == 0) && (traceCard[1] == 0) && (traceCard[2] == 0) && (traceCard[3] == 0)); -} - -int isBlockEmpty(int blockN) { - for (int i = 0; i < 16; i++) - if (traceCard[blockN * 16 + i] != 0) return 0; - - return 1; -} - -int isBlockTrailer(int blockN) { - return ((blockN & 0x03) == 0x03); -} - -int loadTraceCard(uint8_t *tuid, uint8_t uidlen) { - FILE * f; - char buf[64] = {0x00}; - uint8_t buf8[64] = {0x00}; - int i, blockNum; - uint32_t tmp; - - if (!isTraceCardEmpty()) - saveTraceCard(); - - memset(traceCard, 0x00, 4096); - memcpy(traceCard, tuid, uidlen); - - FillFileNameByUID(traceFileName, tuid, ".eml", uidlen); - - f = fopen(traceFileName, "r"); - if (!f) return 1; - - blockNum = 0; - - while (!feof(f)){ - - memset(buf, 0, sizeof(buf)); - if (fgets(buf, sizeof(buf), f) == NULL) { - PrintAndLogEx(FAILED, "No trace file found or reading error."); - if (f) { - fclose(f); - } - return 2; - } - - if (strlen(buf) < 32){ - if (feof(f)) break; - PrintAndLogEx(FAILED, "File content error. Block data must include 32 HEX symbols"); - if (f) { - fclose(f); - } - return 2; - } - for (i = 0; i < 32; i += 2) { - sscanf(&buf[i], "%02X", &tmp); - buf8[i / 2] = tmp & 0xFF; - } - - memcpy(traceCard + blockNum * 16, buf8, 16); - - blockNum++; - } - if (f) { - fclose(f); - } - return 0; -} - -int saveTraceCard(void) { - - if ((!strlen(traceFileName)) || (isTraceCardEmpty())) return 0; - - FILE * f; - f = fopen(traceFileName, "w+"); - if ( !f ) return 1; - - // given 4096 tracecard size, these loop will only match a 1024, 1kb card memory - // 4086/16 == 256blocks. - for (uint16_t i = 0; i < 256; i++) { // blocks - for (uint8_t j = 0; j < 16; j++) // bytes - fprintf(f, "%02X", *(traceCard + i * 16 + j)); - - // no extra line in the end - if ( i < 255 ) - fprintf(f, "\n"); - } - fflush(f); - fclose(f); - return 0; -} -// -int mfTraceInit(uint8_t *tuid, uint8_t uidlen, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile) { - - if (traceCrypto1) - crypto1_destroy(traceCrypto1); - - traceCrypto1 = NULL; - - if (wantSaveToEmlFile) - loadTraceCard(tuid, uidlen); - - traceCard[4] = traceCard[0] ^ traceCard[1] ^ traceCard[2] ^ traceCard[3]; - traceCard[5] = sak; - memcpy(&traceCard[6], atqa, 2); - traceCurBlock = 0; - cuid = bytes_to_num(tuid + (uidlen-4), 4); - traceState = TRACE_IDLE; - return 0; -} - -void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted){ - uint8_t bt = 0; - int i; - - if (len != 1) { - for (i = 0; i < len; i++) - data[i] = crypto1_byte(pcs, 0x00, isEncrypted) ^ data[i]; - } else { - bt = 0; - bt |= (crypto1_bit(pcs, 0, isEncrypted) ^ BIT(data[0], 0)) << 0; - bt |= (crypto1_bit(pcs, 0, isEncrypted) ^ BIT(data[0], 1)) << 1; - bt |= (crypto1_bit(pcs, 0, isEncrypted) ^ BIT(data[0], 2)) << 2; - bt |= (crypto1_bit(pcs, 0, isEncrypted) ^ BIT(data[0], 3)) << 3; - data[0] = bt; - } -} - -int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) { - - if (traceState == TRACE_ERROR) - return 1; - - if (len > 255) { - traceState = TRACE_ERROR; - return 1; - } - - uint8_t data[255]; - memset(data, 0x00, sizeof(data)); - - memcpy(data, data_src, len); - - if ((traceCrypto1) && ((traceState == TRACE_IDLE) || (traceState > TRACE_AUTH_OK))) { - mf_crypto1_decrypt(traceCrypto1, data, len, 0); - PrintAndLogEx(NORMAL, "DEC| %s", sprint_hex(data, len)); - AddLogHex(logHexFileName, "DEC| ", data, len); - } - - switch (traceState) { - case TRACE_IDLE: - // check packet crc16! - if ((len >= 4) && (!check_crc(CRC_14443_A, data, len))) { - PrintAndLogEx(NORMAL, "DEC| CRC ERROR!!!"); - AddLogLine(logHexFileName, "DEC| ", "CRC ERROR!!!"); - traceState = TRACE_ERROR; // do not decrypt the next commands - return 1; - } - - // AUTHENTICATION - if ((len == 4) && ((data[0] == MIFARE_AUTH_KEYA) || (data[0] == MIFARE_AUTH_KEYB))) { - traceState = TRACE_AUTH1; - traceCurBlock = data[1]; - traceCurKey = data[0] == 60 ? 1:0; - return 0; - } - - // READ - if ((len == 4) && ((data[0] == ISO14443A_CMD_READBLOCK))) { - traceState = TRACE_READ_DATA; - traceCurBlock = data[1]; - return 0; - } - - // WRITE - if ((len == 4) && ((data[0] == ISO14443A_CMD_WRITEBLOCK))) { - traceState = TRACE_WRITE_OK; - traceCurBlock = data[1]; - return 0; - } - - // HALT - if ((len == 4) && ((data[0] == ISO14443A_CMD_HALT) && (data[1] == 0x00))) { - traceState = TRACE_ERROR; // do not decrypt the next commands - return 0; - } - return 0; - - case TRACE_READ_DATA: - if (len == 18) { - traceState = TRACE_IDLE; - - if (isBlockTrailer(traceCurBlock)) { - memcpy(traceCard + traceCurBlock * 16 + 6, data + 6, 4); - } else { - memcpy(traceCard + traceCurBlock * 16, data, 16); - } - if (wantSaveToEmlFile) saveTraceCard(); - return 0; - } else { - traceState = TRACE_ERROR; - return 1; - } - break; - case TRACE_WRITE_OK: - if ((len == 1) && (data[0] == 0x0a)) { - traceState = TRACE_WRITE_DATA; - return 0; - } else { - traceState = TRACE_ERROR; - return 1; - } - break; - case TRACE_WRITE_DATA: - if (len == 18) { - traceState = TRACE_IDLE; - memcpy(traceCard + traceCurBlock * 16, data, 16); - if (wantSaveToEmlFile) saveTraceCard(); - return 0; - } else { - traceState = TRACE_ERROR; - return 1; - } - break; - case TRACE_AUTH1: - if (len == 4) { - traceState = TRACE_AUTH2; - nt = bytes_to_num(data, 4); - return 0; - } else { - traceState = TRACE_ERROR; - return 1; - } - break; - case TRACE_AUTH2: - if (len == 8) { - traceState = TRACE_AUTH_OK; - nr_enc = bytes_to_num(data, 4); - ar_enc = bytes_to_num(data + 4, 4); - return 0; - } else { - traceState = TRACE_ERROR; - return 1; - } - break; - case TRACE_AUTH_OK: - if (len == 4) { - traceState = TRACE_IDLE; - at_enc = bytes_to_num(data, 4); - - // mfkey64 recover key. - 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, cuid ^ nt, 0); - crypto1_get_lfsr(revstate, &key); - PrintAndLogEx(SUCCESS, "found Key: [%012" PRIx64 "]", key); - - //if ( tryMfk64(cuid, nt, nr_enc, ar_enc, at_enc, &key) ) - AddLogUint64(logHexFileName, "Found Key: ", key); - - int blockShift = ((traceCurBlock & 0xFC) + 3) * 16; - if (isBlockEmpty((traceCurBlock & 0xFC) + 3)) - memcpy(traceCard + blockShift + 6, trailerAccessBytes, 4); - - // keytype A/B - if (traceCurKey) - num_to_bytes(key, 6, traceCard + blockShift + 10); - else - num_to_bytes(key, 6, traceCard + blockShift); - - if (wantSaveToEmlFile) - saveTraceCard(); - - if (traceCrypto1) - crypto1_destroy(traceCrypto1); - - // set cryptosystem state - traceCrypto1 = lfsr_recovery64(ks2, ks3); - - } else { - PrintAndLogEx(NORMAL, "[!] nested key recovery not implemented!\n"); - at_enc = bytes_to_num(data, 4); - crypto1_destroy(traceCrypto1); - traceState = TRACE_ERROR; - } - break; - default: - traceState = TRACE_ERROR; - return 1; - } - return 0; -} - -int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len){ - PrintAndLogEx(SUCCESS, "\nencrypted data: [%s]", sprint_hex(data, len) ); - struct Crypto1State *s; - ks2 = ar_enc ^ prng_successor(nt, 64); - ks3 = at_enc ^ prng_successor(nt, 96); - s = lfsr_recovery64(ks2, ks3); - mf_crypto1_decrypt(s, data, len, false); - PrintAndLogEx(SUCCESS, "decrypted data: [%s]", sprint_hex(data, len) ); - crypto1_destroy(s); - return 0; -} - -/* Detect Tag Prng, -* function performs a partial AUTH, where it tries to authenticate against block0, key A, but only collects tag nonce. -* the tag nonce is check to see if it has a predictable PRNG. -* @returns -* TRUE if tag uses WEAK prng (ie Now the NACK bug also needs to be present for Darkside attack) -* FALSE is tag uses HARDEND prng (ie hardnested attack possible, with known key) -*/ -int detect_classic_prng(void){ - - UsbCommand resp, respA; - uint8_t cmd[] = {MIFARE_AUTH_KEYA, 0x00}; - uint32_t flags = ISO14A_CONNECT | ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_RATS; - - UsbCommand c = {CMD_READER_ISO_14443a, {flags, sizeof(cmd), 0}}; - memcpy(c.d.asBytes, cmd, sizeof(cmd)); - - clearCommandBuffer(); - SendCommand(&c); - - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(WARNING, "PRNG UID: Reply timeout."); - return -1; - } - - // if select tag failed. - if ( resp.arg[0] == 0 ) { - PrintAndLogEx(WARNING, "error: selecting tag failed, can't detect prng\n"); - return -2; - } - if (!WaitForResponseTimeout(CMD_ACK, &respA, 2500)) { - PrintAndLogEx(WARNING, "PRNG data: Reply timeout."); - return -3; - } - - // check respA - if (respA.arg[0] != 4) { - PrintAndLogEx(WARNING, "PRNG data error: Wrong length: %d", respA.arg[0]); - return -4; - } - - uint32_t nonce = bytes_to_num(respA.d.asBytes, respA.arg[0]); - return validate_prng_nonce(nonce); -} -/* Detect Mifare Classic NACK bug - -returns: -0 = error during test / aborted -1 = has nack bug -2 = has not nack bug -3 = always leak nacks (clones) -*/ -int detect_classic_nackbug(bool verbose){ - - UsbCommand c = {CMD_MIFARE_NACK_DETECT, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - - if ( verbose ) - PrintAndLogEx(SUCCESS, "press pm3-button on the proxmark3 device to abort both proxmark3 and client.\n"); - - // for nice animation - bool term = !isatty(STDIN_FILENO); -#if defined(__linux__) || (__APPLE__) - char star[] = {'-', '\\', '|', '/'}; - uint8_t staridx = 0; -#endif - - while (true) { - - if (term) { - printf("."); - } else { - printf( - #if defined(__linux__) || (__APPLE__) - "\e[32m\e[s%c\e[u\e[0m", star[ (staridx++ % 4) ] - #else - "." - #endif - ); - } - fflush(stdout); - if (ukbhit()) { - int gc = getchar(); (void)gc; - return -1; - break; - } - - if (WaitForResponseTimeout(CMD_ACK, &resp, 500)) { - int32_t ok = resp.arg[0]; - uint32_t nacks = resp.arg[1]; - uint32_t auths = resp.arg[2]; - PrintAndLogEx(NORMAL, ""); - - if ( verbose ) { - PrintAndLogEx(SUCCESS, "num of auth requests : %u", auths); - PrintAndLogEx(SUCCESS, "num of received NACK : %u", nacks); - } - switch( ok ) { - case 99 : PrintAndLogEx(WARNING, "button pressed. Aborted."); return 0; - case 96 : - case 98 : { - if (verbose) - PrintAndLogEx(FAILED, "card random number generator is not predictable."); - PrintAndLogEx(WARNING, "detection failed"); - return 2; - } - case 97 : { - if (verbose) { - PrintAndLogEx(FAILED, "card random number generator seems to be based on the well-known generating polynomial"); - PrintAndLogEx(NORMAL, "[- ]with 16 effective bits only, but shows unexpected behavior, try again."); - return 0; - } - } - case 2 : PrintAndLogEx(SUCCESS, "always leak NACK detected"); return 3; - case 1 : PrintAndLogEx(SUCCESS, "NACK bug detected"); return 1; - case 0 : PrintAndLogEx(SUCCESS, "No NACK bug detected"); return 2; - default : PrintAndLogEx(WARNING, "errorcode from device [%i]", ok); return 0; - } - break; - } - } - return 0; -} -/* try to see if card responses to "chinese magic backdoor" commands. */ -void detect_classic_magic(void) { - - uint8_t isGeneration = 0; - UsbCommand resp; - UsbCommand c = {CMD_MIFARE_CIDENT, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) - isGeneration = resp.arg[0] & 0xff; - - switch( isGeneration ){ - case 1: PrintAndLogEx(SUCCESS, "Answers to magic commands (GEN 1a): YES"); break; - case 2: PrintAndLogEx(SUCCESS, "Answers to magic commands (GEN 1b): YES"); break; - //case 4: PrintAndLogEx(SUCCESS, "Answers to magic commands (GEN 2): YES"); break; - default: PrintAndLogEx(INFO, "Answers to magic commands: NO"); break; - } +// Merlok, 2011, 2012, 2019 +// people from mifare@nethemba.com, 2010 +// +// 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. +//----------------------------------------------------------------------------- +// mifare commands +//----------------------------------------------------------------------------- +#include "mifarehost.h" +#include "cmdmain.h" + +int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) { + uint32_t uid = 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; + int16_t isOK = 0; + + UsbCommand c = {CMD_READER_MIFARE, {true, blockno, key_type}}; + + // message + PrintAndLogEx(NORMAL, "--------------------------------------------------------------------------------\n"); + PrintAndLogEx(NORMAL, "executing Darkside attack. Expected execution time: 25sec on average"); + PrintAndLogEx(NORMAL, "press pm3-button on the proxmark3 device to abort both proxmark3 and client."); + PrintAndLogEx(NORMAL, "--------------------------------------------------------------------------------\n"); + + while (true) { + clearCommandBuffer(); + SendCommand(&c); + + //flush queue + while (ukbhit()) { + int gc = getchar(); (void)gc; + return -5; + } + + // wait cycle + while (true) { + printf("."); fflush(stdout); + if (ukbhit()) { + int gc = getchar(); (void)gc; + return -5; + } + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + isOK = resp.arg[0]; + if (isOK < 0) + return isOK; + + uid = (uint32_t)bytes_to_num(resp.d.asBytes + 0, 4); + 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 = (uint32_t)bytes_to_num(resp.d.asBytes + 24, 4); + ar = (uint32_t)bytes_to_num(resp.d.asBytes + 28, 4); + break; + } + } + PrintAndLogEx(NORMAL, "\n"); + + if (par_list == 0 && c.arg[0] == true) { + PrintAndLogEx(SUCCESS, "Parity is all zero. Most likely this card sends NACK on every authentication."); + } + c.arg[0] = false; + + keycount = nonce2key(uid, nt, nr, ar, par_list, ks_list, &keylist); + + if (keycount == 0) { + PrintAndLogEx(FAILED, "key not found (lfsr_common_prefix list is null). Nt=%08x", nt); + PrintAndLogEx(FAILED, "this is expected to happen in 25%% of all cases. Trying again with a different reader nonce..."); + continue; + } + + // only parity zero attack + 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; + PrintAndLogEx(FAILED, "no candidates found, trying again"); + continue; + } + } + + PrintAndLogEx(SUCCESS, "found %u candidate key%s\n", keycount, (keycount > 1) ? "s." : "."); + + *key = -1; + uint8_t keyBlock[USB_CMD_DATA_SIZE]; + int max_keys = USB_CMD_DATA_SIZE / 6; + 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 (par_list == 0) { + num_to_bytes(last_keylist[i*max_keys + j], 6, keyBlock+(j*6)); + } else { + num_to_bytes(keylist[i*max_keys + j], 6, keyBlock+(j*6)); + } + } + + if (!mfCheckKeys(blockno, key_type - 0x60, false, size, keyBlock, key)) { + break; + } + } + + if (*key != -1) { + break; + } else { + PrintAndLogEx(FAILED, "all candidate keys failed. Restarting darkside attack"); + free(last_keylist); + last_keylist = keylist; + c.arg[0] = true; + } + } + free(last_keylist); + free(keylist); + return 0; +} +int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){ + *key = -1; + UsbCommand c = {CMD_MIFARE_CHKKEYS, { (blockNo | (keyType << 8)), clear_trace, keycnt}}; + memcpy(c.d.asBytes, keyBlock, 6 * keycnt); + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) return 1; + if ((resp.arg[0] & 0xff) != 0x01) return 2; + *key = bytes_to_num(resp.d.asBytes, 6); + return 0; +} + +// Sends chunks of keys to device. +// 0 == ok all keys found +// 1 == +// 2 == Time-out, aborting +int mfCheckKeys_fast( uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, uint8_t strategy, + uint32_t size, uint8_t *keyBlock, sector_t *e_sector, bool use_flashmemory) { + + uint64_t t2 = msclock(); + uint32_t timeout = 0; + + // send keychunk + UsbCommand c = {CMD_MIFARE_CHKKEYS_FAST, { (sectorsCnt | (firstChunk << 8) | (lastChunk << 12) ), ((use_flashmemory << 8) | strategy), size}}; + memcpy(c.d.asBytes, keyBlock, 6 * size); + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + + while ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { + timeout++; + printf("."); fflush(stdout); + // max timeout for one chunk of 85keys, 60*3sec = 180seconds + // s70 with 40*2 keys to check, 80*85 = 6800 auth. + // takes about 97s, still some margin before abort + if (timeout > 180) { + PrintAndLogEx(WARNING, "\nno response from Proxmark. Aborting..."); + return 2; + } + } + t2 = msclock() - t2; + + // time to convert the returned data. + uint8_t curr_keys = resp.arg[0]; + + PrintAndLogEx(SUCCESS, "\nChunk: %.1fs | found %u/%u keys (%u)", (float)(t2/1000.0), curr_keys, (sectorsCnt<<1), size); + + // all keys? + if ( curr_keys == sectorsCnt*2 || lastChunk ) { + + // success array. each byte is status of key + uint8_t arr[80]; + uint64_t foo = 0; + uint16_t bar = 0; + foo = bytes_to_num(resp.d.asBytes+480, 8); + bar = (resp.d.asBytes[489] << 8 | resp.d.asBytes[488]); + + for (uint8_t i = 0; i < 64; i++) + arr[i] = (foo >> i) & 0x1; + + for (uint8_t i = 0; i < 16; i++) + arr[i+64] = (bar >> i) & 0x1; + + // initialize storage for found keys + icesector_t *tmp = calloc(sectorsCnt, sizeof(icesector_t)); + if (tmp == NULL) + return 1; + memcpy(tmp, resp.d.asBytes, sectorsCnt * sizeof(icesector_t) ); + + for ( int i = 0; i < sectorsCnt; i++) { + // key A + if ( !e_sector[i].foundKey[0] ) { + e_sector[i].Key[0] = bytes_to_num( tmp[i].keyA, 6); + e_sector[i].foundKey[0] = arr[ (i*2) ]; + } + // key B + if ( !e_sector[i].foundKey[1] ) { + e_sector[i].Key[1] = bytes_to_num( tmp[i].keyB, 6); + e_sector[i].foundKey[1] = arr[ (i*2) + 1 ]; + } + } + free(tmp); + + if ( curr_keys == sectorsCnt*2 ) + return 0; + if ( lastChunk ) + return 1; + } + return 1; +} + +// PM3 imp of J-Run mf_key_brute (part 2) +// ref: https://github.com/J-Run/mf_key_brute +int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey){ + + #define KEYS_IN_BLOCK 85 + #define KEYBLOCK_SIZE 510 + #define CANDIDATE_SIZE 0xFFFF * 6 + uint8_t found = false; + uint64_t key64 = 0; + uint8_t candidates[CANDIDATE_SIZE] = {0x00}; + uint8_t keyBlock[KEYBLOCK_SIZE] = {0x00}; + + memset(candidates, 0, sizeof(candidates)); + memset(keyBlock, 0, sizeof(keyBlock)); + + // Generate all possible keys for the first two unknown bytes. + for (uint16_t i = 0; i < 0xFFFF; ++i) { + uint32_t j = i * 6; + candidates[0 + j] = i >> 8; + candidates[1 + j] = i; + candidates[2 + j] = key[2]; + candidates[3 + j] = key[3]; + candidates[4 + j] = key[4]; + candidates[5 + j] = key[5]; + } + uint32_t counter, i; + for ( i = 0, counter = 1; i < CANDIDATE_SIZE; i += KEYBLOCK_SIZE, ++counter){ + + key64 = 0; + + // copy candidatekeys to test key block + memcpy(keyBlock, candidates + i, KEYBLOCK_SIZE); + + // check a block of generated candidate keys. + if (!mfCheckKeys(blockNo, keyType, true, KEYS_IN_BLOCK, keyBlock, &key64)) { + *resultkey = key64; + found = true; + break; + } + + // progress + if ( counter % 20 == 0 ) + PrintAndLogEx(SUCCESS, "tried : %s.. \t %u keys", sprint_hex(candidates + i, 6), counter * KEYS_IN_BLOCK ); + } + return found; +} + +// Compare 16 Bits out of cryptostate +int Compare16Bits(const void * a, const void * b) { + if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0; + if ((*(uint64_t*)b & 0x00ff000000ff0000) > (*(uint64_t*)a & 0x00ff000000ff0000)) return 1; + return -1; +} + +// wrapper function for multi-threaded lfsr_recovery32 +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; + statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt ^ statelist->uid); + + for (p1 = statelist->head.slhead; *(uint64_t *)p1 != 0; p1++) {}; + + statelist->len = p1 - statelist->head.slhead; + statelist->tail.sltail = --p1; + qsort(statelist->head.slhead, statelist->len, sizeof(uint64_t), Compare16Bits); + + 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; + uint32_t uid; + UsbCommand resp; + StateList_t statelists[2]; + struct Crypto1State *p1, *p2, *p3, *p4; + + UsbCommand c = {CMD_MIFARE_NESTED, {blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, calibrate}}; + memcpy(c.d.asBytes, key, 6); + clearCommandBuffer(); + SendCommand(&c); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return -1; + + // error during nested + if (resp.arg[0]) return resp.arg[0]; + + memcpy(&uid, resp.d.asBytes, 4); + + for (i = 0; i < 2; i++) { + statelists[i].blockNo = resp.arg[2] & 0xff; + statelists[i].keyType = (resp.arg[2] >> 8) & 0xff; + statelists[i].uid = uid; + memcpy(&statelists[i].nt, (void *)(resp.d.asBytes + 4 + i * 8 + 0), 4); + memcpy(&statelists[i].ks1, (void *)(resp.d.asBytes + 4 + i * 8 + 4), 4); + } + + // calc keys + pthread_t thread_id[2]; + + // create and run worker threads + for (i = 0; i < 2; i++) + pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]); + + // wait for threads to terminate: + for (i = 0; i < 2; i++) + pthread_join(thread_id[i], (void*)&statelists[i].head.slhead); + + // the first 16 Bits of the cryptostate already contain part of our key. + // Create the intersection of the two lists based on these 16 Bits and + // roll back the cryptostate + p1 = p3 = statelists[0].head.slhead; + p2 = p4 = statelists[1].head.slhead; + + while (p1 <= statelists[0].tail.sltail && p2 <= statelists[1].tail.sltail) { + if (Compare16Bits(p1, p2) == 0) { + + struct Crypto1State savestate, *savep = &savestate; + savestate = *p1; + while(Compare16Bits(p1, savep) == 0 && p1 <= statelists[0].tail.sltail) { + *p3 = *p1; + lfsr_rollback_word(p3, statelists[0].nt ^ statelists[0].uid, 0); + p3++; + p1++; + } + savestate = *p2; + while(Compare16Bits(p2, savep) == 0 && p2 <= statelists[1].tail.sltail) { + *p4 = *p2; + lfsr_rollback_word(p4, statelists[1].nt ^ statelists[1].uid, 0); + p4++; + p2++; + } + } + else { + while (Compare16Bits(p1, p2) == -1) p1++; + while (Compare16Bits(p1, p2) == 1) p2++; + } + } + + *(uint64_t*)p3 = -1; + *(uint64_t*)p4 = -1; + statelists[0].len = p3 - statelists[0].head.slhead; + statelists[1].len = p4 - statelists[1].head.slhead; + statelists[0].tail.sltail = --p3; + statelists[1].tail.sltail = --p4; + + // the statelists now contain possible keys. The key we are searching for must be in the + // intersection of both lists + qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compare_uint64); + qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64); + // Create the intersection + statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead); + + //statelists[0].tail.keytail = --p7; + uint32_t keycnt = statelists[0].len; + if ( keycnt == 0 ) goto out; + + memset(resultKey, 0, 6); + uint64_t key64 = -1; + + // The list may still contain several key candidates. Test each of them with mfCheckKeys + uint32_t max_keys = keycnt > (USB_CMD_DATA_SIZE/6) ? (USB_CMD_DATA_SIZE/6) : keycnt; + uint8_t keyBlock[USB_CMD_DATA_SIZE] = {0x00}; + + for (int i = 0; i < keycnt; i += max_keys) { + + int size = keycnt - i > max_keys ? max_keys : keycnt - i; + + for (int j = 0; j < size; j++) { + crypto1_get_lfsr(statelists[0].head.slhead + i, &key64); + num_to_bytes(key64, 6, keyBlock + i * 6); + } + + if (!mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, size, keyBlock, &key64)) { + free(statelists[0].head.slhead); + free(statelists[1].head.slhead); + num_to_bytes(key64, 6, resultKey); + + PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [%012" PRIx64 "]", + (uint16_t)resp.arg[2] & 0xff, + (resp.arg[2] >> 8) ? 'B' : 'A', + key64 + ); + return -5; + } + } + +out: + PrintAndLogEx(SUCCESS, "target block:%3u key type: %c", + (uint16_t)resp.arg[2] & 0xff, + (resp.arg[2] >> 8) ? 'B' : 'A' + ); + + free(statelists[0].head.slhead); + free(statelists[1].head.slhead); + return -4; +} + +// MIFARE +int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data) { + + UsbCommand c = {CMD_MIFARE_READSC, {sectorNo, keyType, 0}}; + memcpy(c.d.asBytes, key, 6); + clearCommandBuffer(); + SendCommand(&c); + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + + if (isOK) { + memcpy(data, resp.d.asBytes, mfNumBlocksPerSector(sectorNo) * 16); + return 0; + } else { + return 1; + } + } else { + PrintAndLogEx(ERR, "Command execute timeout"); + return 2; + } + + return 0; +} + +// EMULATOR +int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) { + UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}}; + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return 1; + memcpy(data, resp.d.asBytes, blocksCount * 16); + return 0; +} + +int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount) { + return mfEmlSetMem_xt(data, blockNum, blocksCount, 16); +} + +int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth) { + UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNum, blocksCount, blockBtWidth}}; + memcpy(c.d.asBytes, data, blocksCount * blockBtWidth); + clearCommandBuffer(); + SendCommand(&c); + return 0; +} + +// "MAGIC" CARD +int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_t wipecard) { + + uint8_t params = MAGIC_SINGLE; + uint8_t block0[16]; + memset(block0, 0x00, sizeof(block0)); + + int old = mfCGetBlock(0, block0, params); + if (old == 0) + PrintAndLogEx(SUCCESS, "old block 0: %s", sprint_hex(block0, sizeof(block0))); + else + PrintAndLogEx(FAILED, "couldn't get old data. Will write over the last bytes of Block 0."); + + // fill in the new values + // UID + memcpy(block0, uid, 4); + // Mifare UID BCC + block0[4] = block0[0] ^ block0[1] ^ block0[2] ^ block0[3]; + // mifare classic SAK(byte 5) and ATQA(byte 6 and 7, reversed) + if ( sak != NULL ) + block0[5] = sak[0]; + + if ( atqa != NULL ) { + block0[6] = atqa[1]; + block0[7] = atqa[0]; + } + PrintAndLogEx(SUCCESS, "new block 0: %s", sprint_hex(block0,16)); + + if ( wipecard ) params |= MAGIC_WIPE; + if ( oldUID == NULL) params |= MAGIC_UID; + + return mfCSetBlock(0, block0, oldUID, params); +} + +int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params) { + + uint8_t isOK = 0; + UsbCommand c = {CMD_MIFARE_CSETBLOCK, {params, blockNo, 0}}; + memcpy(c.d.asBytes, data, 16); + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + isOK = resp.arg[0] & 0xff; + if (uid != NULL) + memcpy(uid, resp.d.asBytes, 4); + if (!isOK) + return 2; + } else { + PrintAndLogEx(WARNING, "command execute timeout"); + return 1; + } + return 0; +} + +int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) { + uint8_t isOK = 0; + UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, blockNo, 0}}; + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + isOK = resp.arg[0] & 0xff; + if (!isOK) + return 2; + memcpy(data, resp.d.asBytes, 16); + } else { + PrintAndLogEx(WARNING, "command execute timeout"); + return 1; + } + return 0; +} + +// SNIFFER +// [iceman] so many global variables.... + +// constants +static uint8_t trailerAccessBytes[4] = {0x08, 0x77, 0x8F, 0x00}; + +// variables +char logHexFileName[FILE_PATH_SIZE] = {0x00}; +static uint8_t traceCard[4096] = {0x00}; +static char traceFileName[FILE_PATH_SIZE] = {0x00}; +static int traceState = TRACE_IDLE; +static uint8_t traceCurBlock = 0; +static uint8_t traceCurKey = 0; + +struct Crypto1State *traceCrypto1 = NULL; +struct Crypto1State *revstate = NULL; +uint64_t key = 0; +uint32_t ks2 = 0; +uint32_t ks3 = 0; + +uint32_t cuid = 0; // uid part used for crypto1. +uint32_t nt = 0; // tag challenge +uint32_t nr_enc = 0; // encrypted reader challenge +uint32_t ar_enc = 0; // encrypted reader response +uint32_t at_enc = 0; // encrypted tag response + +int isTraceCardEmpty(void) { + return ((traceCard[0] == 0) && (traceCard[1] == 0) && (traceCard[2] == 0) && (traceCard[3] == 0)); +} + +int isBlockEmpty(int blockN) { + for (int i = 0; i < 16; i++) + if (traceCard[blockN * 16 + i] != 0) return 0; + + return 1; +} + +int isBlockTrailer(int blockN) { + return ((blockN & 0x03) == 0x03); +} + +int loadTraceCard(uint8_t *tuid, uint8_t uidlen) { + FILE * f; + char buf[64] = {0x00}; + uint8_t buf8[64] = {0x00}; + int i, blockNum; + uint32_t tmp; + + if (!isTraceCardEmpty()) + saveTraceCard(); + + memset(traceCard, 0x00, 4096); + memcpy(traceCard, tuid, uidlen); + + FillFileNameByUID(traceFileName, tuid, ".eml", uidlen); + + f = fopen(traceFileName, "r"); + if (!f) return 1; + + blockNum = 0; + + while (!feof(f)){ + + memset(buf, 0, sizeof(buf)); + if (fgets(buf, sizeof(buf), f) == NULL) { + PrintAndLogEx(FAILED, "No trace file found or reading error."); + if (f) { + fclose(f); + } + return 2; + } + + if (strlen(buf) < 32){ + if (feof(f)) break; + PrintAndLogEx(FAILED, "File content error. Block data must include 32 HEX symbols"); + if (f) { + fclose(f); + } + return 2; + } + for (i = 0; i < 32; i += 2) { + sscanf(&buf[i], "%02X", &tmp); + buf8[i / 2] = tmp & 0xFF; + } + + memcpy(traceCard + blockNum * 16, buf8, 16); + + blockNum++; + } + if (f) { + fclose(f); + } + return 0; +} + +int saveTraceCard(void) { + + if ((!strlen(traceFileName)) || (isTraceCardEmpty())) return 0; + + FILE * f; + f = fopen(traceFileName, "w+"); + if ( !f ) return 1; + + // given 4096 tracecard size, these loop will only match a 1024, 1kb card memory + // 4086/16 == 256blocks. + for (uint16_t i = 0; i < 256; i++) { // blocks + for (uint8_t j = 0; j < 16; j++) // bytes + fprintf(f, "%02X", *(traceCard + i * 16 + j)); + + // no extra line in the end + if ( i < 255 ) + fprintf(f, "\n"); + } + fflush(f); + fclose(f); + return 0; +} +// +int mfTraceInit(uint8_t *tuid, uint8_t uidlen, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile) { + + if (traceCrypto1) + crypto1_destroy(traceCrypto1); + + traceCrypto1 = NULL; + + if (wantSaveToEmlFile) + loadTraceCard(tuid, uidlen); + + traceCard[4] = traceCard[0] ^ traceCard[1] ^ traceCard[2] ^ traceCard[3]; + traceCard[5] = sak; + memcpy(&traceCard[6], atqa, 2); + traceCurBlock = 0; + cuid = bytes_to_num(tuid + (uidlen-4), 4); + traceState = TRACE_IDLE; + return 0; +} + +void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted){ + uint8_t bt = 0; + int i; + + if (len != 1) { + for (i = 0; i < len; i++) + data[i] = crypto1_byte(pcs, 0x00, isEncrypted) ^ data[i]; + } else { + bt = 0; + bt |= (crypto1_bit(pcs, 0, isEncrypted) ^ BIT(data[0], 0)) << 0; + bt |= (crypto1_bit(pcs, 0, isEncrypted) ^ BIT(data[0], 1)) << 1; + bt |= (crypto1_bit(pcs, 0, isEncrypted) ^ BIT(data[0], 2)) << 2; + bt |= (crypto1_bit(pcs, 0, isEncrypted) ^ BIT(data[0], 3)) << 3; + data[0] = bt; + } +} + +int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) { + + if (traceState == TRACE_ERROR) + return 1; + + if (len > 255) { + traceState = TRACE_ERROR; + return 1; + } + + uint8_t data[255]; + memset(data, 0x00, sizeof(data)); + + memcpy(data, data_src, len); + + if ((traceCrypto1) && ((traceState == TRACE_IDLE) || (traceState > TRACE_AUTH_OK))) { + mf_crypto1_decrypt(traceCrypto1, data, len, 0); + PrintAndLogEx(NORMAL, "DEC| %s", sprint_hex(data, len)); + AddLogHex(logHexFileName, "DEC| ", data, len); + } + + switch (traceState) { + case TRACE_IDLE: + // check packet crc16! + if ((len >= 4) && (!check_crc(CRC_14443_A, data, len))) { + PrintAndLogEx(NORMAL, "DEC| CRC ERROR!!!"); + AddLogLine(logHexFileName, "DEC| ", "CRC ERROR!!!"); + traceState = TRACE_ERROR; // do not decrypt the next commands + return 1; + } + + // AUTHENTICATION + if ((len == 4) && ((data[0] == MIFARE_AUTH_KEYA) || (data[0] == MIFARE_AUTH_KEYB))) { + traceState = TRACE_AUTH1; + traceCurBlock = data[1]; + traceCurKey = data[0] == 60 ? 1:0; + return 0; + } + + // READ + if ((len == 4) && ((data[0] == ISO14443A_CMD_READBLOCK))) { + traceState = TRACE_READ_DATA; + traceCurBlock = data[1]; + return 0; + } + + // WRITE + if ((len == 4) && ((data[0] == ISO14443A_CMD_WRITEBLOCK))) { + traceState = TRACE_WRITE_OK; + traceCurBlock = data[1]; + return 0; + } + + // HALT + if ((len == 4) && ((data[0] == ISO14443A_CMD_HALT) && (data[1] == 0x00))) { + traceState = TRACE_ERROR; // do not decrypt the next commands + return 0; + } + return 0; + + case TRACE_READ_DATA: + if (len == 18) { + traceState = TRACE_IDLE; + + if (isBlockTrailer(traceCurBlock)) { + memcpy(traceCard + traceCurBlock * 16 + 6, data + 6, 4); + } else { + memcpy(traceCard + traceCurBlock * 16, data, 16); + } + if (wantSaveToEmlFile) saveTraceCard(); + return 0; + } else { + traceState = TRACE_ERROR; + return 1; + } + break; + case TRACE_WRITE_OK: + if ((len == 1) && (data[0] == 0x0a)) { + traceState = TRACE_WRITE_DATA; + return 0; + } else { + traceState = TRACE_ERROR; + return 1; + } + break; + case TRACE_WRITE_DATA: + if (len == 18) { + traceState = TRACE_IDLE; + memcpy(traceCard + traceCurBlock * 16, data, 16); + if (wantSaveToEmlFile) saveTraceCard(); + return 0; + } else { + traceState = TRACE_ERROR; + return 1; + } + break; + case TRACE_AUTH1: + if (len == 4) { + traceState = TRACE_AUTH2; + nt = bytes_to_num(data, 4); + return 0; + } else { + traceState = TRACE_ERROR; + return 1; + } + break; + case TRACE_AUTH2: + if (len == 8) { + traceState = TRACE_AUTH_OK; + nr_enc = bytes_to_num(data, 4); + ar_enc = bytes_to_num(data + 4, 4); + return 0; + } else { + traceState = TRACE_ERROR; + return 1; + } + break; + case TRACE_AUTH_OK: + if (len == 4) { + traceState = TRACE_IDLE; + at_enc = bytes_to_num(data, 4); + + // mfkey64 recover key. + 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, cuid ^ nt, 0); + crypto1_get_lfsr(revstate, &key); + PrintAndLogEx(SUCCESS, "found Key: [%012" PRIx64 "]", key); + + //if ( tryMfk64(cuid, nt, nr_enc, ar_enc, at_enc, &key) ) + AddLogUint64(logHexFileName, "Found Key: ", key); + + int blockShift = ((traceCurBlock & 0xFC) + 3) * 16; + if (isBlockEmpty((traceCurBlock & 0xFC) + 3)) + memcpy(traceCard + blockShift + 6, trailerAccessBytes, 4); + + // keytype A/B + if (traceCurKey) + num_to_bytes(key, 6, traceCard + blockShift + 10); + else + num_to_bytes(key, 6, traceCard + blockShift); + + if (wantSaveToEmlFile) + saveTraceCard(); + + if (traceCrypto1) + crypto1_destroy(traceCrypto1); + + // set cryptosystem state + traceCrypto1 = lfsr_recovery64(ks2, ks3); + + } else { + PrintAndLogEx(NORMAL, "[!] nested key recovery not implemented!\n"); + at_enc = bytes_to_num(data, 4); + crypto1_destroy(traceCrypto1); + traceState = TRACE_ERROR; + } + break; + default: + traceState = TRACE_ERROR; + return 1; + } + return 0; +} + +int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len){ + PrintAndLogEx(SUCCESS, "\nencrypted data: [%s]", sprint_hex(data, len) ); + struct Crypto1State *s; + ks2 = ar_enc ^ prng_successor(nt, 64); + ks3 = at_enc ^ prng_successor(nt, 96); + s = lfsr_recovery64(ks2, ks3); + mf_crypto1_decrypt(s, data, len, false); + PrintAndLogEx(SUCCESS, "decrypted data: [%s]", sprint_hex(data, len) ); + crypto1_destroy(s); + return 0; +} + +/* Detect Tag Prng, +* function performs a partial AUTH, where it tries to authenticate against block0, key A, but only collects tag nonce. +* the tag nonce is check to see if it has a predictable PRNG. +* @returns +* TRUE if tag uses WEAK prng (ie Now the NACK bug also needs to be present for Darkside attack) +* FALSE is tag uses HARDEND prng (ie hardnested attack possible, with known key) +*/ +int detect_classic_prng(void){ + + UsbCommand resp, respA; + uint8_t cmd[] = {MIFARE_AUTH_KEYA, 0x00}; + uint32_t flags = ISO14A_CONNECT | ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_RATS; + + UsbCommand c = {CMD_READER_ISO_14443a, {flags, sizeof(cmd), 0}}; + memcpy(c.d.asBytes, cmd, sizeof(cmd)); + + clearCommandBuffer(); + SendCommand(&c); + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(WARNING, "PRNG UID: Reply timeout."); + return -1; + } + + // if select tag failed. + if ( resp.arg[0] == 0 ) { + PrintAndLogEx(WARNING, "error: selecting tag failed, can't detect prng\n"); + return -2; + } + if (!WaitForResponseTimeout(CMD_ACK, &respA, 2500)) { + PrintAndLogEx(WARNING, "PRNG data: Reply timeout."); + return -3; + } + + // check respA + if (respA.arg[0] != 4) { + PrintAndLogEx(WARNING, "PRNG data error: Wrong length: %d", respA.arg[0]); + return -4; + } + + uint32_t nonce = bytes_to_num(respA.d.asBytes, respA.arg[0]); + return validate_prng_nonce(nonce); +} +/* Detect Mifare Classic NACK bug + +returns: +0 = error during test / aborted +1 = has nack bug +2 = has not nack bug +3 = always leak nacks (clones) +*/ +int detect_classic_nackbug(bool verbose){ + + UsbCommand c = {CMD_MIFARE_NACK_DETECT, {0, 0, 0}}; + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + + if ( verbose ) + PrintAndLogEx(SUCCESS, "press pm3-button on the proxmark3 device to abort both proxmark3 and client.\n"); + + // for nice animation + bool term = !isatty(STDIN_FILENO); +#if defined(__linux__) || (__APPLE__) + char star[] = {'-', '\\', '|', '/'}; + uint8_t staridx = 0; +#endif + + while (true) { + + if (term) { + printf("."); + } else { + printf( + #if defined(__linux__) || (__APPLE__) + "\e[32m\e[s%c\e[u\e[0m", star[ (staridx++ % 4) ] + #else + "." + #endif + ); + } + fflush(stdout); + if (ukbhit()) { + int gc = getchar(); (void)gc; + return -1; + break; + } + + if (WaitForResponseTimeout(CMD_ACK, &resp, 500)) { + int32_t ok = resp.arg[0]; + uint32_t nacks = resp.arg[1]; + uint32_t auths = resp.arg[2]; + PrintAndLogEx(NORMAL, ""); + + if ( verbose ) { + PrintAndLogEx(SUCCESS, "num of auth requests : %u", auths); + PrintAndLogEx(SUCCESS, "num of received NACK : %u", nacks); + } + switch( ok ) { + case 99 : PrintAndLogEx(WARNING, "button pressed. Aborted."); return 0; + case 96 : + case 98 : { + if (verbose) + PrintAndLogEx(FAILED, "card random number generator is not predictable."); + PrintAndLogEx(WARNING, "detection failed"); + return 2; + } + case 97 : { + if (verbose) { + PrintAndLogEx(FAILED, "card random number generator seems to be based on the well-known generating polynomial"); + PrintAndLogEx(NORMAL, "[- ]with 16 effective bits only, but shows unexpected behavior, try again."); + } + return 2; + } + case 2 : PrintAndLogEx(SUCCESS, _GREEN_(always leak NACK detected)); return 3; + case 1 : PrintAndLogEx(SUCCESS, _GREEN_(NACK bug detected)); return 1; + case 0 : PrintAndLogEx(SUCCESS, "No NACK bug detected"); return 2; + default : PrintAndLogEx(WARNING, "errorcode from device [%i]", ok); return 0; + } + break; + } + } + return 0; +} +/* try to see if card responses to "chinese magic backdoor" commands. */ +void detect_classic_magic(void) { + + uint8_t isGeneration = 0; + UsbCommand resp; + UsbCommand c = {CMD_MIFARE_CIDENT, {0, 0, 0}}; + clearCommandBuffer(); + SendCommand(&c); + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) + isGeneration = resp.arg[0] & 0xff; + + switch( isGeneration ){ + case 1: PrintAndLogEx(SUCCESS, "Answers to magic commands (GEN 1a): " _GREEN_(YES)); break; + case 2: PrintAndLogEx(SUCCESS, "Answers to magic commands (GEN 1b): " _GREEN_(YES)); break; + //case 4: PrintAndLogEx(SUCCESS, "Answers to magic commands (GEN 2): " _GREEN_(YES)); break; + default: PrintAndLogEx(INFO, "Answers to magic commands: " _YELLOW_(NO)); break; + } } \ No newline at end of file diff --git a/client/mifarehost.h b/client/mifare/mifarehost.h similarity index 95% rename from client/mifarehost.h rename to client/mifare/mifarehost.h index 65500ded8..917cf5557 100644 --- a/client/mifarehost.h +++ b/client/mifare/mifarehost.h @@ -1,103 +1,103 @@ -// Merlok, 2011 -// people from mifare@nethemba.com, 2010 -// -// 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. -//----------------------------------------------------------------------------- -// High frequency ISO14443A commands -//----------------------------------------------------------------------------- -#ifndef __MIFARE_HOST_H -#define __MIFARE_HOST_H - -#include -#include -#include -#include -#include - -#include "proxmark3.h" // time_t -#include "common.h" -#include "util.h" // FILE_PATH_SIZE -#include "ui.h" // PrintAndLog... -#include "crapto1/crapto1.h" -#include "crc16.h" -#include "protocols.h" -#include "mifare.h" -#include "mfkey.h" -#include "util_posix.h" // msclock - -#define MIFARE_SECTOR_RETRY 10 - -// mifare tracer flags -#define TRACE_IDLE 0x00 -#define TRACE_AUTH1 0x01 -#define TRACE_AUTH2 0x02 -#define TRACE_AUTH_OK 0x03 -#define TRACE_READ_DATA 0x04 -#define TRACE_WRITE_OK 0x05 -#define TRACE_WRITE_DATA 0x06 -#define TRACE_ERROR 0xFF - -typedef struct { - union { - struct Crypto1State *slhead; - uint64_t *keyhead; - } head; - union { - struct Crypto1State *sltail; - uint64_t *keytail; - } tail; - uint32_t len; - uint32_t uid; - uint32_t blockNo; - uint32_t keyType; - uint32_t nt; - uint32_t ks1; -} StateList_t; - -typedef struct { - uint64_t Key[2]; - uint8_t foundKey[2]; -} sector_t; - -typedef struct { - uint8_t keyA[6]; - uint8_t keyB[6]; - //uint8_t foundKey[2]; -} icesector_t; - -extern char logHexFileName[FILE_PATH_SIZE]; - -extern int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key); -extern int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate); -extern int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key); -extern int mfCheckKeys_fast( uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, - uint8_t strategy, uint32_t size, uint8_t *keyBlock, sector_t *e_sector); -extern int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey); - - - -extern int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); -extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); -extern int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth); - -extern int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_t wipecard); -extern int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params); -extern int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params); - -extern int mfTraceInit(uint8_t *tuid, uint8_t uidlen, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile); -extern int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile); - -extern int isTraceCardEmpty(void); -extern int isBlockEmpty(int blockN); -extern int isBlockTrailer(int blockN); -extern int loadTraceCard(uint8_t *tuid, uint8_t uidlen); -extern int saveTraceCard(void); -extern int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len); - -extern int detect_classic_prng(void); -extern int detect_classic_nackbug(bool verbose); -extern void detect_classic_magic(void); -extern void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted); +// Merlok, 2011, 2019 +// people from mifare@nethemba.com, 2010 +// +// 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. +//----------------------------------------------------------------------------- +// High frequency ISO14443A commands +//----------------------------------------------------------------------------- +#ifndef __MIFARE_HOST_H +#define __MIFARE_HOST_H + +#include +#include +#include +#include +#include + +#include "proxmark3.h" // time_t +#include "common.h" +#include "util.h" // FILE_PATH_SIZE +#include "ui.h" // PrintAndLog... +#include "crapto1/crapto1.h" +#include "crc16.h" +#include "protocols.h" +#include "mifare.h" +#include "mfkey.h" +#include "util_posix.h" // msclock + +#define MIFARE_SECTOR_RETRY 10 + +// mifare tracer flags +#define TRACE_IDLE 0x00 +#define TRACE_AUTH1 0x01 +#define TRACE_AUTH2 0x02 +#define TRACE_AUTH_OK 0x03 +#define TRACE_READ_DATA 0x04 +#define TRACE_WRITE_OK 0x05 +#define TRACE_WRITE_DATA 0x06 +#define TRACE_ERROR 0xFF + +typedef struct { + union { + struct Crypto1State *slhead; + uint64_t *keyhead; + } head; + union { + struct Crypto1State *sltail; + uint64_t *keytail; + } tail; + uint32_t len; + uint32_t uid; + uint32_t blockNo; + uint32_t keyType; + uint32_t nt; + uint32_t ks1; +} StateList_t; + +typedef struct { + uint64_t Key[2]; + uint8_t foundKey[2]; +} sector_t; + +typedef struct { + uint8_t keyA[6]; + uint8_t keyB[6]; + //uint8_t foundKey[2]; +} icesector_t; + +extern char logHexFileName[FILE_PATH_SIZE]; + +extern int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key); +extern int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate); +extern int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key); +extern int mfCheckKeys_fast( uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, + uint8_t strategy, uint32_t size, uint8_t *keyBlock, sector_t *e_sector, bool use_flashmemory); +extern int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey); + +extern int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data); + +extern int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); +extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); +extern int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth); + +extern int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_t wipecard); +extern int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params); +extern int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params); + +extern int mfTraceInit(uint8_t *tuid, uint8_t uidlen, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile); +extern int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile); + +extern int isTraceCardEmpty(void); +extern int isBlockEmpty(int blockN); +extern int isBlockTrailer(int blockN); +extern int loadTraceCard(uint8_t *tuid, uint8_t uidlen); +extern int saveTraceCard(void); +extern int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len); + +extern int detect_classic_prng(void); +extern int detect_classic_nackbug(bool verbose); +extern void detect_classic_magic(void); +extern void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted); #endif \ No newline at end of file diff --git a/client/obj/amiitool/.dummy b/client/obj/amiitool/.dummy new file mode 100644 index 000000000..e69de29bb diff --git a/client/obj/mifare/.dummy b/client/obj/mifare/.dummy new file mode 100644 index 000000000..e69de29bb diff --git a/client/proxmark3.c b/client/proxmark3.c index ed7fd245d..246da350b 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -215,11 +215,11 @@ const char *get_my_executable_directory(void) { static void set_my_executable_path(void) { int path_length = wai_getExecutablePath(NULL, 0, NULL); if (path_length != -1) { - my_executable_path = (char*)malloc(path_length + 1); + my_executable_path = (char*)calloc(path_length + 1, sizeof(uint8_t)); int dirname_length = 0; if (wai_getExecutablePath(my_executable_path, path_length, &dirname_length) != -1) { my_executable_path[path_length] = '\0'; - my_executable_directory = (char *)malloc(dirname_length + 2); + my_executable_directory = (char *)calloc(dirname_length + 2, sizeof(uint8_t)); strncpy(my_executable_directory, my_executable_path, dirname_length+1); my_executable_directory[dirname_length+1] = '\0'; } @@ -321,9 +321,9 @@ int main(int argc, char* argv[]) { } else { if (addLuaExec){ // add "script run " to command - char *ctmp = NULL; int len = strlen(script_cmd) + 11 + 1; - if ((ctmp = (char*) malloc(len)) != NULL) { + char *ctmp = (char*) calloc(len, sizeof(uint8_t)); + if (ctmp != NULL) { memset(ctmp, 0, len); strcpy(ctmp, "script run "); strcpy(&ctmp[11], script_cmd); diff --git a/client/reveng/cli.c b/client/reveng/cli.c index f4b40856a..6e147ba20 100644 --- a/client/reveng/cli.c +++ b/client/reveng/cli.c @@ -377,7 +377,9 @@ ipqx: /* allocate argument array */ args = argc - optind; - if(!(apolys = malloc(args * sizeof(poly_t)))){ + + apolys = calloc(args * sizeof(poly_t), sizeof(char)); + if ( !apolys ){ uerror("cannot allocate memory for argument list"); return 0; } diff --git a/client/reveng/model.c b/client/reveng/model.c index 60870d80a..2c58d695a 100644 --- a/client/reveng/model.c +++ b/client/reveng/model.c @@ -118,10 +118,10 @@ char * mtostr(const model_t *model) { + (checkstr && *checkstr ? strlen(checkstr) : 6) + (magicstr && *magicstr ? strlen(magicstr) : 6) + (model->name && *model->name ? 2 + strlen(model->name) : 6); - if ((string = malloc(size))) { + if ((string = calloc(size, sizeof(uint8_t)))) { sprintf(strbuf, "\"%s\"", model->name); sprintf(string, - "width=%lu" + "width=%lu " "poly=0x%s " "init=0x%s " "refin=%s " diff --git a/client/reveng/poly.c b/client/reveng/poly.c index 011a09978..7056c118a 100644 --- a/client/reveng/poly.c +++ b/client/reveng/poly.c @@ -349,7 +349,7 @@ pxsubs(const poly_t poly, int flags, int bperhx, unsigned long start, unsigned l size *= cperhx; if(!size || ~flags & P_SPACE) ++size; /* for trailing null */ - if(!(sptr = string = (char *) malloc(size))) + if(!(sptr = string = (char *) calloc(size, sizeof(char)))) uerror("cannot allocate memory for string"); size = end - start; diff --git a/client/reveng/preset.c b/client/reveng/preset.c index 9e7b721ff..82a18b977 100644 --- a/client/reveng/preset.c +++ b/client/reveng/preset.c @@ -1,5 +1,5 @@ /* preset.c - * Greg Cook, 26/Jul/2018 + * Greg Cook, 21/Nov/2018 */ /* CRC RevEng: arbitrary-precision CRC calculator and algorithm finder @@ -22,7 +22,9 @@ * along with CRC RevEng. If not, see . */ -/* 2018-07-26: added CRC-24/OS-9 +/* 2018-11-21: added CRC-8/NRSC-5, CRC-16/NRSC-5 + * 2018-11-21: renamed algorithms, new aliases, added classes + * 2018-07-26: added CRC-24/OS-9 * 2018-07-26: struct malias.name declared const char *const * 2017-06-19: added CRC-8/BLUETOOTH, CRC-17/CAN-FD, CRC-21/CAN-FD * 2017-02-18: added 8 new GSM algorithms @@ -269,200 +271,203 @@ static const bmp_t b32[] = { 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(0x0c200000) << (BMP_BIT - 32), /* 14 -- 11, 061 */ - BMP_C(0x0c780000) << (BMP_BIT - 32), /* 15 -- 14, 031e */ - BMP_C(0x0fb30000) << (BMP_BIT - 32), /* 16 -- 16, 0fb3 */ - BMP_C(0x10210000) << (BMP_BIT - 32), /* 17 -- 16, 1021 */ - BMP_C(0x12000000) << (BMP_BIT - 32), /* 18 -- 7, 09 */ - BMP_C(0x130d2afc) << (BMP_BIT - 32), /* 19 -- 30,04c34abf */ - BMP_C(0x144e6300) << (BMP_BIT - 32), /* 20 -- 24, 144e63 */ - BMP_C(0x15000000) << (BMP_BIT - 32), /* 21 -- 8, 15 */ - BMP_C(0x1697d06a) << (BMP_BIT - 32), /* 22 -- 32,1697d06a */ - BMP_C(0x17800000) << (BMP_BIT - 32), /* 23 -- 12, 178 */ - BMP_C(0x18000000) << (BMP_BIT - 32), /* 24 -- 6, 06 */ - BMP_C(0x19d3c8d8) << (BMP_BIT - 32), /* 25 -- 31,0ce9e46c */ - BMP_C(0x1c000000) << (BMP_BIT - 32), /* 26 -- 6, 07 */ - BMP_C(0x1d000000) << (BMP_BIT - 32), /* 27 -- 8, 1d */ - BMP_C(0x1d0f0000) << (BMP_BIT - 32), /* 28 -- 16, 1d0f */ - BMP_C(0x1dcf0000) << (BMP_BIT - 32), /* 29 -- 16, 1dcf */ - BMP_C(0x1edc6f41) << (BMP_BIT - 32), /* 30 -- 32,1edc6f41 */ - BMP_C(0x1f23b800) << (BMP_BIT - 32), /* 31 -- 24, 1f23b8 */ - BMP_C(0x20000000) << (BMP_BIT - 32), /* 32 -- 4, 2 */ - BMP_C(0x200fa500) << (BMP_BIT - 32), /* 33 -- 24, 200fa5 */ - BMP_C(0x20140000) << (BMP_BIT - 32), /* 34 -- 14, 0805 */ - BMP_C(0x20b40000) << (BMP_BIT - 32), /* 35 -- 14, 082d */ - BMP_C(0x20fe0000) << (BMP_BIT - 32), /* 36 -- 16, 20fe */ - BMP_C(0x21890000) << (BMP_BIT - 32), /* 37 -- 16, 2189 */ - BMP_C(0x21cf0200) << (BMP_BIT - 32), /* 38 -- 24, 21cf02 */ - BMP_C(0x23ef5200) << (BMP_BIT - 32), /* 39 -- 24, 23ef52 */ - BMP_C(0x25000000) << (BMP_BIT - 32), /* 40 -- 8, 25 */ - BMP_C(0x26000000) << (BMP_BIT - 32), /* 41 -- 8, 26 */ - BMP_C(0x26b10000) << (BMP_BIT - 32), /* 42 -- 16, 26b1 */ - BMP_C(0x27818000) << (BMP_BIT - 32), /* 43 -- 17, 04f03 */ - BMP_C(0x27d00000) << (BMP_BIT - 32), /* 44 -- 13, 04fa */ - BMP_C(0x28000000) << (BMP_BIT - 32), /* 45 -- 5, 05 */ - BMP_C(0x29b10000) << (BMP_BIT - 32), /* 46 -- 16, 29b1 */ - BMP_C(0x2f000000) << (BMP_BIT - 32), /* 47 -- 8, 2f */ - BMP_C(0x30000000) << (BMP_BIT - 32), /* 48 -- 4, 3/ 5, 6 */ - BMP_C(0x3010bf7f) << (BMP_BIT - 32), /* 49 -- 32,3010bf7f */ - BMP_C(0x31000000) << (BMP_BIT - 32), /* 50 -- 8, 31 */ - BMP_C(0x31800000) << (BMP_BIT - 32), /* 51 -- 10, 0c6 */ - BMP_C(0x31c30000) << (BMP_BIT - 32), /* 52 -- 16, 31c3 */ - BMP_C(0x328b6300) << (BMP_BIT - 32), /* 53 -- 24, 328b63 */ - BMP_C(0x34000000) << (BMP_BIT - 32), /* 54 -- 6, 0d */ - BMP_C(0x340bc6d9) << (BMP_BIT - 32), /* 55 -- 32,340bc6d9 */ - BMP_C(0x37000000) << (BMP_BIT - 32), /* 56 -- 8, 37 */ - BMP_C(0x38000000) << (BMP_BIT - 32), /* 57 -- 5, 07 */ - BMP_C(0x39000000) << (BMP_BIT - 32), /* 58 -- 8, 39 */ - BMP_C(0x3d650000) << (BMP_BIT - 32), /* 59 -- 16, 3d65 */ - BMP_C(0x3e000000) << (BMP_BIT - 32), /* 60 -- 8, 3e */ - BMP_C(0x40000000) << (BMP_BIT - 32), /* 61 -- 3, 2 */ - BMP_C(0x42000000) << (BMP_BIT - 32), /* 62 -- 8, 42 */ - BMP_C(0x44c20000) << (BMP_BIT - 32), /* 63 -- 16, 44c2 */ - BMP_C(0x45270551) << (BMP_BIT - 32), /* 64 -- 32,45270551 */ - BMP_C(0x48000000) << (BMP_BIT - 32), /* 65 -- 5, 09 */ - BMP_C(0x49000000) << (BMP_BIT - 32), /* 66 -- 8, 49 */ - BMP_C(0x4a800000) << (BMP_BIT - 32), /* 67 -- 10, 12a */ - BMP_C(0x4acc0000) << (BMP_BIT - 32), /* 68 -- 15, 2566 */ - BMP_C(0x4b000000) << (BMP_BIT - 32), /* 69 -- 8, 4b */ - BMP_C(0x4b370000) << (BMP_BIT - 32), /* 70 -- 16, 4b37 */ - BMP_C(0x4c000000) << (BMP_BIT - 32), /* 71 -- 6, 13 */ - BMP_C(0x4c060000) << (BMP_BIT - 32), /* 72 -- 16, 4c06 */ - BMP_C(0x53000000) << (BMP_BIT - 32), /* 73 -- 8, 53 */ - BMP_C(0x55000000) << (BMP_BIT - 32), /* 74 -- 8, 55 */ - BMP_C(0x55555500) << (BMP_BIT - 32), /* 75 -- 24, 555555 */ - BMP_C(0x59350000) << (BMP_BIT - 32), /* 76 -- 16, 5935 */ - BMP_C(0x5d380000) << (BMP_BIT - 32), /* 77 -- 16, 5d38 */ - BMP_C(0x5d400000) << (BMP_BIT - 32), /* 78 -- 10, 175 */ - BMP_C(0x5d6dcb00) << (BMP_BIT - 32), /* 79 -- 24, 5d6dcb */ - BMP_C(0x60000000) << (BMP_BIT - 32), /* 80 -- 3, 3 */ - BMP_C(0x60e00000) << (BMP_BIT - 32), /* 81 -- 11, 307 */ - BMP_C(0x63d00000) << (BMP_BIT - 32), /* 82 -- 16, 63d0 */ - BMP_C(0x64000000) << (BMP_BIT - 32), /* 83 -- 6, 19 */ - BMP_C(0x66400000) << (BMP_BIT - 32), /* 84 -- 10, 199 */ - BMP_C(0x66c50000) << (BMP_BIT - 32), /* 85 -- 16, 66c5 */ - BMP_C(0x6f630000) << (BMP_BIT - 32), /* 86 -- 16, 6f63 */ - BMP_C(0x6f910000) << (BMP_BIT - 32), /* 87 -- 16, 6f91 */ - BMP_C(0x70000000) << (BMP_BIT - 32), /* 88 -- 4, 7 */ - BMP_C(0x70a00000) << (BMP_BIT - 32), /* 89 -- 11, 385 */ - BMP_C(0x755b0000) << (BMP_BIT - 32), /* 90 -- 16, 755b */ - BMP_C(0x765e7680) << (BMP_BIT - 32), /* 91 -- 32,765e7680 */ - BMP_C(0x76c20800) << (BMP_BIT - 32), /* 92 -- 32, 0ed841 */ - BMP_C(0x7979bd00) << (BMP_BIT - 32), /* 93 -- 24, 7979bd */ - BMP_C(0x7e000000) << (BMP_BIT - 32), /* 94 -- 8, 7e */ - BMP_C(0x80000000) << (BMP_BIT - 32), /* 95 -- 3, 4 */ - BMP_C(0x80006300) << (BMP_BIT - 32), /* 96 -- 24, 800063 */ - BMP_C(0x80050000) << (BMP_BIT - 32), /* 97 -- 16, 8005 */ - BMP_C(0x800d0000) << (BMP_BIT - 32), /* 98 -- 16, 800d */ - BMP_C(0x800fe300) << (BMP_BIT - 32), /* 99 -- 24, 800fe3 */ - BMP_C(0x80b40000) << (BMP_BIT - 32), /* 100 -- 14, 202d */ - BMP_C(0x80c2e71c) << (BMP_BIT - 32), /* 101 -- 30,2030b9c7 */ - BMP_C(0x80f00000) << (BMP_BIT - 32), /* 102 -- 12, 80f */ - BMP_C(0x814141ab) << (BMP_BIT - 32), /* 103 -- 32,814141ab */ - BMP_C(0x8144c800) << (BMP_BIT - 32), /* 104 -- 21, 102899 */ - BMP_C(0x864cfb00) << (BMP_BIT - 32), /* 105 -- 24, 864cfb */ - BMP_C(0x87315576) << (BMP_BIT - 32), /* 106 -- 32,87315576 */ - BMP_C(0x89ec0000) << (BMP_BIT - 32), /* 107 -- 16, 89ec */ - BMP_C(0x8a000000) << (BMP_BIT - 32), /* 108 -- 7, 45 */ - BMP_C(0x8b320000) << (BMP_BIT - 32), /* 109 -- 15, 4599 */ - BMP_C(0x8bb70000) << (BMP_BIT - 32), /* 110 -- 16, 8bb7 */ - BMP_C(0x8cc00000) << (BMP_BIT - 32), /* 111 -- 10, 233 */ - BMP_C(0x904cddbf) << (BMP_BIT - 32), /* 112 -- 32,904cddbf */ - BMP_C(0x906e0000) << (BMP_BIT - 32), /* 113 -- 16, 906e */ - BMP_C(0x94000000) << (BMP_BIT - 32), /* 114 -- 8, 94 */ - BMP_C(0x97000000) << (BMP_BIT - 32), /* 115 -- 8, 97 */ - BMP_C(0x98000000) << (BMP_BIT - 32), /* 116 -- 6, 26 */ - BMP_C(0x9b000000) << (BMP_BIT - 32), /* 117 -- 8, 9b */ - BMP_C(0x9c000000) << (BMP_BIT - 32), /* 118 -- 6, 27 */ - BMP_C(0x9d5e4de2) << (BMP_BIT - 32), /* 119 -- 31,4eaf26f1 */ - BMP_C(0x9e000000) << (BMP_BIT - 32), /* 120 -- 7, 4f */ - BMP_C(0x9ecf0000) << (BMP_BIT - 32), /* 121 -- 16, 9ecf */ - BMP_C(0xa0970000) << (BMP_BIT - 32), /* 122 -- 16, a097 */ - BMP_C(0xa1000000) << (BMP_BIT - 32), /* 123 -- 8, a1 */ - BMP_C(0xa3660000) << (BMP_BIT - 32), /* 124 -- 16, a366 */ - BMP_C(0xa6000000) << (BMP_BIT - 32), /* 125 -- 7, 53 */ - BMP_C(0xa7000000) << (BMP_BIT - 32), /* 126 -- 8, a7 */ - BMP_C(0xa8000000) << (BMP_BIT - 32), /* 127 -- 5, 15 */ - BMP_C(0xa8190000) << (BMP_BIT - 32), /* 128 -- 16, a819 */ - BMP_C(0xa833982b) << (BMP_BIT - 32), /* 129 -- 32,a833982b */ - BMP_C(0xabcdef00) << (BMP_BIT - 32), /* 130 -- 24, abcdef */ - BMP_C(0xac000000) << (BMP_BIT - 32), /* 131 -- 8, ac */ - BMP_C(0xaee70000) << (BMP_BIT - 32), /* 132 -- 16, aee7 */ - BMP_C(0xb0000000) << (BMP_BIT - 32), /* 133 -- 4, b */ - BMP_C(0xb0010000) << (BMP_BIT - 32), /* 134 -- 16, b001 */ - BMP_C(0xb2aa0000) << (BMP_BIT - 32), /* 135 -- 16, b2aa */ - BMP_C(0xb3400000) << (BMP_BIT - 32), /* 136 -- 12, b34 */ - BMP_C(0xb42d8000) << (BMP_BIT - 32), /* 137 -- 17, 1685b */ - BMP_C(0xb4600000) << (BMP_BIT - 32), /* 138 -- 11, 5a3 */ - BMP_C(0xb4c80000) << (BMP_BIT - 32), /* 139 -- 16, b4c8 */ - BMP_C(0xb4f3e600) << (BMP_BIT - 32), /* 140 -- 24, b4f3e6 */ - BMP_C(0xb704ce00) << (BMP_BIT - 32), /* 141 -- 24, b704ce */ - BMP_C(0xb798b438) << (BMP_BIT - 32), /* 142 -- 32,b798b438 */ - BMP_C(0xbb3d0000) << (BMP_BIT - 32), /* 143 -- 16, bb3d */ - BMP_C(0xbc000000) << (BMP_BIT - 32), /* 144 -- 6,2f/ 8,bc */ - BMP_C(0xbd0be338) << (BMP_BIT - 32), /* 145 -- 32,bd0be338 */ - BMP_C(0xbdf40000) << (BMP_BIT - 32), /* 146 -- 16, bdf4 */ - BMP_C(0xbf050000) << (BMP_BIT - 32), /* 147 -- 16, bf05 */ - BMP_C(0xc0000000) << (BMP_BIT - 32), /* 148 -- 3, 6 */ - BMP_C(0xc2000000) << (BMP_BIT - 32), /* 149 -- 7, 61 */ - BMP_C(0xc25a5600) << (BMP_BIT - 32), /* 150 -- 24, c25a56 */ - BMP_C(0xc2b70000) << (BMP_BIT - 32), /* 151 -- 16, c2b7 */ - BMP_C(0xc2b80000) << (BMP_BIT - 32), /* 152 -- 14, 30ae */ - BMP_C(0xc4000000) << (BMP_BIT - 32), /* 153 -- 8, c4 */ - BMP_C(0xc6c60000) << (BMP_BIT - 32), /* 154 -- 16, c6c6 */ - BMP_C(0xc704dd7b) << (BMP_BIT - 32), /* 155 -- 32,c704dd7b */ - BMP_C(0xc8000000) << (BMP_BIT - 32), /* 156 -- 5, 19 */ - BMP_C(0xc8670000) << (BMP_BIT - 32), /* 157 -- 16, c867 */ - BMP_C(0xcbf43926) << (BMP_BIT - 32), /* 158 -- 32,cbf43926 */ - BMP_C(0xcde70300) << (BMP_BIT - 32), /* 159 -- 24, cde703 */ - BMP_C(0xce3c0000) << (BMP_BIT - 32), /* 160 -- 16, ce3c */ - BMP_C(0xd0000000) << (BMP_BIT - 32), /* 161 -- 8, d0 */ - BMP_C(0xd02a0000) << (BMP_BIT - 32), /* 162 -- 15, 6815 */ - BMP_C(0xd0db0000) << (BMP_BIT - 32), /* 163 -- 16, d0db */ - BMP_C(0xd3100000) << (BMP_BIT - 32), /* 164 -- 12, d31 */ - BMP_C(0xd3be9568) << (BMP_BIT - 32), /* 165 -- 30,34efa55a */ - BMP_C(0xd4d00000) << (BMP_BIT - 32), /* 166 -- 12, d4d */ - BMP_C(0xd5000000) << (BMP_BIT - 32), /* 167 -- 8, d5 */ - BMP_C(0xd64e0000) << (BMP_BIT - 32), /* 168 -- 16, d64e */ - BMP_C(0xda000000) << (BMP_BIT - 32), /* 169 -- 8, da */ - BMP_C(0xdaf00000) << (BMP_BIT - 32), /* 170 -- 12, daf */ - BMP_C(0xdebb20e3) << (BMP_BIT - 32), /* 171 -- 32,debb20e3 */ - BMP_C(0xdf000000) << (BMP_BIT - 32), /* 172 -- 8, df */ - BMP_C(0xe0000000) << (BMP_BIT - 32), /* 173 -- 3, 7 */ - BMP_C(0xe3069283) << (BMP_BIT - 32), /* 174 -- 32,e3069283 */ - BMP_C(0xe3940000) << (BMP_BIT - 32), /* 175 -- 16, e394 */ - BMP_C(0xe5cc0000) << (BMP_BIT - 32), /* 176 -- 16, e5cc */ - BMP_C(0xe7a80000) << (BMP_BIT - 32), /* 177 -- 13, 1cf5 */ - BMP_C(0xe8000000) << (BMP_BIT - 32), /* 178 -- 6, 3a */ - BMP_C(0xea000000) << (BMP_BIT - 32), /* 179 -- 7, 75 */ - BMP_C(0xea820000) << (BMP_BIT - 32), /* 180 -- 16, ea82 */ - BMP_C(0xec000000) << (BMP_BIT - 32), /* 181 -- 6, 3b */ - BMP_C(0xf0000000) << (BMP_BIT - 32), /* 182 -- 4, f */ - BMP_C(0xf0b80000) << (BMP_BIT - 32), /* 183 -- 16, f0b8 */ - BMP_C(0xf1300000) << (BMP_BIT - 32), /* 184 -- 12, f13 */ - BMP_C(0xf4000000) << (BMP_BIT - 32), /* 185 -- 8, f4 */ - BMP_C(0xf4acfb13) << (BMP_BIT - 32), /* 186 -- 32,f4acfb13 */ - BMP_C(0xf5b00000) << (BMP_BIT - 32), /* 187 -- 12, f5b */ - BMP_C(0xf6400000) << (BMP_BIT - 32), /* 188 -- 10, 3d9 */ - BMP_C(0xf8000000) << (BMP_BIT - 32), /* 189 -- 5, 1f */ - BMP_C(0xfc000000) << (BMP_BIT - 32), /* 190 -- 6, 3f */ - BMP_C(0xfc891918) << (BMP_BIT - 32), /* 191 -- 32,fc891918 */ - BMP_C(0xfd000000) << (BMP_BIT - 32), /* 192 -- 8, fd */ - BMP_C(0xfe000000) << (BMP_BIT - 32), /* 193 -- 7, 7f */ - BMP_C(0xfedcba00) << (BMP_BIT - 32), /* 194 -- 24, fedcba */ - BMP_C(0xfee80000) << (BMP_BIT - 32), /* 195 -- 16, fee8 */ - BMP_C(0xff000000) << (BMP_BIT - 32), /* 196 -- 8, ff */ - BMP_C(0xffc00000) << (BMP_BIT - 32), /* 197 -- 10, 3ff */ - BMP_C(0xfff00000) << (BMP_BIT - 32), /* 198 -- 12, fff */ - BMP_C(0xfffc0000) << (BMP_BIT - 32), /* 199 -- 14, 3fff */ - BMP_C(0xffff0000) << (BMP_BIT - 32), /* 200 -- 16, ffff */ - BMP_C(0xffffff00) << (BMP_BIT - 32), /* 201 -- 24, ffffff */ - BMP_C(0xfffffffc) << (BMP_BIT - 32), /* 202 -- 30,3fffffff */ - BMP_C(0xfffffffe) << (BMP_BIT - 32), /* 203 -- 31,7fffffff */ - BMP_C(0xffffffff) << (BMP_BIT - 32), /* 204 -- 32,ffffffff */ + BMP_C(0x080b0000) << (BMP_BIT - 32), /* 11 -- 16, 080b */ + BMP_C(0x09823b6e) << (BMP_BIT - 32), /* 12 -- 31,04c11db7 */ + BMP_C(0x0b3c0000) << (BMP_BIT - 32), /* 13 -- 15, 059e */ + BMP_C(0x0c000000) << (BMP_BIT - 32), /* 14 -- 6, 03 */ + BMP_C(0x0c200000) << (BMP_BIT - 32), /* 15 -- 11, 061 */ + BMP_C(0x0c780000) << (BMP_BIT - 32), /* 16 -- 14, 031e */ + BMP_C(0x0fb30000) << (BMP_BIT - 32), /* 17 -- 16, 0fb3 */ + BMP_C(0x10210000) << (BMP_BIT - 32), /* 18 -- 16, 1021 */ + BMP_C(0x12000000) << (BMP_BIT - 32), /* 19 -- 7, 09 */ + BMP_C(0x130d2afc) << (BMP_BIT - 32), /* 20 -- 30,04c34abf */ + BMP_C(0x144e6300) << (BMP_BIT - 32), /* 21 -- 24, 144e63 */ + BMP_C(0x15000000) << (BMP_BIT - 32), /* 22 -- 8, 15 */ + BMP_C(0x1697d06a) << (BMP_BIT - 32), /* 23 -- 32,1697d06a */ + BMP_C(0x17800000) << (BMP_BIT - 32), /* 24 -- 12, 178 */ + BMP_C(0x18000000) << (BMP_BIT - 32), /* 25 -- 6, 06 */ + BMP_C(0x19d3c8d8) << (BMP_BIT - 32), /* 26 -- 31,0ce9e46c */ + BMP_C(0x1c000000) << (BMP_BIT - 32), /* 27 -- 6, 07 */ + BMP_C(0x1d000000) << (BMP_BIT - 32), /* 28 -- 8, 1d */ + BMP_C(0x1d0f0000) << (BMP_BIT - 32), /* 29 -- 16, 1d0f */ + BMP_C(0x1dcf0000) << (BMP_BIT - 32), /* 30 -- 16, 1dcf */ + BMP_C(0x1edc6f41) << (BMP_BIT - 32), /* 31 -- 32,1edc6f41 */ + BMP_C(0x1f23b800) << (BMP_BIT - 32), /* 32 -- 24, 1f23b8 */ + BMP_C(0x20000000) << (BMP_BIT - 32), /* 33 -- 4, 2 */ + BMP_C(0x200fa500) << (BMP_BIT - 32), /* 34 -- 24, 200fa5 */ + BMP_C(0x20140000) << (BMP_BIT - 32), /* 35 -- 14, 0805 */ + BMP_C(0x20b40000) << (BMP_BIT - 32), /* 36 -- 14, 082d */ + BMP_C(0x20fe0000) << (BMP_BIT - 32), /* 37 -- 16, 20fe */ + BMP_C(0x21890000) << (BMP_BIT - 32), /* 38 -- 16, 2189 */ + BMP_C(0x21cf0200) << (BMP_BIT - 32), /* 39 -- 24, 21cf02 */ + BMP_C(0x23ef5200) << (BMP_BIT - 32), /* 40 -- 24, 23ef52 */ + BMP_C(0x25000000) << (BMP_BIT - 32), /* 41 -- 8, 25 */ + BMP_C(0x26000000) << (BMP_BIT - 32), /* 42 -- 8, 26 */ + BMP_C(0x26b10000) << (BMP_BIT - 32), /* 43 -- 16, 26b1 */ + BMP_C(0x27818000) << (BMP_BIT - 32), /* 44 -- 17, 04f03 */ + BMP_C(0x27d00000) << (BMP_BIT - 32), /* 45 -- 13, 04fa */ + BMP_C(0x28000000) << (BMP_BIT - 32), /* 46 -- 5, 05 */ + BMP_C(0x29b10000) << (BMP_BIT - 32), /* 47 -- 16, 29b1 */ + BMP_C(0x2f000000) << (BMP_BIT - 32), /* 48 -- 8, 2f */ + BMP_C(0x30000000) << (BMP_BIT - 32), /* 49 -- 4, 3/ 5, 6 */ + BMP_C(0x3010bf7f) << (BMP_BIT - 32), /* 50 -- 32,3010bf7f */ + BMP_C(0x31000000) << (BMP_BIT - 32), /* 51 -- 8, 31 */ + BMP_C(0x31800000) << (BMP_BIT - 32), /* 52 -- 10, 0c6 */ + BMP_C(0x31c30000) << (BMP_BIT - 32), /* 53 -- 16, 31c3 */ + BMP_C(0x328b6300) << (BMP_BIT - 32), /* 54 -- 24, 328b63 */ + BMP_C(0x34000000) << (BMP_BIT - 32), /* 55 -- 6, 0d */ + BMP_C(0x340bc6d9) << (BMP_BIT - 32), /* 56 -- 32,340bc6d9 */ + BMP_C(0x37000000) << (BMP_BIT - 32), /* 57 -- 8, 37 */ + BMP_C(0x38000000) << (BMP_BIT - 32), /* 58 -- 5, 07 */ + BMP_C(0x39000000) << (BMP_BIT - 32), /* 59 -- 8, 39 */ + BMP_C(0x3d650000) << (BMP_BIT - 32), /* 60 -- 16, 3d65 */ + BMP_C(0x3e000000) << (BMP_BIT - 32), /* 61 -- 8, 3e */ + BMP_C(0x40000000) << (BMP_BIT - 32), /* 62 -- 3, 2 */ + BMP_C(0x42000000) << (BMP_BIT - 32), /* 63 -- 8, 42 */ + BMP_C(0x44c20000) << (BMP_BIT - 32), /* 64 -- 16, 44c2 */ + BMP_C(0x45270551) << (BMP_BIT - 32), /* 65 -- 32,45270551 */ + BMP_C(0x48000000) << (BMP_BIT - 32), /* 66 -- 5, 09 */ + BMP_C(0x49000000) << (BMP_BIT - 32), /* 67 -- 8, 49 */ + BMP_C(0x4a800000) << (BMP_BIT - 32), /* 68 -- 10, 12a */ + BMP_C(0x4acc0000) << (BMP_BIT - 32), /* 69 -- 15, 2566 */ + BMP_C(0x4b000000) << (BMP_BIT - 32), /* 70 -- 8, 4b */ + BMP_C(0x4b370000) << (BMP_BIT - 32), /* 71 -- 16, 4b37 */ + BMP_C(0x4c000000) << (BMP_BIT - 32), /* 72 -- 6, 13 */ + BMP_C(0x4c060000) << (BMP_BIT - 32), /* 73 -- 16, 4c06 */ + BMP_C(0x53000000) << (BMP_BIT - 32), /* 74 -- 8, 53 */ + BMP_C(0x55000000) << (BMP_BIT - 32), /* 75 -- 8, 55 */ + BMP_C(0x55555500) << (BMP_BIT - 32), /* 76 -- 24, 555555 */ + BMP_C(0x59350000) << (BMP_BIT - 32), /* 77 -- 16, 5935 */ + BMP_C(0x5d380000) << (BMP_BIT - 32), /* 78 -- 16, 5d38 */ + BMP_C(0x5d400000) << (BMP_BIT - 32), /* 79 -- 10, 175 */ + BMP_C(0x5d6dcb00) << (BMP_BIT - 32), /* 80 -- 24, 5d6dcb */ + BMP_C(0x60000000) << (BMP_BIT - 32), /* 81 -- 3, 3 */ + BMP_C(0x60e00000) << (BMP_BIT - 32), /* 82 -- 11, 307 */ + BMP_C(0x63d00000) << (BMP_BIT - 32), /* 83 -- 16, 63d0 */ + BMP_C(0x64000000) << (BMP_BIT - 32), /* 84 -- 6, 19 */ + BMP_C(0x66400000) << (BMP_BIT - 32), /* 85 -- 10, 199 */ + BMP_C(0x66c50000) << (BMP_BIT - 32), /* 86 -- 16, 66c5 */ + BMP_C(0x6f630000) << (BMP_BIT - 32), /* 87 -- 16, 6f63 */ + BMP_C(0x6f910000) << (BMP_BIT - 32), /* 88 -- 16, 6f91 */ + BMP_C(0x70000000) << (BMP_BIT - 32), /* 89 -- 4, 7 */ + BMP_C(0x70a00000) << (BMP_BIT - 32), /* 90 -- 11, 385 */ + BMP_C(0x755b0000) << (BMP_BIT - 32), /* 91 -- 16, 755b */ + BMP_C(0x765e7680) << (BMP_BIT - 32), /* 92 -- 32,765e7680 */ + BMP_C(0x76c20800) << (BMP_BIT - 32), /* 93 -- 32, 0ed841 */ + BMP_C(0x7979bd00) << (BMP_BIT - 32), /* 94 -- 24, 7979bd */ + BMP_C(0x7e000000) << (BMP_BIT - 32), /* 95 -- 8, 7e */ + BMP_C(0x80000000) << (BMP_BIT - 32), /* 96 -- 3, 4 */ + BMP_C(0x80006300) << (BMP_BIT - 32), /* 97 -- 24, 800063 */ + BMP_C(0x80050000) << (BMP_BIT - 32), /* 98 -- 16, 8005 */ + BMP_C(0x800d0000) << (BMP_BIT - 32), /* 99 -- 16, 800d */ + BMP_C(0x800fe300) << (BMP_BIT - 32), /* 100 -- 24, 800fe3 */ + BMP_C(0x80b40000) << (BMP_BIT - 32), /* 101 -- 14, 202d */ + BMP_C(0x80c2e71c) << (BMP_BIT - 32), /* 102 -- 30,2030b9c7 */ + BMP_C(0x80f00000) << (BMP_BIT - 32), /* 103 -- 12, 80f */ + BMP_C(0x814141ab) << (BMP_BIT - 32), /* 104 -- 32,814141ab */ + BMP_C(0x8144c800) << (BMP_BIT - 32), /* 105 -- 21, 102899 */ + BMP_C(0x864cfb00) << (BMP_BIT - 32), /* 106 -- 24, 864cfb */ + BMP_C(0x87315576) << (BMP_BIT - 32), /* 107 -- 32,87315576 */ + BMP_C(0x89ec0000) << (BMP_BIT - 32), /* 108 -- 16, 89ec */ + BMP_C(0x8a000000) << (BMP_BIT - 32), /* 109 -- 7, 45 */ + BMP_C(0x8b320000) << (BMP_BIT - 32), /* 110 -- 15, 4599 */ + BMP_C(0x8bb70000) << (BMP_BIT - 32), /* 111 -- 16, 8bb7 */ + BMP_C(0x8cc00000) << (BMP_BIT - 32), /* 112 -- 10, 233 */ + BMP_C(0x904cddbf) << (BMP_BIT - 32), /* 113 -- 32,904cddbf */ + BMP_C(0x906e0000) << (BMP_BIT - 32), /* 114 -- 16, 906e */ + BMP_C(0x94000000) << (BMP_BIT - 32), /* 115 -- 8, 94 */ + BMP_C(0x97000000) << (BMP_BIT - 32), /* 116 -- 8, 97 */ + BMP_C(0x98000000) << (BMP_BIT - 32), /* 117 -- 6, 26 */ + BMP_C(0x9b000000) << (BMP_BIT - 32), /* 118 -- 8, 9b */ + BMP_C(0x9c000000) << (BMP_BIT - 32), /* 119 -- 6, 27 */ + BMP_C(0x9d5e4de2) << (BMP_BIT - 32), /* 120 -- 31,4eaf26f1 */ + BMP_C(0x9e000000) << (BMP_BIT - 32), /* 121 -- 7, 4f */ + BMP_C(0x9ecf0000) << (BMP_BIT - 32), /* 122 -- 16, 9ecf */ + BMP_C(0xa0660000) << (BMP_BIT - 32), /* 123 -- 16, a066 */ + BMP_C(0xa0970000) << (BMP_BIT - 32), /* 124 -- 16, a097 */ + BMP_C(0xa1000000) << (BMP_BIT - 32), /* 125 -- 8, a1 */ + BMP_C(0xa3660000) << (BMP_BIT - 32), /* 126 -- 16, a366 */ + BMP_C(0xa6000000) << (BMP_BIT - 32), /* 127 -- 7, 53 */ + BMP_C(0xa7000000) << (BMP_BIT - 32), /* 128 -- 8, a7 */ + BMP_C(0xa8000000) << (BMP_BIT - 32), /* 129 -- 5, 15 */ + BMP_C(0xa8190000) << (BMP_BIT - 32), /* 130 -- 16, a819 */ + BMP_C(0xa833982b) << (BMP_BIT - 32), /* 131 -- 32,a833982b */ + BMP_C(0xabcdef00) << (BMP_BIT - 32), /* 132 -- 24, abcdef */ + BMP_C(0xac000000) << (BMP_BIT - 32), /* 133 -- 8, ac */ + BMP_C(0xaee70000) << (BMP_BIT - 32), /* 134 -- 16, aee7 */ + BMP_C(0xb0000000) << (BMP_BIT - 32), /* 135 -- 4, b */ + BMP_C(0xb0010000) << (BMP_BIT - 32), /* 136 -- 16, b001 */ + BMP_C(0xb2aa0000) << (BMP_BIT - 32), /* 137 -- 16, b2aa */ + BMP_C(0xb3400000) << (BMP_BIT - 32), /* 138 -- 12, b34 */ + BMP_C(0xb42d8000) << (BMP_BIT - 32), /* 139 -- 17, 1685b */ + BMP_C(0xb4600000) << (BMP_BIT - 32), /* 140 -- 11, 5a3 */ + BMP_C(0xb4c80000) << (BMP_BIT - 32), /* 141 -- 16, b4c8 */ + BMP_C(0xb4f3e600) << (BMP_BIT - 32), /* 142 -- 24, b4f3e6 */ + BMP_C(0xb704ce00) << (BMP_BIT - 32), /* 143 -- 24, b704ce */ + BMP_C(0xb798b438) << (BMP_BIT - 32), /* 144 -- 32,b798b438 */ + BMP_C(0xbb3d0000) << (BMP_BIT - 32), /* 145 -- 16, bb3d */ + BMP_C(0xbc000000) << (BMP_BIT - 32), /* 146 -- 6,2f/ 8,bc */ + BMP_C(0xbd0be338) << (BMP_BIT - 32), /* 147 -- 32,bd0be338 */ + BMP_C(0xbdf40000) << (BMP_BIT - 32), /* 148 -- 16, bdf4 */ + BMP_C(0xbf050000) << (BMP_BIT - 32), /* 149 -- 16, bf05 */ + BMP_C(0xc0000000) << (BMP_BIT - 32), /* 150 -- 3, 6 */ + BMP_C(0xc2000000) << (BMP_BIT - 32), /* 151 -- 7, 61 */ + BMP_C(0xc25a5600) << (BMP_BIT - 32), /* 152 -- 24, c25a56 */ + BMP_C(0xc2b70000) << (BMP_BIT - 32), /* 153 -- 16, c2b7 */ + BMP_C(0xc2b80000) << (BMP_BIT - 32), /* 154 -- 14, 30ae */ + BMP_C(0xc4000000) << (BMP_BIT - 32), /* 155 -- 8, c4 */ + BMP_C(0xc6c60000) << (BMP_BIT - 32), /* 156 -- 16, c6c6 */ + BMP_C(0xc704dd7b) << (BMP_BIT - 32), /* 157 -- 32,c704dd7b */ + BMP_C(0xc8000000) << (BMP_BIT - 32), /* 158 -- 5, 19 */ + BMP_C(0xc8670000) << (BMP_BIT - 32), /* 159 -- 16, c867 */ + BMP_C(0xcbf43926) << (BMP_BIT - 32), /* 160 -- 32,cbf43926 */ + BMP_C(0xcde70300) << (BMP_BIT - 32), /* 161 -- 24, cde703 */ + BMP_C(0xce3c0000) << (BMP_BIT - 32), /* 162 -- 16, ce3c */ + BMP_C(0xd0000000) << (BMP_BIT - 32), /* 163 -- 8, d0 */ + BMP_C(0xd02a0000) << (BMP_BIT - 32), /* 164 -- 15, 6815 */ + BMP_C(0xd0db0000) << (BMP_BIT - 32), /* 165 -- 16, d0db */ + BMP_C(0xd3100000) << (BMP_BIT - 32), /* 166 -- 12, d31 */ + BMP_C(0xd3be9568) << (BMP_BIT - 32), /* 167 -- 30,34efa55a */ + BMP_C(0xd4d00000) << (BMP_BIT - 32), /* 168 -- 12, d4d */ + BMP_C(0xd5000000) << (BMP_BIT - 32), /* 169 -- 8, d5 */ + BMP_C(0xd64e0000) << (BMP_BIT - 32), /* 170 -- 16, d64e */ + BMP_C(0xda000000) << (BMP_BIT - 32), /* 171 -- 8, da */ + BMP_C(0xdaf00000) << (BMP_BIT - 32), /* 172 -- 12, daf */ + BMP_C(0xdebb20e3) << (BMP_BIT - 32), /* 173 -- 32,debb20e3 */ + BMP_C(0xdf000000) << (BMP_BIT - 32), /* 174 -- 8, df */ + BMP_C(0xe0000000) << (BMP_BIT - 32), /* 175 -- 3, 7 */ + BMP_C(0xe3069283) << (BMP_BIT - 32), /* 176 -- 32,e3069283 */ + BMP_C(0xe3940000) << (BMP_BIT - 32), /* 177 -- 16, e394 */ + BMP_C(0xe5cc0000) << (BMP_BIT - 32), /* 178 -- 16, e5cc */ + BMP_C(0xe7a80000) << (BMP_BIT - 32), /* 179 -- 13, 1cf5 */ + BMP_C(0xe8000000) << (BMP_BIT - 32), /* 180 -- 6, 3a */ + BMP_C(0xea000000) << (BMP_BIT - 32), /* 181 -- 7, 75 */ + BMP_C(0xea820000) << (BMP_BIT - 32), /* 182 -- 16, ea82 */ + BMP_C(0xec000000) << (BMP_BIT - 32), /* 183 -- 6, 3b */ + BMP_C(0xf0000000) << (BMP_BIT - 32), /* 184 -- 4, f */ + BMP_C(0xf0b80000) << (BMP_BIT - 32), /* 185 -- 16, f0b8 */ + BMP_C(0xf1300000) << (BMP_BIT - 32), /* 186 -- 12, f13 */ + BMP_C(0xf4000000) << (BMP_BIT - 32), /* 187 -- 8, f4 */ + BMP_C(0xf4acfb13) << (BMP_BIT - 32), /* 188 -- 32,f4acfb13 */ + BMP_C(0xf5b00000) << (BMP_BIT - 32), /* 189 -- 12, f5b */ + BMP_C(0xf6400000) << (BMP_BIT - 32), /* 190 -- 10, 3d9 */ + BMP_C(0xf7000000) << (BMP_BIT - 32), /* 191 -- 8, f7 */ + BMP_C(0xf8000000) << (BMP_BIT - 32), /* 192 -- 5, 1f */ + BMP_C(0xfc000000) << (BMP_BIT - 32), /* 193 -- 6, 3f */ + BMP_C(0xfc891918) << (BMP_BIT - 32), /* 194 -- 32,fc891918 */ + BMP_C(0xfd000000) << (BMP_BIT - 32), /* 195 -- 8, fd */ + BMP_C(0xfe000000) << (BMP_BIT - 32), /* 196 -- 7, 7f */ + BMP_C(0xfedcba00) << (BMP_BIT - 32), /* 197 -- 24, fedcba */ + BMP_C(0xfee80000) << (BMP_BIT - 32), /* 198 -- 16, fee8 */ + BMP_C(0xff000000) << (BMP_BIT - 32), /* 199 -- 8, ff */ + BMP_C(0xffc00000) << (BMP_BIT - 32), /* 200 -- 10, 3ff */ + BMP_C(0xfff00000) << (BMP_BIT - 32), /* 201 -- 12, fff */ + BMP_C(0xfffc0000) << (BMP_BIT - 32), /* 202 -- 14, 3fff */ + BMP_C(0xffff0000) << (BMP_BIT - 32), /* 203 -- 16, ffff */ + BMP_C(0xffffff00) << (BMP_BIT - 32), /* 204 -- 24, ffffff */ + BMP_C(0xfffffffc) << (BMP_BIT - 32), /* 205 -- 30,3fffffff */ + BMP_C(0xfffffffe) << (BMP_BIT - 32), /* 206 -- 31,7fffffff */ + BMP_C(0xffffffff) << (BMP_BIT - 32), /* 207 -- 32,ffffffff */ }; static const struct malias aliases[]; @@ -471,265 +476,303 @@ static const struct malias aliases[]; * Sorted by left-justified polynomial for bsearch(). */ static const struct mpreset models[] = { - {64UL, b64, b64a, P_LE, b64a, b64b, b64c, aliases+100}, /* 0 */ - {32UL, b32+ 0, 0, P_BE, 0, b32+145, 0, aliases+138}, /* 1 */ - {40UL, b40, 0, P_BE, b40a, b40b, b40c, aliases+ 88}, /* 2 */ - {24UL, b32+ 3, b32+ 75, P_LE, 0, b32+150, 0, aliases+ 60}, /* 3 */ - {32UL, b32+ 8, 0, P_BE, b32+204, b32+ 91, b32+155, aliases+ 82}, /* 4 */ - {32UL, b32+ 8, b32+204, P_BE, 0, b32+ 7, 0, aliases+ 81}, /* 5 */ - {32UL, b32+ 8, b32+204, P_BE, b32+204, b32+191, b32+155, aliases+ 76}, /* 6 */ - {32UL, b32+ 8, b32+204, P_LE, 0, b32+ 55, 0, aliases+130}, /* 7 */ - {32UL, b32+ 8, b32+204, P_LE, b32+204, b32+158, b32+171, aliases+ 72}, /* 8 */ - {16UL, b32+ 9, 0, P_BE, 0, b32+ 5, 0, aliases+ 31}, /* 9 */ - {16UL, b32+ 9, 0, P_BE, b32+ 1, b32+ 4, b32+ 9, aliases+ 30}, /* 10 */ - { 8UL, b32+ 10, 0, P_BE, 0, b32+185, 0, aliases+106}, /* 11 */ - { 8UL, b32+ 10, 0, P_BE, b32+ 74, b32+123, b32+131, aliases+117}, /* 12 */ - { 8UL, b32+ 10, b32+196, P_LE, 0, b32+161, 0, aliases+121}, /* 13 */ - {31UL, b32+ 11, b32+203, P_BE, b32+203, b32+ 25, b32+119, aliases+ 71}, /* 14 */ - { 6UL, b32+ 13, 0, P_LE, 0, b32+ 24, 0, aliases+ 96}, /* 15 */ - {82UL, b82, 0, P_LE, 0, b82a, 0, aliases+124}, /* 16 */ - {16UL, b32+ 17, 0, P_BE, 0, b32+ 52, 0, aliases+139}, /* 17 */ - {16UL, b32+ 17, 0, P_BE, b32+200, b32+160, b32+ 28, aliases+ 36}, /* 18 */ - {16UL, b32+ 17, 0, P_LE, 0, b32+ 37, 0, aliases+131}, /* 19 */ - {16UL, b32+ 17, b32+ 28, P_BE, 0, b32+176, 0, aliases+ 21}, /* 20 */ - {16UL, b32+ 17, b32+107, P_LE, 0, b32+ 42, 0, aliases+ 53}, /* 21 */ - {16UL, b32+ 17, b32+135, P_LE, 0, b32+ 82, 0, aliases+ 49}, /* 22 */ - {16UL, b32+ 17, b32+154, P_LE, 0, b32+147, 0, aliases+125}, /* 23 */ - {16UL, b32+ 17, b32+200, P_BE, 0, b32+ 46, 0, aliases+ 24}, /* 24 */ - {16UL, b32+ 17, b32+200, P_BE, b32+200, b32+168, b32+ 28, aliases+ 35}, /* 25 */ - {16UL, b32+ 17, b32+200, P_LE, 0, b32+ 87, 0, aliases+ 45}, /* 26 */ - {16UL, b32+ 17, b32+200, P_LE, b32+200, b32+113, b32+183, aliases+135}, /* 27 */ - { 7UL, b32+ 18, 0, P_BE, 0, b32+179, 0, aliases+103}, /* 28 */ - { 6UL, b32+ 26, b32+190, P_BE, 0, b32+181, 0, aliases+ 93}, /* 29 */ - { 8UL, b32+ 27, 0, P_BE, 0, b32+ 56, 0, aliases+114}, /* 30 */ - { 8UL, b32+ 27, b32+192, P_BE, 0, b32+ 94, 0, aliases+116}, /* 31 */ - { 8UL, b32+ 27, b32+196, P_BE, b32+196, b32+ 69, b32+153, aliases+122}, /* 32 */ - { 8UL, b32+ 27, b32+196, P_LE, 0, b32+115, 0, aliases+113}, /* 33 */ - {16UL, b32+ 29, b32+200, P_BE, b32+200, b32+128, b32+175, aliases+ 48}, /* 34 */ - {32UL, b32+ 30, b32+204, P_LE, b32+204, b32+174, b32+142, aliases+ 83}, /* 35 */ - {14UL, b32+ 34, 0, P_LE, 0, b32+ 35, 0, aliases+ 14}, /* 36 */ - { 5UL, b32+ 45, b32+189, P_LE, b32+189, b32+156, b32+ 48, aliases+ 91}, /* 37 */ - { 8UL, b32+ 47, 0, P_BE, 0, b32+ 60, 0, aliases+120}, /* 38 */ - { 8UL, b32+ 47, b32+196, P_BE, b32+196, b32+172, b32+ 62, aliases+108}, /* 39 */ - { 4UL, b32+ 48, 0, P_LE, 0, b32+ 88, 0, aliases+ 87}, /* 40 */ - { 4UL, b32+ 48, b32+182, P_BE, b32+182, b32+133, b32+ 32, aliases+ 86}, /* 41 */ - { 8UL, b32+ 50, 0, P_LE, 0, b32+123, 0, aliases+119}, /* 42 */ - {24UL, b32+ 53, b32+201, P_BE, b32+201, b32+140, b32+ 20, aliases+ 63}, /* 43 */ - { 8UL, b32+ 58, 0, P_LE, 0, b32+ 21, 0, aliases+111}, /* 44 */ - {16UL, b32+ 59, 0, P_BE, b32+200, b32+151, b32+124, aliases+ 33}, /* 45 */ - {16UL, b32+ 59, 0, P_LE, b32+200, b32+180, b32+ 85, aliases+ 32}, /* 46 */ - {64UL, b64d, 0, P_BE, 0, b64e, 0, aliases+ 97}, /* 47 */ - {64UL, b64d, b64a, P_BE, b64a, b64f, b64g, aliases+101}, /* 48 */ - {64UL, b64d, b64a, P_LE, b64a, b64h, b64i, aliases+102}, /* 49 */ - { 5UL, b32+ 65, b32+ 65, P_BE, 0, 0, 0, aliases+ 89}, /* 50 */ - { 8UL, b32+ 66, 0, P_BE, b32+196, b32+114, b32+ 73, aliases+115}, /* 51 */ - {16UL, b32+ 76, 0, P_BE, 0, b32+ 77, 0, aliases+ 46}, /* 52 */ - {10UL, b32+ 78, 0, P_BE, b32+197, b32+ 67, b32+ 51, aliases+ 5}, /* 53 */ - {24UL, b32+ 79, b32+130, P_BE, 0, b32+ 31, 0, aliases+ 62}, /* 54 */ - {24UL, b32+ 79, b32+194, P_BE, 0, b32+ 93, 0, aliases+ 61}, /* 55 */ - { 3UL, b32+ 80, 0, P_BE, b32+173, b32+ 95, b32+ 61, aliases+ 68}, /* 56 */ - { 3UL, b32+ 80, b32+173, P_LE, 0, b32+148, 0, aliases+ 69}, /* 57 */ - {11UL, b32+ 81, 0, P_BE, 0, b32+ 14, 0, aliases+ 7}, /* 58 */ - { 6UL, b32+ 83, 0, P_LE, 0, b32+116, 0, aliases+ 94}, /* 59 */ - {16UL, b32+ 86, 0, P_BE, 0, b32+146, 0, aliases+ 42}, /* 60 */ - {11UL, b32+ 89, b32+ 6, P_BE, 0, b32+138, 0, aliases+ 6}, /* 61 */ - {16UL, b32+ 90, 0, P_BE, 0, b32+ 36, 0, aliases+ 47}, /* 62 */ - {24UL, b32+ 96, 0, P_BE, 0, b32+ 39, 0, aliases+ 65}, /* 63 */ - {24UL, b32+ 96, b32+201, P_BE, b32+201, b32+ 33, b32+ 99, aliases+ 67}, /* 64 */ - {16UL, b32+ 97, 0, P_BE, 0, b32+195, 0, aliases+ 22}, /* 65 */ - {16UL, b32+ 97, 0, P_LE, 0, b32+143, 0, aliases+ 0}, /* 66 */ - {16UL, b32+ 97, 0, P_LE, b32+200, b32+ 63, b32+134, aliases+ 44}, /* 67 */ - {16UL, b32+ 97, b32+ 98, P_BE, 0, b32+121, 0, aliases+ 29}, /* 68 */ - {16UL, b32+ 97, b32+200, P_BE, 0, b32+132, 0, aliases+ 27}, /* 69 */ - {16UL, b32+ 97, b32+200, P_LE, 0, b32+ 70, 0, aliases+132}, /* 70 */ - {16UL, b32+ 97, b32+200, P_LE, b32+200, b32+139, b32+134, aliases+ 55}, /* 71 */ - {14UL, b32+100, 0, P_BE, b32+199, b32+152, b32+ 15, aliases+ 15}, /* 72 */ - {30UL, b32+101, b32+202, P_BE, b32+202, b32+ 19, b32+165, aliases+ 70}, /* 73 */ - {12UL, b32+102, 0, P_BE, 0, b32+187, 0, aliases+ 10}, /* 74 */ - {12UL, b32+102, 0, P_BELE, 0, b32+170, 0, aliases+ 12}, /* 75 */ - {32UL, b32+103, 0, P_BE, 0, b32+ 49, 0, aliases+ 85}, /* 76 */ - {21UL, b32+104, 0, P_BE, 0, b32+ 92, 0, aliases+ 58}, /* 77 */ - {24UL, b32+105, 0, P_BE, 0, b32+159, 0, aliases+ 64}, /* 78 */ - {24UL, b32+105, b32+141, P_BE, 0, b32+ 38, 0, aliases+ 59}, /* 79 */ - { 7UL, b32+108, 0, P_BE, 0, b32+149, 0, aliases+105}, /* 80 */ - {15UL, b32+109, 0, P_BE, 0, b32+ 12, 0, aliases+ 16}, /* 81 */ - {16UL, b32+110, 0, P_BE, 0, b32+163, 0, aliases+ 51}, /* 82 */ - {10UL, b32+111, 0, P_BE, 0, b32+ 84, 0, aliases+ 3}, /* 83 */ - { 8UL, b32+117, 0, P_BE, 0, b32+179, 0, aliases+118}, /* 84 */ - { 8UL, b32+117, 0, P_LE, 0, b32+ 40, 0, aliases+123}, /* 85 */ - { 8UL, b32+117, b32+196, P_BE, 0, b32+169, 0, aliases+110}, /* 86 */ - { 6UL, b32+118, b32+190, P_BE, 0, b32+ 54, 0, aliases+ 92}, /* 87 */ - { 7UL, b32+120, b32+193, P_LE, 0, b32+125, 0, aliases+104}, /* 88 */ - {16UL, b32+122, 0, P_BE, 0, b32+ 16, 0, aliases+ 52}, /* 89 */ - { 8UL, b32+126, 0, P_LE, 0, b32+ 41, 0, aliases+109}, /* 90 */ - { 5UL, b32+127, 0, P_LE, 0, b32+ 57, 0, aliases+ 90}, /* 91 */ - {32UL, b32+129, b32+204, P_LE, b32+204, b32+106, b32+ 64, aliases+ 84}, /* 92 */ - {17UL, b32+137, 0, P_BE, 0, b32+ 43, 0, aliases+ 57}, /* 93 */ - { 6UL, b32+144, 0, P_BE, b32+190, b32+ 71, b32+178, aliases+ 95}, /* 94 */ - {16UL, b32+157, b32+200, P_BE, 0, b32+ 72, 0, aliases+ 26}, /* 95 */ - {15UL, b32+162, 0, P_BE, b32+ 2, b32+ 68, b32+162, aliases+ 17}, /* 96 */ - {12UL, b32+164, 0, P_BE, b32+198, b32+136, b32+ 23, aliases+ 11}, /* 97 */ - { 8UL, b32+167, 0, P_BE, 0, b32+144, 0, aliases+112}, /* 98 */ - {13UL, b32+177, 0, P_BE, 0, b32+ 44, 0, aliases+ 13}, /* 99 */ - {12UL, b32+184, b32+198, P_BE, 0, b32+166, 0, aliases+ 9}, /* 100 */ - {32UL, b32+186, b32+204, P_LE, b32+204, b32+ 22, b32+112, aliases+ 75}, /* 101 */ - {10UL, b32+188, b32+197, P_BE, 0, b32+111, 0, aliases+ 4}, /* 102 */ - { 0UL, 0, 0, P_BE, 0, 0, 0, NULL }, /* terminating entry */ + {64UL, b64, b64a, P_LE | P_CONFIR, b64a, b64b, b64c, aliases+130}, /* 0 */ + {32UL, b32+ 0, 0, P_BE | P_CONFIR, 0, b32+147, 0, aliases+107}, /* 1 */ + {40UL, b40, 0, P_BE | P_ACADEM, b40a, b40b, b40c, aliases+115}, /* 2 */ + {24UL, b32+ 3, b32+ 76, P_LE | P_ATTEST, 0, b32+152, 0, aliases+ 77}, /* 3 */ + {32UL, b32+ 8, 0, P_BE | P_ATTEST, b32+207, b32+ 92, b32+157, aliases+ 98}, /* 4 */ + {32UL, b32+ 8, b32+207, P_BE | P_ATTEST, 0, b32+ 7, 0, aliases+104}, /* 5 */ + {32UL, b32+ 8, b32+207, P_BE | P_ATTEST, b32+207, b32+194, b32+157, aliases+ 96}, /* 6 */ + {32UL, b32+ 8, b32+207, P_LE | P_CONFIR, 0, b32+ 56, 0, aliases+103}, /* 7 */ + {32UL, b32+ 8, b32+207, P_LE | P_ATTEST, b32+207, b32+160, b32+173, aliases+102}, /* 8 */ + {16UL, b32+ 9, 0, P_BE | P_ATTEST, 0, b32+ 5, 0, aliases+ 36}, /* 9 */ + {16UL, b32+ 9, 0, P_BE | P_ATTEST, b32+ 1, b32+ 4, b32+ 9, aliases+ 35}, /* 10 */ + { 8UL, b32+ 10, 0, P_BE | P_ATTEST, 0, b32+187, 0, aliases+157}, /* 11 */ + { 8UL, b32+ 10, 0, P_BE | P_ACADEM, b32+ 75, b32+125, b32+133, aliases+147}, /* 12 */ + { 8UL, b32+ 10, b32+199, P_LE | P_ACADEM, 0, b32+163, 0, aliases+155}, /* 13 */ + {16UL, b32+ 11, b32+203, P_LE | P_ATTEST, 0, b32+123, 0, aliases+ 58}, /* 14 */ + {31UL, b32+ 12, b32+206, P_BE | P_CONFIR, b32+206, b32+ 26, b32+120, aliases+ 88}, /* 15 */ + { 6UL, b32+ 14, 0, P_LE | P_ACADEM, 0, b32+ 25, 0, aliases+124}, /* 16 */ + {82UL, b82, 0, P_LE | P_ATTEST, 0, b82a, 0, aliases+160}, /* 17 */ + {16UL, b32+ 18, 0, P_BE | P_ATTEST, 0, b32+ 53, 0, aliases+ 73}, /* 18 */ + {16UL, b32+ 18, 0, P_BE | P_ACADEM, b32+203, b32+162, b32+ 29, aliases+ 42}, /* 19 */ + {16UL, b32+ 18, 0, P_LE | P_ATTEST, 0, b32+ 38, 0, aliases+ 50}, /* 20 */ + {16UL, b32+ 18, b32+ 29, P_BE | P_ATTEST, 0, b32+178, 0, aliases+ 63}, /* 21 */ + {16UL, b32+ 18, b32+108, P_LE | P_ATTEST, 0, b32+ 43, 0, aliases+ 66}, /* 22 */ + {16UL, b32+ 18, b32+137, P_LE | P_THIRDP, 0, b32+ 83, 0, aliases+ 62}, /* 23 */ + {16UL, b32+ 18, b32+156, P_LE | P_ATTEST, 0, b32+149, 0, aliases+ 48}, /* 24 */ + {16UL, b32+ 18, b32+203, P_BE | P_ATTEST, 0, b32+ 47, 0, aliases+ 44}, /* 25 */ + {16UL, b32+ 18, b32+203, P_BE | P_ATTEST, b32+203, b32+170, b32+ 29, aliases+ 41}, /* 26 */ + {16UL, b32+ 18, b32+203, P_LE | P_ATTEST, 0, b32+ 88, 0, aliases+ 56}, /* 27 */ + {16UL, b32+ 18, b32+203, P_LE | P_ATTEST, b32+203, b32+114, b32+185, aliases+ 45}, /* 28 */ + { 7UL, b32+ 19, 0, P_BE | P_ACADEM, 0, b32+181, 0, aliases+134}, /* 29 */ + { 6UL, b32+ 27, b32+193, P_BE | P_ACADEM, 0, b32+183, 0, aliases+122}, /* 30 */ + { 8UL, b32+ 28, 0, P_BE | P_ACADEM, 0, b32+ 57, 0, aliases+145}, /* 31 */ + { 8UL, b32+ 28, b32+195, P_BE | P_ATTEST, 0, b32+ 95, 0, aliases+148}, /* 32 */ + { 8UL, b32+ 28, b32+199, P_BE | P_ATTEST, b32+199, b32+ 70, b32+155, aliases+156}, /* 33 */ + { 8UL, b32+ 28, b32+199, P_LE | P_ATTEST, 0, b32+116, 0, aliases+158}, /* 34 */ + {16UL, b32+ 30, b32+203, P_BE | P_ATTEST, b32+203, b32+130, b32+177, aliases+ 61}, /* 35 */ + {32UL, b32+ 31, b32+207, P_LE | P_ATTEST, b32+207, b32+176, b32+144, aliases+101}, /* 36 */ + {14UL, b32+ 35, 0, P_LE | P_ATTEST, 0, b32+ 36, 0, aliases+ 17}, /* 37 */ + { 5UL, b32+ 46, b32+192, P_LE | P_THIRDP, b32+192, b32+158, b32+ 49, aliases+120}, /* 38 */ + { 8UL, b32+ 48, 0, P_BE | P_ATTEST, 0, b32+ 61, 0, aliases+154}, /* 39 */ + { 8UL, b32+ 48, b32+199, P_BE | P_ATTEST, b32+199, b32+174, b32+ 63, aliases+139}, /* 40 */ + { 4UL, b32+ 49, 0, P_LE | P_ACADEM, 0, b32+ 89, 0, aliases+112}, /* 41 */ + { 4UL, b32+ 49, b32+184, P_BE | P_ACADEM, b32+184, b32+135, b32+ 33, aliases+113}, /* 42 */ + { 8UL, b32+ 51, 0, P_LE | P_ATTEST, 0, b32+125, 0, aliases+152}, /* 43 */ + { 8UL, b32+ 51, b32+199, P_BE | P_ATTEST, 0, b32+191, 0, aliases+153}, /* 44 */ + {24UL, b32+ 54, b32+204, P_BE | P_ACADEM, b32+204, b32+142, b32+ 21, aliases+ 80}, /* 45 */ + { 8UL, b32+ 59, 0, P_LE | P_ATTEST, 0, b32+ 22, 0, aliases+142}, /* 46 */ + {16UL, b32+ 60, 0, P_BE | P_CONFIR, b32+203, b32+153, b32+126, aliases+ 38}, /* 47 */ + {16UL, b32+ 60, 0, P_LE | P_CONFIR, b32+203, b32+182, b32+ 86, aliases+ 37}, /* 48 */ + {64UL, b64d, 0, P_BE | P_ACADEM, 0, b64e, 0, aliases+128}, /* 49 */ + {64UL, b64d, b64a, P_BE | P_CONFIR, b64a, b64f, b64g, aliases+131}, /* 50 */ + {64UL, b64d, b64a, P_LE | P_ATTEST, b64a, b64h, b64i, aliases+132}, /* 51 */ + { 5UL, b32+ 66, b32+ 66, P_BE | P_ATTEST, 0, 0, 0, aliases+117}, /* 52 */ + { 8UL, b32+ 67, 0, P_BE | P_ACADEM, b32+199, b32+115, b32+ 74, aliases+146}, /* 53 */ + {16UL, b32+ 77, 0, P_BE | P_ATTEST, 0, b32+ 78, 0, aliases+ 59}, /* 54 */ + {10UL, b32+ 79, 0, P_BE | P_ACADEM, b32+200, b32+ 68, b32+ 52, aliases+ 6}, /* 55 */ + {24UL, b32+ 80, b32+132, P_BE | P_ATTEST, 0, b32+ 32, 0, aliases+ 79}, /* 56 */ + {24UL, b32+ 80, b32+197, P_BE | P_ATTEST, 0, b32+ 94, 0, aliases+ 78}, /* 57 */ + { 3UL, b32+ 81, 0, P_BE | P_ACADEM, b32+175, b32+ 96, b32+ 62, aliases+ 85}, /* 58 */ + { 3UL, b32+ 81, b32+175, P_LE | P_ACADEM, 0, b32+150, 0, aliases+ 86}, /* 59 */ + {11UL, b32+ 82, 0, P_BE | P_ACADEM, 0, b32+ 15, 0, aliases+ 10}, /* 60 */ + { 6UL, b32+ 84, 0, P_LE | P_ATTEST, 0, b32+117, 0, aliases+123}, /* 61 */ + {16UL, b32+ 87, 0, P_BE | P_THIRDP, 0, b32+148, 0, aliases+ 52}, /* 62 */ + {11UL, b32+ 90, b32+ 6, P_BE | P_ATTEST, 0, b32+140, 0, aliases+ 9}, /* 63 */ + {16UL, b32+ 91, 0, P_BE | P_ATTEST, 0, b32+ 37, 0, aliases+ 60}, /* 64 */ + {24UL, b32+ 97, 0, P_BE | P_ACADEM, 0, b32+ 40, 0, aliases+ 82}, /* 65 */ + {24UL, b32+ 97, b32+204, P_BE | P_ATTEST, b32+204, b32+ 34, b32+100, aliases+ 84}, /* 66 */ + {16UL, b32+ 98, 0, P_BE | P_ATTEST, 0, b32+198, 0, aliases+ 67}, /* 67 */ + {16UL, b32+ 98, 0, P_LE | P_CONFIR, 0, b32+145, 0, aliases+ 24}, /* 68 */ + {16UL, b32+ 98, 0, P_LE | P_ATTEST, b32+203, b32+ 64, b32+136, aliases+ 55}, /* 69 */ + {16UL, b32+ 98, b32+ 99, P_BE | P_ATTEST, 0, b32+122, 0, aliases+ 34}, /* 70 */ + {16UL, b32+ 98, b32+203, P_BE | P_THIRDP, 0, b32+134, 0, aliases+ 32}, /* 71 */ + {16UL, b32+ 98, b32+203, P_LE | P_ATTEST, 0, b32+ 71, 0, aliases+ 57}, /* 72 */ + {16UL, b32+ 98, b32+203, P_LE | P_THIRDP, b32+203, b32+141, b32+136, aliases+ 68}, /* 73 */ + {14UL, b32+101, 0, P_BE | P_ACADEM, b32+202, b32+154, b32+ 16, aliases+ 18}, /* 74 */ + {30UL, b32+102, b32+205, P_BE | P_ACADEM, b32+205, b32+ 20, b32+167, aliases+ 87}, /* 75 */ + {12UL, b32+103, 0, P_BE | P_ACADEM, 0, b32+189, 0, aliases+ 13}, /* 76 */ + {12UL, b32+103, 0, P_BELE | P_ACADEM, 0, b32+172, 0, aliases+ 15}, /* 77 */ + {32UL, b32+104, 0, P_BE | P_ATTEST, 0, b32+ 50, 0, aliases+ 92}, /* 78 */ + {21UL, b32+105, 0, P_BE | P_ACADEM, 0, b32+ 93, 0, aliases+ 75}, /* 79 */ + {24UL, b32+106, 0, P_BE | P_ACADEM, 0, b32+161, 0, aliases+ 81}, /* 80 */ + {24UL, b32+106, b32+143, P_BE | P_ATTEST, 0, b32+ 39, 0, aliases+ 83}, /* 81 */ + { 7UL, b32+109, 0, P_BE | P_ACADEM, 0, b32+151, 0, aliases+136}, /* 82 */ + {15UL, b32+110, 0, P_BE | P_ACADEM, 0, b32+ 13, 0, aliases+ 20}, /* 83 */ + {16UL, b32+111, 0, P_BE | P_ATTEST, 0, b32+165, 0, aliases+ 64}, /* 84 */ + {10UL, b32+112, 0, P_BE | P_ATTEST, 0, b32+ 85, 0, aliases+ 4}, /* 85 */ + { 8UL, b32+118, 0, P_BE | P_ACADEM, 0, b32+181, 0, aliases+150}, /* 86 */ + { 8UL, b32+118, 0, P_LE | P_THIRDP, 0, b32+ 41, 0, aliases+159}, /* 87 */ + { 8UL, b32+118, b32+199, P_BE | P_ACADEM, 0, b32+171, 0, aliases+141}, /* 88 */ + { 6UL, b32+119, b32+193, P_BE | P_ATTEST, 0, b32+ 55, 0, aliases+121}, /* 89 */ + { 7UL, b32+121, b32+196, P_LE | P_ACADEM, 0, b32+127, 0, aliases+135}, /* 90 */ + {16UL, b32+124, 0, P_BE | P_CONFIR, 0, b32+ 17, 0, aliases+ 65}, /* 91 */ + { 8UL, b32+128, 0, P_LE | P_ATTEST, 0, b32+ 42, 0, aliases+140}, /* 92 */ + { 5UL, b32+129, 0, P_LE | P_ACADEM, 0, b32+ 58, 0, aliases+118}, /* 93 */ + {32UL, b32+131, b32+207, P_LE | P_CONFIR, b32+207, b32+107, b32+ 65, aliases+ 95}, /* 94 */ + {17UL, b32+139, 0, P_BE | P_ACADEM, 0, b32+ 44, 0, aliases+ 74}, /* 95 */ + { 6UL, b32+146, 0, P_BE | P_ACADEM, b32+193, b32+ 72, b32+180, aliases+125}, /* 96 */ + {16UL, b32+159, b32+203, P_BE | P_ACADEM, 0, b32+ 73, 0, aliases+ 31}, /* 97 */ + {15UL, b32+164, 0, P_BE | P_ATTEST, b32+ 2, b32+ 69, b32+164, aliases+ 21}, /* 98 */ + {12UL, b32+166, 0, P_BE | P_ACADEM, b32+201, b32+138, b32+ 24, aliases+ 14}, /* 99 */ + { 8UL, b32+169, 0, P_BE | P_ACADEM, 0, b32+146, 0, aliases+143}, /* 100 */ + {13UL, b32+179, 0, P_BE | P_ATTEST, 0, b32+ 45, 0, aliases+ 16}, /* 101 */ + {12UL, b32+186, b32+201, P_BE | P_ACADEM, 0, b32+168, 0, aliases+ 12}, /* 102 */ + {32UL, b32+188, b32+207, P_LE | P_ATTEST, b32+207, b32+ 23, b32+113, aliases+ 93}, /* 103 */ + {10UL, b32+190, b32+200, P_BE | P_ACADEM, 0, b32+112, 0, aliases+ 5}, /* 104 */ + { 0UL, 0, 0, P_BE | P_UNDFCL, 0, 0, 0, NULL }, /* terminating entry */ }; -# define NPRESETS 103 +# define NPRESETS 105 /* List of names with pointers to models, pre-sorted for use with bsearch() */ static const struct malias aliases[] = { - {"ARC", models+ 66}, /* 0 */ - {"B-CRC-32", models+ 6}, /* 1 */ - {"CKSUM", models+ 4}, /* 2 */ - {"CRC-10", models+ 83}, /* 3 */ - {"CRC-10/CDMA2000", models+102}, /* 4 */ - {"CRC-10/GSM", models+ 53}, /* 5 */ - {"CRC-11", models+ 61}, /* 6 */ - {"CRC-11/UMTS", models+ 58}, /* 7 */ - {"CRC-12/3GPP", models+ 75}, /* 8 */ - {"CRC-12/CDMA2000", models+100}, /* 9 */ - {"CRC-12/DECT", models+ 74}, /* 10 */ - {"CRC-12/GSM", models+ 97}, /* 11 */ - {"CRC-12/UMTS", models+ 75}, /* 12 */ - {"CRC-13/BBC", models+ 99}, /* 13 */ - {"CRC-14/DARC", models+ 36}, /* 14 */ - {"CRC-14/GSM", models+ 72}, /* 15 */ - {"CRC-15", models+ 81}, /* 16 */ - {"CRC-15/MPT1327", models+ 96}, /* 17 */ - {"CRC-16", models+ 66}, /* 18 */ - {"CRC-16/ACORN", models+ 17}, /* 19 */ - {"CRC-16/ARC", models+ 66}, /* 20 */ - {"CRC-16/AUG-CCITT", models+ 20}, /* 21 */ - {"CRC-16/BUYPASS", models+ 65}, /* 22 */ - {"CRC-16/CCITT", models+ 19}, /* 23 */ - {"CRC-16/CCITT-FALSE", models+ 24}, /* 24 */ - {"CRC-16/CCITT-TRUE", models+ 19}, /* 25 */ - {"CRC-16/CDMA2000", models+ 95}, /* 26 */ - {"CRC-16/CMS", models+ 69}, /* 27 */ - {"CRC-16/DARC", models+ 25}, /* 28 */ - {"CRC-16/DDS-110", models+ 68}, /* 29 */ - {"CRC-16/DECT-R", models+ 10}, /* 30 */ - {"CRC-16/DECT-X", models+ 9}, /* 31 */ - {"CRC-16/DNP", models+ 46}, /* 32 */ - {"CRC-16/EN-13757", models+ 45}, /* 33 */ - {"CRC-16/EPC", models+ 25}, /* 34 */ - {"CRC-16/GENIBUS", models+ 25}, /* 35 */ - {"CRC-16/GSM", models+ 18}, /* 36 */ - {"CRC-16/I-CODE", models+ 25}, /* 37 */ - {"CRC-16/IBM-SDLC", models+ 27}, /* 38 */ - {"CRC-16/IEC-61158-2", models+ 34}, /* 39 */ - {"CRC-16/ISO-HDLC", models+ 27}, /* 40 */ - {"CRC-16/LHA", models+ 66}, /* 41 */ - {"CRC-16/LJ1200", models+ 60}, /* 42 */ - {"CRC-16/LTE", models+ 17}, /* 43 */ - {"CRC-16/MAXIM", models+ 67}, /* 44 */ - {"CRC-16/MCRF4XX", models+ 26}, /* 45 */ - {"CRC-16/OPENSAFETY-A", models+ 52}, /* 46 */ - {"CRC-16/OPENSAFETY-B", models+ 62}, /* 47 */ - {"CRC-16/PROFIBUS", models+ 34}, /* 48 */ - {"CRC-16/RIELLO", models+ 22}, /* 49 */ - {"CRC-16/SPI-FUJITSU", models+ 20}, /* 50 */ - {"CRC-16/T10-DIF", models+ 82}, /* 51 */ - {"CRC-16/TELEDISK", models+ 89}, /* 52 */ - {"CRC-16/TMS37157", models+ 21}, /* 53 */ - {"CRC-16/UMTS", models+ 65}, /* 54 */ - {"CRC-16/USB", models+ 71}, /* 55 */ - {"CRC-16/VERIFONE", models+ 65}, /* 56 */ - {"CRC-17/CAN-FD", models+ 93}, /* 57 */ - {"CRC-21/CAN-FD", models+ 77}, /* 58 */ - {"CRC-24", models+ 79}, /* 59 */ - {"CRC-24/BLE", models+ 3}, /* 60 */ - {"CRC-24/FLEXRAY-A", models+ 55}, /* 61 */ - {"CRC-24/FLEXRAY-B", models+ 54}, /* 62 */ - {"CRC-24/INTERLAKEN", models+ 43}, /* 63 */ - {"CRC-24/LTE-A", models+ 78}, /* 64 */ - {"CRC-24/LTE-B", models+ 63}, /* 65 */ - {"CRC-24/OPENPGP", models+ 79}, /* 66 */ - {"CRC-24/OS-9", models+ 64}, /* 67 */ - {"CRC-3/GSM", models+ 56}, /* 68 */ - {"CRC-3/ROHC", models+ 57}, /* 69 */ - {"CRC-30/CDMA", models+ 73}, /* 70 */ - {"CRC-31/PHILIPS", models+ 14}, /* 71 */ - {"CRC-32", models+ 8}, /* 72 */ - {"CRC-32/AAL5", models+ 6}, /* 73 */ - {"CRC-32/ADCCP", models+ 8}, /* 74 */ - {"CRC-32/AUTOSAR", models+101}, /* 75 */ - {"CRC-32/BZIP2", models+ 6}, /* 76 */ - {"CRC-32/CASTAGNOLI", models+ 35}, /* 77 */ - {"CRC-32/DECT-B", models+ 6}, /* 78 */ - {"CRC-32/INTERLAKEN", models+ 35}, /* 79 */ - {"CRC-32/ISCSI", models+ 35}, /* 80 */ - {"CRC-32/MPEG-2", models+ 5}, /* 81 */ - {"CRC-32/POSIX", models+ 4}, /* 82 */ - {"CRC-32C", models+ 35}, /* 83 */ - {"CRC-32D", models+ 92}, /* 84 */ - {"CRC-32Q", models+ 76}, /* 85 */ - {"CRC-4/INTERLAKEN", models+ 41}, /* 86 */ - {"CRC-4/ITU", models+ 40}, /* 87 */ - {"CRC-40/GSM", models+ 2}, /* 88 */ - {"CRC-5/EPC", models+ 50}, /* 89 */ - {"CRC-5/ITU", models+ 91}, /* 90 */ - {"CRC-5/USB", models+ 37}, /* 91 */ - {"CRC-6/CDMA2000-A", models+ 87}, /* 92 */ - {"CRC-6/CDMA2000-B", models+ 29}, /* 93 */ - {"CRC-6/DARC", models+ 59}, /* 94 */ - {"CRC-6/GSM", models+ 94}, /* 95 */ - {"CRC-6/ITU", models+ 15}, /* 96 */ - {"CRC-64", models+ 47}, /* 97 */ - {"CRC-64/ECMA-182", models+ 47}, /* 98 */ - {"CRC-64/GO-ECMA", models+ 49}, /* 99 */ - {"CRC-64/GO-ISO", models+ 0}, /* 100 */ - {"CRC-64/WE", models+ 48}, /* 101 */ - {"CRC-64/XZ", models+ 49}, /* 102 */ - {"CRC-7", models+ 28}, /* 103 */ - {"CRC-7/ROHC", models+ 88}, /* 104 */ - {"CRC-7/UMTS", models+ 80}, /* 105 */ - {"CRC-8", models+ 11}, /* 106 */ - {"CRC-8/AES", models+ 33}, /* 107 */ - {"CRC-8/AUTOSAR", models+ 39}, /* 108 */ - {"CRC-8/BLUETOOTH", models+ 90}, /* 109 */ - {"CRC-8/CDMA2000", models+ 86}, /* 110 */ - {"CRC-8/DARC", models+ 44}, /* 111 */ - {"CRC-8/DVB-S2", models+ 98}, /* 112 */ - {"CRC-8/EBU", models+ 33}, /* 113 */ - {"CRC-8/GSM-A", models+ 30}, /* 114 */ - {"CRC-8/GSM-B", models+ 51}, /* 115 */ - {"CRC-8/I-CODE", models+ 31}, /* 116 */ - {"CRC-8/ITU", models+ 12}, /* 117 */ - {"CRC-8/LTE", models+ 84}, /* 118 */ - {"CRC-8/MAXIM", models+ 42}, /* 119 */ - {"CRC-8/OPENSAFETY", models+ 38}, /* 120 */ - {"CRC-8/ROHC", models+ 13}, /* 121 */ - {"CRC-8/SAE-J1850", models+ 32}, /* 122 */ - {"CRC-8/WCDMA", models+ 85}, /* 123 */ - {"CRC-82/DARC", models+ 16}, /* 124 */ - {"CRC-A", models+ 23}, /* 125 */ - {"CRC-B", models+ 27}, /* 126 */ - {"CRC-CCITT", models+ 19}, /* 127 */ - {"CRC-IBM", models+ 66}, /* 128 */ - {"DOW-CRC", models+ 42}, /* 129 */ - {"JAMCRC", models+ 7}, /* 130 */ - {"KERMIT", models+ 19}, /* 131 */ - {"MODBUS", models+ 70}, /* 132 */ - {"PKZIP", models+ 8}, /* 133 */ - {"R-CRC-16", models+ 10}, /* 134 */ - {"X-25", models+ 27}, /* 135 */ - {"X-CRC-12", models+ 74}, /* 136 */ - {"X-CRC-16", models+ 9}, /* 137 */ - {"XFER", models+ 1}, /* 138 */ - {"XMODEM", models+ 17}, /* 139 */ - {"ZMODEM", models+ 17}, /* 140 */ - {NULL, NULL }, /* terminating entry */ + {"ARC", models+ 68}, /* 0 */ + {"B-CRC-32", models+ 6}, /* 1 */ + {"CKSUM", models+ 4}, /* 2 */ + {"CRC-10", models+ 85}, /* 3 */ + {"CRC-10/ATM", models+ 85}, /* 4 */ + {"CRC-10/CDMA2000", models+104}, /* 5 */ + {"CRC-10/GSM", models+ 55}, /* 6 */ + {"CRC-10/I-610", models+ 85}, /* 7 */ + {"CRC-11", models+ 63}, /* 8 */ + {"CRC-11/FLEXRAY", models+ 63}, /* 9 */ + {"CRC-11/UMTS", models+ 60}, /* 10 */ + {"CRC-12/3GPP", models+ 77}, /* 11 */ + {"CRC-12/CDMA2000", models+102}, /* 12 */ + {"CRC-12/DECT", models+ 76}, /* 13 */ + {"CRC-12/GSM", models+ 99}, /* 14 */ + {"CRC-12/UMTS", models+ 77}, /* 15 */ + {"CRC-13/BBC", models+101}, /* 16 */ + {"CRC-14/DARC", models+ 37}, /* 17 */ + {"CRC-14/GSM", models+ 74}, /* 18 */ + {"CRC-15", models+ 83}, /* 19 */ + {"CRC-15/CAN", models+ 83}, /* 20 */ + {"CRC-15/MPT1327", models+ 98}, /* 21 */ + {"CRC-16", models+ 68}, /* 22 */ + {"CRC-16/ACORN", models+ 18}, /* 23 */ + {"CRC-16/ARC", models+ 68}, /* 24 */ + {"CRC-16/AUG-CCITT", models+ 21}, /* 25 */ + {"CRC-16/AUTOSAR", models+ 25}, /* 26 */ + {"CRC-16/BUYPASS", models+ 67}, /* 27 */ + {"CRC-16/CCITT", models+ 20}, /* 28 */ + {"CRC-16/CCITT-FALSE", models+ 25}, /* 29 */ + {"CRC-16/CCITT-TRUE", models+ 20}, /* 30 */ + {"CRC-16/CDMA2000", models+ 97}, /* 31 */ + {"CRC-16/CMS", models+ 71}, /* 32 */ + {"CRC-16/DARC", models+ 26}, /* 33 */ + {"CRC-16/DDS-110", models+ 70}, /* 34 */ + {"CRC-16/DECT-R", models+ 10}, /* 35 */ + {"CRC-16/DECT-X", models+ 9}, /* 36 */ + {"CRC-16/DNP", models+ 48}, /* 37 */ + {"CRC-16/EN-13757", models+ 47}, /* 38 */ + {"CRC-16/EPC", models+ 26}, /* 39 */ + {"CRC-16/EPC-C1G2", models+ 26}, /* 40 */ + {"CRC-16/GENIBUS", models+ 26}, /* 41 */ + {"CRC-16/GSM", models+ 19}, /* 42 */ + {"CRC-16/I-CODE", models+ 26}, /* 43 */ + {"CRC-16/IBM-3740", models+ 25}, /* 44 */ + {"CRC-16/IBM-SDLC", models+ 28}, /* 45 */ + {"CRC-16/IEC-61158-2", models+ 35}, /* 46 */ + {"CRC-16/ISO-HDLC", models+ 28}, /* 47 */ + {"CRC-16/ISO-IEC-14443-3-A", models+ 24}, /* 48 */ + {"CRC-16/ISO-IEC-14443-3-B", models+ 28}, /* 49 */ + {"CRC-16/KERMIT", models+ 20}, /* 50 */ + {"CRC-16/LHA", models+ 68}, /* 51 */ + {"CRC-16/LJ1200", models+ 62}, /* 52 */ + {"CRC-16/LTE", models+ 18}, /* 53 */ + {"CRC-16/MAXIM", models+ 69}, /* 54 */ + {"CRC-16/MAXIM-DOW", models+ 69}, /* 55 */ + {"CRC-16/MCRF4XX", models+ 27}, /* 56 */ + {"CRC-16/MODBUS", models+ 72}, /* 57 */ + {"CRC-16/NRSC-5", models+ 14}, /* 58 */ + {"CRC-16/OPENSAFETY-A", models+ 54}, /* 59 */ + {"CRC-16/OPENSAFETY-B", models+ 64}, /* 60 */ + {"CRC-16/PROFIBUS", models+ 35}, /* 61 */ + {"CRC-16/RIELLO", models+ 23}, /* 62 */ + {"CRC-16/SPI-FUJITSU", models+ 21}, /* 63 */ + {"CRC-16/T10-DIF", models+ 84}, /* 64 */ + {"CRC-16/TELEDISK", models+ 91}, /* 65 */ + {"CRC-16/TMS37157", models+ 22}, /* 66 */ + {"CRC-16/UMTS", models+ 67}, /* 67 */ + {"CRC-16/USB", models+ 73}, /* 68 */ + {"CRC-16/V-41-LSB", models+ 20}, /* 69 */ + {"CRC-16/V-41-MSB", models+ 18}, /* 70 */ + {"CRC-16/VERIFONE", models+ 67}, /* 71 */ + {"CRC-16/X-25", models+ 28}, /* 72 */ + {"CRC-16/XMODEM", models+ 18}, /* 73 */ + {"CRC-17/CAN-FD", models+ 95}, /* 74 */ + {"CRC-21/CAN-FD", models+ 79}, /* 75 */ + {"CRC-24", models+ 81}, /* 76 */ + {"CRC-24/BLE", models+ 3}, /* 77 */ + {"CRC-24/FLEXRAY-A", models+ 57}, /* 78 */ + {"CRC-24/FLEXRAY-B", models+ 56}, /* 79 */ + {"CRC-24/INTERLAKEN", models+ 45}, /* 80 */ + {"CRC-24/LTE-A", models+ 80}, /* 81 */ + {"CRC-24/LTE-B", models+ 65}, /* 82 */ + {"CRC-24/OPENPGP", models+ 81}, /* 83 */ + {"CRC-24/OS-9", models+ 66}, /* 84 */ + {"CRC-3/GSM", models+ 58}, /* 85 */ + {"CRC-3/ROHC", models+ 59}, /* 86 */ + {"CRC-30/CDMA", models+ 75}, /* 87 */ + {"CRC-31/PHILIPS", models+ 15}, /* 88 */ + {"CRC-32", models+ 8}, /* 89 */ + {"CRC-32/AAL5", models+ 6}, /* 90 */ + {"CRC-32/ADCCP", models+ 8}, /* 91 */ + {"CRC-32/AIXM", models+ 78}, /* 92 */ + {"CRC-32/AUTOSAR", models+103}, /* 93 */ + {"CRC-32/BASE91-C", models+ 36}, /* 94 */ + {"CRC-32/BASE91-D", models+ 94}, /* 95 */ + {"CRC-32/BZIP2", models+ 6}, /* 96 */ + {"CRC-32/CASTAGNOLI", models+ 36}, /* 97 */ + {"CRC-32/CKSUM", models+ 4}, /* 98 */ + {"CRC-32/DECT-B", models+ 6}, /* 99 */ + {"CRC-32/INTERLAKEN", models+ 36}, /* 100 */ + {"CRC-32/ISCSI", models+ 36}, /* 101 */ + {"CRC-32/ISO-HDLC", models+ 8}, /* 102 */ + {"CRC-32/JAMCRC", models+ 7}, /* 103 */ + {"CRC-32/MPEG-2", models+ 5}, /* 104 */ + {"CRC-32/POSIX", models+ 4}, /* 105 */ + {"CRC-32/V-42", models+ 8}, /* 106 */ + {"CRC-32/XFER", models+ 1}, /* 107 */ + {"CRC-32/XZ", models+ 8}, /* 108 */ + {"CRC-32C", models+ 36}, /* 109 */ + {"CRC-32D", models+ 94}, /* 110 */ + {"CRC-32Q", models+ 78}, /* 111 */ + {"CRC-4/G-704", models+ 41}, /* 112 */ + {"CRC-4/INTERLAKEN", models+ 42}, /* 113 */ + {"CRC-4/ITU", models+ 41}, /* 114 */ + {"CRC-40/GSM", models+ 2}, /* 115 */ + {"CRC-5/EPC", models+ 52}, /* 116 */ + {"CRC-5/EPC-C1G2", models+ 52}, /* 117 */ + {"CRC-5/G-704", models+ 93}, /* 118 */ + {"CRC-5/ITU", models+ 93}, /* 119 */ + {"CRC-5/USB", models+ 38}, /* 120 */ + {"CRC-6/CDMA2000-A", models+ 89}, /* 121 */ + {"CRC-6/CDMA2000-B", models+ 30}, /* 122 */ + {"CRC-6/DARC", models+ 61}, /* 123 */ + {"CRC-6/G-704", models+ 16}, /* 124 */ + {"CRC-6/GSM", models+ 96}, /* 125 */ + {"CRC-6/ITU", models+ 16}, /* 126 */ + {"CRC-64", models+ 49}, /* 127 */ + {"CRC-64/ECMA-182", models+ 49}, /* 128 */ + {"CRC-64/GO-ECMA", models+ 51}, /* 129 */ + {"CRC-64/GO-ISO", models+ 0}, /* 130 */ + {"CRC-64/WE", models+ 50}, /* 131 */ + {"CRC-64/XZ", models+ 51}, /* 132 */ + {"CRC-7", models+ 29}, /* 133 */ + {"CRC-7/MMC", models+ 29}, /* 134 */ + {"CRC-7/ROHC", models+ 90}, /* 135 */ + {"CRC-7/UMTS", models+ 82}, /* 136 */ + {"CRC-8", models+ 11}, /* 137 */ + {"CRC-8/AES", models+ 34}, /* 138 */ + {"CRC-8/AUTOSAR", models+ 40}, /* 139 */ + {"CRC-8/BLUETOOTH", models+ 92}, /* 140 */ + {"CRC-8/CDMA2000", models+ 88}, /* 141 */ + {"CRC-8/DARC", models+ 46}, /* 142 */ + {"CRC-8/DVB-S2", models+100}, /* 143 */ + {"CRC-8/EBU", models+ 34}, /* 144 */ + {"CRC-8/GSM-A", models+ 31}, /* 145 */ + {"CRC-8/GSM-B", models+ 53}, /* 146 */ + {"CRC-8/I-432-1", models+ 12}, /* 147 */ + {"CRC-8/I-CODE", models+ 32}, /* 148 */ + {"CRC-8/ITU", models+ 12}, /* 149 */ + {"CRC-8/LTE", models+ 86}, /* 150 */ + {"CRC-8/MAXIM", models+ 43}, /* 151 */ + {"CRC-8/MAXIM-DOW", models+ 43}, /* 152 */ + {"CRC-8/NRSC-5", models+ 44}, /* 153 */ + {"CRC-8/OPENSAFETY", models+ 39}, /* 154 */ + {"CRC-8/ROHC", models+ 13}, /* 155 */ + {"CRC-8/SAE-J1850", models+ 33}, /* 156 */ + {"CRC-8/SMBUS", models+ 11}, /* 157 */ + {"CRC-8/TECH-3250", models+ 34}, /* 158 */ + {"CRC-8/WCDMA", models+ 87}, /* 159 */ + {"CRC-82/DARC", models+ 17}, /* 160 */ + {"CRC-A", models+ 24}, /* 161 */ + {"CRC-B", models+ 28}, /* 162 */ + {"CRC-CCITT", models+ 20}, /* 163 */ + {"CRC-IBM", models+ 68}, /* 164 */ + {"DOW-CRC", models+ 43}, /* 165 */ + {"JAMCRC", models+ 7}, /* 166 */ + {"KERMIT", models+ 20}, /* 167 */ + {"MODBUS", models+ 72}, /* 168 */ + {"PKZIP", models+ 8}, /* 169 */ + {"R-CRC-16", models+ 10}, /* 170 */ + {"X-25", models+ 28}, /* 171 */ + {"X-CRC-12", models+ 76}, /* 172 */ + {"X-CRC-16", models+ 9}, /* 173 */ + {"XFER", models+ 1}, /* 174 */ + {"XMODEM", models+ 18}, /* 175 */ + {"ZMODEM", models+ 18}, /* 176 */ + {NULL, NULL }, /* terminating entry */ }; -# define NALIASES 141 +# define NALIASES 177 # endif /* BMP_BIT */ #else /* PRESETS */ static const struct mpreset models[] = { - { 0UL, 0, 0, P_BE, 0, 0, 0, NULL }, /* terminating entry */ + { 0UL, 0, 0, P_BE | P_UNDFCL, 0, 0, 0, NULL }, /* terminating entry */ }; # define NPRESETS 0 @@ -768,7 +811,9 @@ int mbynam(model_t *dest, const char *key) { if (!aliases->name) return(-1); - if (!(ukey = malloc((size_t) 1 + strlen(key) + 1))) { + + ukey = calloc((size_t) 1 + strlen(key) + 1, sizeof(char)); + if (!ukey) { uerror("[!] cannot allocate memory for comparison string"); return(0); } @@ -818,7 +863,9 @@ char * mnames(void) { ++aptr; } if (!size) return(NULL); - if ((string = malloc(size))) { + + string = calloc(size, sizeof(char)); + if (string) { aptr = aliases; sptr = string; while (aptr->name) { diff --git a/client/reveng/reveng.c b/client/reveng/reveng.c index 004a6fc3c..550dc2da5 100644 --- a/client/reveng/reveng.c +++ b/client/reveng/reveng.c @@ -173,8 +173,9 @@ modpol(const poly_t init, int rflags, int args, const poly_t *argpolys) { unsigned long alen, blen; if(args < 2) return(NULL); - - if(!(result = malloc(((((args - 1) * args) >> 1) + 1) * sizeof(poly_t)))) + + result = calloc(((((args - 1) * args) >> 1) + 1) * sizeof(poly_t), sizeof(char)); + if(!result) uerror("cannot allocate memory for codeword table"); rptr = result; @@ -240,7 +241,8 @@ engini(int *resc, model_t **result, const poly_t divisor, int flags, int args, c dlen = plen(divisor); /* Allocate the CRC matrix */ - if(!(mat = (poly_t *) malloc((dlen << 1) * sizeof(poly_t)))) + mat = (poly_t *) calloc((dlen << 1) * sizeof(poly_t), sizeof(char)); + if(!mat) uerror("cannot allocate memory for CRC matrix"); /* Find arguments of the two shortest lengths */ diff --git a/client/reveng/reveng.h b/client/reveng/reveng.h index 08a7a6d1a..70f594072 100644 --- a/client/reveng/reveng.h +++ b/client/reveng/reveng.h @@ -1,5 +1,5 @@ /* reveng.h - * Greg Cook, 26/Jul/2018 + * Greg Cook, 21/Nov/2018 */ /* CRC RevEng: arbitrary-precision CRC calculator and algorithm finder @@ -93,7 +93,7 @@ /* Global definitions */ /* CRC RevEng version string */ -#define VERSION "1.5.3" +#define VERSION "1.6.0" /* bmpbit.c */ typedef BMP_T bmp_t; @@ -111,6 +111,19 @@ extern void setbmp(void); #define P_LTLBYT 64 #define P_DIRECT 128 +/* class flags */ +#define P_CLBIT0 256 +#define P_CLBIT1 512 +#define P_SOLID 1024 +#define P_CLMASK (P_SOLID | P_CLBIT1 | P_CLBIT0) + +#define P_UNDFCL 0 +#define P_UNCONF (P_CLBIT0) +#define P_THIRDP (P_CLBIT1) +#define P_ACADEM (P_CLBIT1 | P_CLBIT0) +#define P_CONFIR (P_SOLID | P_CLBIT0) +#define P_ATTEST (P_SOLID | P_CLBIT1) + /* default flags */ #define P_BE (P_RTJUST | P_MULXN) #define P_LE (P_REFIN | P_REFOUT | P_MULXN) @@ -187,7 +200,7 @@ extern void mrev(model_t *model); extern void mnovel(model_t *model); /* preset.c */ -#define M_OVERWR 256 +#define M_OVERWR 1 extern int mbynam(model_t *dest, const char *key); extern void mbynum(model_t *dest, int num); @@ -196,12 +209,12 @@ extern char *mnames(void); extern void mmatch(model_t *model, int flags); /* 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_HAVEP 1 +#define R_HAVEI 2 +#define R_HAVERI 4 +#define R_HAVERO 8 +#define R_HAVEX 16 +#define R_HAVEQ 32 #define R_SPMASK 0x7FFFFFFUL diff --git a/client/scandir.c b/client/scandir.c index 12bbef110..619bd72c6 100644 --- a/client/scandir.c +++ b/client/scandir.c @@ -51,7 +51,8 @@ int scandir (const char *dir, nl = ntmp; } - if (!(etmp = (struct dirent *) malloc (sizeof *ent))) { + etmp = (struct dirent *) calloc (sizeof *ent, sizeof(char)); + if (!etmp) { err_no = 1; break; } diff --git a/client/scripting.c b/client/scripting.c index 762a9c470..6f6a30f53 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -515,7 +515,7 @@ static int l_sha1(lua_State *L) { static int l_reveng_models(lua_State *L){ // This array needs to be adjusted if RevEng adds more crc-models. -#define NMODELS 103 +#define NMODELS 105 int count = 0; uint8_t in_width = luaL_checkunsigned(L, 1); @@ -608,7 +608,7 @@ static int l_hardnested(lua_State *L){ char filename[FILE_PATH_SIZE]="nonces.bin"; const char *p_filename = luaL_checklstring(L, 11, &size); if(size != 0) - strcpy(filename, p_filename); + memcpy(filename, p_filename, FILE_PATH_SIZE-1); uint32_t blockNo = 0, keyType = 0; uint32_t trgBlockNo = 0, trgKeyType = 0; @@ -758,6 +758,15 @@ int set_pm3_libraries(lua_State *L) { //-- remove the global environment table from the stack lua_pop(L, 1); + + //--add to the LUA_PATH (package.path in lua) + // so we can load scripts from the ./scripts/ - directory + char scripts_path[strlen(get_my_executable_directory()) + strlen(LUA_SCRIPTS_DIRECTORY) + strlen(LUA_LIBRARIES_WILDCARD) + 1]; + strcpy(scripts_path, get_my_executable_directory()); + strcat(scripts_path, LUA_SCRIPTS_DIRECTORY); + strcat(scripts_path, LUA_LIBRARIES_WILDCARD); + setLuaPath(L, scripts_path); + //-- Last but not least, add to the LUA_PATH (package.path in lua) // so we can load libraries from the ./lualib/ - directory char libraries_path[strlen(get_my_executable_directory()) + strlen(LUA_LIBRARIES_DIRECTORY) + strlen(LUA_LIBRARIES_WILDCARD) + 1]; @@ -765,6 +774,5 @@ int set_pm3_libraries(lua_State *L) { strcat(libraries_path, LUA_LIBRARIES_DIRECTORY); strcat(libraries_path, LUA_LIBRARIES_WILDCARD); setLuaPath(L, libraries_path); - return 1; } \ No newline at end of file diff --git a/client/scripting.h b/client/scripting.h index 4d39a6c6f..81b95cbe0 100644 --- a/client/scripting.h +++ b/client/scripting.h @@ -19,7 +19,7 @@ #include "cmdmain.h" #include "comms.h" #include "util.h" -#include "mifarehost.h" +#include "mifare/mifarehost.h" #include "crc.h" #include "crc16.h" #include "crc64.h" diff --git a/client/scripts/calypso.lua b/client/scripts/calypso.lua index ad74c8183..ce90a25fd 100644 --- a/client/scripts/calypso.lua +++ b/client/scripts/calypso.lua @@ -68,9 +68,9 @@ end --- -- This is only meant to be used when errors occur local function oops(err) - print("ERROR: ",err) + print("ERROR: ", err) calypso_switch_off_field() - return nil,err + return nil, err end --- -- Usage help diff --git a/client/scripts/iso15_magic.lua b/client/scripts/iso15_magic.lua index 36e8100a8..3923f2b1e 100644 --- a/client/scripts/iso15_magic.lua +++ b/client/scripts/iso15_magic.lua @@ -5,7 +5,7 @@ local utils = require('utils') copyright = 'Copyright (c) 2018 IceSQL AB. All rights reserved.' author = 'Christian Herrmann' -version = 'v1.0.3' +version = 'v1.0.4' desc = [[ This script tries to set UID on a IS15693 SLIX magic card Remember the UID ->MUST<- start with 0xE0 @@ -15,6 +15,8 @@ example = [[ -- ISO15693 slix magic tag script run iso15_magic -u E004013344556677 + + script run iso15_magic -u E004013344556677 -a ]] usage = [[ script run iso15_magic -h -u @@ -22,6 +24,7 @@ script run iso15_magic -h -u Arguments: -h : this help -u : UID (16 hexsymbols) + -a : use offical pm3 repo ISO15 commands instead of iceman fork. ]] local DEBUG = true @@ -82,11 +85,13 @@ function main(args) print() local uid = 'E004013344556677' + local use_iceman = true -- Read the parameters - for o, a in getopt.getopt(args, 'hu:') do + for o, a in getopt.getopt(args, 'hu:a') do if o == "h" then return help() end if o == "u" then uid = a end + if o == "a" then use_iceman = false end end -- uid string checks @@ -103,8 +108,11 @@ function main(args) core.clearCommandBuffer() - magicUID_iceman(block0, block1) - --magicUID_offical(block0, block1) + if use_iceman then + magicUID_iceman(block0, block1) + else + magicUID_offical(block0, block1) + end end main(args) diff --git a/client/scripts/legic.lua b/client/scripts/legic.lua index 546e5cc1a..264d4dfef 100644 --- a/client/scripts/legic.lua +++ b/client/scripts/legic.lua @@ -513,8 +513,8 @@ function readFromPM3() return tag end -function padString(str) - if (str:len() == 1) then +local function padString(str) + if (#str == 1) then return '0'..str end @@ -524,73 +524,84 @@ end --- -- write virtual Tag to real Tag function writeToTag(tag) - local bytes - local filename='MylegicClone.hex' - local taglen=22 + local bytes + local filename = 'MylegicClone.hex' + local taglen = 22 if(utils.confirm(acred.."\nplace the (empty) Tag onto the PM3\nand confirm writing to this Tag: "..acoff) == false) then - return - end - -- get used bytes / tag-len - if(istable(tag.SEG)) then - if (istable(tag.Bck)) then - for i=0, #tag.SEG do - taglen=taglen+tag.SEG[i].len+5 - end - end - local uid_old=tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2 - -- read new tag into memory so we can xor the new data with the new MCC - outTAG=readFromPM3() - outbytes=tagToBytes(outTAG) - -- copy 'inputbuffer' to 'outputbuffer' - tag.MCD = outbytes[1] - tag.MSN0 = outbytes[2] - tag.MSN1 = outbytes[3] - tag.MSN2 = outbytes[4] - tag.MCC = outbytes[5] - -- recheck all segments-crc/kghcrc (only on a credential) - if(istable(tag.Bck)) then - checkAllSegCrc(tag) - checkAllKghCrc(tag) - local uid_new=tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2 - for i=0, #tag.SEG do - if (check43rdPartyCash1(uid_old, tag.SEG[i].data)) then - io.write(accyan.."\nfixing known checksums"..acoff.." ... ") - if (fix3rdPartyCash1(uid_new, tag.SEG[i].data)) then - io.write(acgreen.." done\n"..acoff) - else oops("\nsomething went wrong at the repair of the 3rd-party-cash-segment") end - end - end - end - bytes=tagToBytes(tag) - -- master-token-crc - if (tag.Type ~= "SAM") then bytes[22] = calcMtCrc(bytes) end - if (bytes) then - print("write temp-file '"..filename.."'") - print(accyan) - writeFile(bytes, filename..".bin") - print(acoff) - end - end + return + end + + -- get used bytes / tag-len + if (istable(tag.SEG)) then + if (istable(tag.Bck)) then + for i=0, #tag.SEG do + taglen = taglen + tag.SEG[i] . len + 5 + end + end + local uid_old = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2 + + -- read new tag into memory so we can xor the new data with the new MCC + outTAG = readFromPM3() + outbytes = tagToBytes(outTAG) + -- copy 'inputbuffer' to 'outputbuffer' + tag.MCD = outbytes[1] + tag.MSN0 = outbytes[2] + tag.MSN1 = outbytes[3] + tag.MSN2 = outbytes[4] + tag.MCC = outbytes[5] + -- recheck all segments-crc/kghcrc (only on a credential) + if (istable(tag.Bck)) then + checkAllSegCrc(tag) + checkAllKghCrc(tag) + local uid_new = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2 + for i=0, #tag.SEG do + if (check43rdPartyCash1(uid_old, tag.SEG[i].data)) then + io.write(accyan.."\nfixing known checksums"..acoff.." ... ") + if (fix3rdPartyCash1(uid_new, tag.SEG[i].data)) then + io.write(acgreen.." done\n"..acoff) + else + oops("\nsomething went wrong at the repair of the 3rd-party-cash-segment") + end + end + end + end + bytes = tagToBytes(tag) + -- master-token-crc + if (tag.Type ~= "SAM") then + bytes[22] = calcMtCrc(bytes) + end + if (bytes) then + print("write temp-file '"..filename.."'") + print(accyan) + writeFile(bytes, filename..".bin") + print(acoff) + end + end - -- write data to file + -- write data to file if (taglen > 0) then WriteBytes = utils.input(acyellow.."enter number of bytes to write?"..acoff, taglen) -- load file into pm3-buffer - if (type(filename) ~= "string") then filename=input(acyellow.."filename to load to pm3-buffer?"..acoff,"legic.temp") end + if (type(filename) ~= "string") then + filename = input(acyellow.."filename to load to pm3-buffer?"..acoff, "legic.temp") + end + cmd = 'hf legic eload 2 '..filename core.console(cmd) -- write pm3-buffer to Tag for i=0, WriteBytes do if (i > 6) then - cmd = 'hf legic write o '..string.format("%x", i)..' d '..padString(bytes[i]) - print(acgreen..cmd..acoff) + cmd = ("hf legic write o %x d %s "):format(i, padString(bytes[i])) + print(acgreen..cmd..acoff) core.console(cmd) + core.clearCommandBuffer() elseif (i == 6) then - -- write DCF in reverse order (requires 'mosci-patch') - cmd = 'hf legic write o 05 d '..padString(bytes[i-1])..padString(bytes[i]) - print(acgreen..cmd..acoff) + -- write DCF in reverse order (requires 'mosci-patch') + cmd = ('hf legic write o 05 d %s%s'):format(padString(bytes[i-1]), padString(bytes[i])) + print(acgreen..cmd..acoff) core.console(cmd) - elseif (i == 5) then + core.clearCommandBuffer() + elseif (i == 5) then print(acgreen.."skip byte 0x05 - will be written next step"..acoff) else print(acgreen.."skip byte 0x00-0x04 - unwritable area"..acoff) @@ -603,26 +614,28 @@ end --- File I/O --- --- -- read file into virtual-tag -function readFile(filename) - print(accyan) - local bytes = {} - local tag = {} - if file_check(filename) == false then return oops("input file: "..filename.." not found") end +local function readFile(filename) + print(accyan) + local bytes = {} + local tag = {} + if file_check(filename) == false then + return oops("input file: "..filename.." not found") + end - bytes = getInputBytes(filename) + bytes = getInputBytes(filename) - if bytes == false then return oops('couldnt get input bytes') end + if bytes == false then return oops('couldnt get input bytes') end - -- make plain bytes - bytes = xorBytes(bytes,bytes[5]) - print("create virtual tag from ".. #bytes .. " bytes") - -- create Tag for plain bytes - tag=createTagTable() - -- load plain bytes to tag-table - print(acoff) - tag=bytesToTag(bytes, tag) + -- make plain bytes + bytes = xorBytes(bytes,bytes[5]) + print("create virtual tag from ".. #bytes .. " bytes") + -- create Tag for plain bytes + tag = createTagTable() + -- load plain bytes to tag-table + print(acoff) + tag = bytesToTag(bytes, tag) - return tag + return tag end --- @@ -631,14 +644,16 @@ function writeFile(bytes, filename) if (filename ~= 'MylegicClone.hex') then if (file_check(filename)) then local answer = confirm("\nthe output-file "..filename.." already exists!\nthis will delete the previous content!\ncontinue?") - if (answer==false) then return print("user abort") end + if not answer then return print("user abort") end end end local line - local bcnt=0 - local fho,err = io.open(filename, "w") - if err then oops("OOps ... failed to open output-file ".. filename) end - bytes=xorBytes(bytes, bytes[5]) + local bcnt = 0 + local fho, err = io.open(filename, "w") + if err then + return oops("OOps ... failed to open output-file ".. filename) + end + bytes = xorBytes(bytes, bytes[5]) for i = 1, #bytes do if (bcnt == 0) then line = bytes[i] @@ -662,96 +677,96 @@ end --- Map related --- --- -- make tagMap -function makeTagMap() - local tagMap={} - if (#tagMap == 0) then - tagMap['name'] = input(accyan.."enter Name for this Map: "..acoff , "newTagMap") - tagMap['mappings']={} - tagMap['crc8']={} - -- insert fixed Tag-CRC - table.insert(tagMap.crc8, {name='TAG-CRC', pos=5, seq={1, 4}}) - tagMap['crc16']={} - end - print(accyan.."new tagMap created"..acoff) - return tagMap +local function makeTagMap() + local tagMap = {} + if (#tagMap == 0) then + tagMap['name'] = input(accyan.."enter Name for this Map: "..acoff , "newTagMap") + tagMap['mappings'] = {} + tagMap['crc8'] = {} + -- insert fixed Tag-CRC + table.insert(tagMap.crc8, {name = 'TAG-CRC', pos = 5, seq = {1, 4}}) + tagMap['crc16'] = {} + end + print(accyan.."new tagMap created"..acoff) + return tagMap end --- -- save mapping to file -function saveTagMap(map, filename) - if (string.len(filename)>0) then - if (file_check(filename)) then - local answer = confirm("\nthe output-file "..filename.." alredy exists!\nthis will delete the previous content!\ncontinue?") - if (answer==false) then return print("user abort") end - end - end +local function saveTagMap(map, filename) + if (string.len(filename)>0) then + if (file_check(filename)) then + local answer = confirm("\nthe output-file "..filename.." alredy exists!\nthis will delete the previous content!\ncontinue?") + if not answer then return print("user abort") end + end + end - local line + local line local fho,err = io.open(filename, "w") if err then oops("OOps ... faild to open output-file ".. filename) end - -- write line to new file - for k, v in pairs(map) do - if (istable(v)) then - for k2, v2 in pairs(v) do - if (k=='mappings') then - fho:write(k..","..k2..","..v2['name']..","..v2['start']..","..v2['end']..","..((v2['highlight']) and "1" or "0").."\n") - elseif (k=="crc8") then - local tmp="" - tmp=k..","..k2..","..v2['name']..","..v2['pos'].."," - tmp=tmp..tbl2seqstr(v2['seq']) - fho:write(tmp.."\n") - end - end - else - fho:write(k..","..v.."\n") - end - end + -- write line to new file + for k, v in pairs(map) do + if (istable(v)) then + for k2, v2 in pairs(v) do + if (k == 'mappings') then + fho:write(k..","..k2..","..v2['name']..","..v2['start']..","..v2['end']..","..((v2['highlight']) and "1" or "0").."\n") + elseif (k == "crc8") then + local tmp = "" + tmp = k..","..k2..","..v2['name']..","..v2['pos'].."," + tmp=tmp..tbl2seqstr(v2['seq']) + fho:write(tmp.."\n") + end + end + else + fho:write(k..","..v.."\n") + end + end fho:close() return true end --- -- toggle higligh -function toggleHighlight(tbl) +local function toggleHighlight(tbl) if (tbl['highlight']) then tbl['highlight'] = false else tbl['highlight'] = true end - return tbl + return tbl end --- -- return table od seqence-string -function seqstr2tbl(seqstr) - local s=split(seqstr) - local res={} - if (#s>=1) then - for sk, sv in pairs(s) do - s2=split(sv, '-') - if(#s2==2) then - table.insert(res, s2[1]) - table.insert(res, s2[2]) - end - end - end - return res +local function seqstr2tbl(seqstr) + local s = split(seqstr) + local res = {} + if (#s >= 1) then + for sk, sv in pairs(s) do + s2 = split(sv, '-') + if(#s2 == 2) then + table.insert(res, s2[1]) + table.insert(res, s2[2]) + end + end + end + return res end --- -- return sequence-string from table -function tbl2seqstr(seqtbl) - local res="" - if (istable(seqtbl)) then - for sk, sv in pairs(seqtbl) do - res=res..sv..((sk%2==0) and "," or "-") - end - if (string.sub(res, string.len(res))==",") then - res=string.sub(res, 1, string.len(res)-1) - end - end - return res +local function tbl2seqstr(seqtbl) + local res = "" + if (istable(seqtbl)) then + for sk, sv in pairs(seqtbl) do + res = res..sv..((sk%2==0) and "," or "-") + end + if (string.sub(res, string.len(res))== ",") then + res = string.sub(res, 1, string.len(res)-1) + end + end + return res end --- diff --git a/client/scripts/mifare_autopwn.lua b/client/scripts/mifare_autopwn.lua index 9bd149a55..738ca6950 100644 --- a/client/scripts/mifare_autopwn.lua +++ b/client/scripts/mifare_autopwn.lua @@ -12,8 +12,10 @@ This is a script which automates cracking and dumping mifare classic cards. It s place by the device. Arguments: - -d debug logging on - -h this help + -h this help + -d debug logging on + -k known key for Sector 0 , keytype A + Output files from this operation: .eml - emulator file @@ -73,12 +75,12 @@ local function nested(key,sak) if 0x18 == sak then --NXP MIFARE Classic 4k | Plus 4k | Ev1 4k typ = 4 elseif 0x08 == sak then -- NXP MIFARE CLASSIC 1k | Plus 2k | Ev1 1K - typ= 1 + typ = 1 elseif 0x09 == sak then -- NXP MIFARE Mini 0.3k typ = 0 - elseif 0x10 == sak then-- "NXP MIFARE Plus 2k" + elseif 0x10 == sak then-- "NXP MIFARE Plus 2k" typ = 2 - elseif 0x01 == sak then-- "NXP MIFARE TNP3xxx 1K" + elseif 0x01 == sak then-- "NXP MIFARE TNP3xxx 1K" typ = 1 else print("I don't know how many sectors there are on this type of card, defaulting to 16") @@ -87,22 +89,40 @@ local function nested(key,sak) core.console(cmd) end -local function dump(uid) +local function dump(uid, numsectors) dbg('dumping tag memory') + local typ = 1 + if 0x18 == sak then --NXP MIFARE Classic 4k | Plus 4k | Ev1 4k + typ = 4 + elseif 0x08 == sak then -- NXP MIFARE CLASSIC 1k | Plus 2k | Ev1 1K + typ = 1 + elseif 0x09 == sak then -- NXP MIFARE Mini 0.3k + typ = 0 + elseif 0x10 == sak then-- "NXP MIFARE Plus 2k" + typ = 2 + elseif 0x01 == sak then-- "NXP MIFARE TNP3xxx 1K" + typ = 1 + end + if utils.confirm('Do you wish to create a memory dump of tag?') then - core.console("hf mf dump") + local dumpfile = 'hf-mf-'..uid..'-data.bin' + + local dmp = ('hf mf dump %s f %s'):format(typ, dumpfile) + core.console(dmp) + -- Save the global args, those are *our* arguments local myargs = args -- Set the arguments for htmldump script - args =("-o %s.html"):format(uid) + args =('-i %s -o %s.html'):format(dumpfile, uid) -- call it - require('../scripts/htmldump') + require('htmldump') - args ="" -- dump to emulator - require('../scripts/dumptoemul') + args =('-i %s -o %s.eml'):format(dumpfile, uid) + require('dumptoemul') + -- Set back args. Not that it's used, just for the karma... args = myargs end @@ -177,9 +197,9 @@ local function main(args) print("Found valid key: "..key); end -- Use nested attack - nested(key,sak) + nested(key, sak) -- Dump info - dump(uid) + dump(uid, sak) if #key == 12 then exit = true end else diff --git a/client/scripts/ndef_dump.lua b/client/scripts/ndef_dump.lua index 3b27cac37..f1bf70ddd 100644 --- a/client/scripts/ndef_dump.lua +++ b/client/scripts/ndef_dump.lua @@ -24,13 +24,13 @@ local example = "script run xxx" local author = "Martin Holst Swende & Asper" --- -- PrintAndLog -function prlog(...) +local function prlog(...) -- TODO; replace this with a call to the proper PrintAndLog print(...) end --- -- This is only meant to be used when errors occur -function oops(err) +local function oops(err) prlog("ERROR: ",err) return nil,err end @@ -66,23 +66,39 @@ local utils = { end, } - - --- -- Usage help -function help() +local function help() prlog(desc) prlog("Example usage") prlog(example) end -function debug(...) +local function debug(...) if DEBUG then prlog("debug:", ...) end end +--- This function is a lua-implementation of +-- cmdhf14a.c:waitCmd(uint8_t iSelect) +local function waitCmd(iSelect) + local response = core.WaitForResponseTimeout(cmds.CMD_ACK,1000) + if response then + local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL',response) + + local iLen = arg0 + if iSelect then iLen = arg1 end + debug(("Received %i octets (arg0:%d, arg1:%d)"):format(iLen, arg0, arg1)) + if iLen == 0 then return nil, "No response from tag" end + local recv = string.sub(response,count, iLen+count-1) + return recv + end + return nil, "No response from device" +end + + local function show(data) if DEBUG then local formatString = ("H%d"):format(string.len(data)) @@ -156,23 +172,6 @@ local function getBlock(block) end ---- This function is a lua-implementation of --- cmdhf14a.c:waitCmd(uint8_t iSelect) -function waitCmd(iSelect) - local response = core.WaitForResponseTimeout(cmds.CMD_ACK,1000) - if response then - local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL',response) - - local iLen = arg0 - if iSelect then iLen = arg1 end - debug(("Received %i octets (arg0:%d, arg1:%d)"):format(iLen, arg0, arg1)) - if iLen == 0 then return nil, "No response from tag" end - local recv = string.sub(response,count, iLen+count-1) - return recv - end - return nil, "No response from device" -end - local function main( args) diff --git a/client/scripts/read_pwd_mem.lua b/client/scripts/read_pwd_mem.lua index fbe4d0459..a0688a639 100644 --- a/client/scripts/read_pwd_mem.lua +++ b/client/scripts/read_pwd_mem.lua @@ -1,23 +1,32 @@ local getopt = require('getopt') local bin = require('bin') +copyright = 'Copyright (c) 2018 Bogito. All rights reserved.' author = "Bogito" -version = 'v1.0.0' -desc =[[ +version = 'v1.0.1' +desc = +[[ This script will read the flash memory of RDV4 and print the stored passwords. It was meant to be used as a help tool after using the BogRun standalone mode. + +(Iceman) script adapted to read and print keys in the default dictionary flashmemory sections. ]] -usage = [[ +usage = +[[ Usage: - script run read_pwd_mem -h -o -l + script run read_pwd_mem -h -o -l -k Arguments: - -h : this help - -o : Memory offset. Default is 0. - -l : Length in bytes. Default is 256. + -h : this help + -o : memory offset, default is 0 + -l : length in bytes, default is 256 + -k : key length in bytes <4|6|8> , default is 4 + -m : print Mifare dictionary keys + -t : print t55xx dictionary passwords + -i : print iClass dictionary keys ]] -example =[[ -Examples: +example = +[[ -- This will scan the first 256 bytes of flash memory for stored passwords script run read_pwd_mem @@ -26,61 +35,107 @@ Examples: -- This will scan 32 bytes of flash memory at offset 64 for stored passwords script run read_pwd_mem -o 64 -l 32 + + -- This will print found + script run read_pwd_mem -o 241664 -k 6 ]] - +--- +-- This is only meant to be used when errors occur +local function oops(err) + print("ERROR: ", err) + return nil, err +end +--- -- Usage help local function help() + print(copyright) + print(version) print(desc) print(usage) + print('Example usage:') print(example) end - +--- +-- The main entry point local function main(args) - local data, err, quadlet, pwdcnt + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() + + local data, err, quadlet + local cnt = 0 local offset = 0 local length = 256 + local keylength = 4 + local usedkey = false - -- Read the parameters - for o, a in getopt.getopt(args, 'ho:l:') do + for o, a in getopt.getopt(args, 'ho:l:k:mti') do + + -- help if o == "h" then return help() end + + -- offset if o == "o" then offset = tonumber(a) end + + -- num of bytes to read if o == "l" then length = tonumber(a) end + + -- keylength + if o == "k" then keylength = tonumber(a); usedkey = true end + + if o == "m" then keylength =6; usedkey = true; offset = 0x3F000-0x4000; end + if o == "t" then keylength =4; usedkey = true; offset = 0x3F000-0x3000; end + if o == "i" then keylength =8; usedkey = true; offset = 0x3F000-0x5000; end end if length < 0 or length > 256 then - return print('Error: Length is not valid. Must be less than 256') + return oops('Error: Length is not valid. Must be less than 256') end - if ((offset < 0) or (offset % 4 ~= 0)) then - return print('Error: Offset is not valid. Mod-4 values are only allowed.') + if (offset < 0) or (offset % 4 ~= 0) then + return oops('Error: Offset is not valid. Mod-4 values are only allowed.') end - print('Offset: ' .. offset) - print('Length: ' .. length) - print() + print('Memory offset', offset) + print('Length ', length) + print('Key length ', keylength) + print( string.rep('--',20) ) - data, err = core.GetFromFlashMem(offset, length) + if usedkey then length = 4096 end + + data, err = core.GetFromFlashMem(offset, length) + if err then return oops(err) end - if err then - print(err) - return + if usedkey then + + _, keys, s = bin.unpack('SH'..length-2, data) + if keys == 0xFFFF then return "No keys found in section" end + + local kl = keylength * 2 + for i = 1, keys do + + key = string.sub(s, (i - 1) * kl + 1, i * kl ) + print(string.format("[%02d] %s",i, key)) + end + print( string.rep('--',20) ) + print( ('[+] found %d passwords'):format(keys)) + else + + _, s = bin.unpack('H'..length, data) + + local cnt = 0, i + for i = 1, (length/keylength) do + + key = string.sub(s, (i-1)*8+1, i*8) + if key == "FFFFFFFF" then break end + print(string.format("[%02d] %s",i, key)) + cnt = cnt + 1 + end + print( string.rep('--',20) ) + print( ('[+] found %d passwords'):format(cnt)) end - - local count, s = bin.unpack('H'..length, data) - - pwdcnt = 0 - for i = 1,(length/4),1 - do - quadlet = string.sub(s, (i-1)*8+1, i*8) - if quadlet == "FFFFFFFF" then break end - print(string.format("[%02d]",i) .. ' ' .. quadlet) - pwdcnt = pwdcnt + 1 - - end - print() - print('Found passwords: ' .. pwdcnt) - + print( string.rep('--',20) ) end main(args) diff --git a/client/scripts/remagic.lua b/client/scripts/remagic.lua index 5062d8cf4..10e25583a 100644 --- a/client/scripts/remagic.lua +++ b/client/scripts/remagic.lua @@ -72,6 +72,7 @@ local function sendCmds( cmds ) if cmds[i] then print ( cmds[i] ) core.console( cmds[i] ) + core.clearCommandBuffer() end end end diff --git a/client/scripts/tnp3clone.lua b/client/scripts/tnp3clone.lua index 2e1ee7019..b17cf2661 100644 --- a/client/scripts/tnp3clone.lua +++ b/client/scripts/tnp3clone.lua @@ -37,13 +37,12 @@ Arguments: 0020 - Swapforce ]] - -- This is only meant to be used when errors occur -function oops(err) +local function oops(err) print("ERROR: ",err) end -- Usage help -function help() +local function help() print(desc) print("Example usage") print(example) @@ -64,7 +63,7 @@ local function waitCmd() end local function readblock( blocknum, keyA ) - -- Read block 0 + -- Read block N cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blocknum, arg2 = 0, arg3 = 0, data = keyA} err = core.SendCommand(cmd:getBytes()) if err then return nil, err end @@ -72,8 +71,9 @@ local function readblock( blocknum, keyA ) if err then return nil, err end return block0 end + local function readmagicblock( blocknum ) - -- Read block 0 + -- Read block N local CSETBLOCK_SINGLE_OPERATION = 0x1F cmd = Command:new{cmd = cmds.CMD_MIFARE_CGETBLOCK, arg1 = CSETBLOCK_SINGLE_OPERATION, arg2 = 0, arg3 = blocknum} err = core.SendCommand(cmd:getBytes()) @@ -89,11 +89,13 @@ local function main(args) print( string.rep('--',20) ) local numBlocks = 64 - local cset = 'hf mf csetbl ' + local cset = 'hf mf csetbl ' local csetuid = 'hf mf csetuid ' local cget = 'hf mf cgetbl ' local empty = '00000000000000000000000000000000' - local AccAndKeyB = '7F078869000000000000' + local AccAndKeyB = '7F0F0869000000000000' + local atqa = '0F01' + local sak = '81' -- Defaults to Gusto local toytype = 'C201' local subtype = '0030' @@ -107,42 +109,43 @@ local function main(args) if o == "l" then return toys.List() end end - if #toytype ~= 4 then return oops('Wrong size - toytype. (4hex symbols)') end - if #subtype ~= 4 then return oops('Wrong size - subtype. (4hex symbols)') end + if #toytype ~= 4 then return oops('[!] Wrong size - toytype. (4hex symbols)') end + if #subtype ~= 4 then return oops('[!] Wrong size - subtype. (4hex symbols)') end -- look up type, find & validate types local item = toys.Find( toytype, subtype) if item then - print( (' Looking up input: Found %s - %s (%s)'):format(item[6],item[5], item[4]) ) + print( ('[+] Looking up input: Found %s - %s (%s)'):format(item[6],item[5], item[4]) ) else - print('Didn\'t find item type. If you are sure about it, report it in') + print('[-] Didn\'t find item type. If you are sure about it, post on forum') end --15,16 - --13-14 - + --13-14 -- find tag result, err = lib14a.read(false, true) - if not result then return oops(err) end + if not result then return oops(err) end -- load keys local akeys = pre.GetAll(result.uid) - local keyA = akeys:sub(1, 12 ) + local keyA = akeys:sub(1, 12 ) - local b0 = readblock(0,keyA) + local b0 = readblock(0, keyA) if not b0 then - print('failed reading block with factorydefault key. Trying chinese magic read.') + print('[-] failed reading block with factorydefault key. Trying chinese magic read.') b0, err = readmagicblock(0) if not b0 then - oops(err) - return oops('failed reading block with chinese magic command. quitting...') + oops('[!] '..err) + return oops('[!] failed reading block with chinese magic command. Quitting...') end end - - -- wipe card. - local cmd = (csetuid..'%s 0004 08 w'):format(result.uid) - core.console(cmd) + core.clearCommandBuffer() + -- wipe card. + local cmd = (csetuid..'%s %s %s w'):format(result.uid, atqa, sak) + core.console(cmd) + core.clearCommandBuffer() + local b1 = toytype..string.rep('00',10)..subtype local calc = utils.Crc16(b0..b1) @@ -150,6 +153,7 @@ local function main(args) local cmd = (cset..'1 %s%04x'):format( b1, calcEndian) core.console(cmd) + core.clearCommandBuffer() local pos, key for blockNo = 2, numBlocks-1, 1 do @@ -161,5 +165,10 @@ local function main(args) end end core.clearCommandBuffer() + + -- Set sector trailer S0, since it has different access rights + cmd = ('%s 3 %s0f0f0f69000000000000'):format(cset, keyA) + core.console(cmd) + core.clearCommandBuffer() end -main(args) \ No newline at end of file +main(args) diff --git a/client/tinycbor/cborparser_dup_string.c b/client/tinycbor/cborparser_dup_string.c index 061c5ac77..202cd2022 100644 --- a/client/tinycbor/cborparser_dup_string.c +++ b/client/tinycbor/cborparser_dup_string.c @@ -105,7 +105,7 @@ CborError _cbor_value_dup_string(const CborValue *value, void **buffer, size_t * return err; ++*buflen; - *buffer = malloc(*buflen); + *buffer = calloc(*buflen, sizeof(uint8_t)); if (!*buffer) { /* out of memory */ return CborErrorOutOfMemory; diff --git a/client/tinycbor/cbortojson.c b/client/tinycbor/cbortojson.c index 5a1a2e5dc..34b900bab 100644 --- a/client/tinycbor/cbortojson.c +++ b/client/tinycbor/cbortojson.c @@ -178,7 +178,7 @@ static CborError dump_bytestring_base16(char **result, CborValue *it) return err; /* a Base16 (hex) output is twice as big as our buffer */ - buffer = (uint8_t *)malloc(n * 2 + 1); + buffer = (uint8_t *)calloc(n * 2 + 1, sizeof(uint8_t)); *result = (char *)buffer; /* let cbor_value_copy_byte_string know we have an extra byte for the terminating NUL */ @@ -204,7 +204,7 @@ static CborError generic_dump_base64(char **result, CborValue *it, const char al /* a Base64 output (untruncated) has 4 bytes for every 3 in the input */ size_t len = (n + 5) / 3 * 4; - out = buffer = (uint8_t *)malloc(len + 1); + out = buffer = (uint8_t *)calloc(len + 1, sizeof(uint8_t)); *result = (char *)buffer; /* we read our byte string at the tail end of the buffer diff --git a/client/tinycbor/open_memstream.c b/client/tinycbor/open_memstream.c index 18f3de8b1..f618db8ae 100644 --- a/client/tinycbor/open_memstream.c +++ b/client/tinycbor/open_memstream.c @@ -90,7 +90,7 @@ static int close_buffer(void *cookie) FILE *open_memstream(char **bufptr, size_t *lenptr) { - struct Buffer *b = (struct Buffer *)malloc(sizeof(struct Buffer)); + struct Buffer *b = (struct Buffer *)calloc(sizeof(struct Buffer), sizeof(uint8_t)); if (b == NULL) return NULL; b->alloc = 0; diff --git a/client/ui.c b/client/ui.c index 3f7e2611f..71603fed6 100644 --- a/client/ui.c +++ b/client/ui.c @@ -41,17 +41,17 @@ void PrintAndLogOptions(char *str[][2], size_t size, size_t space) { if (i < size-1) strncat(buff, "\n", sizeof(buff)-strlen(buff) -1); } - PrintAndLogEx(NORMAL, buff); + PrintAndLogEx(NORMAL, "%s", buff); } void PrintAndLogEx(logLevel_t level, char *fmt, ...) { // skip debug messages if client debugging is turned off i.e. 'DATA SETDEBUG 0' if (g_debugMode == 0 && level == DEBUG) return; - + + char prefix[20] = {0}; char buffer[MAX_PRINT_BUFFER] = {0}; - char buffer2[MAX_PRINT_BUFFER] = {0}; - char prefix[20] = {0}; + char buffer2[MAX_PRINT_BUFFER+20] = {0}; char *token = NULL; int size = 0; // {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG} @@ -85,7 +85,7 @@ void PrintAndLogEx(logLevel_t level, char *fmt, ...) { // no prefixes for normal if ( level == NORMAL ) { - PrintAndLog(buffer); + PrintAndLog("%s", buffer); return; } @@ -110,10 +110,10 @@ void PrintAndLogEx(logLevel_t level, char *fmt, ...) { token = strtok(NULL, delim); } - PrintAndLog(buffer2); + PrintAndLog("%s", buffer2); } else { snprintf(buffer2, sizeof(buffer2), "%s%s", prefix, buffer); - PrintAndLog(buffer2); + PrintAndLog("%s", buffer2); } } @@ -196,7 +196,7 @@ void SetFlushAfterWrite(bool value) { int i,j; - int * output = (int* ) malloc(sizeof(int) * len); + int * output = (int* ) calloc(sizeof(int) * len, sizeof(uint8_t)); if ( !output ) return; // clear mem diff --git a/client/util.c b/client/util.c index 22490f62a..cea42f338 100644 --- a/client/util.c +++ b/client/util.c @@ -212,7 +212,7 @@ void print_hex_break(const uint8_t *data, const size_t len, uint8_t breaks) { } char *sprint_hex(const uint8_t *data, const size_t len) { - static char buf[UTIL_BUFFER_SIZE_SPRINT] = {0}; + static char buf[UTIL_BUFFER_SIZE_SPRINT - 3] = {0}; hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, 0, 1, true); return buf; } @@ -280,7 +280,7 @@ void sprint_bin_break_ex(uint8_t *src, size_t srclen, char *dest , uint8_t break printf("(sprint_bin_break) rowlen %d\n", rowlen); // 3072 + end of line characters if broken at 8 bits - dest = (char *)malloc(MAX_BIN_BREAK_LENGTH); + dest = (char *)calloc(MAX_BIN_BREAK_LENGTH, sizeof(uint8_t)); if (dest == NULL) return; //clear memory @@ -313,11 +313,11 @@ char *sprint_hex_ascii(const uint8_t *data, const size_t len) { memset(buf, 0x00, UTIL_BUFFER_SIZE_SPRINT); size_t max_len = (len > 1010) ? 1010 : len; - sprintf(tmp, "%s| ", sprint_hex(data, max_len) ); + snprintf(tmp, UTIL_BUFFER_SIZE_SPRINT, "%s| ", sprint_hex(data, max_len) ); size_t i = 0; - size_t pos = (max_len * 3)+2; - while(i < max_len){ + size_t pos = (max_len * 3) + 2; + while (i < max_len){ char c = data[i]; if ( (c < 32) || (c == 127)) c = '.'; @@ -884,8 +884,8 @@ extern void strcreplace(char *buf, size_t len, char from, char to) { } extern char *strmcopy(char *buf) { - char* str = NULL; - if ((str = (char*) malloc(strlen(buf) + 1)) != NULL) { + char* str = (char*) calloc(strlen(buf) + 1, sizeof(uint8_t)); + if (str != NULL) { memset(str, 0, strlen(buf) + 1); strcpy(str, buf); } diff --git a/client/util.h b/client/util.h index c9f13870d..e10f06497 100644 --- a/client/util.h +++ b/client/util.h @@ -178,6 +178,14 @@ } #endif +#ifndef DropFieldEx +#define DropFieldEx(x) { \ + if ( (x) == ECC_CONTACTLESS) { \ + DropField(); \ + } \ +} +#endif + extern uint8_t g_debugMode; extern int ukbhit(void); diff --git a/client/util_posix.c b/client/util_posix.c index 7704e9d4b..a45dc48e9 100644 --- a/client/util_posix.c +++ b/client/util_posix.c @@ -130,7 +130,7 @@ uint64_t msclock(void) { #else struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); - return (t.tv_sec * 1000 + t.tv_nsec / 1000000); + return ( 1000 * (uint64_t)t.tv_sec + t.tv_nsec / 1000000); #endif } diff --git a/common/crapto1/crapto1.c b/common/crapto1/crapto1.c index 8dc8f26c8..f0b37dbae 100644 --- a/common/crapto1/crapto1.c +++ b/common/crapto1/crapto1.c @@ -33,21 +33,6 @@ static void __attribute__((constructor)) fill_lut() #define filter(x) (filterlut[(x) & 0xfffff]) #endif -/** binsearch - * Binary search for the first occurence of *stop's MSB in sorted [start,stop] - */ -/* static inline uint32_t* binsearch(uint32_t *start, uint32_t *stop) -{ - uint32_t mid, val = *stop & 0xff000000; - while(start != stop) - if(start[mid = (stop - start) >> 1] > val) - stop = &start[mid]; - else - start += mid + 1; - - return start; -} - */ /** update_contribution * helper, calculates the partial linear feedback contributions and puts in MSB */ @@ -174,7 +159,7 @@ struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in) // allocate memory for out of place bucket_sort bucket_array_t bucket; - + for (uint32_t i = 0; i < 2; i++) { for (uint32_t j = 0; j <= 0xff; j++) { bucket[i][j].head = malloc(sizeof(uint32_t) << 14); @@ -311,7 +296,7 @@ uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) int out; uint8_t ret; uint32_t t; - + s->odd &= 0xffffff; t = s->odd, s->odd = s->even, s->even = t; @@ -329,12 +314,6 @@ uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) */ uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb) { - /* - int i, ret=0; - for (i = 7; i >= 0; --i) - ret |= lfsr_rollback_bit(s, BIT(in, i), fb) << i; -*/ -// unfold loop 20160112 uint8_t ret = 0; ret |= lfsr_rollback_bit(s, BIT(in, 7), fb) << 7; ret |= lfsr_rollback_bit(s, BIT(in, 6), fb) << 6; @@ -351,13 +330,7 @@ uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb) */ uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) { - /* - int i; - uint32_t ret = 0; - for (i = 31; i >= 0; --i) - ret |= lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); -*/ -// unfold loop 20160112 + uint32_t ret = 0; ret |= lfsr_rollback_bit(s, BEBIT(in, 31), fb) << (31 ^ 24); ret |= lfsr_rollback_bit(s, BEBIT(in, 30), fb) << (30 ^ 24); @@ -376,7 +349,7 @@ uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) ret |= lfsr_rollback_bit(s, BEBIT(in, 18), fb) << (18 ^ 24); ret |= lfsr_rollback_bit(s, BEBIT(in, 17), fb) << (17 ^ 24); ret |= lfsr_rollback_bit(s, BEBIT(in, 16), fb) << (16 ^ 24); - + ret |= lfsr_rollback_bit(s, BEBIT(in, 15), fb) << (15 ^ 24); ret |= lfsr_rollback_bit(s, BEBIT(in, 14), fb) << (14 ^ 24); ret |= lfsr_rollback_bit(s, BEBIT(in, 13), fb) << (13 ^ 24); @@ -385,7 +358,7 @@ uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) ret |= lfsr_rollback_bit(s, BEBIT(in, 10), fb) << (10 ^ 24); ret |= lfsr_rollback_bit(s, BEBIT(in, 9), fb) << (9 ^ 24); ret |= lfsr_rollback_bit(s, BEBIT(in, 8), fb) << (8 ^ 24); - + ret |= lfsr_rollback_bit(s, BEBIT(in, 7), fb) << (7 ^ 24); ret |= lfsr_rollback_bit(s, BEBIT(in, 6), fb) << (6 ^ 24); ret |= lfsr_rollback_bit(s, BEBIT(in, 5), fb) << (5 ^ 24); @@ -405,7 +378,7 @@ int nonce_distance(uint32_t from, uint32_t to) { uint16_t x, i; if(!dist) { - dist = malloc(2 << 16); + dist = calloc(2 << 16, sizeof(uint8_t)); if(!dist) return -1; for (x = i = 1; i; ++i) { @@ -443,9 +416,9 @@ static uint32_t fastfwd[2][8] = { */ uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd) { - uint32_t *candidates = malloc(4 << 10); + uint32_t *candidates = calloc(4 << 10, sizeof(uint8_t)); if (!candidates) return 0; - + uint32_t c, entry; int size = 0, i, good; @@ -458,7 +431,7 @@ uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd) if (good) candidates[size++] = i; } - + candidates[size] = -1; return candidates; diff --git a/common/crapto1/crypto1.c b/common/crapto1/crypto1.c index bc0e7337a..034d92215 100644 --- a/common/crapto1/crypto1.c +++ b/common/crapto1/crypto1.c @@ -48,9 +48,8 @@ struct Crypto1State * crypto1_create(uint64_t key) if ( !s ) return NULL; s->odd = s->even = 0; - + int i; - //for(i = 47;s && i > 0; i -= 2) { for(i = 47; i > 0; i -= 2) { s->odd = s->odd << 1 | BIT(key, (i - 1) ^ 7); s->even = s->even << 1 | BIT(key, i ^ 7); @@ -89,13 +88,6 @@ uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted) } uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted) { - /* - uint8_t i, ret = 0; - - for (i = 0; i < 8; ++i) - ret |= crypto1_bit(s, BIT(in, i), is_encrypted) << i; - */ -// unfold loop 20161012 uint8_t ret = 0; ret |= crypto1_bit(s, BIT(in, 0), is_encrypted) << 0; ret |= crypto1_bit(s, BIT(in, 1), is_encrypted) << 1; @@ -109,13 +101,6 @@ uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted) } uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted) { - /* - uint32_t i, ret = 0; - - for (i = 0; i < 32; ++i) - ret |= crypto1_bit(s, BEBIT(in, i), is_encrypted) << (i ^ 24); -*/ -//unfold loop 2016012 uint32_t ret = 0; ret |= crypto1_bit(s, BEBIT(in, 0), is_encrypted) << (0 ^ 24); ret |= crypto1_bit(s, BEBIT(in, 1), is_encrypted) << (1 ^ 24); @@ -125,7 +110,7 @@ uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted) ret |= crypto1_bit(s, BEBIT(in, 5), is_encrypted) << (5 ^ 24); ret |= crypto1_bit(s, BEBIT(in, 6), is_encrypted) << (6 ^ 24); ret |= crypto1_bit(s, BEBIT(in, 7), is_encrypted) << (7 ^ 24); - + ret |= crypto1_bit(s, BEBIT(in, 8), is_encrypted) << (8 ^ 24); ret |= crypto1_bit(s, BEBIT(in, 9), is_encrypted) << (9 ^ 24); ret |= crypto1_bit(s, BEBIT(in, 10), is_encrypted) << (10 ^ 24); diff --git a/common/crc.c b/common/crc.c index b710404cc..77bea0b47 100644 --- a/common/crc.c +++ b/common/crc.c @@ -99,14 +99,13 @@ uint32_t CRC8Maxim(uint8_t *buff, size_t size) { crc_update2(&crc, buff[i], 8); return crc_finish(&crc); } -// width=8 poly=0x1d, reversed poly=0x?? init=0xe3 refin=true refout=true xorout=0x0000 check=0xC6 name="CRC-8/MAD" -// the CRC needs to be reversed before returned. +// width=8 poly=0x1d, init=0xc7 (0xe3 - WRONG! but it mentioned in MAD datasheet) refin=false refout=false xorout=0x00 name="CRC-8/MIFARE-MAD" uint32_t CRC8Mad(uint8_t *buff, size_t size) { crc_t crc; - crc_init_ref(&crc, 8, 0x1d, 0xe3, 0, true, true); + crc_init_ref(&crc, 8, 0x1d, 0xc7, 0, false, false); for ( int i = 0; i < size; ++i) crc_update2(&crc, buff[i], 8); - return reflect8(crc_finish(&crc)); + return crc_finish(&crc); } // width=4 poly=0xC, reversed poly=0x7 init=0x5 refin=true refout=true xorout=0x0000 check= name="CRC-4/LEGIC" uint32_t CRC4Legic(uint8_t *cmd, size_t size) { diff --git a/common/i2c.c b/common/i2c.c index ea830a1bd..25b17b6bc 100644 --- a/common/i2c.c +++ b/common/i2c.c @@ -161,10 +161,11 @@ bool WaitSCL_L(void) { return WaitSCL_L_delay(15000); } -// Wait max 300ms or until SCL goes LOW. +// Wait max 1800ms or until SCL goes LOW. +// It timeout reading response from card // Which ever comes first -bool WaitSCL_L_300ms(void){ - volatile uint16_t delay = 310; +bool WaitSCL_L_timeout(void){ + volatile uint16_t delay = 1800; while ( delay-- ) { // exit on SCL LOW if (!SCL_read) @@ -193,7 +194,8 @@ bool I2C_Start(void) { bool I2C_WaitForSim() { - if (!WaitSCL_L_300ms()) + // wait for data from card + if (!WaitSCL_L_timeout()) return false; // 8051 speaks with smart card. @@ -575,7 +577,7 @@ void I2C_print_status(void) { I2C_Reset_EnterMainProgram(); uint8_t len = I2C_BufferRead(resp, sizeof(resp), I2C_DEVICE_CMD_GETVERSION, I2C_DEVICE_ADDRESS_MAIN); if ( len > 0 ) - Dbprintf(" version.................v%x.%02x", resp[0], resp[1]); + Dbprintf(" version.................v%x.%02d", resp[0], resp[1]); else DbpString(" version.................FAILED"); } diff --git a/common/iso15693tools.h b/common/iso15693tools.h index 053ca56ca..70382ce04 100644 --- a/common/iso15693tools.h +++ b/common/iso15693tools.h @@ -1,5 +1,11 @@ -// ISO15693 commons -// Adrian Dabrowski 2010 and others, GPLv2 +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// ISO15693 other commons +//----------------------------------------------------------------------------- +// Adrian Dabrowski 2010 and otherss // Christian Herrmann 2018 #ifndef ISO15693_H__ diff --git a/common/lfdemod.c b/common/lfdemod.c index 6b755d3dc..1ef5915c9 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -77,7 +77,7 @@ static void resetSignal(void) { signalprop.isnoise = true; } static void printSignal(void) { - prnt("LF Signal properties:"); + prnt("LF signal properties:"); prnt(" high..........%d", signalprop.high); prnt(" low...........%d", signalprop.low); prnt(" mean..........%d", signalprop.mean); @@ -1922,7 +1922,7 @@ int pskRawDemod_ext(uint8_t *dest, size_t *size, int *clock, int *invert, int *s dest[numBits++] = curPhase; } else if (waveLenCnt < fc - 1) { //wave is smaller than field clock (shouldn't happen often) errCnt2++; - if(errCnt2 > 101) return errCnt2; + if (errCnt2 > 101) return errCnt2; avgWaveVal += dest[i+1]; continue; } diff --git a/common/protocols.h b/common/protocols.h index 0f3ef3407..73355c85d 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -144,6 +144,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define ISO14443A_CMD_REQA 0x26 #define ISO14443A_CMD_READBLOCK 0x30 #define ISO14443A_CMD_WUPA 0x52 +#define ISO14443A_CMD_OPTS 0x35 #define ISO14443A_CMD_ANTICOLL_OR_SELECT 0x93 #define ISO14443A_CMD_ANTICOLL_OR_SELECT_2 0x95 #define ISO14443A_CMD_ANTICOLL_OR_SELECT_3 0x97 @@ -301,60 +302,60 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define ISO7816_VERIFY 0x20 #define ISO7816_INTERNAL_AUTHENTICATION 0x88 #define ISO7816_EXTERNAL_AUTHENTICATION 0x82 -#define ISO7816_GET_CHALLENGE 0xB4 +#define ISO7816_GET_CHALLENGE 0x84 #define ISO7816_MANAGE_CHANNEL 0x70 -#define ISO7816_GETSTATUS 0xC0 +#define ISO7816_GET_RESPONSE 0xC0 // ISO7816-4 For response APDU's #define ISO7816_OK 0x9000 // 6x xx = ERROR // MIFARE DESFire command set: -#define MFDES_CREATE_APPLICATION 0xca -#define MFDES_DELETE_APPLICATION 0xda -#define MFDES_GET_APPLICATION_IDS 0x6a -#define MFDES_SELECT_APPLICATION 0x5a -#define MFDES_FORMAT_PICC 0xfc -#define MFDES_GET_VERSION 0x60 -#define MFDES_READ_DATA 0xbd -#define MFDES_WRITE_DATA 0x3d -#define MFDES_GET_VALUE 0x6c -#define MFDES_CREDIT 0x0c -#define MFDES_DEBIT 0xdc -#define MFDES_LIMITED_CREDIT 0x1c -#define MFDES_WRITE_RECORD 0x3b -#define MFDES_READ_RECORDS 0xbb -#define MFDES_CLEAR_RECORD_FILE 0xeb -#define MFDES_COMMIT_TRANSACTION 0xc7 -#define MFDES_ABORT_TRANSACTION 0xa7 -#define MFDES_GET_FREE_MEMORY 0x6e -#define MFDES_GET_FILE_IDS 0x6f -#define MFDES_GET_ISOFILE_IDS 0x61 -#define MFDES_GET_FILE_SETTINGS 0xf5 -#define MFDES_CHANGE_FILE_SETTINGS 0x5f -#define MFDES_CREATE_STD_DATA_FILE 0xcd -#define MFDES_CREATE_BACKUP_DATA_FILE 0xcb -#define MFDES_CREATE_VALUE_FILE 0xcc -#define MFDES_CREATE_LINEAR_RECORD_FILE 0xc1 -#define MFDES_CREATE_CYCLIC_RECORD_FILE 0xc0 -#define MFDES_DELETE_FILE 0xdf -#define MFDES_AUTHENTICATE 0x0a // AUTHENTICATE_NATIVE -#define MFDES_AUTHENTICATE_ISO 0x1a // AUTHENTICATE_STANDARD -#define MFDES_AUTHENTICATE_AES 0xaa -#define MFDES_CHANGE_KEY_SETTINGS 0x54 -#define MFDES_GET_KEY_SETTINGS 0x45 -#define MFDES_CHANGE_KEY 0xc4 -#define MFDES_GET_KEY_VERSION 0x64 -#define MFDES_AUTHENTICATION_FRAME 0xAF +#define MFDES_CREATE_APPLICATION 0xca +#define MFDES_DELETE_APPLICATION 0xda +#define MFDES_GET_APPLICATION_IDS 0x6a +#define MFDES_SELECT_APPLICATION 0x5a +#define MFDES_FORMAT_PICC 0xfc +#define MFDES_GET_VERSION 0x60 +#define MFDES_READ_DATA 0xbd +#define MFDES_WRITE_DATA 0x3d +#define MFDES_GET_VALUE 0x6c +#define MFDES_CREDIT 0x0c +#define MFDES_DEBIT 0xdc +#define MFDES_LIMITED_CREDIT 0x1c +#define MFDES_WRITE_RECORD 0x3b +#define MFDES_READ_RECORDS 0xbb +#define MFDES_CLEAR_RECORD_FILE 0xeb +#define MFDES_COMMIT_TRANSACTION 0xc7 +#define MFDES_ABORT_TRANSACTION 0xa7 +#define MFDES_GET_FREE_MEMORY 0x6e +#define MFDES_GET_FILE_IDS 0x6f +#define MFDES_GET_ISOFILE_IDS 0x61 +#define MFDES_GET_FILE_SETTINGS 0xf5 +#define MFDES_CHANGE_FILE_SETTINGS 0x5f +#define MFDES_CREATE_STD_DATA_FILE 0xcd +#define MFDES_CREATE_BACKUP_DATA_FILE 0xcb +#define MFDES_CREATE_VALUE_FILE 0xcc +#define MFDES_CREATE_LINEAR_RECORD_FILE 0xc1 +#define MFDES_CREATE_CYCLIC_RECORD_FILE 0xc0 +#define MFDES_DELETE_FILE 0xdf +#define MFDES_AUTHENTICATE 0x0a // AUTHENTICATE_NATIVE +#define MFDES_AUTHENTICATE_ISO 0x1a // AUTHENTICATE_STANDARD +#define MFDES_AUTHENTICATE_AES 0xaa +#define MFDES_CHANGE_KEY_SETTINGS 0x54 +#define MFDES_GET_KEY_SETTINGS 0x45 +#define MFDES_CHANGE_KEY 0xc4 +#define MFDES_GET_KEY_VERSION 0x64 +#define MFDES_AUTHENTICATION_FRAME 0xAF // LEGIC Commands -#define LEGIC_MIM_22 0x0D -#define LEGIC_MIM_256 0x1D -#define LEGIC_MIM_1024 0x3D -#define LEGIC_ACK_22 0x19 -#define LEGIC_ACK_256 0x39 -#define LEGIC_READ 0x01 -#define LEGIC_WRITE 0x00 +#define LEGIC_MIM_22 0x0D +#define LEGIC_MIM_256 0x1D +#define LEGIC_MIM_1024 0x3D +#define LEGIC_ACK_22 0x19 +#define LEGIC_ACK_256 0x39 +#define LEGIC_READ 0x01 +#define LEGIC_WRITE 0x00 void printIclassDumpInfo(uint8_t* iclass_dump); void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *max_blk, uint8_t *app_areas, uint8_t *kb); @@ -379,7 +380,7 @@ void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *max_blk, uint8_t * #define T55x7_MODULATION_MANCHESTER 0x00008000 #define T55x7_MODULATION_BIPHASE 0x00010000 #define T55x7_MODULATION_DIPHASE 0x00018000 -#define T55x7_X_MODE 0x00020000 +#define T55x7_X_MODE 0x00020000 #define T55x7_BITRATE_RF_8 0 #define T55x7_BITRATE_RF_16 0x00040000 #define T55x7_BITRATE_RF_32 0x00080000 @@ -388,6 +389,7 @@ void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *max_blk, uint8_t * #define T55x7_BITRATE_RF_64 0x00140000 #define T55x7_BITRATE_RF_100 0x00180000 #define T55x7_BITRATE_RF_128 0x001C0000 +#define T55x7_TESTMODE_DISABLED 0x60000000 /* T5555 (Q5) configuration register definitions */ #define T5555_ST_TERMINATOR 0x00000001 @@ -406,9 +408,9 @@ void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *max_blk, uint8_t * #define T5555_PSK_RF_8 0x00000200 #define T5555_USE_PWD 0x00000400 #define T5555_USE_AOR 0x00000800 -#define T5555_SET_BITRATE(x) (((x-2)/2)<<12) -#define T5555_GET_BITRATE(x) ((((x >> 12) & 0x3F)*2)+2) -#define T5555_BITRATE_SHIFT 12 //(RF=2n+2) ie 64=2*0x1F+2 or n = (RF-2)/2 +#define T5555_SET_BITRATE(x) (((x-2)/2)<<12) +#define T5555_GET_BITRATE(x) ((((x >> 12) & 0x3F)*2)+2) +#define T5555_BITRATE_SHIFT 12 //(RF=2n+2) ie 64=2*0x1F+2 or n = (RF-2)/2 #define T5555_FAST_WRITE 0x00004000 #define T5555_PAGE_SELECT 0x00008000 @@ -446,58 +448,61 @@ uint32_t GetT55xxClockBit(uint32_t clock); // FeliCa protocol -#define FELICA_POLL_REQ 0x00 -#define FELICA_POLL_ACK 0x01 +#define FELICA_POLL_REQ 0x00 +#define FELICA_POLL_ACK 0x01 -#define FELICA_REQSRV_REQ 0x02 -#define FELICA_REQSRV_ACK 0x03 +#define FELICA_REQSRV_REQ 0x02 +#define FELICA_REQSRV_ACK 0x03 -#define FELICA_RDBLK_REQ 0x06 -#define FELICA_RDBLK_ACK 0x07 +#define FELICA_REQRESP_REQ 0x04 +#define FELICA_REQRESP_ACK 0x05 -#define FELICA_WRTBLK_REQ 0x08 -#define FELICA_WRTBLK_ACK 0x09 +#define FELICA_RDBLK_REQ 0x06 +#define FELICA_RDBLK_ACK 0x07 -#define FELICA_SRCHSYSCODE_REQ 0x0a -#define FELICA_SRCHSYSCODE_ACK 0x0b +#define FELICA_WRTBLK_REQ 0x08 +#define FELICA_WRTBLK_ACK 0x09 -#define FELICA_REQSYSCODE_REQ 0x0c -#define FELICA_REQSYSCODE_ACK 0x0d +#define FELICA_SRCHSYSCODE_REQ 0x0a +#define FELICA_SRCHSYSCODE_ACK 0x0b -#define FELICA_AUTH1_REQ 0x10 -#define FELICA_AUTH1_ACK 0x11 +#define FELICA_REQSYSCODE_REQ 0x0c +#define FELICA_REQSYSCODE_ACK 0x0d -#define FELICA_AUTH2_REQ 0x12 -#define FELICA_AUTH2_ACK 0x13 +#define FELICA_AUTH1_REQ 0x10 +#define FELICA_AUTH1_ACK 0x11 -#define FELICA_RDSEC_REQ 0x14 -#define FELICA_RDSEC_ACK 0x15 +#define FELICA_AUTH2_REQ 0x12 +#define FELICA_AUTH2_ACK 0x13 -#define FELICA_WRTSEC_REQ 0x16 -#define FELICA_WRTSEC_ACK 0x17 +#define FELICA_RDSEC_REQ 0x14 +#define FELICA_RDSEC_ACK 0x15 -#define FELICA_REQSRV2_REQ 0x32 -#define FELICA_REQSRV2_ACK 0x33 +#define FELICA_WRTSEC_REQ 0x16 +#define FELICA_WRTSEC_ACK 0x17 -#define FELICA_GETSTATUS_REQ 0x38 -#define FELICA_GETSTATUS_ACK 0x39 +#define FELICA_REQSRV2_REQ 0x32 +#define FELICA_REQSRV2_ACK 0x33 -#define FELICA_OSVER_REQ 0x3c -#define FELICA_OSVER_ACK 0x3d +#define FELICA_GETSTATUS_REQ 0x38 +#define FELICA_GETSTATUS_ACK 0x39 -#define FELICA_RESET_MODE_REQ 0x3e -#define FELICA_RESET_MODE_ACK 0x3f +#define FELICA_OSVER_REQ 0x3c +#define FELICA_OSVER_ACK 0x3d -#define FELICA_AUTH1V2_REQ 0x40 -#define FELICA_AUTH1V2_ACK 0x41 +#define FELICA_RESET_MODE_REQ 0x3e +#define FELICA_RESET_MODE_ACK 0x3f -#define FELICA_AUTH2V2_REQ 0x42 -#define FELICA_AUTH2V2_ACK 0x43 +#define FELICA_AUTH1V2_REQ 0x40 +#define FELICA_AUTH1V2_ACK 0x41 -#define FELICA_RDSECV2_REQ 0x44 -#define FELICA_RDSECV2_ACK 0x45 -#define FELICA_WRTSECV2_REQ 0x46 -#define FELICA_WRTSECV2_ACK 0x47 +#define FELICA_AUTH2V2_REQ 0x42 +#define FELICA_AUTH2V2_ACK 0x43 + +#define FELICA_RDSECV2_REQ 0x44 +#define FELICA_RDSECV2_ACK 0x45 +#define FELICA_WRTSECV2_REQ 0x46 +#define FELICA_WRTSECV2_ACK 0x47 #define FELICA_UPDATE_RNDID_REQ 0x4C #define FELICA_UPDATE_RNDID_ACK 0x4D diff --git a/common/radixsort.c b/common/radixsort.c index 91495316c..981c19191 100644 --- a/common/radixsort.c +++ b/common/radixsort.c @@ -3,7 +3,7 @@ uint64_t * radixSort(uint64_t * array, uint32_t size) { rscounts_t counts; memset(&counts, 0, 256 * 8 * sizeof(uint32_t)); - uint64_t * cpy = (uint64_t *)malloc(size * sizeof(uint64_t)); + uint64_t * cpy = (uint64_t *)calloc(size * sizeof(uint64_t), sizeof(uint8_t)); uint32_t o8=0, o7=0, o6=0, o5=0, o4=0, o3=0, o2=0, o1=0; uint32_t t8, t7, t6, t5, t4, t3, t2, t1; uint32_t x; diff --git a/include/common.h b/include/common.h index 90394448c..d3da792aa 100644 --- a/include/common.h +++ b/include/common.h @@ -90,13 +90,17 @@ extern uint32_t FLASHMEM_SPIBAUDRATE; #ifndef T55XX_CONFIG_OFFSET # define T55XX_CONFIG_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x2000) #endif - - #ifndef DEFAULT_MF_KEYS_OFFSET - # define DEFAULT_MF_KEYS_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x3000) + + #ifndef DEFAULT_T55XX_KEYS_OFFSET + # define DEFAULT_T55XX_KEYS_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x3000) #endif - #ifndef DEFAULT_LF_KEYS_OFFSET - # define DEFAULT_LF_KEYS_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x4000) + #ifndef DEFAULT_MF_KEYS_OFFSET + # define DEFAULT_MF_KEYS_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x4000) + #endif + + #ifndef DEFAULT_ICLASS_KEYS_OFFSET + # define DEFAULT_ICLASS_KEYS_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x5000) #endif #endif diff --git a/include/mifare.h b/include/mifare.h index cda7cfe9d..90077f60d 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -13,6 +13,12 @@ #include "common.h" +#define MF_KEY_A 0 +#define MF_KEY_B 1 + +#define MF_MAD1_SECTOR 0x00 +#define MF_MAD2_SECTOR 0x10 + //----------------------------------------------------------------------------- // ISO 14443A //----------------------------------------------------------------------------- @@ -35,7 +41,8 @@ typedef enum ISO14A_COMMAND { ISO14A_SET_TIMEOUT = (1 << 6), ISO14A_NO_SELECT = (1 << 7), ISO14A_TOPAZMODE = (1 << 8), - ISO14A_NO_RATS = (1 << 9) + ISO14A_NO_RATS = (1 << 9), + ISO14A_SEND_CHAINING = (1 << 10) } iso14a_command_t; typedef struct { diff --git a/include/usb_cmd.h b/include/usb_cmd.h index d6b240fb6..a54b27e0f 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -140,6 +140,8 @@ typedef struct{ #define CMD_COTAG 0x0225 #define CMD_SET_LF_T55XX_CONFIG 0x0226 +#define CMD_T55XX_CHKPWDS 0x0230 + /* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ // For the 13.56 MHz tags @@ -300,11 +302,12 @@ typedef struct{ #define FLAG_ICLASS_READER_CEDITKEY 0x40 // Dbprintf flags -#define FLAG_RAWPRINT 0x0111 -#define FLAG_NOOPT 0x0000 -#define FLAG_NOLOG 0x0001 -#define FLAG_NONEWLINE 0x0010 -#define FLAG_NOPROMPT 0x0100 +#define FLAG_RAWPRINT 0x0111 +#define FLAG_NOOPT 0x0000 +#define FLAG_NOLOG 0x0001 +#define FLAG_NONEWLINE 0x0010 +#define FLAG_NOPROMPT 0x0100 + // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions: /* Whether a bootloader that understands the common_area is present */ diff --git a/tools/Makefile b/tools/Makefile index 0a6e4430e..b72503158 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -8,4 +8,12 @@ get_crapto1: get_nonce_bf: # git clone https://github.com/J-Run/mf_key_brute.git mf_key_brute - git clone https://github.com/iceman1001/mf_nonce_brute mf_nonce_brute \ No newline at end of file + git clone https://github.com/iceman1001/mf_nonce_brute mf_nonce_brute + +get_xorsearch: + mkdir xorsearch + wget -N https://didierstevens.com/files/software/XORSearch_V1_11_2.zip +# Mingw +# unzzip-big XORSearch_V1_11_2.zip +# linux +# gunzip XORSearch_V1_11_2.zip \ No newline at end of file diff --git a/tools/mkversion.pl b/tools/mkversion.pl index 1acca6efa..674c44177 100644 --- a/tools/mkversion.pl +++ b/tools/mkversion.pl @@ -28,7 +28,7 @@ my $clean = 2; # fatal: No names found, cannot describe anything. ## # anyway forcing any kind of shell is at least useless, at worst fatal. -my $commandGIT = "env -S which git"; +my $commandGIT = "env which git"; if ( defined($commandGIT) ) { diff --git a/tools/simmodule/SIM010.BIN b/tools/simmodule/SIM010.BIN new file mode 100644 index 000000000..dea57a7d8 Binary files /dev/null and b/tools/simmodule/SIM010.BIN differ diff --git a/tools/simmodule/SIM010.md5.txt b/tools/simmodule/SIM010.md5.txt new file mode 100644 index 000000000..c790101f7 --- /dev/null +++ b/tools/simmodule/SIM010.md5.txt @@ -0,0 +1 @@ +136e157364609e5c395540dc8dadbfd6 *SIM010.BIN diff --git a/tools/simmodule/SIM010.sha512.txt b/tools/simmodule/SIM010.sha512.txt new file mode 100644 index 000000000..b7bab7246 --- /dev/null +++ b/tools/simmodule/SIM010.sha512.txt @@ -0,0 +1 @@ +e6ac5e6f1d7cc86d56f2128f2a495f1395fe044bf6ff3b6ca24ce90d1e361ae835fe273a206f2fc90e4344a13b37b180dd017a2c7f23312f1ed163f10c01ea5a *SIM010.BIN diff --git a/tools/simmodule/readme.txt b/tools/simmodule/readme.txt new file mode 100644 index 000000000..7efa40205 --- /dev/null +++ b/tools/simmodule/readme.txt @@ -0,0 +1,36 @@ + +2018-12-20 Iceman + +======================================= + +The latest firmware for the SIM MODULE is : SIM010.bin + + +You can use it to upgrade you sim module via the pm3 client. + + +pm3 --> sc upgrade -h +pm3 --> sc upgrade f ../tools/simmodule/SIM010.bin + + + +Even its a quite fast command you should be warned. You may brick it if you interrupt it. + + + +Run hw status command to verify that the upgrade went well. + +pm3 --> hw status + + + +If you didn't download this file from the RRG Repo be aware that it might be corrupt or faulty. + +You find to hash text files in this folder. They were generated with the following linux commands. + + +md5sum -b SIM010.bin > SIM010.md5.txt +sha512sum -b SIM010.bin > SIM010.sha512.txt + + +You should validate the SIM010.bin file against these hash files in order to be sure the file is not corrupt or faulty. \ No newline at end of file diff --git a/uart/uart_posix.c b/uart/uart_posix.c index d857729d6..c3ff7dcca 100644 --- a/uart/uart_posix.c +++ b/uart/uart_posix.c @@ -62,346 +62,363 @@ typedef struct termios term_info; typedef struct { - int fd; // Serial port file descriptor - term_info tiOld; // Terminal info before using the port - term_info tiNew; // Terminal info during the transaction + int fd; // Serial port file descriptor + term_info tiOld; // Terminal info before using the port + term_info tiNew; // Terminal info during the transaction } serial_port_unix; // Set time-out on 30 miliseconds -const struct timeval timeout = { - .tv_sec = 0, // 0 second - .tv_usec = 300000 // 300 000 micro seconds +struct timeval timeout = { + .tv_sec = 0, // 0 second + .tv_usec = 30000 // 30 000 micro seconds }; -serial_port uart_open(const char* pcPortName) -{ - serial_port_unix* sp = malloc(sizeof(serial_port_unix)); - if (sp == 0) return INVALID_SERIAL_PORT; +serial_port uart_open(const char* pcPortName) { + serial_port_unix* sp = calloc(sizeof(serial_port_unix), sizeof(uint8_t)); + if (sp == 0) return INVALID_SERIAL_PORT; - if (memcmp(pcPortName, "tcp:", 4) == 0) { - struct addrinfo *addr, *rp; - char *addrstr = strdup(pcPortName + 4); + if (memcmp(pcPortName, "tcp:", 4) == 0) { + struct addrinfo *addr, *rp; + char *addrstr = strdup(pcPortName + 4); - if (addrstr == NULL) { - printf("Error: strdup\n"); - return INVALID_SERIAL_PORT; - } + if (addrstr == NULL) { + printf("Error: strdup\n"); + free(sp); + return INVALID_SERIAL_PORT; + } - char *colon = strrchr(addrstr, ':'); - char *portstr; - if (colon) { - portstr = colon + 1; - *colon = '\0'; - } else { - portstr = "7901"; + timeout.tv_usec = 300000; // 300 000 micro seconds + + char *colon = strrchr(addrstr, ':'); + char *portstr; + if (colon) { + portstr = colon + 1; + *colon = '\0'; + } else { + portstr = "7901"; + } + + int s = getaddrinfo(addrstr, portstr, NULL, &addr); + if (s != 0) { + printf("Error: getaddrinfo: %s\n", gai_strerror(s)); + freeaddrinfo(addr); + free(addrstr); + free(sp); + return INVALID_SERIAL_PORT; + } + + int sfd; + for (rp = addr; rp != NULL; rp = rp->ai_next) { + sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + + if (sfd == -1) + continue; + + if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) + break; + + close(sfd); + } + + if (rp == NULL) { /* No address succeeded */ + printf("Error: Could not connect\n"); + freeaddrinfo(addr); + free(addrstr); + free(sp); + return INVALID_SERIAL_PORT; + } + + freeaddrinfo(addr); + free(addrstr); + + sp->fd = sfd; + + int one = 1; + int res = setsockopt(sp->fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)); + if ( res != 0) { + free(sp); + return INVALID_SERIAL_PORT; + } + return sp; } - - int s = getaddrinfo(addrstr, portstr, NULL, &addr); - if (s != 0) { - printf("Error: getaddrinfo: %s\n", gai_strerror(s)); - return INVALID_SERIAL_PORT; - } - - int sfd; - for (rp = addr; rp != NULL; rp = rp->ai_next) { - sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - - if (sfd == -1) - continue; - - if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) - break; - - close(sfd); - } - - if (rp == NULL) { /* No address succeeded */ - printf("Error: Could not connect\n"); - return INVALID_SERIAL_PORT; - } - - freeaddrinfo(addr); - free(addrstr); - - sp->fd = sfd; - - int one = 1; - setsockopt(sp->fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)); - return sp; - } - sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); - if(sp->fd == -1) { - uart_close(sp); - return INVALID_SERIAL_PORT; - } + sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); + if (sp->fd == -1) { + uart_close(sp); + return INVALID_SERIAL_PORT; + } - // Finally figured out a way to claim a serial port interface under unix - // We just try to set a (advisory) lock on the file descriptor - struct flock fl; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 0; - fl.l_pid = getpid(); - - // Does the system allows us to place a lock on this file descriptor - if (fcntl(sp->fd, F_SETLK, &fl) == -1) { - // A conflicting lock is held by another process - free(sp); - return CLAIMED_SERIAL_PORT; - } + // Finally figured out a way to claim a serial port interface under unix + // We just try to set a (advisory) lock on the file descriptor + struct flock fl; + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_pid = getpid(); + + // Does the system allows us to place a lock on this file descriptor + if (fcntl(sp->fd, F_SETLK, &fl) == -1) { + // A conflicting lock is held by another process + free(sp); + return CLAIMED_SERIAL_PORT; + } + + // Try to retrieve the old (current) terminal info struct + if (tcgetattr(sp->fd,&sp->tiOld) == -1) { + uart_close(sp); + return INVALID_SERIAL_PORT; + } + + // Duplicate the (old) terminal info struct + sp->tiNew = sp->tiOld; + + // Configure the serial port + sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD; + sp->tiNew.c_iflag = IGNPAR; + sp->tiNew.c_oflag = 0; + sp->tiNew.c_lflag = 0; + + // Block until n bytes are received + sp->tiNew.c_cc[VMIN] = 0; + // Block until a timer expires (n * 100 mSec.) + sp->tiNew.c_cc[VTIME] = 0; + + // Try to set the new terminal info struct + if (tcsetattr(sp->fd, TCSANOW, &sp->tiNew) == -1) { + uart_close(sp); + return INVALID_SERIAL_PORT; + } - // Try to retrieve the old (current) terminal info struct - if(tcgetattr(sp->fd,&sp->tiOld) == -1) { - uart_close(sp); - return INVALID_SERIAL_PORT; - } - - // Duplicate the (old) terminal info struct - sp->tiNew = sp->tiOld; - - // Configure the serial port - sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD; - sp->tiNew.c_iflag = IGNPAR; - sp->tiNew.c_oflag = 0; - sp->tiNew.c_lflag = 0; - - // Block until n bytes are received - sp->tiNew.c_cc[VMIN] = 0; - // Block until a timer expires (n * 100 mSec.) - sp->tiNew.c_cc[VTIME] = 0; - - // Try to set the new terminal info struct - if(tcsetattr(sp->fd, TCSANOW, &sp->tiNew) == -1) { - uart_close(sp); - return INVALID_SERIAL_PORT; - } - // Flush all lingering data that may exist tcflush(sp->fd, TCIOFLUSH); #ifdef WITH_FPC if ( uart_set_speed(sp, 115200) ) { - printf("[=] UART Setting serial baudrate 115200 [FPC enabled]\n"); + printf("[=] UART Setting serial baudrate 115200 [FPC enabled]\n"); } else { uart_set_speed(sp, 9600); printf("[=] UART Setting serial baudrate 9600 [FPC enabled]\n"); } #else - // set speed, works for UBUNTU 14.04 - bool success = uart_set_speed(sp, 460800); - if (success) { - printf("[=] UART Setting serial baudrate 460800\n"); - } else { - uart_set_speed(sp, 115200); - printf("[=] UART Setting serial baudrate 115200\n"); - } + // set speed, works for UBUNTU 14.04 + bool success = uart_set_speed(sp, 460800); + if (success) { + printf("[=] UART Setting serial baudrate 460800\n"); + } else { + uart_set_speed(sp, 115200); + printf("[=] UART Setting serial baudrate 115200\n"); + } #endif - return sp; + return sp; } void uart_close(const serial_port sp) { - serial_port_unix* spu = (serial_port_unix*)sp; - tcflush(spu->fd, TCIOFLUSH); - tcsetattr(spu->fd, TCSANOW, &(spu->tiOld)); - struct flock fl; - fl.l_type = F_UNLCK; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 0; - fl.l_pid = getpid(); + serial_port_unix* spu = (serial_port_unix*)sp; + tcflush(spu->fd, TCIOFLUSH); + tcsetattr(spu->fd, TCSANOW, &(spu->tiOld)); + struct flock fl; + fl.l_type = F_UNLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_pid = getpid(); - // Does the system allows us to place a lock on this file descriptor - int err = fcntl(spu->fd, F_SETLK, &fl); - if ( err == -1) { - //perror("fcntl"); - } - close(spu->fd); - free(sp); + // Does the system allows us to place a lock on this file descriptor + int err = fcntl(spu->fd, F_SETLK, &fl); + if ( err == -1) { + //perror("fcntl"); + } + close(spu->fd); + free(sp); } bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen) { - int res; - int byteCount; - fd_set rfds; - struct timeval tv; + int res; + int byteCount; + fd_set rfds; + struct timeval tv; + + // Reset the output count + *pszRxLen = 0; - // Reset the output count - *pszRxLen = 0; - - do { - // Reset file descriptor - FD_ZERO(&rfds); - FD_SET(((serial_port_unix*)sp)->fd, &rfds); - tv = timeout; - res = select(((serial_port_unix*)sp)->fd + 1, &rfds, NULL, NULL, &tv); - - // Read error - if (res < 0) { - return false; - } - - // Read time-out - if (res == 0) { - if (*pszRxLen == 0) { - // Error, we received no data - return false; - } else { - // We received some data, but nothing more is available - return true; - } - } - - // Retrieve the count of the incoming bytes - res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount); - if (res < 0) return false; - - // Cap the number of bytes, so we don't overrun the buffer - if (pszMaxRxLen - (*pszRxLen) < byteCount) { - byteCount = pszMaxRxLen - (*pszRxLen); - } + do { + // Reset file descriptor + FD_ZERO(&rfds); + FD_SET(((serial_port_unix*)sp)->fd, &rfds); + tv = timeout; + res = select(((serial_port_unix*)sp)->fd + 1, &rfds, NULL, NULL, &tv); - // There is something available, read the data - res = read(((serial_port_unix*)sp)->fd, pbtRx + (*pszRxLen), byteCount); + // Read error + if (res < 0) { + return false; + } - // Stop if the OS has some troubles reading the data - if (res <= 0) return false; - - *pszRxLen += res; + // Read time-out + if (res == 0) { + if (*pszRxLen == 0) { + // Error, we received no data + return false; + } else { + // We received some data, but nothing more is available + return true; + } + } - if (*pszRxLen == pszMaxRxLen) { - // We have all the data we wanted. - return true; - } - - } while (byteCount); + // Retrieve the count of the incoming bytes + res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount); + if (res < 0) return false; - return true; + // Cap the number of bytes, so we don't overrun the buffer + if (pszMaxRxLen - (*pszRxLen) < byteCount) { + byteCount = pszMaxRxLen - (*pszRxLen); + } + + // There is something available, read the data + res = read(((serial_port_unix*)sp)->fd, pbtRx + (*pszRxLen), byteCount); + + // Stop if the OS has some troubles reading the data + if (res <= 0) return false; + + *pszRxLen += res; + + if (*pszRxLen == pszMaxRxLen) { + // We have all the data we wanted. + return true; + } + + } while (byteCount); + + return true; } bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t len) { - int32_t res; - size_t pos = 0; - fd_set rfds; - struct timeval tv; + int32_t res; + size_t pos = 0; + fd_set rfds; + struct timeval tv; - while (pos < len) { - // Reset file descriptor - FD_ZERO(&rfds); - FD_SET(((serial_port_unix*)sp)->fd, &rfds); - tv = timeout; - res = select(((serial_port_unix*)sp)->fd+1, NULL, &rfds, NULL, &tv); - - // Write error - if (res < 0) { - printf("UART:: write error (%d)\n", res); - return false; - } - - // Write time-out - if (res == 0) { - printf("UART:: write time-out\n"); - return false; - } - - // Send away the bytes - res = write(((serial_port_unix*)sp)->fd, pbtTx + pos, len - pos); - - // Stop if the OS has some troubles sending the data - if (res <= 0) return false; - - pos += res; - } - return true; + while (pos < len) { + // Reset file descriptor + FD_ZERO(&rfds); + FD_SET(((serial_port_unix*)sp)->fd, &rfds); + tv = timeout; + res = select(((serial_port_unix*)sp)->fd+1, NULL, &rfds, NULL, &tv); + + // Write error + if (res < 0) { + printf("UART:: write error (%d)\n", res); + return false; + } + + // Write time-out + if (res == 0) { + printf("UART:: write time-out\n"); + return false; + } + + // Send away the bytes + res = write(((serial_port_unix*)sp)->fd, pbtTx + pos, len - pos); + + // Stop if the OS has some troubles sending the data + if (res <= 0) return false; + + pos += res; + } + return true; } bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) { - const serial_port_unix* spu = (serial_port_unix*)sp; - speed_t stPortSpeed; - switch (uiPortSpeed) { - case 0: stPortSpeed = B0; break; - case 50: stPortSpeed = B50; break; - case 75: stPortSpeed = B75; break; - case 110: stPortSpeed = B110; break; - case 134: stPortSpeed = B134; break; - case 150: stPortSpeed = B150; break; - case 300: stPortSpeed = B300; break; - case 600: stPortSpeed = B600; break; - case 1200: stPortSpeed = B1200; break; - case 1800: stPortSpeed = B1800; break; - case 2400: stPortSpeed = B2400; break; - case 4800: stPortSpeed = B4800; break; - case 9600: stPortSpeed = B9600; break; - case 19200: stPortSpeed = B19200; break; - case 38400: stPortSpeed = B38400; break; + const serial_port_unix* spu = (serial_port_unix*)sp; + speed_t stPortSpeed; + switch (uiPortSpeed) { + case 0: stPortSpeed = B0; break; + case 50: stPortSpeed = B50; break; + case 75: stPortSpeed = B75; break; + case 110: stPortSpeed = B110; break; + case 134: stPortSpeed = B134; break; + case 150: stPortSpeed = B150; break; + case 300: stPortSpeed = B300; break; + case 600: stPortSpeed = B600; break; + case 1200: stPortSpeed = B1200; break; + case 1800: stPortSpeed = B1800; break; + case 2400: stPortSpeed = B2400; break; + case 4800: stPortSpeed = B4800; break; + case 9600: stPortSpeed = B9600; break; + case 19200: stPortSpeed = B19200; break; + case 38400: stPortSpeed = B38400; break; # ifdef B57600 - case 57600: stPortSpeed = B57600; break; + case 57600: stPortSpeed = B57600; break; # endif # ifdef B115200 - case 115200: stPortSpeed = B115200; break; + case 115200: stPortSpeed = B115200; break; # endif # ifdef B230400 - case 230400: stPortSpeed = B230400; break; + case 230400: stPortSpeed = B230400; break; # endif # ifdef B460800 - case 460800: stPortSpeed = B460800; break; + case 460800: stPortSpeed = B460800; break; # endif # ifdef B921600 - case 921600: stPortSpeed = B921600; break; + case 921600: stPortSpeed = B921600; break; # endif - default: return false; - }; - struct termios ti; - if (tcgetattr(spu->fd,&ti) == -1) return false; - // Set port speed (Input and Output) - cfsetispeed(&ti, stPortSpeed); - cfsetospeed(&ti, stPortSpeed); - return (tcsetattr(spu->fd, TCSANOW, &ti) != -1); + default: return false; + }; + + struct termios ti; + if (tcgetattr(spu->fd,&ti) == -1) + return false; + + // Set port speed (Input and Output) + cfsetispeed(&ti, stPortSpeed); + cfsetospeed(&ti, stPortSpeed); + return (tcsetattr(spu->fd, TCSANOW, &ti) != -1); } uint32_t uart_get_speed(const serial_port sp) { - struct termios ti; - uint32_t uiPortSpeed; - const serial_port_unix* spu = (serial_port_unix*)sp; - if (tcgetattr(spu->fd, &ti) == -1) return 0; - // Set port speed (Input) - speed_t stPortSpeed = cfgetispeed(&ti); - switch (stPortSpeed) { - case B0: uiPortSpeed = 0; break; - case B50: uiPortSpeed = 50; break; - case B75: uiPortSpeed = 75; break; - case B110: uiPortSpeed = 110; break; - case B134: uiPortSpeed = 134; break; - case B150: uiPortSpeed = 150; break; - case B300: uiPortSpeed = 300; break; - case B600: uiPortSpeed = 600; break; - case B1200: uiPortSpeed = 1200; break; - case B1800: uiPortSpeed = 1800; break; - case B2400: uiPortSpeed = 2400; break; - case B4800: uiPortSpeed = 4800; break; - case B9600: uiPortSpeed = 9600; break; - case B19200: uiPortSpeed = 19200; break; - case B38400: uiPortSpeed = 38400; break; + struct termios ti; + uint32_t uiPortSpeed; + const serial_port_unix* spu = (serial_port_unix*)sp; + + if (tcgetattr(spu->fd, &ti) == -1) + return 0; + + // Set port speed (Input) + speed_t stPortSpeed = cfgetispeed(&ti); + switch (stPortSpeed) { + case B0: uiPortSpeed = 0; break; + case B50: uiPortSpeed = 50; break; + case B75: uiPortSpeed = 75; break; + case B110: uiPortSpeed = 110; break; + case B134: uiPortSpeed = 134; break; + case B150: uiPortSpeed = 150; break; + case B300: uiPortSpeed = 300; break; + case B600: uiPortSpeed = 600; break; + case B1200: uiPortSpeed = 1200; break; + case B1800: uiPortSpeed = 1800; break; + case B2400: uiPortSpeed = 2400; break; + case B4800: uiPortSpeed = 4800; break; + case B9600: uiPortSpeed = 9600; break; + case B19200: uiPortSpeed = 19200; break; + case B38400: uiPortSpeed = 38400; break; # ifdef B57600 - case B57600: uiPortSpeed = 57600; break; + case B57600: uiPortSpeed = 57600; break; # endif # ifdef B115200 - case B115200: uiPortSpeed = 115200; break; + case B115200: uiPortSpeed = 115200; break; # endif # ifdef B230400 - case B230400: uiPortSpeed = 230400; break; + case B230400: uiPortSpeed = 230400; break; # endif # ifdef B460800 - case B460800: uiPortSpeed = 460800; break; + case B460800: uiPortSpeed = 460800; break; # endif # ifdef B921600 - case B921600: uiPortSpeed = 921600; break; + case B921600: uiPortSpeed = 921600; break; # endif - default: return 0; - }; - return uiPortSpeed; + default: return 0; + }; + return uiPortSpeed; } - #endif diff --git a/uart/uart_win32.c b/uart/uart_win32.c index 11c90f15f..438f586c8 100644 --- a/uart/uart_win32.c +++ b/uart/uart_win32.c @@ -50,7 +50,7 @@ typedef struct { serial_port uart_open(const char* pcPortName) { char acPortName[255]; - serial_port_windows* sp = malloc(sizeof(serial_port_windows)); + serial_port_windows* sp = calloc(sizeof(serial_port_windows), sizeof(uint8_t)); if (sp == 0) { printf("[!] UART failed to allocate memory\n");