Merge remote-tracking branch 'upstream/master'

This commit is contained in:
mazodude 2019-03-05 08:35:03 +11:00
commit fef7e78957
186 changed files with 10639 additions and 4950 deletions

View file

@ -1,6 +1,9 @@
--- ---
name: Bug report name: Bug report
about: Create a report to help us improve about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
--- ---

View file

@ -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.

View file

@ -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... 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] ## [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 TCP ports support (on linux) (@phcoder)
- Added HF sniff standalone mode with optional storing of ULC/NTAG/ULEV1 authentication attempts (@bogiton) - Added HF sniff standalone mode with optional storing of ULC/NTAG/ULEV1 authentication attempts (@bogiton)
- Fix 'Lining up plot and control window' (@anticat) - 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 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 `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 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 ### Fixed
- Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi) - Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi)

155
README.md
View file

@ -5,6 +5,33 @@ Proxmark3 RDV40 dedicated repo, based on iceman fork
## Notice ## 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. 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 ## Coverity Scan Config & Run
Download the Coverity Scan Self-buld and install it. Download the Coverity Scan Self-buld and install it.
You will need to configure ARM-NON-EABI- Compiler for it to use: You will need to configure ARM-NON-EABI- Compiler for it to use:
@ -38,17 +65,27 @@ Give us a hint, and we'll see if we can't merge in the stuff you have.
## PM3 GUI ## PM3 GUI
The official PM3-GUI from Gaucho will not work. The official PM3-GUI from Gaucho will not work.
The new universial GUI will work. The new universial GUI will work. [Proxmark3 Univerisal GUI](https://github.com/burma69/PM3UniversalGUI)
## Development ## Development
This fork now compiles just fine on This fork now compiles just fine on
- Windows/mingw environment with Qt5.6.1 & GCC 4.8 - Windows/mingw environment with Qt5.6.1 & GCC 4.8
- Ubuntu 1404, 1510, 1604 - Ubuntu 1404, 1510, 1604, 1804
- Mac OS X / Homebrew - Mac OS X / Homebrew
- ParrotOS
- WSL (Windows subsystem linux) on Windows 10
- Docker container - Docker container
## KALI and ARCHLINUX users ## KALI and ARCHLINUX users
Kali and ArchLinux users usually must kill their modem manager in order for the proxmark3 to enumerate properly. 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 ## 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 GC made updates to allow this to build easily on Ubuntu 14.04.2 LTS, 15.10 or 16.04
@ -60,7 +97,7 @@ I have also added this script to the fork.
https://github.com/RfidResearchGroup/proxmark3/blob/master/install.sh https://github.com/RfidResearchGroup/proxmark3/blob/master/install.sh
- Run - 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 - Clone fork
`git clone https://github.com/RfidResearchGroup/proxmark3.git` `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 ## Setup and build for ArchLinux
- Run - 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` `yaourt -S termcap`
- Remove modemmanager
`sudo apt remove modemmanager`
- Clone fork - Clone fork
`git clone https://github.com/RfidResearchGroup/proxmark3.git` `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) - 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 - Clone fork
`git clone https://github.com/RfidResearchGroup/proxmark3.git` `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 - Run the client
`proxmark3.exe comX` `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`

View file

@ -30,8 +30,8 @@ static uint16_t BigBuf_hi = BIGBUF_SIZE;
static uint8_t *emulator_memory = NULL; static uint8_t *emulator_memory = NULL;
// trace related variables // trace related variables
static uint16_t traceLen = 0; static uint32_t traceLen = 0;
int tracing = 1; //Last global one.. todo static? static bool tracing = true; //todo static?
// get the address of BigBuf // get the address of BigBuf
uint8_t *BigBuf_get_addr(void) { uint8_t *BigBuf_get_addr(void) {
@ -112,7 +112,7 @@ uint16_t BigBuf_max_traceLen(void) {
void clear_trace(void) { void clear_trace(void) {
traceLen = 0; traceLen = 0;
} }
void set_tracelen(uint16_t value) { void set_tracelen(uint32_t value) {
traceLen = value; traceLen = value;
} }
void set_tracing(bool enable) { void set_tracing(bool enable) {
@ -127,7 +127,7 @@ bool get_tracing(void) {
* Get the number of bytes traced * Get the number of bytes traced
* @return * @return
*/ */
uint16_t BigBuf_get_traceLen(void) { uint32_t BigBuf_get_traceLen(void) {
return traceLen; 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(); uint8_t *trace = BigBuf_get_addr();
uint16_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity uint32_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity
uint16_t duration = timestamp_end - timestamp_start; uint32_t duration = timestamp_end - timestamp_start;
// Return when trace is full // Return when trace is full
if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= BigBuf_max_traceLen()) { 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; if (!tracing) return false;
uint8_t *trace = BigBuf_get_addr(); uint8_t *trace = BigBuf_get_addr();
uint16_t iLen = nbytes(iBits); uint32_t iLen = nbytes(iBits);
// Return when trace is full // Return when trace is full
if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) return false; if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) return false;

View file

@ -36,10 +36,10 @@ extern uint8_t *BigBuf_malloc(uint16_t);
extern void BigBuf_free(void); extern void BigBuf_free(void);
extern void BigBuf_free_keep_EM(void); extern void BigBuf_free_keep_EM(void);
extern void BigBuf_print_status(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 clear_trace(void);
extern void set_tracing(bool enable); 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 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 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); extern int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int bReader);

View file

@ -21,7 +21,7 @@ APP_CFLAGS = -DWITH_CRC \
-DWITH_ISO14443a \ -DWITH_ISO14443a \
-DWITH_ICLASS \ -DWITH_ICLASS \
-DWITH_FELICA \ -DWITH_FELICA \
-DWITH_FLASH \ -DWITH_FLASH \
-DWITH_SMARTCARD \ -DWITH_SMARTCARD \
-DWITH_FPC \ -DWITH_FPC \
-DWITH_HFSNOOP \ -DWITH_HFSNOOP \
@ -122,8 +122,9 @@ APP_CFLAGS += $(ZLIB_CFLAGS)
# zlib includes: # zlib includes:
APP_CFLAGS += -I../zlib APP_CFLAGS += -I../zlib
# stdint.h provided locally until GCC 4.5 becomes C99 compliant # stdint.h provided locally until GCC 4.5 becomes C99 compliant,
APP_CFLAGS += -I. # 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) # Compile these in thumb mode (small size)
THUMBSRC = start.c \ THUMBSRC = start.c \
@ -190,7 +191,7 @@ $(OBJDIR)/fpga_all.bit.z: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR)
$(FPGA_COMPRESSOR) $(filter %.bit,$^) $@ $(FPGA_COMPRESSOR) $(filter %.bit,$^) $@
$(FPGA_COMPRESSOR): $(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) $(OBJDIR)/fullimage.stage1.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ)
$(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS) $(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS)

View file

@ -271,6 +271,11 @@ void RAMFUNC SniffAndStore(uint8_t param) {
uint16_t writelen = Flash_WriteData(0, total_data, memoffset + 4 * auth_attempts); 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 (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); SpinDelay(100);
// Reset the SPI Baudrate to the default value (24MHz) // Reset the SPI Baudrate to the default value (24MHz)

View file

@ -113,7 +113,7 @@ void print_result(char *name, uint8_t *buf, size_t len) {
void DbpStringEx(char *str, uint32_t cmd) { void DbpStringEx(char *str, uint32_t cmd) {
#if DEBUG #if DEBUG
uint8_t len = strlen(str); 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 #endif
} }
@ -307,10 +307,10 @@ void MeasureAntennaTuningHf(void) {
} else { } else {
volt = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; 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); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
DbpString("\n[+] cancelled"); DbprintfEx(FLAG_NOOPT, "\n[+] cancelled", 1);
} }
void ReadMem(int addr) { void ReadMem(int addr) {
@ -724,6 +724,9 @@ void UsbPacketReceived(uint8_t *packet, int len) {
case CMD_T55XX_RESET_READ: case CMD_T55XX_RESET_READ:
T55xxResetRead(); T55xxResetRead();
break; break;
case CMD_T55XX_CHKPWDS:
T55xx_ChkPwds();
break;
case CMD_PCF7931_READ: case CMD_PCF7931_READ:
ReadPCF7931(); ReadPCF7931();
break; break;
@ -1250,12 +1253,12 @@ void UsbPacketReceived(uint8_t *packet, int len) {
size_t size = MIN(USB_CMD_DATA_SIZE, len); size_t size = MIN(USB_CMD_DATA_SIZE, len);
uint8_t *mem = BigBuf_malloc(size); if (!FlashInit()) {
if (!FlashInit()) {
break; break;
} }
uint8_t *mem = BigBuf_malloc(size);
for(size_t i = 0; i < len; i += size) { for(size_t i = 0; i < len; i += size) {
len = MIN((len - i), size); len = MIN((len - i), size);
@ -1268,6 +1271,7 @@ void UsbPacketReceived(uint8_t *packet, int len) {
break; break;
} }
} }
BigBuf_free();
FlashStop(); FlashStop();
LED_B_OFF(); LED_B_OFF();
break; break;
@ -1286,6 +1290,16 @@ void UsbPacketReceived(uint8_t *packet, int len) {
break; 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_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable(); Flash_WriteEnable();

View file

@ -34,7 +34,6 @@ extern "C" {
extern const uint8_t OddByteParity[256]; extern const uint8_t OddByteParity[256];
extern int rsamples; // = 0; extern int rsamples; // = 0;
extern int tracing; // = TRUE;
extern uint8_t trigger; extern uint8_t trigger;
// This may be used (sparingly) to declare a function to be copied to // 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 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 T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd);
void T55xxWakeUp(uint32_t Pwd); void T55xxWakeUp(uint32_t Pwd);
void T55xx_ChkPwds(void);
void TurnReadLFOn(uint32_t delay); void TurnReadLFOn(uint32_t delay);
void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd); void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd);
void EM4xWriteWord(uint32_t flag, uint32_t data, uint32_t pwd); void EM4xWriteWord(uint32_t flag, uint32_t data, uint32_t pwd);

View file

@ -108,7 +108,7 @@ int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response)
switch(iso_type) switch(iso_type)
{ {
case 'a': case 'a':
return iso14_apdu(apdu, (uint16_t) length, response, NULL); return iso14_apdu(apdu, (uint16_t) length, false, response, NULL);
break; break;
case 'b': case 'b':
return iso14443b_apdu(apdu, length, response); return iso14443b_apdu(apdu, length, response);

View file

@ -29,27 +29,25 @@ static uint32_t felica_timeout;
static uint32_t felica_nexttransfertime; static uint32_t felica_nexttransfertime;
static uint32_t felica_lasttime_prox2air_start; 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 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); static void TransmitFor18092_AsReader(uint8_t * frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed);
bool WaitForFelicaReply(uint16_t maxbytes); 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; 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; return felica_timeout - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) - 2;
} }
//random service RW: 0x0009 #ifndef FELICA_MAX_FRAME_SIZE
//random service RO: 0x000B #define FELICA_MAX_FRAME_SIZE 260
#ifndef NFC_MAX_FRAME_SIZE
#define NFC_MAX_FRAME_SIZE 260
#endif #endif
//structure to hold outgoing NFC frame //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 //structure to hold incoming NFC frame, used for ISO/IEC 18092-compatible frames
static struct { static struct {
@ -71,114 +69,114 @@ static struct {
uint8_t *framebytes; uint8_t *framebytes;
//should be enough. maxlen is 255, 254 for data, 2 for sync, 2 for crc //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 // 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 //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 //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 #ifndef SYNC_16BIT
# define SYNC_16BIT 0x4DB2 # define SYNC_16BIT 0xB24D
#endif #endif
static void NFCFrameReset() { static void FelicaFrameReset() {
NFCFrame.state = STATE_UNSYNCD; FelicaFrame.state = STATE_UNSYNCD;
NFCFrame.posCnt = 0; FelicaFrame.posCnt = 0;
NFCFrame.crc_ok = false; FelicaFrame.crc_ok = false;
NFCFrame.byte_offset = 0; FelicaFrame.byte_offset = 0;
} }
static void NFCInit(uint8_t *data) { static void FelicaFrameinit(uint8_t *data) {
NFCFrame.framebytes = data; FelicaFrame.framebytes = data;
NFCFrameReset(); FelicaFrameReset();
} }
//shift byte into frame, reversing it at the same time //shift byte into frame, reversing it at the same time
static void shiftInByte(uint8_t bt) { static void shiftInByte(uint8_t bt) {
uint8_t j; uint8_t j;
for(j=0; j < NFCFrame.byte_offset; j++) { for(j=0; j < FelicaFrame.byte_offset; j++) {
NFCFrame.framebytes[NFCFrame.posCnt] = ( NFCFrame.framebytes[NFCFrame.posCnt]<<1 ) + (bt & 1); FelicaFrame.framebytes[FelicaFrame.posCnt] = ( FelicaFrame.framebytes[FelicaFrame.posCnt]<<1 ) + (bt & 1);
bt >>= 1; bt >>= 1;
} }
NFCFrame.posCnt++; FelicaFrame.posCnt++;
NFCFrame.rem_len--; FelicaFrame.rem_len--;
for(j = NFCFrame.byte_offset; j<8; j++) { for(j = FelicaFrame.byte_offset; j<8; j++) {
NFCFrame.framebytes[NFCFrame.posCnt] = (NFCFrame.framebytes[NFCFrame.posCnt]<<1 ) + (bt & 1); FelicaFrame.framebytes[FelicaFrame.posCnt] = (FelicaFrame.framebytes[FelicaFrame.posCnt]<<1 ) + (bt & 1);
bt >>= 1; bt >>= 1;
} }
} }
static void ProcessNFCByte(uint8_t bt) { static void Process18092Byte(uint8_t bt) {
switch (NFCFrame.state) { switch (FelicaFrame.state) {
case STATE_UNSYNCD: { 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 //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) { if (bt > 0) {
NFCFrame.shiftReg = reflect8(bt); FelicaFrame.shiftReg = reflect8(bt);
NFCFrame.state = STATE_TRYING_SYNC; FelicaFrame.state = STATE_TRYING_SYNC;
} }
break; break;
} }
case STATE_TRYING_SYNC: { case STATE_TRYING_SYNC: {
if (bt == 0) { if (bt == 0) {
//desync //desync
NFCFrame.shiftReg = bt; FelicaFrame.shiftReg = bt;
NFCFrame.state = STATE_UNSYNCD; FelicaFrame.state = STATE_UNSYNCD;
} else { } else {
for (uint8_t i=0; i<8; i++) { for (uint8_t i=0; i<8; i++) {
if (NFCFrame.shiftReg == SYNC_16BIT) { if (FelicaFrame.shiftReg == SYNC_16BIT) {
//SYNC done! //SYNC done!
NFCFrame.state = STATE_GET_LENGTH; FelicaFrame.state = STATE_GET_LENGTH;
NFCFrame.framebytes[0] = 0xb2; FelicaFrame.framebytes[0] = 0xb2;
NFCFrame.framebytes[1] = 0x4d; //write SYNC FelicaFrame.framebytes[1] = 0x4d;
NFCFrame.byte_offset = i; FelicaFrame.byte_offset = i;
//shift in remaining byte, slowly... //shift in remaining byte, slowly...
for(uint8_t j=i; j<8; j++) { 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; bt >>= 1;
} }
NFCFrame.posCnt = 2; FelicaFrame.posCnt = 2;
if (i==0) if (i==0)
break; break;
} }
NFCFrame.shiftReg = (NFCFrame.shiftReg << 1) + (bt & 1); FelicaFrame.shiftReg = (FelicaFrame.shiftReg << 1) + (bt & 1);
bt >>= 1; bt >>= 1;
} }
//that byte was last byte of sync //that byte was last byte of sync
if (NFCFrame.shiftReg == SYNC_16BIT) { if (FelicaFrame.shiftReg == SYNC_16BIT) {
//Force SYNC on next byte //Force SYNC on next byte
NFCFrame.state = STATE_GET_LENGTH; FelicaFrame.state = STATE_GET_LENGTH;
NFCFrame.framebytes[0] = 0xb2; FelicaFrame.framebytes[0] = 0xb2;
NFCFrame.framebytes[1] = 0x4d; FelicaFrame.framebytes[1] = 0x4d;
NFCFrame.byte_offset = 0; FelicaFrame.byte_offset = 0;
NFCFrame.posCnt = 1; FelicaFrame.posCnt = 1;
} }
} }
break; break;
} }
case STATE_GET_LENGTH: { case STATE_GET_LENGTH: {
shiftInByte(bt); shiftInByte(bt);
NFCFrame.rem_len = NFCFrame.framebytes[2] - 1; FelicaFrame.rem_len = FelicaFrame.framebytes[2] - 1;
NFCFrame.len = NFCFrame.framebytes[2] + 4; //with crc and sync FelicaFrame.len = FelicaFrame.framebytes[2] + 4; //with crc and sync
NFCFrame.state = STATE_GET_DATA; FelicaFrame.state = STATE_GET_DATA;
break; break;
} }
case STATE_GET_DATA: { case STATE_GET_DATA: {
shiftInByte(bt); shiftInByte(bt);
if (NFCFrame.rem_len <= 0) { if (FelicaFrame.rem_len <= 0) {
NFCFrame.state = STATE_GET_CRC; FelicaFrame.state = STATE_GET_CRC;
NFCFrame.rem_len = 2; FelicaFrame.rem_len = 2;
} }
break; break;
} }
case STATE_GET_CRC: { case STATE_GET_CRC: {
shiftInByte(bt); shiftInByte(bt);
if ( NFCFrame.rem_len <= 0 ) { if ( FelicaFrame.rem_len <= 0 ) {
// skip sync 2bytes. IF ok, residue should be 0x0000 // skip sync 2bytes. IF ok, residue should be 0x0000
NFCFrame.crc_ok = check_crc(CRC_FELICA, NFCFrame.framebytes+2, NFCFrame.len-2); FelicaFrame.crc_ok = check_crc(CRC_FELICA, FelicaFrame.framebytes+2, FelicaFrame.len-2);
NFCFrame.state = STATE_FULL; FelicaFrame.state = STATE_FULL;
NFCFrame.rem_len = 0; FelicaFrame.rem_len = 0;
if (MF_DBGLEVEL > 3) Dbprintf("[+] got 2 crc bytes [%s]", (NFCFrame.crc_ok) ? "OK" : "No" ); if (MF_DBGLEVEL > 3) Dbprintf("[+] got 2 crc bytes [%s]", (FelicaFrame.crc_ok) ? "OK" : "No" );
} }
break; break;
} }
@ -207,7 +205,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
// b0 = fc/64 (212kbps) // b0 = fc/64 (212kbps)
// 0x00 = timeslot // 0x00 = timeslot
// 0x09 0x21 = crc // 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; 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); TransmitFor18092_AsReader(poll, sizeof(poll), NULL, 1, 0);
// polling card, break if success // polling card, break if success
if (WaitForFelicaReply(512) && NFCFrame.framebytes[3] == FELICA_POLL_ACK) if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK)
break; break;
WDT_HIT(); WDT_HIT();
@ -231,19 +229,19 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
return 1; return 1;
// wrong answer // wrong answer
if (NFCFrame.framebytes[3] != FELICA_POLL_ACK) if (FelicaFrame.framebytes[3] != FELICA_POLL_ACK)
return 2; return 2;
// VALIDATE CRC residue is 0, hence if crc is a value it failed. // 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; return 3;
// copy UID // copy UID
// idm 8 // idm 8
if (card) { if (card) {
memcpy(card->IDm, NFCFrame.framebytes + 4, 8); memcpy(card->IDm, FelicaFrame.framebytes + 4, 8);
memcpy(card->PMm, NFCFrame.framebytes + 4 + 8, 8); memcpy(card->PMm, FelicaFrame.framebytes + 4 + 8, 8);
//memcpy(card->servicecode, NFCFrame.framebytes + 4 + 8 + 8, 2); //memcpy(card->servicecode, FelicaFrame.framebytes + 4 + 8 + 8, 2);
memcpy(card->code, card->IDm, 2); memcpy(card->code, card->IDm, 2);
memcpy(card->uid, card->IDm + 2, 6); memcpy(card->uid, card->IDm + 2, 6);
memcpy(card->iccode, card->PMm, 2); 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 ) { static void BuildFliteRdblk(uint8_t* idm, int blocknum, uint16_t *blocks ) {
if (blocknum > 4 || blocknum <= 0) 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; uint8_t c = 0, i = 0;
@ -389,19 +387,19 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
// power, no modulation // power, no modulation
FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
NFCFrameReset(); FelicaFrameReset();
// clear RXRDY: // clear RXRDY:
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
uint32_t timeout = felica_get_timeout(); uint32_t timeout = iso18092_get_timeout();
for(;;) { for(;;) {
WDT_HIT(); WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
b = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); b = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
ProcessNFCByte(b); Process18092Byte(b);
if (NFCFrame.state == STATE_FULL) { if (FelicaFrame.state == STATE_FULL) {
felica_nexttransfertime = felica_nexttransfertime =
MAX( MAX(
felica_nexttransfertime, felica_nexttransfertime,
@ -410,19 +408,19 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
; ;
LogTrace( LogTrace(
NFCFrame.framebytes, FelicaFrame.framebytes,
NFCFrame.len, FelicaFrame.len,
((GetCountSspClk() & 0xfffffff8)<<4) - DELAY_AIR2ARM_AS_READER - timeout, ((GetCountSspClk() & 0xfffffff8)<<4) - DELAY_AIR2ARM_AS_READER - timeout,
((GetCountSspClk() & 0xfffffff8)<<4) - DELAY_AIR2ARM_AS_READER, ((GetCountSspClk() & 0xfffffff8)<<4) - DELAY_AIR2ARM_AS_READER,
NULL, NULL,
false false
); );
return true; return true;
} else if (c++ > timeout && NFCFrame.state == STATE_UNSYNCD) { } else if (c++ > timeout && FelicaFrame.state == STATE_UNSYNCD) {
return false; return false;
} else if (NFCFrame.state == STATE_GET_CRC) { } else if (FelicaFrame.state == STATE_GET_CRC) {
Dbprintf(" Frame: "); Dbprintf(" Frame: ");
Dbhexdump(16, NFCFrame.framebytes, 0); Dbhexdump(16, FelicaFrame.framebytes, 0);
//return false; //return false;
} }
} }
@ -432,7 +430,7 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
// Set up FeliCa communication (similar to iso14443a_setup) // Set up FeliCa communication (similar to iso14443a_setup)
// field is setup for "Sending as Reader" // 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(); LEDsoff();
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
@ -442,10 +440,12 @@ static void felica_setup(uint8_t fpga_minor_mode) {
// Initialize Demod and Uart structs // Initialize Demod and Uart structs
//DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); //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_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: // connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
@ -456,8 +456,6 @@ static void felica_setup(uint8_t fpga_minor_mode) {
// LSB transfer. Remember to set it back to MSB with // 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); 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 // Signal field is on with the appropriate LED
FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | fpga_minor_mode); FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | fpga_minor_mode);
@ -492,7 +490,7 @@ void felica_sendraw(UsbCommand *c) {
set_tracing(true); set_tracing(true);
if ((param & FELICA_CONNECT)) { 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. // notify client selecting status.
// if failed selecting, turn off antenna and quite. // 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); TransmitFor18092_AsReader(buf, buf[2]+4, NULL, 1, 0);
arg0 = !WaitForFelicaReply(1024); 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)) 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); 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. //the frame bits are slow enough.
int n = BigBuf_max_traceLen() / sizeof(uint8_t); // take all memory 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) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
ProcessNFCByte(dist); Process18092Byte(dist);
//to be sure we are in frame //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% //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 = distance >> 8;
dest++; dest++;
*dest = (distance & 0xff); *dest = (distance & 0xff);
dest++; dest++;
} }
//crc NOT checked //crc NOT checked
if (NFCFrame.state == STATE_FULL) { if (FelicaFrame.state == STATE_FULL) {
endframe = GetCountSspClk(); endframe = GetCountSspClk();
//*dest = NFCFrame.crc_ok; //kind of wasteful //*dest = FelicaFrame.crc_ok; //kind of wasteful
dest++; dest++;
for(int i=0; i < NFCFrame.len; i++) { for(int i=0; i < FelicaFrame.len; i++) {
*dest = NFCFrame.framebytes[i]; *dest = FelicaFrame.framebytes[i];
dest++; dest++;
if (dest >= destend ) break; if (dest >= destend ) break;
@ -590,9 +588,9 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) {
if (remFrames <= 0) break; if (remFrames <= 0) break;
if (dest >= destend ) 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); num_to_bytes(nfcid, 8, ndef);
//prepare our 3 responses... //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_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,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00, 0x88,0xb4,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,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_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 //NFC tag 3/ ISo technically. Many overlapping standards
DbpString("Felica Lite-S sim start"); 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_poll1, resp_poll1[2]);
AddCrc(resp_readblk, resp_readblk[2]); AddCrc(resp_readblk, resp_readblk[2]);
felica_setup( FPGA_HF_ISO18092_FLAG_NOMOD); iso18092_setup( FPGA_HF_ISO18092_FLAG_NOMOD);
bool listenmode = true; bool listenmode = true;
//uint32_t frtm = GetCountSspClk(); //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); uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
//frtm = GetCountSspClk(); //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 //polling... there are two types of polling we answer to
if (NFCFrame.framebytes[6] == 0) { if (FelicaFrame.framebytes[6] == 0) {
curresp = resp_poll0; curresp = resp_poll0;
curlen = R_POLL0_LEN; curlen = R_POLL0_LEN;
listenmode = false; listenmode = false;
} }
if (NFCFrame.framebytes[6] == 1) { if (FelicaFrame.framebytes[6] == 1) {
curresp = resp_poll1; curresp = resp_poll1;
curlen = R_POLL1_LEN; curlen = R_POLL1_LEN;
listenmode = true; 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... //we should rebuild it depending on page size, but...
//Let's see first //Let's see first
curresp = resp_readblk; curresp = resp_readblk;
@ -686,10 +684,10 @@ void felica_sim_lite(uint64_t nfcid) {
listenmode = false; listenmode = false;
} }
//clear frame //clear frame
NFCFrameReset(); FelicaFrameReset();
} else { } else {
//frame invalid, clear it out to allow for the next one //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 //switch back
FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_NOMOD); FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_NOMOD);
NFCFrameReset(); FelicaFrameReset();
listenmode = true; listenmode = true;
curlen = 0; curlen = 0;
curresp = NULL; curresp = NULL;
@ -721,11 +719,11 @@ void felica_sim_lite(uint64_t nfcid) {
void felica_dump_lite_s() { void felica_dump_lite_s() {
uint8_t ndef[8]; uint8_t ndef[8];
uint8_t poll[10] = { 0xb2,0x4d,0x06,0x00,0xff,0xff,0x00,0x00,0x09,0x21}; 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}; 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. // 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; uint8_t blknum;
bool isOK = false; bool isOK = false;
@ -740,12 +738,12 @@ void felica_dump_lite_s() {
//TransmitFor18092_AsReader(poll, 10, GetCountSspClk()+512, 1, 0); //TransmitFor18092_AsReader(poll, 10, GetCountSspClk()+512, 1, 0);
TransmitFor18092_AsReader(poll, 10, NULL, 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. // copy 8bytes to ndef.
memcpy(ndef, NFCFrame.framebytes + 4, 8); memcpy(ndef, FelicaFrame.framebytes + 4, 8);
// for (c=0; c < 8; c++) // for (c=0; c < 8; c++)
// ndef[c] = NFCFrame.framebytes[c+4]; // ndef[c] = FelicaFrame.framebytes[c+4];
for (blknum=0; blknum < sizeof(liteblks); ) { for (blknum=0; blknum < sizeof(liteblks); ) {
@ -756,15 +754,15 @@ void felica_dump_lite_s() {
TransmitFor18092_AsReader(frameSpace, frameSpace[2]+4, NULL, 1, 0); TransmitFor18092_AsReader(frameSpace, frameSpace[2]+4, NULL, 1, 0);
// read block // read block
if (WaitForFelicaReply(1024) && NFCFrame.framebytes[3] == FELICA_RDBLK_ACK) { if (WaitForFelicaReply(1024) && FelicaFrame.framebytes[3] == FELICA_RDBLK_ACK) {
dest[cnt++] = liteblks[blknum]; dest[cnt++] = liteblks[blknum];
uint8_t *fb = NFCFrame.framebytes; uint8_t *fb = FelicaFrame.framebytes;
dest[cnt++] = fb[12]; dest[cnt++] = fb[12];
dest[cnt++] = fb[13]; dest[cnt++] = fb[13];
//memcpy(dest+cnt, NFCFrame.framebytes + 15, 16); //memcpy(dest+cnt, FelicaFrame.framebytes + 15, 16);
//cnt += 16; //cnt += 16;
for(uint8_t j=0; j < 16; j++) for(uint8_t j=0; j < 16; j++)
dest[cnt++] = fb[15+j]; dest[cnt++] = fb[15+j];
@ -773,8 +771,8 @@ void felica_dump_lite_s() {
cntfails = 0; cntfails = 0;
// // print raw log. // // print raw log.
// Dbprintf("LEN %u | Dump bytes count %u ", NFCFrame.len, cnt); // Dbprintf("LEN %u | Dump bytes count %u ", FelicaFrame.len, cnt);
Dbhexdump(NFCFrame.len, NFCFrame.framebytes+15, 0); Dbhexdump(FelicaFrame.len, FelicaFrame.framebytes+15, 0);
} else { } else {
cntfails++; cntfails++;
if (cntfails > 12) { if (cntfails > 12) {

View file

@ -14,7 +14,10 @@
#define MAX_ISO14A_TIMEOUT 524288 #define MAX_ISO14A_TIMEOUT 524288
static uint32_t iso14a_timeout; static uint32_t iso14a_timeout;
uint8_t colpos = 0;
int rsamples = 0; int rsamples = 0;
//int ReqCount;
//char CollisionIndicators[10*8];
uint8_t trigger = 0; uint8_t trigger = 0;
// the block number for the ISO14443-4 PCB // 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 D: 11110000 modulation with subcarrier during first half
// Sequence E: 00001111 modulation with subcarrier during second half // Sequence E: 00001111 modulation with subcarrier during second half
// Sequence F: 00000000 no modulation with subcarrier // 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 // READER TO CARD - miller
// Sequence X: 00001100 drop after half a period // Sequence X: 00001100 drop after half a period
// Sequence Y: 00000000 no drop // Sequence Y: 00000000 no drop
@ -110,6 +115,7 @@ static uint32_t LastProxToAirDuration;
#define SEC_D 0xf0 #define SEC_D 0xf0
#define SEC_E 0x0f #define SEC_E 0x0f
#define SEC_F 0x00 #define SEC_F 0x00
#define SEC_COLL 0xff
#define SEC_X 0x0c #define SEC_X 0x0c
#define SEC_Y 0x00 #define SEC_Y 0x00
#define SEC_Z 0xc0 #define SEC_Z 0xc0
@ -643,7 +649,9 @@ void RAMFUNC SniffIso14443a(uint8_t param) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Prepare tag messages // 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(); ToSendReset();
// Correction bit, might be removed when not needed // 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(0);
ToSendStuffBit(0); ToSendStuffBit(0);
ToSendStuffBit(1); // 1 ToSendStuffBit(1); // <-----
ToSendStuffBit(0); ToSendStuffBit(0);
ToSendStuffBit(0); 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 // Data bits
for(uint16_t j = 0; j < 8; j++) { for(uint16_t j = 0; j < 8; j++) {
if(b & 1) { //if (collision && (localCol >= colpos)){
ToSend[++ToSendMax] = SEC_D; if (collision) {
} else { ToSend[++ToSendMax] = SEC_COLL;
ToSend[++ToSendMax] = SEC_E; //localCol++;
} else {
if (b & 1) {
ToSend[++ToSendMax] = SEC_D;
} else {
ToSend[++ToSendMax] = SEC_E;
}
b >>= 1;
} }
b >>= 1;
} }
// Get the parity bit if (collision) {
if (parity[i>>3] & (0x80>>(i&0x0007))) { ToSend[++ToSendMax] = SEC_COLL;
ToSend[++ToSendMax] = SEC_D;
LastProxToAirDuration = 8 * ToSendMax - 4;
} else {
ToSend[++ToSendMax] = SEC_E;
LastProxToAirDuration = 8 * ToSendMax; LastProxToAirDuration = 8 * ToSendMax;
} else {
// 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++; 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}; uint8_t par[MAX_PARITY_SIZE] = {0};
GetParity(cmd, len, par); 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) { 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 // Make sure we do not exceed the free buffer space
if (ToSendMax > max_buffer_size) { if (ToSendMax > max_buffer_size) {
Dbprintf("Out of memory, when modulating bits for tag answer:"); 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; return false;
} }
// Copy the byte array, used for this modulation to the buffer position // 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 // Store the number of bytes that were used for encoding/modulation and the time needed to transfer them
response_info->modulation_n = ToSendMax; response_info->modulation_n = ToSendMax;
@ -1033,7 +1055,7 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t* data) {
// Clean receive command buffer // Clean receive command buffer
if (!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) { 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; break;
} }
p_response = NULL; p_response = NULL;
@ -1680,9 +1702,11 @@ int EmSend4bit(uint8_t resp){
par); par);
return res; return res;
} }
int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par) {
int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){ return EmSendCmdParEx(resp, respLen, par, false);
CodeIso14443aAsTagPar(resp, respLen, par); }
int EmSendCmdParEx(uint8_t *resp, uint16_t respLen, uint8_t *par, bool collision){
CodeIso14443aAsTagPar(resp, respLen, par, collision);
int res = EmSendCmd14443aRaw(ToSend, ToSendMax); int res = EmSendCmd14443aRaw(ToSend, ToSendMax);
// do the tracing for the previous reader request and this tag answer: // do the tracing for the previous reader request and this tag answer:
EmLogTrace(Uart.output, EmLogTrace(Uart.output,
@ -1697,11 +1721,13 @@ int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){
par); par);
return res; return res;
} }
int EmSendCmd(uint8_t *resp, uint16_t respLen){ 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}; uint8_t par[MAX_PARITY_SIZE] = {0x00};
GetParity(resp, respLen, par); 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, 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 // 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. // increase the uid bytes. The might be an overflow, DoS will occure.
void iso14443a_antifuzz(uint32_t flags){ 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. // We need to listen to the high-frequency, peak-detected path.
iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
// allocate buffers: BigBuf_free_keep_EM();
uint8_t *received = BigBuf_malloc(MAX_FRAME_SIZE); clear_trace();
uint8_t *receivedPar = BigBuf_malloc(MAX_PARITY_SIZE); set_tracing(true);
uint16_t counter = 0;
int len = 0; int len = 0;
BigBuf_free(); // allocate buffers:
clear_trace(); uint8_t *received = BigBuf_malloc(MAX_FRAME_SIZE);
set_tracing(true); uint8_t *receivedPar = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *resp = BigBuf_malloc(20);
memset(resp, 0xFF , 20);
LED_A_ON(); LED_A_ON();
for (;;) { for (;;) {
@ -1850,50 +1854,53 @@ void iso14443a_antifuzz(uint32_t flags){
// Clean receive command buffer // Clean receive command buffer
if (!GetIso14443aCommandFromReader(received, receivedPar, &len)) { 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; break;
} }
p_response = NULL; if ( received[0] == ISO14443A_CMD_WUPA || received[0] == ISO14443A_CMD_REQA) {
resp[0] = 0x04;
resp[1] = 0x00;
// look at the command now. if ( (flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA ) {
if (received[0] == ISO14443A_CMD_REQA) { // Received a REQUEST resp[0] = 0x44;
p_response = &responses[0]; }
} else if (received[0] == ISO14443A_CMD_WUPA) { // Received a WAKEUP
p_response = &responses[0]; EmSendCmd(resp, 2);
} else if (received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { // Received request for UID (cascade 1) continue;
p_response = &responses[1]; }
} else if (received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received request for UID (cascade 2)
p_response = &responses[2]; // 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;
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();
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) { // 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) } else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received a SELECT (cascade 2)
p_response = &responses[4]; } else {
Dbprintf("unknown command %x", received[0]);
} }
if (p_response != NULL) {
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);
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);
}
counter++;
} }
cmd_send(CMD_ACK,1,0,0,0,0); cmd_send(CMD_ACK,1,0,0,0,0);
switch_off(); switch_off();
Dbprintf("-[ UID until no response [%d]", counter); BigBuf_free_keep_EM();
*/
} }
static void iso14a_set_ATS_times(uint8_t *ats) { 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 b5,b6 = 00 - DESELECT
11 - WTX 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 parity[MAX_PARITY_SIZE] = {0x00};
uint8_t real_cmd[cmd_len + 4]; uint8_t real_cmd[cmd_len + 4];
if (cmd_len) { if (cmd_len) {
// ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02 // ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02
real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00) 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 // put block number into the PCB
real_cmd[0] |= iso14_pcb_blocknum; real_cmd[0] |= iso14_pcb_blocknum;
memcpy(real_cmd + 1, cmd, cmd_len); 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 return 0; //DATA LINK ERROR
} else{ } else{
// S-Block WTX // S-Block WTX
while((data_bytes[0] & 0xF2) == 0xF2) { while(len && ((data_bytes[0] & 0xF2) == 0xF2)) {
uint32_t save_iso14a_timeout = iso14a_get_timeout(); uint32_t save_iso14a_timeout = iso14a_get_timeout();
// temporarily increase timeout // temporarily increase timeout
iso14a_set_timeout( MAX((data_bytes[1] & 0x3f) * save_iso14a_timeout, MAX_ISO14A_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); iso14a_set_timeout(save_iso14a_timeout);
} }
// if we received an I- or R(ACK)-Block with a block number equal to the // if we received an I- or R(ACK)-Block with a block number equal to the
// current block number, toggle the current block number // current block number, toggle the current block number
if (len >= 3 // PCB+CRC = 3 bytes if (len >= 3 // PCB+CRC = 3 bytes
&& ((data_bytes[0] & 0xC0) == 0 // I-Block && ((data_bytes[0] & 0xC0) == 0 // I-Block
|| (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 || (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0
&& (data_bytes[0] & 0x01) == iso14_pcb_blocknum) // equal block numbers && (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 we received I-block with chaining we need to send ACK and receive another block of data
if (res) if (res)
*res = data_bytes[0]; *res = data_bytes[0];
// crc check // 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; return -1;
} }
} }
// cut frame byte if (len) {
len -= 1; // cut frame byte
// memmove(data_bytes, data_bytes + 1, len); len -= 1;
for (int i = 0; i < len; i++) // memmove(data_bytes, data_bytes + 1, len);
data_bytes[i] = data_bytes[i + 1]; for (int i = 0; i < len; i++)
data_bytes[i] = data_bytes[i + 1];
}
return len; return len;
} }
@ -2331,7 +2343,7 @@ void ReaderIso14443a(UsbCommand *c) {
if ((param & ISO14A_APDU)) { if ((param & ISO14A_APDU)) {
uint8_t res; 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)); 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) 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); cmd_send(CMD_ACK,1,0,0,0,0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff(); LEDsoff();

View file

@ -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 int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par);
extern void iso14443a_setup(uint8_t fpga_minor_mode); 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_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 int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades);
extern void iso14a_set_trigger(bool enable); 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 EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen);
extern int EmSend4bit(uint8_t resp); extern int EmSend4bit(uint8_t resp);
extern int EmSendCmd(uint8_t *resp, uint16_t respLen); 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 EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity);
extern int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par); 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); 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, bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity,

View file

@ -710,7 +710,7 @@ void SimulateIso14443bTag(uint32_t pupi) {
++cmdsReceived; ++cmdsReceived;
} }
if (MF_DBGLEVEL >= 2) 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 switch_off(); //simulate
} }

View file

@ -61,7 +61,7 @@ static inline uint8_t rx_byte_from_fpga() {
WDT_HIT(); WDT_HIT();
// wait for byte be become available in rx holding register // 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; 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: // To reduce CPU time the amplitude is approximated by using linear functions:
// am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq)) // 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. // on a i/q pair from two subsequent correlations, but does not matter.
static inline int32_t sample_power() { static inline int32_t sample_power() {
int32_t q = (int8_t)rx_byte_from_fpga(); q = ABS(q); 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() { static inline bool rx_bit() {
int32_t power; int32_t power;
for(size_t i = 0; i<5; ++i) { for (size_t i = 0; i<5; ++i) {
power = sample_power(); power = sample_power();
} }
@ -120,12 +120,12 @@ static inline void tx_bit(bool bit) {
// insert pause // insert pause
LOW(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
last_frame_end += RWD_TIME_PAUSE; last_frame_end += RWD_TIME_PAUSE;
while(GET_TICKS < last_frame_end) { }; while (GET_TICKS < last_frame_end) { };
HIGH(GPIO_SSC_DOUT); HIGH(GPIO_SSC_DOUT);
// return to high, wait for bit periode to end // return to high, wait for bit periode to end
last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE; 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 // wait for next tx timeslot
last_frame_end += RWD_FRAME_WAIT; last_frame_end += RWD_FRAME_WAIT;
while(GET_TICKS < last_frame_end) { }; while (GET_TICKS < last_frame_end) { };
// backup ts for trace log // backup ts for trace log
uint32_t last_frame_start = last_frame_end; uint32_t last_frame_start = last_frame_end;
// transmit frame, MSB first // 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; bool bit = (frame >> i) & 0x01;
tx_bit(bit ^ legic_prng_get_bit()); tx_bit(bit ^ legic_prng_get_bit());
legic_prng_forward(1); 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 // add pause to mark end of the frame
LOW(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
last_frame_end += RWD_TIME_PAUSE; last_frame_end += RWD_TIME_PAUSE;
while(GET_TICKS < last_frame_end) { }; while (GET_TICKS < last_frame_end) { };
HIGH(GPIO_SSC_DOUT); HIGH(GPIO_SSC_DOUT);
// log // log
@ -173,19 +173,19 @@ static uint32_t rx_frame(uint8_t len) {
// hold sampling until card is expected to respond // hold sampling until card is expected to respond
last_frame_end += TAG_FRAME_WAIT; last_frame_end += TAG_FRAME_WAIT;
while(GET_TICKS < last_frame_end) { }; while (GET_TICKS < last_frame_end) { };
// backup ts for trace log // backup ts for trace log
uint32_t last_frame_start = last_frame_end; uint32_t last_frame_start = last_frame_end;
uint32_t frame = 0; 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; frame |= (rx_bit() ^ legic_prng_get_bit()) << i;
legic_prng_forward(1); legic_prng_forward(1);
// rx_bit runs only 95us, resync to TAG_BIT_PERIOD // rx_bit runs only 95us, resync to TAG_BIT_PERIOD
last_frame_end += TAG_BIT_PERIOD; last_frame_end += TAG_BIT_PERIOD;
while(GET_TICKS < last_frame_end) { }; while (GET_TICKS < last_frame_end) { };
} }
// log // log
@ -203,23 +203,23 @@ static bool rx_ack() {
// hold sampling until card is expected to respond // hold sampling until card is expected to respond
last_frame_end += TAG_FRAME_WAIT; last_frame_end += TAG_FRAME_WAIT;
while(GET_TICKS < last_frame_end) { }; while (GET_TICKS < last_frame_end) { };
// backup ts for trace log // backup ts for trace log
uint32_t last_frame_start = last_frame_end; uint32_t last_frame_start = last_frame_end;
uint32_t ack = 0; 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 // sample bit
ack = rx_bit(); ack = rx_bit();
legic_prng_forward(1); legic_prng_forward(1);
// rx_bit runs only 95us, resync to TAG_BIT_PERIOD // rx_bit runs only 95us, resync to TAG_BIT_PERIOD
last_frame_end += 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 // check if it was an ACK
if(ack) { if (ack) {
break; 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. // reserve a cardmem, meaning we can use the tracelog function in bigbuff easier.
legic_mem = BigBuf_get_EM_addr(); legic_mem = BigBuf_get_EM_addr();
if(legic_mem) { if (legic_mem) {
memset(legic_mem, 0x00, LEGIC_CARD_MEMSIZE); 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. // Switch on carrier and let the card charge for 5ms.
last_frame_end += 7500; last_frame_end += 7500;
while(GET_TICKS < last_frame_end) { }; while (GET_TICKS < last_frame_end) { };
legic_prng_init(0); legic_prng_init(0);
tx_frame(iv, 7); 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 // check received against calculated crc
uint8_t calc_crc = calc_crc4(cmd, cmd_sz, byte); 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); Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc);
return -1; return -1;
} }
@ -399,15 +399,15 @@ void LegicRfInfo(void) {
// establish shared secret and detect card type // establish shared secret and detect card type
uint8_t card_type = setup_phase(0x01); 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); cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT; goto OUT;
} }
// read UID // 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); int16_t byte = read_byte(i, card.cmdsize);
if(byte == -1) { if (byte == -1) {
cmd_send(CMD_ACK, 0, 0, 0, 0, 0); cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT; goto OUT;
} }
@ -417,7 +417,7 @@ void LegicRfInfo(void) {
// read MCC and check against UID // read MCC and check against UID
int16_t mcc = read_byte(4, card.cmdsize); int16_t mcc = read_byte(4, card.cmdsize);
int16_t calc_mcc = CRC8Legic(card.uid, 4);; 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); cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT; goto OUT;
} }
@ -436,19 +436,19 @@ void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) {
// establish shared secret and detect card type // establish shared secret and detect card type
uint8_t card_type = setup_phase(iv); 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); cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT; goto OUT;
} }
// do not read beyond card memory // do not read beyond card memory
if(len + offset > card.cardsize) { if (len + offset > card.cardsize) {
len = card.cardsize - offset; 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); int16_t byte = read_byte(offset + i, card.cmdsize);
if(byte == -1) { if (byte == -1) {
cmd_send(CMD_ACK, 0, 0, 0, 0, 0); cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT; goto OUT;
} }
@ -468,26 +468,26 @@ void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) {
init_reader(false); init_reader(false);
// uid is not writeable // uid is not writeable
if(offset <= WRITE_LOWERLIMIT) { if (offset <= WRITE_LOWERLIMIT) {
cmd_send(CMD_ACK, 0, 0, 0, 0, 0); cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT; goto OUT;
} }
// establish shared secret and detect card type // establish shared secret and detect card type
uint8_t card_type = setup_phase(iv); 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); cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT; goto OUT;
} }
// do not write beyond card memory // do not write beyond card memory
if(len + offset > card.cardsize) { if (len + offset > card.cardsize) {
len = card.cardsize - offset; len = card.cardsize - offset;
} }
// write in reverse order, only then is DCF (decremental field) writable // write in reverse order, only then is DCF (decremental field) writable
while(len-- > 0 && !BUTTON_PRESS()) { while (len-- > 0 && !BUTTON_PRESS()) {
if(!write_byte(len + offset, data[len], card.addrsize)) { if (!write_byte(len + offset, data[len], card.addrsize)) {
Dbprintf("operation failed | %02X | %02X | %02X", len + offset, len, data[len]); Dbprintf("operation failed | %02X | %02X | %02X", len + offset, len, data[len]);
cmd_send(CMD_ACK, 0, 0, 0, 0, 0); cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT; goto OUT;

View file

@ -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_PAUSE 4 /* 18.9us */
#define RWD_TIME_1 21 /* RWD_TIME_PAUSE 18.9us off + 80.2us on = 99.1us */ #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_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_MIN_FRAME_LEN 6 /* Shortest frame is 6 bits */
#define RWD_MAX_FRAME_LEN 23 /* Longest frame is 23 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 // Returns true if a pulse/pause is received within timeout
static inline bool wait_for(bool value, const uint32_t timeout) { static inline bool wait_for(bool value, const uint32_t timeout) {
while((bool)(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN) != value) { while ((bool)(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN) != value) {
if(GetCountSspClk() > timeout) { if (GetCountSspClk() > timeout) {
return false; return false;
} }
} }
@ -81,12 +81,12 @@ static inline int8_t rx_bit() {
uint32_t bit_start = last_frame_end; uint32_t bit_start = last_frame_end;
// wait for pause to 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; return -1;
} }
// wait for next pause // 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; return -1;
} }
@ -94,7 +94,7 @@ static inline int8_t rx_bit() {
last_frame_end = GetCountSspClk(); last_frame_end = GetCountSspClk();
// check for code violation (bit to short) // 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; return -1;
} }
@ -122,7 +122,7 @@ static inline int8_t rx_bit() {
static inline void tx_bit(bool bit) { static inline void tx_bit(bool bit) {
LED_C_ON(); LED_C_ON();
if(bit) { if (bit) {
// modulate subcarrier // modulate subcarrier
HIGH(GPIO_SSC_DOUT); HIGH(GPIO_SSC_DOUT);
} else { } else {
@ -132,7 +132,7 @@ static inline void tx_bit(bool bit) {
// wait for tx timeslot to end // wait for tx timeslot to end
last_frame_end += TAG_BIT_PERIOD; last_frame_end += TAG_BIT_PERIOD;
while(GetCountSspClk() < last_frame_end) { }; while (GetCountSspClk() < last_frame_end) { };
LED_C_OFF(); LED_C_OFF();
} }
@ -150,13 +150,13 @@ static void tx_frame(uint32_t frame, uint8_t len) {
// wait for next tx timeslot // wait for next tx timeslot
last_frame_end += TAG_FRAME_WAIT; last_frame_end += TAG_FRAME_WAIT;
legic_prng_forward(TAG_FRAME_WAIT/TAG_BIT_PERIOD - 1); 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 // backup ts for trace log
uint32_t last_frame_start = last_frame_end; uint32_t last_frame_start = last_frame_end;
// transmit frame, MSB first // 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; bool bit = (frame >> i) & 0x01;
tx_bit(bit ^ legic_prng_get_bit()); tx_bit(bit ^ legic_prng_get_bit());
legic_prng_forward(1); legic_prng_forward(1);
@ -174,7 +174,7 @@ static void tx_ack() {
// wait for ack timeslot // wait for ack timeslot
last_frame_end += TAG_ACK_WAIT; last_frame_end += TAG_ACK_WAIT;
legic_prng_forward(TAG_ACK_WAIT/TAG_BIT_PERIOD - 1); 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 // backup ts for trace log
uint32_t last_frame_start = last_frame_end; uint32_t last_frame_start = last_frame_end;
@ -206,19 +206,19 @@ static int32_t rx_frame(uint8_t *len) {
last_frame_end -= 2; last_frame_end -= 2;
// wait for first pause (start of frame) // 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 // increment prng every TAG_BIT_PERIOD
last_frame_end += TAG_BIT_PERIOD; last_frame_end += TAG_BIT_PERIOD;
legic_prng_forward(1); legic_prng_forward(1);
// if start of frame was received exit delay loop // 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(); last_frame_end = GetCountSspClk();
break; break;
} }
// check for code violation // check for code violation
if(i > RWD_CMD_TIMEOUT) { if (i > RWD_CMD_TIMEOUT) {
return -1; return -1;
} }
} }
@ -227,19 +227,19 @@ static int32_t rx_frame(uint8_t *len) {
uint32_t last_frame_start = last_frame_end; uint32_t last_frame_start = last_frame_end;
// receive frame // receive frame
for(*len = 0; true; ++(*len)) { for (*len = 0; true; ++(*len)) {
// receive next bit // receive next bit
LED_B_ON(); LED_B_ON();
int8_t bit = rx_bit(); int8_t bit = rx_bit();
LED_B_OFF(); LED_B_OFF();
// check for code violation and to short / long frame // 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; return -1;
} }
// check for code violation caused by end of frame // check for code violation caused by end of frame
if(bit < 0) { if (bit < 0) {
break; break;
} }
@ -256,7 +256,6 @@ static int32_t rx_frame(uint8_t *len) {
// log // log
uint8_t cmdbytes[] = {*len, BYTEx(frame, 0), BYTEx(frame, 1), BYTEx(frame, 2)}; 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); LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, true);
return frame; 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) { static int32_t init_card(uint8_t cardtype, legic_card_select_t *p_card) {
p_card->tagtype = cardtype; p_card->tagtype = cardtype;
switch(p_card->tagtype) { switch (p_card->tagtype) {
case 0: case 0:
p_card->cmdsize = 6; p_card->cmdsize = 6;
p_card->addrsize = 5; p_card->addrsize = 5;
@ -338,7 +337,7 @@ static int32_t setup_phase(legic_card_select_t *p_card) {
// wait for iv // wait for iv
int32_t iv = rx_frame(&len); int32_t iv = rx_frame(&len);
if((len != 7) || (iv < 0)) { if ((len != 7) || (iv < 0)) {
return -1; return -1;
} }
@ -346,7 +345,7 @@ static int32_t setup_phase(legic_card_select_t *p_card) {
legic_prng_init(iv); legic_prng_init(iv);
// reply with card type // reply with card type
switch(p_card->tagtype) { switch (p_card->tagtype) {
case 0: case 0:
tx_frame(0x0D, 6); tx_frame(0x0D, 6);
break; break;
@ -360,12 +359,12 @@ static int32_t setup_phase(legic_card_select_t *p_card) {
// wait for ack // wait for ack
int32_t ack = rx_frame(&len); int32_t ack = rx_frame(&len);
if((len != 6) || (ack < 0)) { if ((len != 6) || (ack < 0)) {
return -1; return -1;
} }
// validate data // validate data
switch(p_card->tagtype) { switch (p_card->tagtype) {
case 0: case 0:
if(ack != 0x19) return -1; if(ack != 0x19) return -1;
break; break;
@ -399,12 +398,12 @@ static int32_t connected_phase(legic_card_select_t *p_card) {
// wait for command // wait for command
int32_t cmd = rx_frame(&len); int32_t cmd = rx_frame(&len);
if(cmd < 0) { if (cmd < 0) {
return -1; return -1;
} }
// check if command is LEGIC_READ // check if command is LEGIC_READ
if(len == p_card->cmdsize) { if (len == p_card->cmdsize) {
// prepare data // prepare data
uint8_t byte = legic_mem[cmd >> 1]; uint8_t byte = legic_mem[cmd >> 1];
uint8_t crc = calc_crc4(cmd, p_card->cmdsize, byte); 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 // check if command is LEGIC_WRITE
if(len == p_card->cmdsize + 8 + 4) { if (len == p_card->cmdsize + 8 + 4) {
// decode data // decode data
uint16_t mask = (1 << p_card->addrsize) - 1; uint16_t mask = (1 << p_card->addrsize) - 1;
uint16_t addr = (cmd >> 1) & mask; 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 // check received against calculated crc
uint8_t calc_crc = calc_crc4(addr << 1, p_card->cmdsize, byte); 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); Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc);
return -1; return -1;
} }
@ -453,7 +452,7 @@ void LegicRfSimulate(uint8_t cardtype) {
init_tag(); init_tag();
// verify command line input // verify command line input
if(init_card(cardtype, &card) != 0) { if (init_card(cardtype, &card) != 0) {
DbpString("Unknown tagtype."); DbpString("Unknown tagtype.");
goto OUT; goto OUT;
} }
@ -464,17 +463,17 @@ void LegicRfSimulate(uint8_t cardtype) {
WDT_HIT(); WDT_HIT();
// wait for carrier, restart after timeout // 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; continue;
} }
// wait for connection, restart on error // wait for connection, restart on error
if(setup_phase(&card)) { if (setup_phase(&card)) {
continue; continue;
} }
// conection is established, process commands until one fails // conection is established, process commands until one fails
while(!connected_phase(&card)) { while (!connected_phase(&card)) {
WDT_HIT(); WDT_HIT();
} }
} }

View file

@ -80,7 +80,7 @@ void setT55xxConfig(uint8_t arg0, t55xx_config *c) {
printT55xxConfig(); printT55xxConfig();
#if WITH_FLASH #ifdef WITH_FLASH
// shall persist to flashmem // shall persist to flashmem
if (arg0 == 0) { if (arg0 == 0) {
return; return;
@ -119,7 +119,7 @@ t55xx_config* getT55xxConfig(void) {
} }
void loadT55xxConfig(void) { void loadT55xxConfig(void) {
#if WITH_FLASH #ifdef WITH_FLASH
if (!FlashInit()) { if (!FlashInit()) {
return; return;
} }
@ -599,6 +599,8 @@ void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycle
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK;
uint8_t check = 1;
for(;;) { for(;;) {
if ( numcycles > -1 ) { if ( numcycles > -1 ) {
@ -616,9 +618,11 @@ void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycle
// used as a simple detection of a reader field? // used as a simple detection of a reader field?
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) {
WDT_HIT(); WDT_HIT();
if ( usb_poll_validate_length() || BUTTON_PRESS() ) if ( !check ) {
goto OUT; if ( usb_poll_validate_length() || BUTTON_PRESS() )
} goto OUT;
}
++check; }
if (buf[i]) if (buf[i])
OPEN_COIL(); OPEN_COIL();
@ -628,9 +632,11 @@ void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycle
//wait until SSC_CLK goes LOW //wait until SSC_CLK goes LOW
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) {
WDT_HIT(); WDT_HIT();
//if ( usb_poll_validate_length() || BUTTON_PRESS() ) if ( !check ) {
if ( BUTTON_PRESS() ) if ( usb_poll_validate_length() || BUTTON_PRESS() )
goto OUT; goto OUT;
}
++check;
} }
i++; i++;
@ -1489,10 +1495,21 @@ void T55xxWriteBlock(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t arg) {
// Read one card block in page [page] // Read one card block in page [page]
void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) {
LED_A_ON(); LED_A_ON();
bool PwdMode = arg0 & 0x1; bool PwdMode = arg0 & 0x1;
uint8_t Page = (arg0 & 0x2) >> 1; uint8_t Page = ( arg0 & 0x2 ) >> 1;
bool brute_mem = arg0 & 0x4;
uint32_t i = 0; uint32_t i = 0;
bool RegReadMode = (Block == 0xFF);//regular read mode
// 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 //clear buffer now so it does not interfere with timing later
BigBuf_Clear_keep_EM(); 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 // Set up FPGA, 125kHz to power up the tag
LFSetupFPGAForADC(95, true); LFSetupFPGAForADC(95, true);
// make sure tag is fully powered up... // make sure tag is fully powered up...
WaitMS(4); WaitMS(start_wait);
// Trigger T55x7 Direct Access Mode with start gap // Trigger T55x7 Direct Access Mode with start gap
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
WaitUS(t_config.start_gap); 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 // Turn field on to read the response
// 137*8 seems to get to the start of data pretty well... // 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... // but we want to go past the start and let the repeating data settle in...
TurnReadLFOn(210*8); TurnReadLFOn(200*8);
// Acquisition // Acquisition
// Now do the acquisition // Now do the acquisition
DoPartialAcquisition(0, true, 12000, 0); DoPartialAcquisition(0, true, samples, 0);
// Turn the field off // Turn the field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off if ( !brute_mem ) {
cmd_send(CMD_ACK,0,0,0,0,0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_A_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){ 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? //Wait 20ms for write to complete?
WaitMS(7); WaitMS(7);
//Capture response if one exists
DoPartialAcquisition(20, true, 6000, 1000); DoPartialAcquisition(20, true, 6000, 1000);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
@ -1994,7 +2112,7 @@ This triggers a COTAG tag to response
*/ */
void Cotag(uint32_t arg0) { void Cotag(uint32_t arg0) {
#ifndef OFF #ifndef OFF
# define OFF { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(2035); } # define OFF(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS((x)); }
#endif #endif
#ifndef ON #ifndef ON
# define ON(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); WaitUS((x)); } # 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(); LED_A_ON();
// Switching to LF image on FPGA. This might empty BigBuff LFSetupFPGAForADC(89, true);
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
//clear buffer now so it does not interfere with timing later //clear buffer now so it does not interfere with timing later
BigBuf_Clear_ext(false); 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 //send COTAG start pulse
ON(740) OFF ON(740) OFF(2035)
ON(3330) OFF ON(3330) OFF(2035)
ON(740) OFF ON(740) OFF(2035)
ON(1000) ON(1000)
switch(rawsignal) { switch(rawsignal) {

View file

@ -117,21 +117,21 @@ void LFSetupFPGAForADC(int divisor, bool lf_field) {
* @return the number of bits occupied by the samples. * @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) { 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(); uint8_t *dest = BigBuf_get_addr();
bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen(); bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen();
if (bits_per_sample < 1) bits_per_sample = 1; if (bits_per_sample < 1) bits_per_sample = 1;
if (bits_per_sample > 8) bits_per_sample = 8; if (bits_per_sample > 8) bits_per_sample = 8;
if (decimation < 1) decimation = 1; 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}; BitstreamOut data = { dest , 0, 0};
int sample_counter = 0; int sample_counter = 0;
uint8_t sample = 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_sum =0 ;
uint32_t sample_total_numbers = 0; uint32_t sample_total_numbers = 0;
uint32_t sample_total_saved = 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() ) { while (!BUTTON_PRESS() && !usb_poll_validate_length() ) {
WDT_HIT(); 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) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
// Testpoint 8 (TP8) can be used to trigger oscilliscope
LED_D_OFF(); LED_D_OFF();
// threshold either high or low values 128 = center 0. if trigger = 178 // 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 ((trigger_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) {
if (cancel_after > 0) { if (cancel_after > 0) {
@ -162,24 +162,26 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
if (averaging) if (averaging)
sample_sum += sample; sample_sum += sample;
//Check decimation // check decimation
if (decimation > 1) { if (decimation > 1) {
sample_counter++; sample_counter++;
if (sample_counter < decimation) continue; if (sample_counter < decimation) continue;
sample_counter = 0; sample_counter = 0;
} }
//Averaging // averaging
if (averaging && decimation > 1) { if (averaging && decimation > 1) {
sample = sample_sum / decimation; sample = sample_sum / decimation;
sample_sum =0; sample_sum =0;
} }
//Store the sample // store the sample
sample_total_saved ++; sample_total_saved ++;
if (bits_per_sample == 8){ if (bits_per_sample == 8) {
dest[sample_total_saved-1] = sample; 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; if (sample_total_saved >= bufsize) break;
} else { } 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 > 4) pushBit(&data, sample & 0x08);
if (bits_per_sample > 5) pushBit(&data, sample & 0x04); if (bits_per_sample > 5) pushBit(&data, sample & 0x04);
if (bits_per_sample > 6) pushBit(&data, sample & 0x02); 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) ) { while(!BUTTON_PRESS() && !usb_poll_validate_length() && skipCnt < 1000 && (i < bufsize) ) {
WDT_HIT(); 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) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
curSample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; curSample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
LED_D_OFF(); LED_D_OFF();
@ -352,10 +351,6 @@ void doCotagAcquisition(size_t sample_size) {
while (!BUTTON_PRESS() && !usb_poll_validate_length() && (i < bufsize) && (noise_counter < (COTAG_T1 << 1)) ) { while (!BUTTON_PRESS() && !usb_poll_validate_length() && (i < bufsize) && (noise_counter < (COTAG_T1 << 1)) ) {
WDT_HIT(); 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) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
@ -407,10 +402,6 @@ uint32_t doCotagAcquisitionManchester() {
while (!BUTTON_PRESS() && !usb_poll_validate_length() && (sample_counter < bufsize) && (noise_counter < (COTAG_T1 << 1)) ) { while (!BUTTON_PRESS() && !usb_poll_validate_length() && (sample_counter < bufsize) && (noise_counter < (COTAG_T1 << 1)) ) {
WDT_HIT(); 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) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;

View file

@ -17,7 +17,7 @@
#include <inttypes.h> #include <inttypes.h>
#ifndef HARDNESTED_AUTHENTICATION_TIMEOUT #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 #endif
#ifndef HARDNESTED_PRE_AUTHENTICATION_LEADTIME #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 # 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) { 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++) { for (uint8_t s = 0; s < *sectorcnt; s++) {
// skip already found A keys // 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; continue;
c->block = FirstBlockOfSector( s ); c->block = FirstBlockOfSector( s );
status = chkKey( c ); if ( chkKey( c ) == 0 ) {
if ( status == 0 ) {
num_to_bytes(c->key, 6, k_sector[s].keyA); num_to_bytes(c->key, 6, k_sector[s].keyA);
found[(s*2)] = 1; found[(s*2)] = 1;
++*foundkeys; ++*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) { 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++) { for (uint8_t s = 0; s < *sectorcnt; s++) {
// skip already found B keys // 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; continue;
c->block = FirstBlockOfSector( s ); c->block = FirstBlockOfSector( s );
status = chkKey( c ); if ( chkKey( c ) == 0 ) {
if ( status == 0 ) {
num_to_bytes(c->key, 6, k_sector[s].keyB); num_to_bytes(c->key, 6, k_sector[s].keyB);
found[(s*2)+1] = 1; found[(s*2)+1] = 1;
++*foundkeys; ++*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. // read Block B, if A is found.
for (uint8_t s = 0; s < *sectorcnt; ++s) { for (uint8_t s = 0; s < *sectorcnt; ++s) {
if ( found[(s*2)] && found[(s*2)+1] )
continue;
c->block = (FirstBlockOfSector( s ) + NumBlocksPerSector( s ) - 1); c->block = (FirstBlockOfSector( s ) + NumBlocksPerSector( s ) - 1);
// A but not B // A but not B
if ( found[(s*2)] && !found[(s*2)+1] ){ if ( found[(s*2)] && !found[(s*2)+1] ){
c->key = bytes_to_num(k_sector[s].keyA, 6); 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. // get Chunks of keys, to test authentication against card.
// arg0 = antal sectorer // arg0 = antal sectorer
// arg0 = first time // 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 firstchunk = (arg0 >> 8) & 0xF;
uint8_t lastchunk = (arg0 >> 12) & 0xF; uint8_t lastchunk = (arg0 >> 12) & 0xF;
uint8_t strategy = arg1 & 0xFF; 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; uint8_t status = 0;
struct Crypto1State mpcs = {0, 0}; struct Crypto1State mpcs = {0, 0};
@ -1217,21 +1222,43 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
static uint8_t found[80]; static uint8_t found[80];
static uint8_t *uid; 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) { if (uid == NULL || firstchunk) {
uid = BigBuf_malloc(10); uid = BigBuf_malloc(10);
if (uid == NULL ) { if (uid == NULL )
if (MF_DBGLEVEL >= 3) Dbprintf("ChkKeys: uid malloc failed");
goto OUT; goto OUT;
}
} }
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
LEDsoff(); LEDsoff();
LED_A_ON(); LED_A_ON();
if ( firstchunk ) { if ( firstchunk ) {
clear_trace(); clear_trace();
set_tracing(false); set_tracing(false);
@ -1241,9 +1268,10 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
iso14a_card_select_t card_info; iso14a_card_select_t card_info;
if ( !iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) { 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; goto OUT;
} }
switch (card_info.uidlen) { switch (card_info.uidlen) {
case 4 : cascade_levels = 1; break; case 4 : cascade_levels = 1; break;
case 7 : cascade_levels = 2; break; case 7 : cascade_levels = 2; break;
@ -1262,10 +1290,12 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
chk_data.block = 0; chk_data.block = 0;
// keychunk loop - depth first one sector. // keychunk loop - depth first one sector.
if ( strategy == 1 ) { if ( strategy == 1 || use_flashmem) {
uint8_t newfound = foundkeys; uint8_t newfound = foundkeys;
uint16_t lastpos = 0;
uint16_t s_point = 0;
// Sector main loop // Sector main loop
// keep track of how many sectors on card. // keep track of how many sectors on card.
for (uint8_t s = 0; s < sectorcnt; ++s) { for (uint8_t s = 0; s < sectorcnt; ++s) {
@ -1273,7 +1303,9 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
if ( found[(s*2)] && found[(s*2)+1] ) if ( found[(s*2)] && found[(s*2)+1] )
continue; 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 // Allow button press / usb cmd to interrupt device
if (BUTTON_PRESS() && !usb_poll_validate_length()) { if (BUTTON_PRESS() && !usb_poll_validate_length()) {
@ -1292,8 +1324,6 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
// new key // new key
chk_data.key = bytes_to_num(datain + i * 6, 6); 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 // skip already found A keys
if( !found[(s*2)] ) { if( !found[(s*2)] ) {
chk_data.keyType = 0; chk_data.keyType = 0;
@ -1308,7 +1338,21 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
// read Block B, if A is found. // read Block B, if A is found.
chkKey_loopBonly( &chk_data, k_sector, found, &sectorcnt, &foundkeys); chkKey_loopBonly( &chk_data, k_sector, found, &sectorcnt, &foundkeys);
chk_data.keyType = 1;
chkKey_scanB(&chk_data, k_sector, found, &sectorcnt, &foundkeys);
chk_data.keyType = 0;
chk_data.block = FirstBlockOfSector( s ); 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; ++foundkeys;
chkKey_scanB(&chk_data, k_sector, found, &sectorcnt, &foundkeys); chkKey_scanB(&chk_data, k_sector, found, &sectorcnt, &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 } // end keys test loop - depth first
// assume1. if no keys found in first sector, get next keychunk from client // 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; goto OUT;
} // end loop - sector } // end loop - sector
} // end strategy 1 } // end strategy 1
if ( strategy == 2 ) { if ( foundkeys == allkeys )
goto OUT;
if ( strategy == 2 || use_flashmem ) {
// Keychunk loop // 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 // Allow button press / usb cmd to interrupt device
if (BUTTON_PRESS() && !usb_poll_validate_length()) break; if (BUTTON_PRESS() && !usb_poll_validate_length()) break;
// found all keys?
if ( foundkeys == allkeys )
goto OUT;
WDT_HIT(); WDT_HIT();
// new key // new key
@ -1350,6 +1415,8 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
// keep track of how many sectors on card. // keep track of how many sectors on card.
for (uint8_t s = 0; s < sectorcnt; ++s) { for (uint8_t s = 0; s < sectorcnt; ++s) {
if ( found[(s*2)] && found[(s*2)+1] ) continue;
// found all keys? // found all keys?
if ( foundkeys == allkeys ) if ( foundkeys == allkeys )
goto OUT; goto OUT;
@ -1387,8 +1454,6 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
chkKey_scanB(&chk_data, k_sector, found, &sectorcnt, &foundkeys); chkKey_scanB(&chk_data, k_sector, found, &sectorcnt, &foundkeys);
} }
} }
} // end loop sectors } // end loop sectors
} // end loop keys } // end loop keys
} // end loop strategy 2 } // end loop strategy 2
@ -1401,17 +1466,22 @@ OUT:
if (foundkeys == allkeys || lastchunk ) { if (foundkeys == allkeys || lastchunk ) {
uint64_t foo = 0; uint64_t foo = 0;
for (uint8_t m = 0; m < 64; m++) {
foo |= ((uint64_t)(found[m] & 1) << m);
}
uint16_t bar = 0; uint16_t bar = 0;
for (uint8_t m = 0; m < 64; ++m) uint8_t j = 0;
foo |= (found[m] << m); for (uint8_t m=64; m < sizeof(found); m++) {
for (uint8_t m=64; m < sizeof(found); ++m) bar |= ((uint16_t)(found[m] & 1) << j++);
bar |= (found[m] << (m-64)); }
uint8_t *tmp = BigBuf_malloc(480+10); uint8_t *tmp = BigBuf_malloc(480+10);
memcpy(tmp, k_sector, sectorcnt * sizeof(sector_t) ); memcpy(tmp, k_sector, sectorcnt * sizeof(sector_t) );
num_to_bytes(foo, 8, tmp+480); num_to_bytes(foo, 8, tmp+480);
tmp[488] = bar & 0xFF; tmp[488] = bar & 0xFF;
tmp[489] = bar >> 8 & 0xFF; tmp[489] = bar >> 8 & 0xFF;
cmd_send(CMD_ACK, foundkeys, 0, 0, tmp, 480+10); cmd_send(CMD_ACK, foundkeys, 0, 0, tmp, 480+10);
set_tracing(false); set_tracing(false);

View file

@ -22,7 +22,7 @@
* *
* This is free software: you can redistribute it and/or modify * 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 * 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, * This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of

View file

@ -3,8 +3,7 @@
#define T0_PCF 8 //period for the pcf7931 in us #define T0_PCF 8 //period for the pcf7931 in us
#define ALLOC 16 #define ALLOC 16
int DemodPCF7931(uint8_t **outBlocks) { size_t DemodPCF7931(uint8_t **outBlocks) {
uint8_t bits[256] = {0x00}; uint8_t bits[256] = {0x00};
uint8_t blocks[8][16]; uint8_t blocks[8][16];
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
@ -18,7 +17,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
int tolerance = clock / 8; int tolerance = clock / 8;
int pmc, block_done; int pmc, block_done;
int lc, warnings = 0; int lc, warnings = 0;
int num_blocks = 0; size_t num_blocks = 0;
int lmin=128, lmax=128; int lmin=128, lmax=128;
uint8_t dir; uint8_t dir;
//clear read buffer //clear read buffer
@ -40,8 +39,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
i++; i++;
} }
dir = 0; dir = 0;
} } else {
else {
while(i < GraphTraceLen) { while(i < GraphTraceLen) {
if( !(dest[i] < dest[i-1]) && dest[i] < lmin) if( !(dest[i] < dest[i-1]) && dest[i] < lmin)
break; break;
@ -55,10 +53,8 @@ int DemodPCF7931(uint8_t **outBlocks) {
pmc = 0; pmc = 0;
block_done = 0; block_done = 0;
for (bitidx = 0; i < GraphTraceLen; i++) 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)) {
if ( (dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin))
{
lc = i - lastval; lc = i - lastval;
lastval = i; lastval = i;
@ -72,8 +68,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
lastval = i; lastval = i;
pmc = 0; pmc = 0;
block_done = 1; block_done = 1;
} } else {
else {
pmc = i; pmc = i;
} }
} else if (ABS(lc-clock/2) < tolerance) { } else if (ABS(lc-clock/2) < tolerance) {
@ -84,8 +79,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
lastval = i; lastval = i;
pmc = 0; pmc = 0;
block_done = 1; block_done = 1;
} } else if(half_switch == 1) {
else if(half_switch == 1) {
bits[bitidx++] = 0; bits[bitidx++] = 0;
half_switch = 0; half_switch = 0;
} }
@ -96,26 +90,25 @@ int DemodPCF7931(uint8_t **outBlocks) {
bits[bitidx++] = 1; bits[bitidx++] = 1;
} else { } else {
// Error // Error
warnings++; if (++warnings > 10) {
if (warnings > 10) Dbprintf("Error: too many detection errors, aborting.");
{
Dbprintf("Error: too many detection errors, aborting...");
return 0; return 0;
} }
} }
if(block_done == 1) { if(block_done == 1) {
if(bitidx == 128) { if(bitidx == 128) {
for(j=0; j<16; j++) { for(j = 0; j < 16; ++j) {
blocks[num_blocks][j] = 128*bits[j*8+7]+ blocks[num_blocks][j] =
128 * bits[j*8 + 7]+
64*bits[j*8+6]+ 64*bits[j*8+6]+
32*bits[j*8+5]+ 32*bits[j*8+5]+
16*bits[j*8+4]+ 16*bits[j*8+4]+
8*bits[j*8+3]+ 8*bits[j*8+3]+
4*bits[j*8+2]+ 4*bits[j*8+2]+
2*bits[j*8+1]+ 2*bits[j*8+1]+
bits[j*8]; bits[j*8]
;
} }
num_blocks++; num_blocks++;
} }
@ -135,185 +128,209 @@ int DemodPCF7931(uint8_t **outBlocks) {
return num_blocks; return num_blocks;
} }
int IsBlock0PCF7931(uint8_t *Block) { bool IsBlock0PCF7931(uint8_t *block) {
// Assume RFU means 0 :) // assuming all RFU bits are set to 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 // if PAC is enabled password is set to 0
return 1; if (block[7] == 0x01)
if((memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) && Block[7] == 0) // PAC disabled, can it *really* happen ? {
return 1; if (!memcmp(block, "\x00\x00\x00\x00\x00\x00\x00", 7) && !memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7))
return 0; 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) { bool IsBlock1PCF7931(uint8_t *block) {
// Assume RFU means 0 :) // assuming all RFU bits are set to 0
if( Block[10] == 0 && if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0)
Block[11] == 0 && if((block[14] & 0x7f) <= 9 && block[15] <= 9)
Block[12] == 0 && return true;
Block[13] == 0)
if ( (Block[14] & 0x7f) <= 9 && Block[15] <= 9) return false;
return 1;
return 0;
} }
void ReadPCF7931() { void ReadPCF7931() {
uint8_t Blocks[8][17]; int found_blocks = 0; // successfully read blocks
uint8_t tmpBlocks[4][16]; int max_blocks = 8; // readable blocks
int i, j, ind, ind2, n; uint8_t memory_blocks[8][17]; // PCF content
int num_blocks = 0;
int max_blocks = 8;
int ident = 0;
int error = 0;
int tries = 0;
memset(Blocks, 0, 8*17*sizeof(uint8_t)); uint8_t single_blocks[8][17]; // PFC blocks with unknown position
int single_blocks_cnt = 0;
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 { do {
memset(tmpBlocks, 0, 4*16*sizeof(uint8_t)); i = 0;
n = DemodPCF7931((uint8_t**)tmpBlocks);
memset(tmp_blocks, 0, 4*16*sizeof(uint8_t));
n = DemodPCF7931((uint8_t**)tmp_blocks);
if(!n) if(!n)
error++; ++errors;
if(error==10 && num_blocks == 0) {
// exit if no block is received
if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) {
Dbprintf("Error, no tag or bad tag"); Dbprintf("Error, no tag or bad tag");
return; 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("Error reading the tag");
Dbprintf("Here is the partial content"); Dbprintf("Here is the partial content");
goto end; goto end;
} }
for(i=0; i<n; i++) // our logic breaks if we don't get at least two blocks
Dbprintf("(dbg) %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", if (n < 2) {
tmpBlocks[i][0], tmpBlocks[i][1], tmpBlocks[i][2], tmpBlocks[i][3], tmpBlocks[i][4], tmpBlocks[i][5], tmpBlocks[i][6], tmpBlocks[i][7], if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
tmpBlocks[i][8], tmpBlocks[i][9], tmpBlocks[i][10], tmpBlocks[i][11], tmpBlocks[i][12], tmpBlocks[i][13], tmpBlocks[i][14], tmpBlocks[i][15]); continue;
if(!ident) {
for(i=0; i<n; i++) { if (single_blocks_cnt < max_blocks) {
if(IsBlock0PCF7931(tmpBlocks[i])) { for (i = 0; i < single_blocks_cnt; ++i) {
// Found block 0 ? if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) {
if(i < n-1 && IsBlock1PCF7931(tmpBlocks[i+1])) { j = 1;
// Found block 1!
// \o/
ident = 1;
memcpy(Blocks[0], tmpBlocks[i], 16);
Blocks[0][ALLOC] = 1;
memcpy(Blocks[1], tmpBlocks[i+1], 16);
Blocks[1][ALLOC] = 1;
max_blocks = MAX((Blocks[1][14] & 0x7f), Blocks[1][15]) + 1;
// Debug print
Dbprintf("(dbg) Max blocks: %d", max_blocks);
num_blocks = 2;
// Handle following blocks
for(j=i+2, ind2=2; j!=i; j++, ind2++, num_blocks++) {
if(j==n) j=0;
if(j==i) break;
memcpy(Blocks[ind2], tmpBlocks[j], 16);
Blocks[ind2][ALLOC] = 1;
}
break; break;
} }
} }
if (j != 1) {
memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16);
single_blocks_cnt++;
}
j = 0;
} }
} ++tries;
else { continue;
for(i=0; i<n; i++) { // Look for identical block in known blocks }
if(memcmp(tmpBlocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) { // Block is not full of 00
for(j=0; j<max_blocks; j++) { Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors);
if(Blocks[j][ALLOC] == 1 && !memcmp(tmpBlocks[i], Blocks[j], 16)) {
// Found an identical block i = 0;
for(ind=i-1,ind2=j-1; ind >= 0; ind--,ind2--) { if(!found_0_1) {
if(ind2 < 0) while (i < n - 1) {
ind2 = max_blocks; if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i+1])) {
if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found found_0_1 = 1;
// Dbprintf("Tmp %d -> Block %d", ind, ind2); memcpy(memory_blocks[0], tmp_blocks[i], 16);
memcpy(Blocks[ind2], tmpBlocks[ind], 16); memcpy(memory_blocks[1], tmp_blocks[i+1], 16);
Blocks[ind2][ALLOC] = 1; memory_blocks[0][ALLOC] = memory_blocks[1][ALLOC] = 1;
num_blocks++; // block 1 tells how many blocks are going to be sent
if(num_blocks == max_blocks) goto end; max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1;
} found_blocks = 2;
}
for(ind=i+1,ind2=j+1; ind < n; ind++,ind2++) { Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks);
if(ind2 > max_blocks)
ind2 = 0; // handle the following blocks
if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found for (j = i + 2; j < n; ++j) {
// Dbprintf("Tmp %d -> Block %d", ind, ind2); memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16);
memcpy(Blocks[ind2], tmpBlocks[ind], 16); memory_blocks[found_blocks][ALLOC] = 1;
Blocks[ind2][ALLOC] = 1; ++found_blocks;
num_blocks++; }
if(num_blocks == max_blocks) goto end; 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++; ++tries;
if (BUTTON_PRESS()) return; if (BUTTON_PRESS()) {
} while (num_blocks != max_blocks); Dbprintf("Button pressed, stopping.");
goto end;
}
}
while (found_blocks != max_blocks);
end: end:
Dbprintf("-----------------------------------------"); Dbprintf("-----------------------------------------");
Dbprintf("Memory content:"); Dbprintf("Memory content:");
Dbprintf("-----------------------------------------"); Dbprintf("-----------------------------------------");
for(i=0; i<max_blocks; i++) { for (i = 0; i < max_blocks; ++i) {
if(Blocks[i][ALLOC]==1) if (memory_blocks[i][ALLOC])
Dbprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", print_result("Block", memory_blocks[i], 16);
Blocks[i][0], Blocks[i][1], Blocks[i][2], Blocks[i][3], Blocks[i][4], Blocks[i][5], Blocks[i][6], Blocks[i][7],
Blocks[i][8], Blocks[i][9], Blocks[i][10], Blocks[i][11], Blocks[i][12], Blocks[i][13], Blocks[i][14], Blocks[i][15]);
else else
Dbprintf("<missing block %d>", i); Dbprintf("<missing block %d>", i);
} }
Dbprintf("-----------------------------------------"); 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); cmd_send(CMD_ACK,0,0,0,0,0);
} }
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) {
/* 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)
{
uint32_t tab[1024] = {0}; // data times frame uint32_t tab[1024] = {0}; // data times frame
uint32_t u = 0; uint32_t u = 0;
uint8_t parity = 0; uint8_t parity = 0;
bool comp = 0; bool comp = 0;
//BUILD OF THE DATA FRAME //BUILD OF THE DATA FRAME
//alimentation of the tag (time for initializing) //alimentation of the tag (time for initializing)
AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab); 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); 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 //password indication bit
AddBitPCF7931(1, tab, l, p); AddBitPCF7931(1, tab, l, p);
//password (on 56 bits) //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(pass[0], tab, l, p);
AddBytePCF7931(pass1, tab, l, p); AddBytePCF7931(pass[1], tab, l, p);
AddBytePCF7931(pass2, tab, l, p); AddBytePCF7931(pass[2], tab, l, p);
AddBytePCF7931(pass3, tab, l, p); AddBytePCF7931(pass[3], tab, l, p);
AddBytePCF7931(pass4, tab, l, p); AddBytePCF7931(pass[4], tab, l, p);
AddBytePCF7931(pass5, tab, l, p); AddBytePCF7931(pass[5], tab, l, p);
AddBytePCF7931(pass6, tab, l, p); AddBytePCF7931(pass[6], tab, l, p);
AddBytePCF7931(pass7, tab, l, p);
//programming mode (0 or 1) //programming mode (0 or 1)
AddBitPCF7931(0, tab, l, p); AddBitPCF7931(0, tab, l, p);
//block adress on 6 bits //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<<u)) { // bit 1 if (address&(1<<u)) { // bit 1
parity++; ++parity;
AddBitPCF7931(1, tab, l, p); AddBitPCF7931(1, tab, l, p);
} else{ // bit 0 } else{ // bit 0
AddBitPCF7931(0, tab, l, p); AddBitPCF7931(0, tab, l, p);
@ -321,59 +338,70 @@ void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, ui
} }
//byte address on 4 bits //byte address on 4 bits
Dbprintf("Byte address : %02x", byte); for (u = 0; u < 4; ++u)
for (u=0; u<4; u++)
{ {
if (byte&(1<<u)) { // bit 1 if (byte&(1<<u)) { // bit 1
parity++; parity++;
AddBitPCF7931(1, tab, l, p); AddBitPCF7931(1, tab, l, p);
} else{ // bit 0
AddBitPCF7931(0, tab, l, p);
} }
else // bit 0
AddBitPCF7931(0, tab, l, p);
} }
//data on 8 bits //data on 8 bits
Dbprintf("Data : %02x", data);
for (u=0; u<8; u++) for (u=0; u<8; u++)
{ {
if (data&(1<<u)) { // bit 1 if (data&(1<<u)) { // bit 1
parity++; parity++;
AddBitPCF7931(1, tab, l, p); AddBitPCF7931(1, tab, l, p);
} else{ //bit 0 }
else //bit 0
AddBitPCF7931(0, tab, l, p); AddBitPCF7931(0, tab, l, p);
} }
}
//parity bit //parity bit
if((parity%2)==0){ if ((parity % 2) == 0)
AddBitPCF7931(0, tab, l, p); //even parity AddBitPCF7931(0, tab, l, p); //even parity
}else{ else
AddBitPCF7931(1, tab, l, p);//odd parity AddBitPCF7931(1, tab, l, p);//odd parity
}
//time access memory //time access memory
AddPatternPCF7931(5120+2680, 0, 0, tab); AddPatternPCF7931(5120+2680, 0, 0, tab);
//conversion of the scale time //conversion of the scale time
for(u=0;u<500;u++){ for (u = 0; u < 500; ++u)
tab[u]=(tab[u] * 3)/2; tab[u]=(tab[u] * 3)/2;
}
//compensation of the counter reload //compensation of the counter reload
while (!comp){ while (!comp){
comp = 1; comp = 1;
for(u=0;tab[u]!=0;u++){ for (u = 0; tab[u] != 0; ++u)
if(tab[u] > 0xFFFF){ if(tab[u] > 0xFFFF){
tab[u] -= 0xFFFF; tab[u] -= 0xFFFF;
comp = 0; comp = 0;
} }
} }
}
SendCmdPCF7931(tab); 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 /* Send a trame to a PCF7931 tags
@ -386,9 +414,7 @@ void SendCmdPCF7931(uint32_t * tab){
Dbprintf("Sending data frame..."); Dbprintf("Sending data frame...");
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU ); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU );
LED_A_ON(); LED_A_ON();
@ -405,21 +431,22 @@ void SendCmdPCF7931(uint32_t * tab){
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
AT91C_BASE_TCB->TCB_BCR = 1; AT91C_BASE_TCB->TCB_BCR = 1;
tempo = AT91C_BASE_TC0->TC_CV; tempo = AT91C_BASE_TC0->TC_CV;
for( u = 0; tab[u] != 0; u += 3){ for( u = 0; tab[u] != 0; u += 3){
// modulate antenna // modulate antenna
HIGH(GPIO_SSC_DOUT); 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 // stop modulating antenna
LOW(GPIO_SSC_DOUT); 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 // modulate antenna
HIGH(GPIO_SSC_DOUT); 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(); LED_A_OFF();
@ -437,18 +464,16 @@ void SendCmdPCF7931(uint32_t * tab){
* @param l : offset on low pulse width * @param l : offset on low pulse width
* @param p : offset on low pulse positioning * @param p : offset on low pulse positioning
*/ */
bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p){ bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p){
uint32_t u; uint32_t u;
for ( u=0; u<8; u++) for (u = 0; u < 8; ++u) {
{ if (byte & (1 << u)) { //bit is 1
if (byte&(1<<u)) { //bit à 1
if( AddBitPCF7931(1, tab, l, p)==1) return 1; if( AddBitPCF7931(1, tab, l, p)==1) return 1;
} else { //bit à 0 } else { //bit is 0
if (AddBitPCF7931(0, tab, l, p)==1) return 1; if (AddBitPCF7931(0, tab, l, p)==1) return 1;
} }
} }
return 0; return 0;
} }

View file

@ -7,9 +7,9 @@
#include "pcf7931.h" #include "pcf7931.h"
#include "string.h" #include "string.h"
int DemodPCF7931(uint8_t **outBlocks); size_t DemodPCF7931(uint8_t **outBlocks);
int IsBlock0PCF7931(uint8_t *Block); bool IsBlock0PCF7931(uint8_t *Block);
int IsBlock1PCF7931(uint8_t *Block); bool IsBlock1PCF7931(uint8_t *Block);
void ReadPCF7931(); void ReadPCF7931();
void SendCmdPCF7931(uint32_t * tab); void SendCmdPCF7931(uint32_t * tab);
bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p); bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p);

View file

@ -1,77 +0,0 @@
#include <tlv.h>
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;
}

View file

@ -1,33 +0,0 @@
#ifndef __TLV_H
#define __TLV_H
#include <stdint.h>
#include <string.h>
#include <stddef.h>
//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

View file

@ -25,6 +25,10 @@ VERSIONSRC = version.c
# stdint.h provided locally until GCC 4.5 becomes C99 compliant # stdint.h provided locally until GCC 4.5 becomes C99 compliant
APP_CFLAGS = -I. -fno-strict-aliasing -ffunction-sections -fdata-sections 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 # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
include ../common/Makefile.common include ../common/Makefile.common

View file

@ -108,7 +108,7 @@ CORESRCS = uart_posix.c \
CMDSRCS = crapto1/crapto1.c \ CMDSRCS = crapto1/crapto1.c \
crapto1/crypto1.c \ crapto1/crypto1.c \
mfkey.c \ mifare/mfkey.c \
tea.c \ tea.c \
fido/additional_ca.c \ fido/additional_ca.c \
fido/cose.c \ fido/cose.c \
@ -126,7 +126,7 @@ CMDSRCS = crapto1/crapto1.c \
loclass/elite_crack.c \ loclass/elite_crack.c \
loclass/fileutils.c \ loclass/fileutils.c \
whereami.c \ whereami.c \
mifarehost.c \ mifare/mifarehost.c \
parity.c \ parity.c \
crc.c \ crc.c \
crc16.c \ crc16.c \
@ -155,7 +155,9 @@ CMDSRCS = crapto1/crapto1.c \
emv/test/dda_test.c\ emv/test/dda_test.c\
emv/test/cda_test.c\ emv/test/cda_test.c\
emv/cmdemv.c \ emv/cmdemv.c \
mifare4.c \ emv/emv_roca.c \
mifare/mifare4.c \
mifare/mad.c \
cmdanalyse.c \ cmdanalyse.c \
cmdhf.c \ cmdhf.c \
cmdhflist.c \ cmdhflist.c \
@ -186,6 +188,7 @@ CMDSRCS = crapto1/crapto1.c \
cmdlfio.c \ cmdlfio.c \
cmdlfindala.c \ cmdlfindala.c \
cmdlfjablotron.c \ cmdlfjablotron.c \
cmdlfkeri.c \
cmdlfnexwatch.c \ cmdlfnexwatch.c \
cmdlfnedap.c \ cmdlfnedap.c \
cmdlfnoralsy.c \ cmdlfnoralsy.c \
@ -298,29 +301,29 @@ lualibs/mf_default_keys.lua : default_keys.dic
clean: clean:
$(RM) $(CLEAN) $(RM) $(CLEAN)
cd ../liblua && make clean cd ../liblua && $(MAKE) clean
cd $(JANSSONLIBPATH) && make clean cd $(JANSSONLIBPATH) && $(MAKE) clean
cd $(MBEDTLSLIBPATH) && make clean cd $(MBEDTLSLIBPATH) && $(MAKE) clean
cd $(CBORLIBPATH) && make clean cd $(CBORLIBPATH) && $(MAKE) clean
tarbin: $(BINS) tarbin: $(BINS)
$(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%) $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%)
lua_build: lua_build:
@echo Compiling liblua, using platform $(LUAPLATFORM) @echo Compiling liblua, using platform $(LUAPLATFORM)
cd ../liblua && make $(LUAPLATFORM) cd ../liblua && $(MAKE) $(LUAPLATFORM)
jansson_build: jansson_build:
@echo Compiling jansson @echo Compiling jansson
cd $(JANSSONLIBPATH) && make all cd $(JANSSONLIBPATH) && $(MAKE) all
mbedtls_build: mbedtls_build:
@echo Compiling mbedtls @echo Compiling mbedtls
cd $(MBEDTLSLIBPATH) && make all cd $(MBEDTLSLIBPATH) && $(MAKE) all
cbor_build: cbor_build:
@echo Compiling tinycbor @echo Compiling tinycbor
cd $(CBORLIBPATH) && make all cd $(CBORLIBPATH) && $(MAKE) all
.PHONY: all clean .PHONY: all clean

1
client/aidlist.json Normal file

File diff suppressed because one or more lines are too long

21
client/amiitool/LICENSE Normal file
View file

@ -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.

180
client/amiitool/amiibo.c Normal file
View file

@ -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);
}

32
client/amiitool/amiibo.h Normal file
View file

@ -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 <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#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

175
client/amiitool/amiitool.c Normal file
View file

@ -0,0 +1,175 @@
/*
* (c) 2015-2017 Marcos Del Sol Vives
* (c) 2016 javiMaD
*
* SPDX-License-Identifier: MIT
*/
#include <amiibo.h>
#include <stdio.h>
#include <string.h>
#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 <marcos@dracon.es>\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;
}

78
client/amiitool/drbg.c Normal file
View file

@ -0,0 +1,78 @@
/*
* (c) 2015-2017 Marcos Del Sol Vives
* (c) 2016 javiMaD
*
* SPDX-License-Identifier: MIT
*/
#include "drbg.h"
#include <assert.h>
#include <string.h>
#include <mbedtls/md.h>
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);
}

33
client/amiitool/drbg.h Normal file
View file

@ -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 <stdbool.h>
#include <stdint.h>
#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

Binary file not shown.

53
client/amiitool/keygen.c Normal file
View file

@ -0,0 +1,53 @@
/*
* (c) 2015-2017 Marcos Del Sol Vives
*
* SPDX-License-Identifier: MIT
*/
#include "drbg.h"
#include "keygen.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
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));
}

34
client/amiitool/keygen.h Normal file
View file

@ -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 <stdint.h>
#include <stdbool.h>
#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

View file

@ -16,15 +16,15 @@
#include <unistd.h> #include <unistd.h>
#include "cmdmain.h" #include "cmdmain.h"
#include "proxmark3.h" #include "proxmark3.h"
#include "ui.h" // PrintAndLog #include "ui.h" // PrintAndLog
#include "util.h" #include "util.h"
#include "crc.h" #include "crc.h"
#include "crc16.h" // crc16 ccitt #include "crc16.h" // crc16 ccitt
#include "tea.h" #include "tea.h"
#include "legic_prng.h" #include "legic_prng.h"
#include "loclass/elite_crack.h" #include "loclass/elite_crack.h"
#include "mfkey.h" //nonce2key #include "mifare/mfkey.h" //nonce2key
#include "util_posix.h" // msclock #include "util_posix.h" // msclock
int usage_analyse_lcr(void); int usage_analyse_lcr(void);

View file

@ -39,8 +39,7 @@ int split(char *str, char *arr[MAX_ARGS]){
return wordCnt; return wordCnt;
} }
int CmdCrc(const char *Cmd) int CmdCrc(const char *Cmd) {
{
char name[] = {"reveng "}; char name[] = {"reveng "};
char Cmd2[100 + 7]; char Cmd2[100 + 7];
memcpy(Cmd2, name, 7); memcpy(Cmd2, name, 7);
@ -198,6 +197,11 @@ int GetModels(char *Models[], int *count, uint8_t *width){
pfree(qptr); 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)){ if (!(model.flags & P_REFIN) != !(model.flags & P_REFOUT)){
PrintAndLogEx(WARNING, "cannot search for crossed-endian models"); PrintAndLogEx(WARNING, "cannot search for crossed-endian models");
return 0; return 0;
@ -259,8 +263,9 @@ int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *res
SETBMP(); SETBMP();
//set model //set model
if (!(c = mbynam(&model, inModel))) { c = mbynam(&model, inModel);
PrintAndLogEx(WARNING, "error: preset model '%s' not found. Use reveng -D to list presets.", inModel); if (!c) {
PrintAndLogEx(WARNING, "error: preset model '%s' not found. Use reveng -D to list presets. [%d]", inModel, c);
return 0; return 0;
} }
if (c < 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) // takes hex string in and searches for a matching result (hex string must include checksum)
int CmdrevengSearch(const char *Cmd){ int CmdrevengSearch(const char *Cmd){
#define NMODELS 103 #define NMODELS 105
char inHexStr[100] = {0x00}; char inHexStr[100] = {0x00};
int dataLen = param_getstr(Cmd, 0, inHexStr, sizeof(inHexStr)); 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)); char *outHex = calloc(dataLen-crcChars+1, sizeof(char));
memcpy(outHex, inHexStr, dataLen-crcChars); 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); ans = RunModel(Models[i], outHex, false, 0, result);
if (ans) { if (ans) {
// test for match // test for match

View file

@ -755,18 +755,52 @@ int AutoCorrelate(const int *in, int *out, size_t len, int window, bool SaveGrph
} }
} }
if (verbose && ( correlation > 1 ) ) { //
PrintAndLogEx(SUCCESS, "possible correlation %4d samples", correlation); int hi = 0, idx = 0;
} else { int distance = 0, hi_1 = 0, idx_1 = 0;
PrintAndLogEx(FAILED, "no repeating pattern found"); 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; //GraphTraceLen = GraphTraceLen - window;
memcpy(out, CorrelBuffer, len * sizeof(int)); 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(); RepaintGraphWindow();
} }
return correlation;
return retval;
} }
int CmdAutoCorr(const char *Cmd) { int CmdAutoCorr(const char *Cmd) {
@ -1461,6 +1495,13 @@ int CmdTuneSamples(const char *Cmd) {
#define HF_UNUSABLE_V 3000 #define HF_UNUSABLE_V 3000
#define HF_MARGINAL_V 5000 #define HF_MARGINAL_V 5000
#define ANTENNA_ERROR 1.03 // current algo has 3% error margin. #define ANTENNA_ERROR 1.03 // current algo has 3% error margin.
// hide demod plot line
DemodBufferLen = 0;
setClockGrid(0, 0);
RepaintGraphWindow();
int timeout = 0; int timeout = 0;
PrintAndLogEx(INFO, "\nmeasuring antenna characteristics, please wait..."); 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"); PrintAndLogEx(FAILED, "\nNot showing LF tuning graph since all values is zero.\n\n");
} }
return 0; return 0;
} }
@ -1786,7 +1828,7 @@ int Cmdbin2hex(const char *Cmd) {
//Number of digits supplied as argument //Number of digits supplied as argument
size_t length = en - bg + 1; size_t length = en - bg + 1;
size_t bytelen = (length+7) / 8; 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); memset(arr, 0, bytelen);
BitstreamOut bout = { arr, 0, 0 }; BitstreamOut bout = { arr, 0, 0 };

View file

@ -7,10 +7,13 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Proxmark3 RDV40 Flash memory commands // Proxmark3 RDV40 Flash memory commands
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#ifdef WITH_FLASH
#include "cmdflashmem.h" #include "cmdflashmem.h"
#include "mbedtls/rsa.h" #include "mbedtls/rsa.h"
#include "mbedtls/sha1.h" #include "mbedtls/sha1.h"
#include "mbedtls/base64.h"
#define MCK 48000000 #define MCK 48000000
//#define FLASH_BAUD 24000000 //#define FLASH_BAUD 24000000
@ -50,13 +53,19 @@ int usage_flashmem_read(void){
} }
int usage_flashmem_load(void){ int usage_flashmem_load(void){
PrintAndLogEx(NORMAL, "Loads binary file into flash memory on device"); PrintAndLogEx(NORMAL, "Loads binary file into flash memory on device");
PrintAndLogEx(NORMAL, "Usage: mem load o <offset> f <file name>"); PrintAndLogEx(NORMAL, "Usage: mem load o <offset> f <file name> m t i");
PrintAndLogEx(NORMAL, " o <offset> : offset in memory"); PrintAndLogEx(NORMAL, " o <offset> : offset in memory");
PrintAndLogEx(NORMAL, " f <filename> : file name"); PrintAndLogEx(NORMAL, " f <filename> : 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, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " mem load f myfile"); // upload file myfile at default offset 0 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 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; return 0;
} }
int usage_flashmem_save(void){ int usage_flashmem_save(void){
@ -155,6 +164,7 @@ int CmdFlashMemLoad(const char *Cmd){
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
bool errors = false; bool errors = false;
uint8_t cmdp = 0; uint8_t cmdp = 0;
Dictionary_t d = DICTIONARY_NONE;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) { switch (tolower(param_getchar(Cmd, cmdp))) {
@ -172,6 +182,18 @@ int CmdFlashMemLoad(const char *Cmd){
start_index = param_get32ex(Cmd, cmdp+1, 0, 10); start_index = param_get32ex(Cmd, cmdp+1, 0, 10);
cmdp += 2; 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: default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true; errors = true;
@ -182,19 +204,59 @@ int CmdFlashMemLoad(const char *Cmd){
//Validations //Validations
if (errors || cmdp == 0 ) return usage_flashmem_load(); if (errors || cmdp == 0 ) return usage_flashmem_load();
uint8_t *data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t));
size_t datalen = 0; size_t datalen = 0;
int res = loadFile(filename, "bin", data, &datalen); uint16_t keycount = 0;
//int res = loadFileEML( filename, "eml", data, &datalen); int res = 0;
if ( res ) { uint8_t *data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t));
free(data);
return 1;
}
if (datalen > FLASH_MEM_MAX_SIZE) { switch (d) {
PrintAndLogDevice(WARNING, "error, filesize is larger than available memory"); case DICTIONARY_MIFARE:
free(data); start_index = DEFAULT_MF_KEYS_OFFSET;
return 1; 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); data = realloc(data, datalen);
@ -544,3 +606,5 @@ int CmdHelp(const char *Cmd) {
CmdsHelp(CommandTable); CmdsHelp(CommandTable);
return 0; return 0;
} }
#endif

View file

@ -8,6 +8,8 @@
// Proxmark3 RDV40 Flash memory commands // Proxmark3 RDV40 Flash memory commands
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#ifdef WITH_FLASH
#ifndef CMDFLASHMEM_H__ #ifndef CMDFLASHMEM_H__
#define CMDFLASHMEM_H__ #define CMDFLASHMEM_H__
@ -24,6 +26,13 @@
#include "loclass/fileutils.h" //saveFile #include "loclass/fileutils.h" //saveFile
#include "comms.h" //getfromdevice #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 CmdFlashMem(const char *Cmd);
extern int CmdFlashMemRead(const char* cmd); extern int CmdFlashMemRead(const char* cmd);
@ -32,3 +41,5 @@ extern int CmdFlashMemSave(const char* cmd);
extern int CmdFlashMemWipe(const char *Cmd); extern int CmdFlashMemWipe(const char *Cmd);
extern int CmdFlashMemInfo(const char *Cmd); extern int CmdFlashMemInfo(const char *Cmd);
#endif #endif
#endif

View file

@ -1,6 +1,6 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
// 2011, 2017 Merlok // 2011, 2017 - 2019 Merlok
// 2014, Peter Fillmore // 2014, Peter Fillmore
// 2015, 2016, 2017 Iceman // 2015, 2016, 2017 Iceman
// //
@ -12,6 +12,8 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdhf14a.h" #include "cmdhf14a.h"
bool APDUInFramingEnable = true;
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static int waitCmd(uint8_t iLen); static int waitCmd(uint8_t iLen);
@ -147,6 +149,10 @@ char* getTagInfo(uint8_t uid) {
return manufactureMapping[len-1].desc; 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) { 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 or 10 byte UID\n");
PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 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"); PrintAndLogEx(NORMAL, " n test for nack bug");
return 0; return 0;
} }
int usage_hf_14a_antifuzz(void) {
PrintAndLogEx(NORMAL, "Usage: hf 14a antifuzz [4|7|10]");
PrintAndLogEx(NORMAL, " <len> determine which anticollision phase the command will target.");
return 0;
}
int CmdHF14AList(const char *Cmd) { int CmdHF14AList(const char *Cmd) {
//PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list 14a' instead"); //PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list 14a' instead");
@ -491,10 +492,7 @@ int CmdHF14AInfo(const char *Cmd) {
(tb1 ? "" : " NOT"), (tb1 ? "" : " NOT"),
(tc1 ? "" : " NOT"), (tc1 ? "" : " NOT"),
fsci, fsci,
fsci < 5 ? (fsci - 2) * 8 : fsci < sizeof(atsFSC) ? atsFSC[fsci] : -1
fsci < 8 ? (fsci - 3) * 32 :
fsci == 8 ? 256 :
-1
); );
} }
pos = 2; pos = 2;
@ -581,11 +579,11 @@ int CmdHF14AInfo(const char *Cmd) {
if (isMifareClassic) { if (isMifareClassic) {
int res = detect_classic_prng(); int res = detect_classic_prng();
if ( res == 1 ) if ( res == 1 )
PrintAndLogEx(SUCCESS, "Prng detection: WEAK"); PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_(WEAK));
else if (res == 0 ) else if (res == 0 )
PrintAndLogEx(SUCCESS, "Prng detection: HARD"); PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_(HARD));
else else
PrintAndLogEx(FAILED, "prng detection: failed"); PrintAndLogEx(FAILED, "prng detection: " _RED_(failed));
if ( do_nack_test ) if ( do_nack_test )
detect_classic_nackbug(silent); detect_classic_nackbug(silent);
@ -841,15 +839,90 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
return 0; return 0;
} }
int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chaining) { int SelectCard14443_4(bool disconnect, iso14a_card_select_t *card) {
uint16_t cmdc = 0; UsbCommand resp;
*chaining = false; frameLength = 0;
if (card)
memset(card, 0, sizeof(iso14a_card_select_t));
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) { if (activateField) {
cmdc |= ISO14A_CONNECT; // 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 // "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 // https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size
// here length USB_CMD_DATA_SIZE=512 // 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; uint8_t *recv;
UsbCommand resp; 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)) { if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
recv = resp.d.asBytes; recv = resp.d.asBytes;
int iLen = resp.arg[0]; int iLen = resp.arg[0];
@ -888,13 +949,20 @@ int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t
return 2; return 2;
} }
// I-block ACK
if ((res & 0xf2) == 0xa2) {
*dataoutlen = 0;
*chainingout = true;
return 0;
}
if(!iLen) { if(!iLen) {
PrintAndLogEx(ERR, "APDU: No APDU response."); PrintAndLogEx(ERR, "APDU: No APDU response.");
return 1; return 1;
} }
// check apdu length // check apdu length
if (iLen < 4 && iLen >= 0) { if (iLen < 2 && iLen >= 0) {
PrintAndLogEx(ERR, "APDU: Small APDU response. Len=%d", iLen); PrintAndLogEx(ERR, "APDU: Small APDU response. Len=%d", iLen);
return 2; return 2;
} }
@ -909,7 +977,7 @@ int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t
// chaining // chaining
if ((res & 0x10) != 0) { if ((res & 0x10) != 0) {
*chaining = true; *chainingout = true;
} }
// CRC Check // 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) { int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
*dataoutlen = 0; *dataoutlen = 0;
bool chaining = false; bool chaining = false;
int res;
int res = CmdExchangeAPDU(datain, datainlen, activateField, dataout, maxdataoutlen, dataoutlen, &chaining); // 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) { while (chaining) {
// I-block with 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 (res) {
if (!leaveSignalON) if (!leaveSignalON)
@ -1183,27 +1296,75 @@ static int waitCmd(uint8_t iSelect) {
int CmdHF14AAntiFuzz(const char *cmd) { 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 void* argtable[] = {
uint8_t arg0 = 4; 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}}; UsbCommand c = {CMD_ANTIFUZZ_ISO_14443a, {arg0, 0, 0}};
clearCommandBuffer(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
return 0; 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, "<enable/disable or 0/1>", 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[] = { static command_t CommandTable[] = {
{"help", CmdHelp, 1, "This help"}, {"help", CmdHelp, 1, "This help"},
{"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443-a history"}, {"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443-a history"},
{"info", CmdHF14AInfo, 0, "Tag information"}, {"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, "<n> Collect n>0 ISO14443-a UIDs in one go"}, {"cuids", CmdHF14ACUIDs, 0, "<n> Collect n>0 ISO14443-a UIDs in one go"},
{"sim", CmdHF14ASim, 0, "<UID> -- Simulate ISO 14443-a tag"}, {"sim", CmdHF14ASim, 0, "<UID> -- Simulate ISO 14443-a tag"},
{"sniff", CmdHF14ASniff, 0, "sniff ISO 14443-a traffic"}, {"sniff", CmdHF14ASniff, 0, "sniff ISO 14443-a traffic"},
{"apdu", CmdHF14AAPDU, 0, "Send ISO 14443-4 APDU to tag"}, {"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"}, {"antifuzz", CmdHF14AAntiFuzz, 0, "Fuzzing the anticollision phase. Warning! Readers may react strange"},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };

View file

@ -29,7 +29,7 @@
#include "cmdhfmf.h" #include "cmdhfmf.h"
#include "cmdhfmfu.h" #include "cmdhfmfu.h"
#include "cmdhf.h" // list cmd #include "cmdhf.h" // list cmd
#include "mifarehost.h" #include "mifare/mifarehost.h"
#include "emv/apduinfo.h" #include "emv/apduinfo.h"
#include "emv/emvcore.h" #include "emv/emvcore.h"

View file

@ -246,7 +246,7 @@ static bool get_14b_UID(iso14b_card_select_t *card) {
if (!card) if (!card)
return false; return false;
uint8_t retry = 3; int8_t retry = 3;
UsbCommand resp; UsbCommand resp;
UsbCommand c = {CMD_ISO_14443B_COMMAND, {ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0}}; 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 } // retry
if ( !retry ) if ( retry <= 0 )
PrintAndLogEx(WARNING, "timeout while waiting for reply."); PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return false; return false;
@ -461,6 +461,7 @@ bool HF14B_Std_Info(bool verbose){
PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid); PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid);
print_atqb_resp(card.atqb, card.cid); print_atqb_resp(card.atqb, card.cid);
isSuccess = true; isSuccess = true;
break;
case 2: case 2:
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail");
break; break;

View file

@ -519,21 +519,21 @@ int CmdHF15Info(const char *Cmd) {
SendCommand(&c); SendCommand(&c);
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) {
PrintAndLogEx(NORMAL, "iso15693 card select failed"); PrintAndLogEx(WARNING, "iso15693 card select failed");
return 1; return 1;
} }
uint32_t status = resp.arg[0]; uint32_t status = resp.arg[0];
if ( status < 2 ) { 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; return 1;
} }
recv = resp.d.asBytes; recv = resp.d.asBytes;
if ( recv[0] & ISO15_RES_ERROR ) { 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; return 3;
} }
@ -575,8 +575,8 @@ int CmdHF15Info(const char *Cmd) {
// Record Activity without enabeling carrier // Record Activity without enabeling carrier
//helptext //helptext
int CmdHF15Record(const char *Cmd) { int CmdHF15Record(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h' || cmdp == 'H') return usage_15_record(); if (cmdp == 'h') return usage_15_record();
UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693, {0,0,0}}; UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693, {0,0,0}};
clearCommandBuffer(); clearCommandBuffer();
@ -598,8 +598,8 @@ int HF15Reader(const char *Cmd, bool verbose) {
} }
int CmdHF15Reader(const char *Cmd) { int CmdHF15Reader(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h' || cmdp == 'H') return usage_15_reader(); if (cmdp == 'h') return usage_15_reader();
HF15Reader(Cmd, true); HF15Reader(Cmd, true);
return 0; return 0;
@ -608,16 +608,16 @@ int CmdHF15Reader(const char *Cmd) {
// Simulation is still not working very good // Simulation is still not working very good
// helptext // helptext
int CmdHF15Sim(const char *Cmd) { int CmdHF15Sim(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0); char cmdp =tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') return usage_15_sim(); if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_sim();
uint8_t uid[8] = {0,0,0,0,0,0,0,0}; uint8_t uid[8] = {0,0,0,0,0,0,0,0};
if (param_gethex(Cmd, 0, uid, 16)) { 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; 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}}; UsbCommand c = {CMD_SIMTAG_ISO_15693, {0, 0, 0}};
memcpy(c.d.asBytes, uid, 8); 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) // (There is no standard way of reading the AFI, allthough some tags support this)
// helptext // helptext
int CmdHF15Afi(const char *Cmd) { int CmdHF15Afi(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h' || cmdp == 'H') return usage_15_findafi(); 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}}; UsbCommand c = {CMD_ISO_15693_FIND_AFI, {strtol(Cmd, NULL, 0), 0, 0}};
clearCommandBuffer(); clearCommandBuffer();
@ -689,7 +689,7 @@ int CmdHF15Dump(const char*Cmd) {
} }
// detect blocksize from card :) // 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; int blocknum = 0;
uint8_t *recv = NULL; uint8_t *recv = NULL;
@ -764,7 +764,7 @@ int CmdHF15Dump(const char*Cmd) {
} }
int CmdHF15Restore(const char*Cmd) { int CmdHF15Restore(const char*Cmd) {
FILE *file; FILE *f;
uint8_t uid[8]={0x00}; uint8_t uid[8]={0x00};
char filename[FILE_PATH_SIZE] = {0x00}; char filename[FILE_PATH_SIZE] = {0x00};
@ -774,10 +774,10 @@ int CmdHF15Restore(const char*Cmd) {
char newCmdPrefix[255] = {0x00}, tmpCmd[255] = {0x00}; char newCmdPrefix[255] = {0x00}, tmpCmd[255] = {0x00};
char param[FILE_PATH_SIZE]=""; char param[FILE_PATH_SIZE]="";
char hex[255]=""; char hex[255]="";
uint8_t retries = 3, tried = 0; uint8_t retries = 3, tried = 0, i = 0;
int retval=0; int retval=0;
size_t bytes_read; size_t bytes_read;
uint8_t i=0;
while(param_getchar(Cmd, cmdp) != 0x00) { while(param_getchar(Cmd, cmdp) != 0x00) {
switch(tolower(param_getchar(Cmd, cmdp))) { switch(tolower(param_getchar(Cmd, cmdp))) {
case '-': case '-':
@ -785,7 +785,8 @@ int CmdHF15Restore(const char*Cmd) {
switch(param[1]) switch(param[1])
{ {
case '2': case '2':
case 'o': strncpy(newCmdPrefix, " ",sizeof(newCmdPrefix)-1); case 'o':
strncpy(newCmdPrefix, " ", sizeof(newCmdPrefix)-1);
strncat(newCmdPrefix, param, sizeof(newCmdPrefix)-1); strncat(newCmdPrefix, param, sizeof(newCmdPrefix)-1);
break; break;
default: default:
@ -815,60 +816,64 @@ int CmdHF15Restore(const char*Cmd) {
default: default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
return usage_15_restore(); return usage_15_restore();
break;
} }
cmdp++; cmdp++;
} }
PrintAndLogEx(INFO,"Blocksize: %u",blocksize); PrintAndLogEx(INFO,"Blocksize: %u",blocksize);
if(filename[0]=='\0')
{ if ( !strlen(filename)) {
PrintAndLogEx(WARNING,"Please provide a 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); PrintAndLogEx(WARNING, "Could not find file %s", filename);
return 2; return 2;
} }
if (!getUID(uid)) { if (!getUID(uid)) {
PrintAndLogEx(WARNING, "No tag found"); PrintAndLogEx(WARNING, "No tag found");
fclose(f);
return 3; return 3;
} }
while (1) {
tried=0;
hex[0]=0x00;
tmpCmd[0]=0x00;
bytes_read = fread( buff, 1, blocksize, file ); while (1) {
tried = 0;
hex[0] = 0x00;
tmpCmd[0] = 0x00;
bytes_read = fread( buff, 1, blocksize, f );
if ( bytes_read == 0) { if ( bytes_read == 0) {
PrintAndLogEx(SUCCESS, "File reading done (%s).", filename); PrintAndLogEx(SUCCESS, "File reading done `%s`", filename);
fclose(file); fclose(f);
return 0; 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); PrintAndLogEx(WARNING, "File reading error (%s), %u bytes read instead of %u bytes.", filename, bytes_read, blocksize);
fclose(file); fclose(f);
return 2; return 2;
} }
for(int j=0;j<blocksize;j++)
snprintf(hex+j*2,3,"%02X", (unsigned char)buff[j]); for(int j=0; j < blocksize; j++)
for(int j=0;j<sizeof(uid)/sizeof(uid[0]);j++) snprintf(hex+j*2, 3, "%02X", buff[j]);
for(int j=0; j < sizeof(uid)/sizeof(uid[0]); j++)
snprintf(buff+j*2,3,"%02X", uid[j]); snprintf(buff+j*2,3,"%02X", uid[j]);
//TODO: Addressed mode currently not work //TODO: Addressed mode currently not work
//snprintf(tmpCmd, sizeof(tmpCmd), "%s %s %d %s", newCmdPrefix, buff, i, hex); //snprintf(tmpCmd, sizeof(tmpCmd), "%s %s %d %s", newCmdPrefix, buff, i, hex);
snprintf(tmpCmd, sizeof(tmpCmd), "%s u %d %s", newCmdPrefix, i, hex); snprintf(tmpCmd, sizeof(tmpCmd), "%s u %u %s", newCmdPrefix, i, hex);
PrintAndLogEx(DEBUG, "Command to be sent: %s", tmpCmd); PrintAndLogEx(DEBUG, "Command to be sent| %s", tmpCmd);
for(tried=0;tried<retries;tried++) for(tried=0; tried < retries; tried++)
if(!(retval=CmdHF15Write(tmpCmd))) if(!(retval = CmdHF15Write(tmpCmd)))
break; break;
if(tried >= retries) if(tried >= retries)
return retval; return retval;
i++; i++;
} }
fclose(file); fclose(f);
} }
int CmdHF15List(const char *Cmd) { int CmdHF15List(const char *Cmd) {
@ -1241,7 +1246,7 @@ int CmdHF15Write(const char *Cmd) {
AddCrc(req, reqlen); AddCrc(req, reqlen);
c.arg[0] = reqlen+2; 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(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);

View file

@ -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] <records> <sfi>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " <records> : number of records");
PrintAndLogEx(NORMAL, " <sfi> : 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] <records> <SFI> ");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " <records> : number of records");
PrintAndLogEx(NORMAL, " <sfi> : 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 <filename w/o .bin>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " o <filename> : 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 <filename w/o .bin>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " o <filename> : 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;
}

View file

@ -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 <stdio.h>
#include <string.h>
#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

View file

@ -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]); PrintAndLogEx(FAILED, "Error in step %d, Return code: %d",resp.arg[0],(int)resp.arg[1]);
} else { } else {
size_t nonce_length = resp.arg[1]; 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++) { for(int j = 0; j < nonce_length; j++) {
sprintf(nonce + (2 * j), "%02X", resp.d.asBytes[j]); sprintf(nonce + (2 * j), "%02X", resp.d.asBytes[j]);
} }

View file

@ -66,7 +66,7 @@ int usage_hf_felica_raw(void){
int CmdHFFelicaList(const char *Cmd) { int CmdHFFelicaList(const char *Cmd) {
//PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list felica' instead"); //PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list felica' instead");
CmdTraceList("raw"); CmdTraceList("felica");
return 0; return 0;
} }
@ -242,7 +242,7 @@ static void printSep() {
PrintAndLogEx(NORMAL, "------------------------------------------------------------------------------------"); 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) if (tracepos+19 >= tracelen)
return tracelen; return tracelen;
@ -253,7 +253,7 @@ uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) {
char line[110] = {0}; char line[110] = {0};
for (int j = 0; j < 16; j++) { 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); 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 0x0c: PrintAndLogEx(NORMAL, "S_PAD12: %s",line);break;
case 0x0d: PrintAndLogEx(NORMAL, "S_PAD13: %s",line);break; case 0x0d: PrintAndLogEx(NORMAL, "S_PAD13: %s",line);break;
case 0x0E: { case 0x0E: {
uint32_t regA = trace[3] + (trace[4]>>8) + (trace[5]>>16) + (trace[6]>>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); uint32_t regB = trace[7] | trace[8] << 8 | trace[9] << 16 | trace[10] << 24;
line[0] = 0; line[0] = 0;
for (int j = 0; j < 8; j++) 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); PrintAndLogEx(NORMAL, "REG: regA: %d regB: %d regC: %s ", regA, regB, line);
} }
break; break;
@ -287,10 +288,10 @@ uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) {
char idd[20]; char idd[20];
char idm[20]; char idm[20];
for (int j = 0; j < 8; j++) 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++) 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); 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 idm[20];
char pmm[20]; char pmm[20];
for (int j = 0; j < 8; j++) 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++) 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); PrintAndLogEx(NORMAL, "DeviceId: IDm: 0x%s PMm: 0x%s ", idm, pmm);
} }

View file

@ -914,7 +914,7 @@ static command_t CommandTable[] =
}; };
int CmdHFFido(const char *Cmd) { int CmdHFFido(const char *Cmd) {
(void)WaitForResponseTimeout(CMD_ACK,NULL,100); (void)WaitForResponseTimeout(CMD_ACK, NULL, 100);
CmdsParse(CommandTable, Cmd); CmdsParse(CommandTable, Cmd);
return 0; return 0;
} }

View file

@ -404,7 +404,7 @@ int CmdHFiClassSim(const char *Cmd) {
break; break;
size_t datalen = NUM_CSNS * 24; size_t datalen = NUM_CSNS * 24;
void* dump = malloc(datalen); void* dump = calloc(datalen, sizeof(uint8_t));
if ( !dump ) { if ( !dump ) {
PrintAndLogEx(WARNING, "Failed to allocate memory"); PrintAndLogEx(WARNING, "Failed to allocate memory");
return 2; return 2;
@ -456,7 +456,7 @@ int CmdHFiClassSim(const char *Cmd) {
break; break;
size_t datalen = NUM_CSNS * 24; size_t datalen = NUM_CSNS * 24;
void* dump = malloc(datalen); void* dump = calloc(datalen, sizeof(uint8_t));
if ( !dump ) { if ( !dump ) {
PrintAndLogEx(WARNING, "Failed to allocate memory"); PrintAndLogEx(WARNING, "Failed to allocate memory");
return 2; return 2;
@ -626,7 +626,7 @@ int CmdHFiClassELoad(const char *Cmd) {
f = fopen(filename, "rb"); f = fopen(filename, "rb");
if ( !f ){ if ( !f ){
PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename); PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename);
return 1; return 1;
} }
@ -2162,10 +2162,10 @@ static int cmp_uint32( const void *a, const void *b) {
int CmdHFiClassLookUp(const char *Cmd) { int CmdHFiClassLookUp(const char *Cmd) {
uint8_t CSN[8]; uint8_t CSN[8];
uint8_t EPURSE[8]; uint8_t EPURSE[8] = { 0,0,0,0,0,0,0,0 };
uint8_t MACS[8]; uint8_t MACS[8]= { 0,0,0,0,0,0,0,0 };
uint8_t CCNR[12]; 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 // elite key, raw key, standard key
bool use_elite = false; bool use_elite = false;
@ -2304,7 +2304,7 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) {
int keyitems = 0; int keyitems = 0;
if ( !(f = fopen( filename , "r")) ) { 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; return 1;
} }
@ -2316,7 +2316,8 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) {
while (fgetc(f) != '\n' && !feof(f)) {}; while (fgetc(f) != '\n' && !feof(f)) {};
//The line start with # is comment, skip //The line start with # is comment, skip
if( buf[0]=='#' ) continue; if( buf[0]=='#' )
continue;
// doesn't this only test first char only? // doesn't this only test first char only?
if (!isxdigit(buf[0])){ if (!isxdigit(buf[0])){
@ -2329,7 +2330,7 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) {
p = realloc(*keys, 8 * (keyitems += 64)); p = realloc(*keys, 8 * (keyitems += 64));
if (!p) { if (!p) {
PrintAndLogEx(NORMAL, _RED_([!])" cannot allocate memory for default keys"); PrintAndLogEx(ERR, "cannot allocate memory for default keys");
fclose(f); fclose(f);
return 2; return 2;
} }
@ -2341,7 +2342,7 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) {
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
} }
fclose(f); 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; return 0;
} }
@ -2462,7 +2463,7 @@ static void shave(uint8_t *data, uint8_t len){
data[i] &= 0xFE; data[i] &= 0xFE;
} }
static void generate_rev(uint8_t *data, uint8_t len) { 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)); PrintAndLogEx(SUCCESS, "input permuted key | %s \n", sprint_hex(data, len));
permute_rev(data, len, key); permute_rev(data, len, key);
PrintAndLogEx(SUCCESS, " unpermuted key | %s \n", sprint_hex(key, len)); 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); free(key);
} }
static void generate(uint8_t *data, uint8_t len) { static void generate(uint8_t *data, uint8_t len) {
uint8_t *key = calloc(len,1); uint8_t *key = calloc(len, sizeof(uint8_t));
uint8_t *pkey = calloc(len,1); uint8_t *pkey = calloc(len, sizeof(uint8_t));
PrintAndLogEx(SUCCESS, " input key | %s \n", sprint_hex(data, len)); PrintAndLogEx(SUCCESS, " input key | %s \n", sprint_hex(data, len));
permute(data, len, pkey); permute(data, len, pkey);
PrintAndLogEx(SUCCESS, "permuted key | %s \n", sprint_hex(pkey, len)); PrintAndLogEx(SUCCESS, "permuted key | %s \n", sprint_hex(pkey, len));

View file

@ -180,15 +180,14 @@ int CmdLegicInfo(const char *Cmd) {
return 1; return 1;
} }
PrintAndLogEx(NORMAL, "Reading tag memory %d b...", card.cardsize); PrintAndLogEx(SUCCESS, "Reading tag memory %d b...", card.cardsize);
// allocate receiver buffer // allocate receiver buffer
uint8_t *data = malloc(card.cardsize); uint8_t *data = calloc(card.cardsize, sizeof(uint8_t));
if (!data) { if (!data) {
PrintAndLogEx(WARNING, "Cannot allocate memory"); PrintAndLogEx(WARNING, "Cannot allocate memory");
return 2; return 2;
} }
memset(data, 0, card.cardsize);
int status = legic_read_mem(0, card.cardsize, 0x55, data, &datalen); int status = legic_read_mem(0, card.cardsize, 0x55, data, &datalen);
if ( status > 0 ) { if ( status > 0 ) {
@ -480,15 +479,20 @@ int CmdLegicRdmem(const char *Cmd) {
uint16_t datalen = 0; uint16_t datalen = 0;
sscanf(Cmd, "%x %x %x", &offset, &len, &iv); 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 // allocate receiver buffer
uint8_t *data = malloc(len); uint8_t *data = calloc(len, sizeof(uint8_t));
if ( !data ){ if ( !data ){
PrintAndLogEx(WARNING, "Cannot allocate memory"); PrintAndLogEx(WARNING, "Cannot allocate memory");
return 2; return -2;
} }
memset(data, 0, len);
int status = legic_read_mem(offset, len, iv, data, &datalen); int status = legic_read_mem(offset, len, iv, data, &datalen);
if ( status == 0 ) { if ( status == 0 ) {
@ -540,9 +544,9 @@ int CmdLegicRfWrite(const char *Cmd) {
} }
// limit number of bytes to write. This is not a 'restore' command. // limit number of bytes to write. This is not a 'restore' command.
if ( (len>>1) > 100 ){ if ( (len >> 1) > 100 ){
PrintAndLogEx(NORMAL, "Max bound on 100bytes to write a one time."); PrintAndLogEx(WARNING, "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"); PrintAndLogEx(WARNING, "Use the 'hf legic restore' command if you want to write the whole tag at once");
errors = true; errors = true;
} }
@ -551,7 +555,7 @@ int CmdLegicRfWrite(const char *Cmd) {
if (data) if (data)
free(data); free(data);
data = malloc(len >> 1); data = calloc(len >> 1, sizeof(uint8_t));
if ( data == NULL ) { if ( data == NULL ) {
PrintAndLogEx(WARNING, "Can't allocate memory. exiting"); PrintAndLogEx(WARNING, "Can't allocate memory. exiting");
errors = true; errors = true;
@ -598,12 +602,12 @@ int CmdLegicRfWrite(const char *Cmd) {
// OUT-OF-BOUNDS checks // OUT-OF-BOUNDS checks
// UID 4+1 bytes can't be written to. // UID 4+1 bytes can't be written to.
if ( offset < 5 ) { 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; return -2;
} }
if ( len + offset >= card.cardsize ) { 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; return -2;
} }
@ -622,7 +626,7 @@ int CmdLegicRfWrite(const char *Cmd) {
legic_chk_iv(&IV); legic_chk_iv(&IV);
PrintAndLogEx(NORMAL, "Writing to tag"); PrintAndLogEx(SUCCESS, "Writing to tag");
UsbCommand c = {CMD_WRITER_LEGIC_RF, {offset, len, IV}}; UsbCommand c = {CMD_WRITER_LEGIC_RF, {offset, len, IV}};
memcpy(c.d.asBytes, data, len); memcpy(c.d.asBytes, data, len);
@ -630,10 +634,18 @@ int CmdLegicRfWrite(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
PrintAndLogEx(WARNING, "command execution time out"); uint8_t timeout = 0;
return 1; 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; uint8_t isOK = resp.arg[0] & 0xFF;
if ( !isOK ) { if ( !isOK ) {
PrintAndLogEx(WARNING, "Failed writing tag"); PrintAndLogEx(WARNING, "Failed writing tag");
@ -673,7 +685,7 @@ int CmdLegicCalcCrc(const char *Cmd){
// it's possible for user to accidentally enter "b" parameter // it's possible for user to accidentally enter "b" parameter
// more than once - we have to clean previous malloc // more than once - we have to clean previous malloc
if (data) free(data); if (data) free(data);
data = malloc(len >> 1); data = calloc(len >> 1, sizeof(uint8_t) );
if ( data == NULL ) { if ( data == NULL ) {
PrintAndLogEx(WARNING, "Can't allocate memory. exiting"); PrintAndLogEx(WARNING, "Can't allocate memory. exiting");
errors = true; errors = true;
@ -714,10 +726,10 @@ int CmdLegicCalcCrc(const char *Cmd){
switch (type){ switch (type){
case 16: case 16:
init_table(CRC_LEGIC); 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; break;
default: default:
PrintAndLogEx(NORMAL, "Legic crc8: %X", CRC8Legic(data, len) ); PrintAndLogEx(SUCCESS, "Legic crc8: %X", CRC8Legic(data, len) );
break; break;
} }
@ -733,10 +745,17 @@ int legic_read_mem(uint32_t offset, uint32_t len, uint32_t iv, uint8_t *out, uin
clearCommandBuffer(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
UsbCommand resp; UsbCommand resp;
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 3000) ) {
PrintAndLogEx(WARNING, "command execution time out"); uint8_t timeout = 0;
return 1; 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; uint8_t isOK = resp.arg[0] & 0xFF;
*outlen = resp.arg[1]; *outlen = resp.arg[1];
@ -762,13 +781,13 @@ int legic_print_type(uint32_t tagtype, uint8_t spaces){
char *spacer = spc + (10-spaces); char *spacer = spc + (10-spaces);
if ( tagtype == 22 ) 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 ) 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 ) 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 else
PrintAndLogEx(NORMAL, "%sTYPE : Unknown %06x", spacer, tagtype); PrintAndLogEx(INFO, "%sTYPE : Unknown %06x", spacer, tagtype);
return 0; return 0;
} }
int legic_get_type(legic_card_select_t *card){ 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){ void legic_chk_iv(uint32_t *iv){
if ( (*iv & 0x7F) != *iv ){ if ( (*iv & 0x7F) != *iv ){
*iv &= 0x7F; *iv &= 0x7F;
PrintAndLogEx(NORMAL, "Truncating IV to 7bits, %u", *iv); PrintAndLogEx(INFO, "Truncating IV to 7bits, %u", *iv);
} }
// IV must be odd // IV must be odd
if ( (*iv & 1) == 0 ){ if ( (*iv & 1) == 0 ){
*iv |= 0x01; *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) { 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"); if ( verbose ) PrintAndLogEx(WARNING, "command execution time out");
return 1; return 1;
case 3: case 3:
if ( verbose ) PrintAndLogEx(NORMAL, "legic card select failed"); if ( verbose ) PrintAndLogEx(WARNING, "legic card select failed");
return 2; return 2;
default: break; 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); legic_print_type(card.cardsize, 0);
return 0; return 0;
} }
@ -882,16 +901,23 @@ int CmdLegicDump(const char *Cmd){
dumplen = card.cardsize; dumplen = card.cardsize;
legic_print_type(dumplen, 0); 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}}; UsbCommand c = {CMD_READER_LEGIC_RF, {0x00, dumplen, 0x55}};
clearCommandBuffer(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
UsbCommand resp; UsbCommand resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
PrintAndLogEx(NORMAL, "Command execute time-out"); uint8_t timeout = 0;
return 1; 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; uint8_t isOK = resp.arg[0] & 0xFF;
if ( !isOK ) { if ( !isOK ) {
@ -900,12 +926,11 @@ int CmdLegicDump(const char *Cmd){
} }
uint16_t readlen = resp.arg[1]; uint16_t readlen = resp.arg[1];
uint8_t *data = malloc(readlen); uint8_t *data = calloc(readlen, sizeof(uint8_t));
if (!data) { if (!data) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return 3; return 3;
} }
memset(data, 0, readlen);
if ( readlen != dumplen ) if ( readlen != dumplen )
PrintAndLogEx(WARNING, "Fail, only managed to read 0x%02X bytes of 0x%02X", 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 else
sprintf(fnameptr + fileNlen,".bin"); sprintf(fnameptr + fileNlen,".bin");
f = fopen(filename,"wb"); f = fopen(filename, "wb");
if (!f) { if (!f) {
PrintAndLogEx(WARNING, "Could not create file name %s", filename); PrintAndLogEx(WARNING, "Could not create file name %s", filename);
if (data) if (data)
@ -934,7 +959,7 @@ int CmdLegicDump(const char *Cmd){
fflush(f); fflush(f);
fclose(f); fclose(f);
free(data); free(data);
PrintAndLogEx(NORMAL, "Wrote %d bytes to %s", readlen, filename); PrintAndLogEx(SUCCESS, "Wrote %d bytes to %s", readlen, filename);
return 0; return 0;
} }
@ -982,12 +1007,11 @@ int CmdLegicRestore(const char *Cmd){
numofbytes = card.cardsize; numofbytes = card.cardsize;
// set up buffer // set up buffer
uint8_t *data = malloc(numofbytes); uint8_t *data = calloc(numofbytes, sizeof(uint8_t) );
if (!data) { if (!data) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return 2; return 2;
} }
memset(data, 0, numofbytes);
legic_print_type(numofbytes, 0); legic_print_type(numofbytes, 0);
@ -997,7 +1021,8 @@ int CmdLegicRestore(const char *Cmd){
f = fopen(filename,"rb"); f = fopen(filename,"rb");
if (!f) { if (!f) {
PrintAndLogEx(NORMAL, "File %s not found or locked", filename); PrintAndLogEx(WARNING, "File %s not found or locked", filename);
free(data);
return 3; return 3;
} }
@ -1018,12 +1043,12 @@ int CmdLegicRestore(const char *Cmd){
fclose(f); fclose(f);
if ( bytes_read == 0){ if ( bytes_read == 0){
PrintAndLogEx(NORMAL, "File reading error"); PrintAndLogEx(WARNING, "File reading error");
free(data); free(data);
return 2; return 2;
} }
PrintAndLogEx(NORMAL, "Restoring to card"); PrintAndLogEx(SUCCESS, "Restoring to card");
// transfer to device // transfer to device
size_t len = 0; size_t len = 0;
@ -1038,22 +1063,29 @@ int CmdLegicRestore(const char *Cmd){
clearCommandBuffer(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) { uint8_t timeout = 0;
PrintAndLogEx(WARNING, "command execution time out"); while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
free(data); ++timeout;
return 1; 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; uint8_t isOK = resp.arg[0] & 0xFF;
if ( !isOK ) { if ( !isOK ) {
PrintAndLogEx(WARNING, "Failed writing tag [msg = %u]", resp.arg[1] & 0xFF); PrintAndLogEx(WARNING, "Failed writing tag [msg = %u]", resp.arg[1] & 0xFF);
free(data); free(data);
return 1; 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); 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; return 0;
} }
@ -1077,12 +1109,11 @@ int CmdLegicELoad(const char *Cmd) {
} }
// set up buffer // set up buffer
uint8_t *data = malloc(numofbytes); uint8_t *data = calloc(numofbytes, sizeof(uint8_t));
if (!data) { if (!data) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return 3; return 3;
} }
memset(data, 0, numofbytes);
// set up file // set up file
len = param_getstr(Cmd, nameParamNo, filename, FILE_PATH_SIZE); len = param_getstr(Cmd, nameParamNo, filename, FILE_PATH_SIZE);
@ -1094,7 +1125,7 @@ int CmdLegicELoad(const char *Cmd) {
// open file // open file
f = fopen(filename,"rb"); f = fopen(filename,"rb");
if (!f) { if (!f) {
PrintAndLogEx(NORMAL, "File %s not found or locked", filename); PrintAndLogEx(WARNING, "File %s not found or locked", filename);
free(data); free(data);
return 1; return 1;
} }
@ -1102,7 +1133,7 @@ int CmdLegicELoad(const char *Cmd) {
// load file // load file
size_t bytes_read = fread(data, 1, numofbytes, f); size_t bytes_read = fread(data, 1, numofbytes, f);
if ( bytes_read == 0){ if ( bytes_read == 0){
PrintAndLogEx(NORMAL, "File reading error"); PrintAndLogEx(WARNING, "File reading error");
free(data); free(data);
fclose(f); fclose(f);
f = NULL; f = NULL;
@ -1115,7 +1146,7 @@ int CmdLegicELoad(const char *Cmd) {
legic_seteml(data, 0, numofbytes); legic_seteml(data, 0, numofbytes);
free(data); 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; return 0;
} }
@ -1146,15 +1177,14 @@ int CmdLegicESave(const char *Cmd) {
fileNlen = FILE_PATH_SIZE - 5; fileNlen = FILE_PATH_SIZE - 5;
// set up buffer // set up buffer
uint8_t *data = malloc(numofbytes); uint8_t *data = calloc(numofbytes, sizeof(uint8_t));
if (!data) { if (!data) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return 3; return 3;
} }
memset(data, 0, numofbytes);
// download emulator memory // download emulator memory
PrintAndLogEx(NORMAL, "Reading emulator memory..."); PrintAndLogEx(SUCCESS, "Reading emulator memory...");
if (!GetFromDevice( BIG_BUF_EML, data, numofbytes, 0, NULL, 2500, false)) { if (!GetFromDevice( BIG_BUF_EML, data, numofbytes, 0, NULL, 2500, false)) {
PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
free(data); free(data);
@ -1185,16 +1215,15 @@ int CmdLegicWipe(const char *Cmd){
} }
// set up buffer // set up buffer
uint8_t *data = malloc(card.cardsize); uint8_t *data = calloc(card.cardsize, sizeof(uint8_t));
if (!data) { if (!data) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return 2; return 2;
} }
memset(data, 0, card.cardsize);
legic_print_type(card.cardsize, 0); legic_print_type(card.cardsize, 0);
PrintAndLogEx(NORMAL, "Erasing"); PrintAndLogEx(SUCCESS, "Erasing");
// transfer to device // transfer to device
size_t len = 0; size_t len = 0;
@ -1210,11 +1239,18 @@ int CmdLegicWipe(const char *Cmd){
clearCommandBuffer(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) { uint8_t timeout = 0;
PrintAndLogEx(WARNING, "command execution time out"); while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
free(data); ++timeout;
return 3; 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; uint8_t isOK = resp.arg[0] & 0xFF;
if ( !isOK ) { if ( !isOK ) {
PrintAndLogEx(WARNING, "Failed writing tag [msg = %u]", resp.arg[1] & 0xFF); PrintAndLogEx(WARNING, "Failed writing tag [msg = %u]", resp.arg[1] & 0xFF);
@ -1222,7 +1258,7 @@ int CmdLegicWipe(const char *Cmd){
return 4; return 4;
} }
} }
PrintAndLogEx(NORMAL, "ok\n"); PrintAndLogEx(SUCCESS, "ok\n");
return 0; return 0;
} }
@ -1236,7 +1272,7 @@ static command_t CommandTable[] = {
{"reader", CmdLegicReader, 1, "LEGIC Prime Reader UID and tag info"}, {"reader", CmdLegicReader, 1, "LEGIC Prime Reader UID and tag info"},
{"info", CmdLegicInfo, 0, "Display deobfuscated and decoded LEGIC Prime tag data"}, {"info", CmdLegicInfo, 0, "Display deobfuscated and decoded LEGIC Prime tag data"},
{"dump", CmdLegicDump, 0, "Dump LEGIC Prime tag to binary file"}, {"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"}, {"rdmem", CmdLegicRdmem, 0, "Read bytes from a LEGIC Prime tag"},
{"sim", CmdLegicRfSim, 0, "Start tag simulator"}, {"sim", CmdLegicRfSim, 0, "Start tag simulator"},
{"write", CmdLegicRfWrite, 0, "Write data to a LEGIC Prime tag"}, {"write", CmdLegicRfWrite, 0, "Write data to a LEGIC Prime tag"},

View file

@ -159,6 +159,7 @@ int applyIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) {
MifareAuthState = masNone; MifareAuthState = masNone;
break; break;
case ISO14443A_CMD_RATS: snprintf(exp,size,"RATS"); 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_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break;
case MIFARE_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break; case MIFARE_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break;
case MIFARE_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break; case MIFARE_CMD_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_EXTERNAL_AUTHENTICATION :snprintf(exp, size, "EXTERNAL AUTH");break;
case ISO7816_GET_CHALLENGE :snprintf(exp, size, "GET CHALLENGE");break; case ISO7816_GET_CHALLENGE :snprintf(exp, size, "GET CHALLENGE");break;
case ISO7816_MANAGE_CHANNEL :snprintf(exp, size, "MANAGE CHANNEL");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; 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){ void annotateFelica(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){
switch(cmd[0]){ 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; 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 | |", PrintAndLogEx(NORMAL, " | | * |%49s %012"PRIx64" prng %s | |",
"key", "key",
mfLastKey, mfLastKey,
validate_prng_nonce(AuthData.nt) ? "WEAK": "HARD"); validate_prng_nonce(AuthData.nt) ? _GREEN_(WEAK): _YELLOW_(HARD));
AuthData.first_auth = false; AuthData.first_auth = false;

View file

@ -31,8 +31,8 @@
#include "emv/cmdemv.h" // EMV #include "emv/cmdemv.h" // EMV
#include "protocols.h" #include "protocols.h"
#include "crapto1/crapto1.h" #include "crapto1/crapto1.h"
#include "mifarehost.h" #include "mifare/mifarehost.h"
#include "mifaredefault.h" #include "mifare/mifaredefault.h"
#include "parity.h" // oddparity #include "parity.h" // oddparity
#include "iso15693tools.h" // ISO15693 crc #include "iso15693tools.h" // ISO15693 crc

File diff suppressed because it is too large Load diff

View file

@ -23,18 +23,19 @@
#include "cmdparser.h" #include "cmdparser.h"
#include "common.h" #include "common.h"
#include "util.h" #include "util.h"
#include "mifare.h" // nonces_t struct #include "mifare.h" // nonces_t struct
#include "mfkey.h" // mfkey32_moebious #include "mifare/mfkey.h" // mfkey32_moebious
#include "cmdhfmfhard.h" #include "cmdhfmfhard.h"
#include "mifarehost.h" // icesector_t, sector_t #include "mifare/mifarehost.h" // icesector_t, sector_t
#include "util_posix.h" // msclock #include "util_posix.h" // msclock
#include "mifaredefault.h" // mifare default key array #include "mifare/mifaredefault.h" // mifare default key array
#include "cmdhf14a.h" // dropfield #include "cmdhf14a.h" // dropfield
#include "cliparser/cliparser.h" // argtable #include "cliparser/cliparser.h" // argtable
#include "hardnested/hardnested_bf_core.h" // SetSIMDInstr #include "hardnested/hardnested_bf_core.h" // SetSIMDInstr
extern int CmdHFMF(const char *Cmd); extern int CmdHFMF(const char *Cmd);
extern int CmdHF14AMfList(const char *Cmd);
extern int CmdHF14AMfDbg(const char* cmd); extern int CmdHF14AMfDbg(const char* cmd);
extern int CmdHF14AMfRdBl(const char* cmd); extern int CmdHF14AMfRdBl(const char* cmd);
extern int CmdHF14AMfURdBl(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 CmdHF14AMfWrBl(const char* cmd);
extern int CmdHF14AMfUWrBl(const char* cmd); extern int CmdHF14AMfUWrBl(const char* cmd);
extern int CmdHF14AMfChk(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 CmdHF14AMfNested(const char* cmd);
extern int CmdHF14AMfNestedHard(const char *Cmd); extern int CmdHF14AMfNestedHard(const char *Cmd);
//extern int CmdHF14AMfSniff(const char* cmd); //extern int CmdHF14AMfSniff(const char* cmd);

View file

@ -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) 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; continue;
} else { } else {
fseek(statesfile, 0, SEEK_END); 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); rewind(statesfile);
uint8_t input_buffer[filesize]; uint8_t input_buffer[filesize];
size_t bytesread = fread(input_buffer, 1, filesize, statesfile); size_t bytesread = fread(input_buffer, 1, filesize, statesfile);
if (bytesread != filesize) { if (bytesread != filesize) {
PrintAndLogEx(WARNING, "File read error with %s. Aborting...\n", state_file_name); PrintAndLogEx(WARNING, "File read error with %s. Aborting...\n", state_file_name);
fclose(statesfile); fclose(statesfile);
inflateEnd(&compressed_stream); //inflateEnd(&compressed_stream);
exit(5); exit(5);
} }
fclose(statesfile); fclose(statesfile);
@ -1038,8 +1044,11 @@ static bool shrink_key_space(float *brute_forces)
} }
*brute_forces = MIN(brute_forces1, brute_forces2); *brute_forces = MIN(brute_forces1, brute_forces2);
float reduction_rate = update_reduction_rate(*brute_forces, false); 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 #endif
return false; 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 #ifdef DEBUG_KEY_ELIMINATION
if (known_target_key != -1 && state == test_state[odd_even]) { 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", 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], test_state[odd_even],
byte, byte2, num_common); byte,
byte2,
num_common);
if (failstr[0] == '\0') { 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 #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_a8 = part_sum_a8_bitarrays[odd_even][part_sum_a8/2];
uint32_t *bitarray_bitflips = nonces[best_first_bytes[0]].states_bitarray[odd_even]; 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_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); 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) { if (candidates->len[odd_even] == 0) {
free(candidates->states[odd_even]); free(candidates->states[odd_even]);
candidates->states[odd_even] = NULL; 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); free_bitarray(candidates_bitarray);
pthread_mutex_lock(&statelist_cache_mutex); 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].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].len = candidates->len[odd_even];
sl_cache[part_sum_a0/2][part_sum_a8/2][odd_even].cache_status = COMPLETED; sl_cache[part_sum_a0/2][part_sum_a8/2][odd_even].cache_status = COMPLETED;
pthread_mutex_unlock(&statelist_cache_mutex); pthread_mutex_unlock(&statelist_cache_mutex);
return; return;
} }
static statelist_t *add_more_candidates(void) static statelist_t *add_more_candidates(void)
{ {
statelist_t *new_candidates = candidates; 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 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) static void init_book_of_work(void)
{ {
for (uint8_t p = 0; p < NUM_PART_SUMS; p++) { 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) 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_statelist_cache();
init_book_of_work(); 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) static void free_candidates_memory(statelist_t *sl)
{ {
if (sl == NULL) { if (sl == NULL)
return; return;
} else {
free_candidates_memory(sl->next); free_candidates_memory(sl->next);
free(sl); free(sl);
}
} }
@ -2129,7 +2120,6 @@ static void pre_XOR_nonces(void)
} }
} }
static bool brute_force(uint64_t *found_key) static bool brute_force(uint64_t *found_key)
{ {
if (known_target_key != -1) { if (known_target_key != -1) {
@ -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); 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) static uint16_t SumProperty(struct Crypto1State *s)
{ {
uint16_t sum_odd = PartialSumProperty(s->odd, ODD_STATE); uint16_t sum_odd = PartialSumProperty(s->odd, ODD_STATE);
@ -2215,10 +2204,10 @@ static void set_test_state(uint8_t byte)
int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *trgkey, bool nonce_file_read, bool nonce_file_write, bool slow, int tests, uint64_t *foundkey, char *filename) 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}; char instr_set[12] = {0};
get_SIMD_instruction_set(instr_set); 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)); srand((unsigned) time(NULL));
brute_force_per_second = brute_force_benchmark(); 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"); PrintAndLogEx(WARNING, "Could not create/open file hardnested_stats.txt");
return 3; return 3;
} }
for (uint32_t i = 0; i < tests; i++) { for (uint32_t i = 0; i < tests; i++) {
start_time = msclock(); start_time = msclock();
print_progress_header(); 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_force1 = (float)num_odd * num_even / 2.0;
float expected_brute_force2 = nonces[best_first_bytes[0]].expected_num_brute_force; 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)); 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) { if (expected_brute_force1 < expected_brute_force2) {
hardnested_print_progress(num_acquired_nonces, "(Ignoring Sum(a8) properties)", expected_brute_force1, 0); hardnested_print_progress(num_acquired_nonces, "(Ignoring Sum(a8) properties)", expected_brute_force1, 0);
set_test_state(best_first_byte_smallest_bitarray); 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) { for (statelist_t *sl = candidates; sl != NULL; sl = sl->next) {
maximum_states += (uint64_t)sl->len[ODD_STATE] * sl->len[EVEN_STATE]; 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; best_first_bytes[0] = best_first_byte_smallest_bitarray;
pre_XOR_nonces(); pre_XOR_nonces();
prepare_bf_test_nonces(nonces, best_first_bytes[0]); 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); key_found = brute_force(foundkey);
free(candidates->states[ODD_STATE]); free(candidates->states[ODD_STATE]);
free(candidates->states[EVEN_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); 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); 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); 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); key_found = brute_force(foundkey);
free_statelist_cache(); free_statelist_cache();
free_candidates_memory(candidates); 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]; 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_force1 = (float)num_odd * num_even / 2.0;
float expected_brute_force2 = nonces[best_first_bytes[0]].expected_num_brute_force; float expected_brute_force2 = nonces[best_first_bytes[0]].expected_num_brute_force;
if (expected_brute_force1 < expected_brute_force2) { if (expected_brute_force1 < expected_brute_force2) {
hardnested_print_progress(num_acquired_nonces, "(Ignoring Sum(a8) properties)", expected_brute_force1, 0); hardnested_print_progress(num_acquired_nonces, "(Ignoring Sum(a8) properties)", expected_brute_force1, 0);
set_test_state(best_first_byte_smallest_bitarray); set_test_state(best_first_byte_smallest_bitarray);
add_bitflip_candidates(best_first_byte_smallest_bitarray); add_bitflip_candidates(best_first_byte_smallest_bitarray);
Tests2(); Tests2();
maximum_states = 0; maximum_states = 0;
for (statelist_t *sl = candidates; sl != NULL; sl = sl->next) { for (statelist_t *sl = candidates; sl != NULL; sl = sl->next) {
maximum_states += (uint64_t)sl->len[ODD_STATE] * sl->len[EVEN_STATE]; 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; best_first_bytes[0] = best_first_byte_smallest_bitarray;
pre_XOR_nonces(); pre_XOR_nonces();
prepare_bf_test_nonces(nonces, best_first_bytes[0]); 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); key_found = brute_force(foundkey);
free(candidates->states[ODD_STATE]); free(candidates->states[ODD_STATE]);
free(candidates->states[EVEN_STATE]); free(candidates->states[EVEN_STATE]);
free_candidates_memory(candidates); free_candidates_memory(candidates);
candidates = NULL; candidates = NULL;
} else { } else {
pre_XOR_nonces(); pre_XOR_nonces();
prepare_bf_test_nonces(nonces, best_first_bytes[0]); prepare_bf_test_nonces(nonces, best_first_bytes[0]);
for (uint8_t j = 0; j < NUM_SUMS && !key_found; j++) { for (uint8_t j = 0; j < NUM_SUMS && !key_found; j++) {
float expected_brute_force = nonces[best_first_bytes[0]].expected_num_brute_force; 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]); 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); 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) { 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); 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); 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); 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); key_found = brute_force(foundkey);
free_statelist_cache(); free_statelist_cache();
free_candidates_memory(candidates); free_candidates_memory(candidates);

View file

@ -22,109 +22,15 @@
#include "ui.h" #include "ui.h"
#include "cmdhf14a.h" #include "cmdhf14a.h"
#include "mifare.h" #include "mifare.h"
#include "mifare4.h" #include "mifare/mifare4.h"
#include "mifare/mad.h"
#include "cliparser/cliparser.h" #include "cliparser/cliparser.h"
#include "crypto/libpcrypto.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}; 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 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) { int CmdHFMFPInfo(const char *cmd) {
if (cmd && strlen(cmd) > 0) if (cmd && strlen(cmd) > 0)
@ -229,7 +135,7 @@ int CmdHFMFPWritePerso(const char *cmd) {
CLIGetHexWithReturn(3, key, &keyLen); CLIGetHexWithReturn(3, key, &keyLen);
CLIParserFree(); CLIParserFree();
SetVerboseMode(verbose); mfpSetVerboseMode(verbose);
if (!keyLen) { if (!keyLen) {
memmove(key, DefaultKey, 16); memmove(key, DefaultKey, 16);
@ -260,7 +166,7 @@ int CmdHFMFPWritePerso(const char *cmd) {
} }
if (data[0] != 0x90) { 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; return 1;
} }
PrintAndLogEx(INFO, "Write OK."); PrintAndLogEx(INFO, "Write OK.");
@ -304,7 +210,7 @@ int CmdHFMFPInitPerso(const char *cmd) {
if (!keyLen) if (!keyLen)
memmove(key, DefaultKey, 16); memmove(key, DefaultKey, 16);
SetVerboseMode(verbose2); mfpSetVerboseMode(verbose2);
for (uint16_t sn = 0x4000; sn < 0x4050; sn++) { for (uint16_t sn = 0x4000; sn < 0x4050; sn++) {
keyNum[0] = sn >> 8; keyNum[0] = sn >> 8;
keyNum[1] = sn & 0xff; 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++) { for (int i = 0; i < sizeof(CardAddresses) / 2; i++) {
keyNum[0] = CardAddresses[i] >> 8; keyNum[0] = CardAddresses[i] >> 8;
keyNum[1] = CardAddresses[i] & 0xff; keyNum[1] = CardAddresses[i] & 0xff;
@ -360,7 +266,7 @@ int CmdHFMFPCommitPerso(const char *cmd) {
bool verbose = arg_get_lit(1); bool verbose = arg_get_lit(1);
CLIParserFree(); CLIParserFree();
SetVerboseMode(verbose); mfpSetVerboseMode(verbose);
uint8_t data[250] = {0}; uint8_t data[250] = {0};
int datalen = 0; int datalen = 0;
@ -377,7 +283,7 @@ int CmdHFMFPCommitPerso(const char *cmd) {
} }
if (data[0] != 0x90) { 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; return 1;
} }
PrintAndLogEx(INFO, "Switch level OK."); PrintAndLogEx(INFO, "Switch level OK.");
@ -453,7 +359,7 @@ int CmdHFMFPRdbl(const char *cmd) {
CLIGetHexWithReturn(6, key, &keylen); CLIGetHexWithReturn(6, key, &keylen);
CLIParserFree(); CLIParserFree();
SetVerboseMode(verbose); mfpSetVerboseMode(verbose);
if (!keylen) { if (!keylen) {
memmove(key, DefaultKey, 16); memmove(key, DefaultKey, 16);
@ -504,7 +410,7 @@ int CmdHFMFPRdbl(const char *cmd) {
} }
if (datalen && data[0] != 0x90) { 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; return 6;
} }
@ -563,7 +469,7 @@ int CmdHFMFPRdsc(const char *cmd) {
CLIGetHexWithReturn(5, key, &keylen); CLIGetHexWithReturn(5, key, &keylen);
CLIParserFree(); CLIParserFree();
SetVerboseMode(verbose); mfpSetVerboseMode(verbose);
if (!keylen) { if (!keylen) {
memmove(key, DefaultKey, 16); memmove(key, DefaultKey, 16);
@ -605,7 +511,7 @@ int CmdHFMFPRdsc(const char *cmd) {
} }
if (datalen && data[0] != 0x90) { 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(); DropField();
return 6; return 6;
} }
@ -661,7 +567,7 @@ int CmdHFMFPWrbl(const char *cmd) {
CLIGetHexWithReturn(5, key, &keylen); CLIGetHexWithReturn(5, key, &keylen);
CLIParserFree(); CLIParserFree();
SetVerboseMode(verbose); mfpSetVerboseMode(verbose);
if (!keylen) { if (!keylen) {
memmove(key, DefaultKey, 16); memmove(key, DefaultKey, 16);
@ -714,7 +620,7 @@ int CmdHFMFPWrbl(const char *cmd) {
} }
if (datalen && data[0] != 0x90) { 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(); DropField();
return 6; return 6;
} }
@ -733,6 +639,100 @@ int CmdHFMFPWrbl(const char *cmd) {
return 0; 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(&sector0[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[] = static command_t CommandTable[] =
{ {
{"help", CmdHelp, 1, "This help"}, {"help", CmdHelp, 1, "This help"},
@ -744,6 +744,7 @@ static command_t CommandTable[] =
{"rdbl", CmdHFMFPRdbl, 0, "Read blocks"}, {"rdbl", CmdHFMFPRdbl, 0, "Read blocks"},
{"rdsc", CmdHFMFPRdsc, 0, "Read sectors"}, {"rdsc", CmdHFMFPRdsc, 0, "Read sectors"},
{"wrbl", CmdHFMFPWrbl, 0, "Write blocks"}, {"wrbl", CmdHFMFPWrbl, 0, "Write blocks"},
{"mad", CmdHFMFPMAD, 0, "Checks and prints MAD"},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };

View file

@ -10,7 +10,7 @@
#ifndef CMDHFMFP_H__ #ifndef CMDHFMFP_H__
#define CMDHFMFP_H__ #define CMDHFMFP_H__
#include "mifaredefault.h" #include "mifare/mifaredefault.h"
extern int CmdHFMFP(const char *Cmd); extern int CmdHFMFP(const char *Cmd);

View file

@ -980,11 +980,11 @@ int CmdHF14AMfUInfo(const char *Cmd){
if ( hasAuthKey ) return 1; if ( hasAuthKey ) return 1;
// also try to diversify default keys.. look into CmdHF14AMfuGenDiverseKeys // 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 ) { for (uint8_t i = 0; i < KEYS_3DES_COUNT; ++i ) {
key = default_3des_keys[i]; key = default_3des_keys[i];
if (ulc_authentication(key, true)) { if (ulc_authentication(key, true)) {
PrintAndLogEx(NORMAL, "Found default 3des key: "); PrintAndLogEx(SUCCESS, "Found default 3des key: ");
uint8_t keySwap[16]; uint8_t keySwap[16];
memcpy(keySwap, SwapEndian64(key,16,8), 16); memcpy(keySwap, SwapEndian64(key,16,8), 16);
ulc_print_3deskey(keySwap); ulc_print_3deskey(keySwap);
@ -1079,7 +1079,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
num_to_bytes( ul_ev1_pwdgenA(card.uid), 4, key); num_to_bytes( ul_ev1_pwdgenA(card.uid), 4, key);
len = ulev1_requestAuthentication(key, pack, sizeof(pack)); len = ulev1_requestAuthentication(key, pack, sizeof(pack));
if (len > -1) { 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; goto out;
} }
@ -1089,7 +1089,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
num_to_bytes( ul_ev1_pwdgenB(card.uid), 4, key); num_to_bytes( ul_ev1_pwdgenB(card.uid), 4, key);
len = ulev1_requestAuthentication(key, pack, sizeof(pack)); len = ulev1_requestAuthentication(key, pack, sizeof(pack));
if (len > -1) { 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; goto out;
} }
@ -1099,7 +1099,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
num_to_bytes( ul_ev1_pwdgenC(card.uid), 4, key); num_to_bytes( ul_ev1_pwdgenC(card.uid), 4, key);
len = ulev1_requestAuthentication(key, pack, sizeof(pack)); len = ulev1_requestAuthentication(key, pack, sizeof(pack));
if (len > -1) { 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; goto out;
} }
@ -1109,7 +1109,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
num_to_bytes( ul_ev1_pwdgenD(card.uid), 4, key); num_to_bytes( ul_ev1_pwdgenD(card.uid), 4, key);
len = ulev1_requestAuthentication(key, pack, sizeof(pack)); len = ulev1_requestAuthentication(key, pack, sizeof(pack));
if (len > -1) { 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; goto out;
} }
@ -1119,13 +1119,13 @@ int CmdHF14AMfUInfo(const char *Cmd){
key = default_pwd_pack[i]; key = default_pwd_pack[i];
len = ulev1_requestAuthentication(key, pack, sizeof(pack)); len = ulev1_requestAuthentication(key, pack, sizeof(pack));
if (len > -1) { 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; break;
} else { } else {
if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; 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: out:
@ -1250,7 +1250,7 @@ int CmdHF14AMfUWrBl(const char *Cmd){
UsbCommand resp; UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.arg[0] & 0xff; uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLogEx(NORMAL, "isOk:%02x", isOK); PrintAndLogEx(SUCCESS, "isOk:%02x", isOK);
} else { } else {
PrintAndLogEx(WARNING, "Command execute timeout"); PrintAndLogEx(WARNING, "Command execute timeout");
} }
@ -1365,7 +1365,7 @@ int CmdHF14AMfURdBl(const char *Cmd){
PrintAndLogEx(WARNING, "Failed reading block: (%02x)", isOK); PrintAndLogEx(WARNING, "Failed reading block: (%02x)", isOK);
} }
} else { } else {
PrintAndLogEx(NORMAL, "Command execute time-out"); PrintAndLogEx(WARNING, "Command execute time-out");
} }
return 0; return 0;
} }
@ -1743,7 +1743,7 @@ int CmdHF14AMfUDump(const char *Cmd){
} }
} }
ul_print_type(tagtype, 0); ul_print_type(tagtype, 0);
PrintAndLogEx(NORMAL, "Reading tag memory..."); PrintAndLogEx(SUCCESS, "Reading tag memory...");
UsbCommand c = {CMD_MIFAREU_READCARD, {startPage, pages}}; UsbCommand c = {CMD_MIFAREU_READCARD, {startPage, pages}};
if ( hasAuthKey ) { if ( hasAuthKey ) {
if (tagtype & UL_C) if (tagtype & UL_C)
@ -1912,12 +1912,10 @@ int CmdHF14AMfURestore(const char *Cmd){
memset(authkey, 0x00, sizeof(authkey)); memset(authkey, 0x00, sizeof(authkey));
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch(param_getchar(Cmd, cmdp)) { switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
case 'H':
return usage_hf_mfu_restore(); return usage_hf_mfu_restore();
case 'k': case 'k':
case 'K':
keylen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); keylen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
if (keylen == 32 || keylen == 8) { //ul-c or ev1/ntag key length if (keylen == 32 || keylen == 8) { //ul-c or ev1/ntag key length
errors = param_gethex(tempStr, 0, authkey, keylen); errors = param_gethex(tempStr, 0, authkey, keylen);
@ -1930,12 +1928,10 @@ int CmdHF14AMfURestore(const char *Cmd){
hasKey = true; hasKey = true;
break; break;
case 'l': case 'l':
case 'L':
swapEndian = true; swapEndian = true;
cmdp++; cmdp++;
break; break;
case 'f': case 'f':
case 'F':
filelen = param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE); filelen = param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE);
if (filelen > FILE_PATH_SIZE-5) if (filelen > FILE_PATH_SIZE-5)
@ -1947,17 +1943,14 @@ int CmdHF14AMfURestore(const char *Cmd){
cmdp += 2; cmdp += 2;
break; break;
case 's': case 's':
case 'S':
cmdp++; cmdp++;
write_special = true; write_special = true;
break; break;
case 'e': case 'e':
case 'E':
cmdp++; cmdp++;
write_extra = true; write_extra = true;
break; break;
case 'r': case 'r':
case 'R':
cmdp++; cmdp++;
read_key = true; read_key = true;
break; break;
@ -1972,7 +1965,7 @@ int CmdHF14AMfURestore(const char *Cmd){
if (errors || cmdp == 0) return usage_hf_mfu_restore(); if (errors || cmdp == 0) return usage_hf_mfu_restore();
if ((f = fopen(filename,"rb")) == NULL) { 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; return 1;
} }
@ -1989,6 +1982,7 @@ int CmdHF14AMfURestore(const char *Cmd){
uint8_t *dump = calloc(fsize, sizeof(uint8_t)); uint8_t *dump = calloc(fsize, sizeof(uint8_t));
if ( !dump ) { if ( !dump ) {
PrintAndLogEx(WARNING, "Failed to allocate memory"); PrintAndLogEx(WARNING, "Failed to allocate memory");
fclose(f);
return 1; return 1;
} }
@ -1997,10 +1991,11 @@ int CmdHF14AMfURestore(const char *Cmd){
fclose(f); fclose(f);
if ( bytes_read < 48 ) { if ( bytes_read < 48 ) {
PrintAndLogEx(WARNING, "Error, dump file is too small"); PrintAndLogEx(WARNING, "Error, dump file is too small");
free(dump);
return 1; 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; mfu_dump_t *mem = (mfu_dump_t*)dump;
uint8_t pages = (bytes_read-48)/4; 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 // write all other data
// Skip block 0,1,2,3 (only magic tags can write to them) // Skip block 0,1,2,3 (only magic tags can write to them)
// Skip last 5 blocks usually is configuration // Skip last 5 blocks usually is configuration
@ -2103,7 +2098,7 @@ int CmdHF14AMfURestore(const char *Cmd){
// write special data last // write special data last
if (write_special) { 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)); 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 // Load emulator with dump file
// //
int CmdHF14AMfUeLoad(const char *Cmd){ int CmdHF14AMfUeLoad(const char *Cmd){
char c = param_getchar(Cmd, 0); char c = tolower(param_getchar(Cmd, 0));
if ( c == 'h' || c == 'H' || c == 0x00) return usage_hf_mfu_eload(); if ( c == 'h' || c == 0x00) return usage_hf_mfu_eload();
return CmdHF14AMfELoad(Cmd); return CmdHF14AMfELoad(Cmd);
} }
// //
// Simulate tag // Simulate tag
// //
int CmdHF14AMfUSim(const char *Cmd){ int CmdHF14AMfUSim(const char *Cmd){
char c = param_getchar(Cmd, 0); char c = tolower(param_getchar(Cmd, 0));
if ( c == 'h' || c == 'H' || c == 0x00) return usage_hf_mfu_sim(); if ( c == 'h' || c == 0x00) return usage_hf_mfu_sim();
return CmdHF14ASim(Cmd); return CmdHF14ASim(Cmd);
} }
@ -2153,16 +2148,16 @@ int CmdHF14AMfucAuth(const char *Cmd){
uint8_t keyNo = 3; uint8_t keyNo = 3;
bool errors = false; bool errors = false;
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
//Change key to user defined one //Change key to user defined one
if (cmdp == 'k' || cmdp == 'K'){ if (cmdp == 'k'){
keyNo = param_get8(Cmd, 1); keyNo = param_get8(Cmd, 1);
if(keyNo >= KEYS_3DES_COUNT) if(keyNo >= KEYS_3DES_COUNT)
errors = true; errors = true;
} }
if (cmdp == 'h' || cmdp == 'H') errors = true; if (cmdp == 'h') errors = true;
if (errors) return usage_hf_mfu_ucauth(); if (errors) return usage_hf_mfu_ucauth();
@ -2278,9 +2273,9 @@ int CmdTestDES(const char * cmd)
int CmdHF14AMfucSetPwd(const char *Cmd){ int CmdHF14AMfucSetPwd(const char *Cmd){
uint8_t pwd[16] = {0x00}; 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)) { if (param_gethex(Cmd, 0, pwd, 32)) {
PrintAndLogEx(WARNING, "Password must include 32 HEX symbols"); PrintAndLogEx(WARNING, "Password must include 32 HEX symbols");
@ -2295,7 +2290,7 @@ int CmdHF14AMfucSetPwd(const char *Cmd){
UsbCommand resp; UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { if (WaitForResponseTimeout(CMD_ACK,&resp,1500) ) {
if ( (resp.arg[0] & 0xff) == 1) { 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 { } else {
PrintAndLogEx(WARNING, "Failed writing at block %d", resp.arg[1] & 0xff); PrintAndLogEx(WARNING, "Failed writing at block %d", resp.arg[1] & 0xff);
return 1; return 1;
@ -2315,9 +2310,9 @@ int CmdHF14AMfucSetUid(const char *Cmd){
UsbCommand c = {CMD_MIFAREU_READBL}; UsbCommand c = {CMD_MIFAREU_READBL};
UsbCommand resp; UsbCommand resp;
uint8_t uid[7] = {0x00}; 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)) { if (param_gethex(Cmd, 0, uid, 14)) {
PrintAndLogEx(WARNING, "UID must include 14 HEX symbols"); 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 (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_gendiverse();
if ( cmdp == 'r' ) { if ( cmdp == 'r' ) {
// read uid from tag // read uid from tag
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0}}; UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0}};
clearCommandBuffer(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
@ -2395,8 +2390,13 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
iso14a_card_select_t card; iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); 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 uint64_t select_status = resp.arg[0];
if(select_status == 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"); PrintAndLogEx(WARNING, "iso14443a card select failed");
return 1; return 1;
} }
@ -2451,12 +2451,12 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
PrintAndLogEx(NORMAL, "Diversified key: %s", sprint_hex(divkey+1, 6)); PrintAndLogEx(NORMAL, "Diversified key: %s", sprint_hex(divkey+1, 6));
for (int i=0; i < sizeof(mifarekeyA); ++i){ for (int i=0; i < sizeof(mifarekeyA); ++i){
dkeyA[i] = (mifarekeyA[i] << 1) & 0xff; dkeyA[i] = (mifarekeyA[i] << 1) & 0xff;
dkeyA[6] |= ((mifarekeyA[i] >> 7) & 1) << (i+1); dkeyA[6] |= ((mifarekeyA[i] >> 7) & 1) << (i+1);
} }
for (int i=0; i < sizeof(mifarekeyB); ++i){ 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; dkeyB[2+i] = (mifarekeyB[i] << 1) & 0xff;
} }
@ -2493,6 +2493,7 @@ int CmdHF14AMfuPwdGen(const char *Cmd){
uint8_t uid[7] = {0x00}; uint8_t uid[7] = {0x00};
char cmdp = tolower(param_getchar(Cmd, 0)); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_pwdgen(); if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_pwdgen();
if (cmdp == 't') return ul_ev1_pwdgen_selftest(); if (cmdp == 't') return ul_ev1_pwdgen_selftest();
if ( cmdp == 'r') { if ( cmdp == 'r') {
@ -2505,8 +2506,12 @@ int CmdHF14AMfuPwdGen(const char *Cmd){
iso14a_card_select_t card; iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); 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 uint64_t select_status = resp.arg[0];
if(select_status == 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"); PrintAndLogEx(WARNING, "iso14443a card select failed");
return 1; return 1;
} }
@ -2519,6 +2524,7 @@ int CmdHF14AMfuPwdGen(const char *Cmd){
else { else {
if (param_gethex(Cmd, 0, uid, 14)) return usage_hf_mfu_pwdgen(); if (param_gethex(Cmd, 0, uid, 14)) return usage_hf_mfu_pwdgen();
} }
PrintAndLogEx(NORMAL, "---------------------------------"); PrintAndLogEx(NORMAL, "---------------------------------");
PrintAndLogEx(NORMAL, " Using UID : %s", sprint_hex(uid, 7)); PrintAndLogEx(NORMAL, " Using UID : %s", sprint_hex(uid, 7));
PrintAndLogEx(NORMAL, "---------------------------------"); PrintAndLogEx(NORMAL, "---------------------------------");
@ -2536,8 +2542,7 @@ int CmdHF14AMfuPwdGen(const char *Cmd){
//------------------------------------ //------------------------------------
// Menu Stuff // Menu Stuff
//------------------------------------ //------------------------------------
static command_t CommandTable[] = static command_t CommandTable[] = {
{
{"help", CmdHelp, 1, "This help"}, {"help", CmdHelp, 1, "This help"},
{"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"},
{"info", CmdHF14AMfUInfo, 0, "Tag information"}, {"info", CmdHF14AMfUInfo, 0, "Tag information"},
@ -2557,7 +2562,6 @@ static command_t CommandTable[] =
int CmdHFMFUltra(const char *Cmd){ int CmdHFMFUltra(const char *Cmd){
clearCommandBuffer(); clearCommandBuffer();
//WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd); CmdsParse(CommandTable, Cmd);
return 0; return 0;
} }

View file

@ -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); 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; uint16_t memsize = (data[2] + 1) * 8;
topaz_tag.size = memsize; 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: Physical Memory Size of this tag: %d bytes", data[2], memsize);
PrintAndLogEx(NORMAL, " %02x: %s / %s", data[3], PrintAndLogEx(NORMAL, " %02x: %s / %s", data[3],
(data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", (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 *old = topaz_tag.dynamic_lock_areas;
dynamic_lock_area_t *new = topaz_tag.dynamic_lock_areas; dynamic_lock_area_t *new = topaz_tag.dynamic_lock_areas;
if (old == NULL) { 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 { } else {
while(old->next != NULL) { while(old->next != NULL) {
old = old->next; 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; new->next = NULL;
if (area_start <= next_lockable_byte) { if (area_start <= next_lockable_byte) {

View file

@ -74,7 +74,7 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) {
if ( mem_avail > 0 ) if ( mem_avail > 0 )
mem_left = (mem_avail * 1024) - mem_used; 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_avail,
mem_used, mem_used,
mem_avail == 0 ? 0.0f : (float)mem_used/(mem_avail*1024)*100, mem_avail == 0 ? 0.0f : (float)mem_used/(mem_avail*1024)*100,
@ -257,9 +257,9 @@ int CmdVersion(const char *Cmd) {
SendCommand(&c); SendCommand(&c);
if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
#ifdef __WIN32 #ifdef __WIN32
PrintAndLogEx(NORMAL, "\nProxmark3 RFID instrument\n"); PrintAndLogEx(NORMAL, "\n [ Proxmark3 RFID instrument ]\n");
#else #else
PrintAndLogEx(NORMAL, "\n\e[34mProxmark3 RFID instrument\e[0m\n"); PrintAndLogEx(NORMAL, "\n\e[34m [ Proxmark3 RFID instrument ]\e[0m\n");
#endif #endif
char s[50] = {0}; char s[50] = {0};
#if defined(WITH_FLASH) || defined(WITH_SMARTCARD) || defined(WITH_FPC) #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); strncat(s, "fpc; ", sizeof(s) - strlen(s) - 1);
#endif #endif
PrintAndLogEx(NORMAL, "\n [ CLIENT ]"); PrintAndLogEx(NORMAL, "\n [ CLIENT ]");
PrintAndLogEx(NORMAL, " client: iceman %s \n", s); PrintAndLogEx(NORMAL, " client: iceman %s \n", s);
PrintAndLogEx(NORMAL, (char*)resp.d.asBytes); PrintAndLogEx(NORMAL, (char*)resp.d.asBytes);
lookupChipID(resp.arg[0], resp.arg[1]); lookupChipID(resp.arg[0], resp.arg[1]);

View file

@ -186,15 +186,21 @@ int CmdLFCommandRead(const char *Cmd) {
} }
int CmdFlexdemod(const char *Cmd) { int CmdFlexdemod(const char *Cmd) {
#define LONG_WAIT 100
int i, j, start, bit, sum, phase = 0;
uint8_t data[MAX_GRAPH_TRACE_LEN] = {0}; if ( GraphTraceLen < 0 )
size_t size = getFromGraphBuf(data);
if (size == 0)
return 0; return 0;
for (i = 0; i < size; ++i) #ifndef LONG_WAIT
#define LONG_WAIT 100
#endif
int i, j, start, bit, sum, phase = 0;
int data[GraphTraceLen];
memcpy(data, GraphBuffer, GraphTraceLen);
size_t size = GraphTraceLen;
for (i = 0; i < GraphTraceLen; ++i)
data[i] = (data[i] < 0) ? -1 : 1; data[i] = (data[i] < 0) ? -1 : 1;
for (start = 0; start < size - LONG_WAIT; start++) { for (start = 0; start < size - LONG_WAIT; start++) {
@ -819,14 +825,16 @@ int CheckChipType(bool getDeviceData) {
//check for em4x05/em4x69 chips first //check for em4x05/em4x69 chips first
uint32_t word = 0; uint32_t word = 0;
if (EM4x05IsBlock0(&word)) { 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); save_restoreGB(GRAPH_RESTORE);
return 1; return 1;
} }
//check for t55xx chip... //check for t55xx chip...
if (tryDetectP1(true)) { 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); save_restoreGB(GRAPH_RESTORE);
return 1; return 1;
} }
@ -856,9 +864,10 @@ int CmdLFfind(const char *Cmd) {
return 0; return 0;
} }
PrintAndLogEx(NORMAL, "NOTE: some demods output possible binary\n if it finds something that looks like a tag"); PrintAndLogEx(INFO, "NOTE: some demods output possible binary");
PrintAndLogEx(NORMAL, "False Positives ARE possible\n"); PrintAndLogEx(INFO, "if it finds something that looks like a tag");
PrintAndLogEx(NORMAL, "\nChecking for known tags:\n"); PrintAndLogEx(INFO, "False Positives " _YELLOW_(ARE) "possible\n");
PrintAndLogEx(INFO, "\nChecking for known tags:\n");
// only run these tests if device is online // only run these tests if device is online
if (isOnline) { if (isOnline) {
@ -891,6 +900,7 @@ int CmdLFfind(const char *Cmd) {
if (CmdLFNedapDemod("")) { PrintAndLogEx(SUCCESS, "\nValid NEDAP ID Found!"); goto out;} if (CmdLFNedapDemod("")) { PrintAndLogEx(SUCCESS, "\nValid NEDAP ID Found!"); goto out;}
if (CmdNexWatchDemod("")) { PrintAndLogEx(SUCCESS, "\nValid NexWatch 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 (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 (CmdPacDemod("")) { PrintAndLogEx(SUCCESS, "\nValid PAC/Stanley ID Found!"); goto out;}
if (CmdParadoxDemod("")) { PrintAndLogEx(SUCCESS, "\nValid Paradox ID Found!"); goto out;} if (CmdParadoxDemod("")) { PrintAndLogEx(SUCCESS, "\nValid Paradox ID Found!"); goto out;}
if (CmdPrescoDemod("")) { PrintAndLogEx(SUCCESS, "\nValid Presco 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... }"}, {"indala", CmdLFINDALA, 1, "{ Indala RFIDs... }"},
{"io", CmdLFIO, 1, "{ ioProx RFIDs... }"}, {"io", CmdLFIO, 1, "{ ioProx RFIDs... }"},
{"jablotron", CmdLFJablotron, 1, "{ Jablotron RFIDs... }"}, {"jablotron", CmdLFJablotron, 1, "{ Jablotron RFIDs... }"},
{"keri", CmdLFKeri, 1, "{ KERI RFIDs... }"},
{"nedap", CmdLFNedap, 1, "{ Nedap RFIDs... }"}, {"nedap", CmdLFNedap, 1, "{ Nedap RFIDs... }"},
{"nexwatch", CmdLFNEXWATCH, 1, "{ NexWatch RFIDs... }"}, {"nexwatch", CmdLFNEXWATCH, 1, "{ NexWatch RFIDs... }"},
{"noralsy", CmdLFNoralsy, 1, "{ Noralsy RFIDs... }"}, {"noralsy", CmdLFNoralsy, 1, "{ Noralsy RFIDs... }"},

View file

@ -42,13 +42,14 @@
#include "cmdlfnoralsy.h" // for NORALSY meny #include "cmdlfnoralsy.h" // for NORALSY meny
#include "cmdlffdx.h" // for FDX-B meny #include "cmdlffdx.h" // for FDX-B meny
#include "cmdlfcotag.h" // for COTAG meny #include "cmdlfcotag.h" // for COTAG meny
#include "cmdlfindala.h" // for indala menu #include "cmdlfindala.h" // for indala menu
#include "cmdlfguard.h"// for gproxii menu #include "cmdlfguard.h" // for gproxii menu
#include "cmdlffdx.h" // for fdx-b menu #include "cmdlffdx.h" // for fdx-b menu
#include "cmdlfparadox.h"// for paradox menu #include "cmdlfparadox.h" // for paradox menu
#include "cmdlfnexwatch.h" //for nexwatch menu #include "cmdlfnexwatch.h" //for nexwatch menu
#include "cmdlfsecurakey.h" //for securakey menu #include "cmdlfsecurakey.h" //for securakey menu
#include "cmdlfpac.h" // for pac menu #include "cmdlfpac.h" // for pac menu
#include "cmdlfkeri.h" // for keri menu
#define T55XX_WRITE_TIMEOUT 1500 #define T55XX_WRITE_TIMEOUT 1500

View file

@ -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){ 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 ) 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)) { if ( !getAWIDBits(fmtlen, fc, cn, bits)) {
PrintAndLogEx(WARNING, "Error with tag bitstream generation."); 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; 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; return 1;
} }
@ -181,27 +181,27 @@ static void verify_values(uint8_t *fmtlen, uint32_t *fc, uint32_t *cn){
case 50: case 50:
if ((*fc & 0xFFFF) != *fc) { if ((*fc & 0xFFFF) != *fc) {
*fc &= 0xFFFF; *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; break;
case 37: case 37:
if ((*fc & 0x1FFF) != *fc) { if ((*fc & 0x1FFF) != *fc) {
*fc &= 0x1FFF; *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) { if ((*cn & 0x3FFFF) != *cn) {
*cn &= 0x3FFFF; *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; break;
case 34: case 34:
if ((*fc & 0xFF) != *fc) { if ((*fc & 0xFF) != *fc) {
*fc &= 0xFF; *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) { if ((*cn & 0xFFFFFF) != *cn) {
*cn &= 0xFFFFFF; *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; break;
case 26: case 26:
@ -209,11 +209,11 @@ static void verify_values(uint8_t *fmtlen, uint32_t *fc, uint32_t *cn){
*fmtlen = 26; *fmtlen = 26;
if ((*fc & 0xFF) != *fc) { if ((*fc & 0xFF) != *fc) {
*fc &= 0xFF; *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) { if ((*cn & 0xFFFF) != *cn) {
*cn &= 0xFFFF; *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; break;
} }
@ -290,7 +290,7 @@ int CmdAWIDDemod(const char *Cmd) {
uint32_t rawHi2 = bytebits_to_byte(bits + idx, 32); uint32_t rawHi2 = bytebits_to_byte(bits + idx, 32);
size = removeParity(bits, idx+8, 4, 1, 88); 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"); PrintAndLogEx(DEBUG, "DEBUG: Error - AWID at parity check-tag size does not match AWID format");
return 0; return 0;
} }
@ -323,21 +323,21 @@ int CmdAWIDDemod(const char *Cmd) {
fc = bytebits_to_byte(bits + 9, 8); fc = bytebits_to_byte(bits + 9, 8);
cardnum = bytebits_to_byte(bits + 17, 16); cardnum = bytebits_to_byte(bits + 17, 16);
code1 = bytebits_to_byte(bits + 8,fmtLen); 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; break;
case 34: case 34:
fc = bytebits_to_byte(bits + 9, 8); fc = bytebits_to_byte(bits + 9, 8);
cardnum = bytebits_to_byte(bits + 17, 24); cardnum = bytebits_to_byte(bits + 17, 24);
code1 = bytebits_to_byte(bits + 8, (fmtLen-32) ); code1 = bytebits_to_byte(bits + 8, (fmtLen-32) );
code2 = bytebits_to_byte(bits + 8 + (fmtLen-32), 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; break;
case 37: case 37:
fc = bytebits_to_byte(bits + 9, 13); fc = bytebits_to_byte(bits + 9, 13);
cardnum = bytebits_to_byte(bits + 22, 18); cardnum = bytebits_to_byte(bits + 22, 18);
code1 = bytebits_to_byte(bits + 8, (fmtLen-32) ); code1 = bytebits_to_byte(bits + 8, (fmtLen-32) );
code2 = bytebits_to_byte(bits + 8 + (fmtLen-32), 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; break;
// case 40: // case 40:
// break; // break;
@ -346,18 +346,18 @@ int CmdAWIDDemod(const char *Cmd) {
cardnum = bytebits_to_byte(bits + 25, 32); cardnum = bytebits_to_byte(bits + 25, 32);
code1 = bytebits_to_byte(bits + 8, (fmtLen-32) ); code1 = bytebits_to_byte(bits + 8, (fmtLen-32) );
code2 = bytebits_to_byte(bits + 8 + (fmtLen-32), 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; break;
default: default:
if (fmtLen > 32 ) { if (fmtLen > 32 ) {
cardnum = bytebits_to_byte(bits + 8 + (fmtLen-17), 16); cardnum = bytebits_to_byte(bits + 8 + (fmtLen-17), 16);
code1 = bytebits_to_byte(bits + 8, fmtLen-32); code1 = bytebits_to_byte(bits + 8, fmtLen-32);
code2 = bytebits_to_byte(bits + 8 + (fmtLen-32), 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 { } else {
cardnum = bytebits_to_byte(bits + 8 + (fmtLen-17), 16); cardnum = bytebits_to_byte(bits + 8 + (fmtLen-17), 16);
code1 = bytebits_to_byte(bits + 8, fmtLen); 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; break;
} }
@ -386,8 +386,8 @@ int CmdAWIDSim(const char *Cmd) {
verify_values(&fmtlen, &fc, &cn); verify_values(&fmtlen, &fc, &cn);
PrintAndLogEx(NORMAL, "Emulating AWID %u -- FC: %u; CN: %u\n", fmtlen, fc, cn); PrintAndLogEx(SUCCESS, "Simulating AWID %u -- FC: %u; CN: %u\n", fmtlen, fc, cn);
PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or run another command"); PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command");
if (!getAWIDBits(fmtlen, fc, cn, bits)) { if (!getAWIDBits(fmtlen, fc, cn, bits)) {
PrintAndLogEx(WARNING, "Error with tag bitstream generation."); PrintAndLogEx(WARNING, "Error with tag bitstream generation.");
@ -417,8 +417,8 @@ int CmdAWIDClone(const char *Cmd) {
uint8_t *bs=bits; uint8_t *bs=bits;
memset(bs,0,sizeof(bits)); memset(bs,0,sizeof(bits));
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_awid_clone(); if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_awid_clone();
fmtlen = param_get8(Cmd, 0); fmtlen = param_get8(Cmd, 0);
fc = param_get32ex(Cmd, 1, 0, 10); 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 ( !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) //t5555 (Q5) BITRATE = (RF-2)/2 (iceman)
blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 3<<T5555_MAXBLOCK_SHIFT; blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 3<<T5555_MAXBLOCK_SHIFT;
@ -441,7 +441,7 @@ int CmdAWIDClone(const char *Cmd) {
blocks[2] = bytebits_to_byte(bs + 32, 32); blocks[2] = bytebits_to_byte(bs + 32, 32);
blocks[3] = bytebits_to_byte(bs + 64, 32); blocks[3] = bytebits_to_byte(bs + 64, 32);
PrintAndLogEx(NORMAL, "Preparing to clone AWID %u to T55x7 with FC: %u, CN: %u", fmtlen, fc, cn); PrintAndLogEx(INFO, "Preparing to clone AWID %u to T55x7 with FC: %u, CN: %u", fmtlen, fc, cn);
print_blocks(blocks, 4); print_blocks(blocks, 4);
UsbCommand resp; UsbCommand resp;
@ -470,38 +470,32 @@ int CmdAWIDBrute(const char *Cmd) {
memset(bits, 0x00, size); memset(bits, 0x00, size);
uint8_t cmdp = 0; uint8_t cmdp = 0;
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch(param_getchar(Cmd, cmdp)) { switch ( tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
case 'H':
return usage_lf_awid_brute(); return usage_lf_awid_brute();
case 'f': case 'f':
case 'F':
fc = param_get32ex(Cmd ,cmdp+1, 0, 10); fc = param_get32ex(Cmd ,cmdp+1, 0, 10);
if ( !fc ) if ( !fc )
errors = true; errors = true;
cmdp += 2; cmdp += 2;
break; break;
case 'd': case 'd':
case 'D':
// delay between attemps, defaults to 1000ms. // delay between attemps, defaults to 1000ms.
delay = param_get32ex(Cmd, cmdp+1, 1000, 10); delay = param_get32ex(Cmd, cmdp+1, 1000, 10);
cmdp += 2; cmdp += 2;
break; break;
case 'c': case 'c':
case 'C':
cn = param_get32ex(Cmd, cmdp+1, 0, 10); cn = param_get32ex(Cmd, cmdp+1, 0, 10);
// truncate cardnumber. // truncate cardnumber.
cn &= 0xFFFF; cn &= 0xFFFF;
cmdp += 2; cmdp += 2;
break; break;
case 'a': case 'a':
case 'A':
fmtlen = param_get8(Cmd, cmdp+1); fmtlen = param_get8(Cmd, cmdp+1);
cmdp += 2; cmdp += 2;
break; break;
case 'v': case 'v':
case 'V':
verbose = true; verbose = true;
cmdp++; cmdp++;
break; break;
@ -511,7 +505,7 @@ int CmdAWIDBrute(const char *Cmd) {
break; break;
} }
} }
if ( fc == 0 )errors = true; if ( fc == 0 ) errors = true;
if ( errors ) return usage_lf_awid_brute(); if ( errors ) return usage_lf_awid_brute();
// limit fc according to selected format // limit fc according to selected format
@ -519,19 +513,19 @@ int CmdAWIDBrute(const char *Cmd) {
case 50: case 50:
if ((fc & 0xFFFF) != fc) { if ((fc & 0xFFFF) != fc) {
fc &= 0xFFFF; 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; break;
default: default:
if ((fc & 0xFF) != fc) { if ((fc & 0xFF) != fc) {
fc &= 0xFF; fc &= 0xFF;
PrintAndLogEx(NORMAL, "Facility-code truncated to 8-bits (AWID26): %u", fc); PrintAndLogEx(INFO, "Facility-code truncated to 8-bits (AWID26): %u", fc);
} }
break; break;
} }
PrintAndLogEx(NORMAL, "Bruteforceing AWID %d Reader", fmtlen); PrintAndLogEx(SUCCESS, "Bruteforceing AWID %d Reader", fmtlen);
PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or press key"); PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or press key");
uint16_t up = cn; uint16_t up = cn;
uint16_t down = cn; uint16_t down = cn;

View file

@ -58,7 +58,7 @@ int CmdCOTAGDemod(const char *Cmd) {
0 1001 1100 1100 0001 1000 0101 0000 0000 100001010000000001111011100000011010000010000000000000000000000000000000000000000000000000000000100111001100000110000101000 0 1001 1100 1100 0001 1000 0101 0000 0000 100001010000000001111011100000011010000010000000000000000000000000000000000000000000000000000000100111001100000110000101000
1001 1100 1100 0001 10000101 1001 1100 1100 0001 10000101
*/ */
PrintAndLogEx(NORMAL, "COTAG Found: FC %u, CN: %u Raw: %08X%08X%08X%08X", fc, cn, raw1 ,raw2, raw3, raw4); PrintAndLogEx(SUCCESS, "COTAG Found: FC %u, CN: %u Raw: %08X%08X%08X%08X", fc, cn, raw1 ,raw2, raw3, raw4);
return 1; return 1;
} }

View file

@ -364,9 +364,7 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo ) {
int ans = Em410xDecode(bits, &size, &idx, hi, lo); int ans = Em410xDecode(bits, &size, &idx, hi, lo);
if ( ans < 0){ if ( ans < 0){
if (ans == -1) if (ans == -2)
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x not only 0|1 in decoded bitstream");
else if (ans == -2)
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x not enough samples after demod"); PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x not enough samples after demod");
else if (ans == -4) else if (ans == -4)
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x preamble not found"); PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x preamble not found");
@ -404,8 +402,7 @@ int AskEm410xDemod(const char *Cmd, uint32_t *hi, uint64_t *lo, bool verbose) {
// this read is the "normal" read, which download lf signal and tries to demod here. // this read is the "normal" read, which download lf signal and tries to demod here.
int CmdEM410xRead(const char *Cmd) { int CmdEM410xRead(const char *Cmd) {
lf_read(true, 8192); lf_read(true, 8192);
CmdEM410xDemod(Cmd); return CmdEM410xDemod(Cmd);
return 0;
} }
// this read loops on device side. // this read loops on device side.
@ -446,14 +443,14 @@ int CmdEM410xSim(const char *Cmd) {
uint8_t clock = 64; uint8_t clock = 64;
if (param_gethex(Cmd, 0, uid, 10)) { if (param_gethex(Cmd, 0, uid, 10)) {
PrintAndLogEx(NORMAL, "UID must include 10 HEX symbols"); PrintAndLogEx(FAILED, "UID must include 10 HEX symbols");
return 0; return 0;
} }
param_getdec(Cmd, 1, &clock); param_getdec(Cmd, 1, &clock);
PrintAndLogEx(NORMAL, "Starting simulating UID %02X%02X%02X%02X%02X clock: %d", uid[0],uid[1],uid[2],uid[3],uid[4],clock); PrintAndLogEx(SUCCESS, "Starting simulating UID %02X%02X%02X%02X%02X clock: %d", uid[0],uid[1],uid[2],uid[3],uid[4],clock);
PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation"); PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation");
ConstructEM410xEmulGraph(Cmd, clock); ConstructEM410xEmulGraph(Cmd, clock);
@ -474,14 +471,14 @@ int CmdEM410xBrute(const char *Cmd) {
/* default pause time: 1 second */ /* default pause time: 1 second */
uint32_t delay = 1000; uint32_t delay = 1000;
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h' || cmdp == 'H') return usage_lf_em410x_brute(); if (cmdp == 'h') return usage_lf_em410x_brute();
cmdp = param_getchar(Cmd, 1); cmdp = tolower(param_getchar(Cmd, 1));
if (cmdp == 'd' || cmdp == 'D') { if (cmdp == 'd') {
delay = param_get32ex(Cmd, 2, 1000, 10); delay = param_get32ex(Cmd, 2, 1000, 10);
param_getdec(Cmd, 4, &clock); param_getdec(Cmd, 4, &clock);
} else if (cmdp == 'c' || cmdp == 'C') { } else if (cmdp == 'c') {
param_getdec(Cmd, 2, &clock); param_getdec(Cmd, 2, &clock);
delay = param_get32ex(Cmd, 4, 1000, 10); delay = param_get32ex(Cmd, 4, 1000, 10);
} }
@ -498,7 +495,10 @@ int CmdEM410xBrute(const char *Cmd) {
} }
uidBlock = calloc(stUidBlock, 5); uidBlock = calloc(stUidBlock, 5);
if (uidBlock == NULL) return 1; if (uidBlock == NULL) {
fclose(f);
return 1;
}
while( fgets(buf, sizeof(buf), f) ) { while( fgets(buf, sizeof(buf), f) ) {
if (strlen(buf) < 10 || buf[9] == '\n') continue; if (strlen(buf) < 10 || buf[9] == '\n') continue;
@ -508,7 +508,7 @@ int CmdEM410xBrute(const char *Cmd) {
if( buf[0]=='#' ) continue; if( buf[0]=='#' ) continue;
if (param_gethex(buf, 0, uid, 10)) { if (param_gethex(buf, 0, uid, 10)) {
PrintAndLogEx(NORMAL, "UIDs must include 10 HEX symbols"); PrintAndLogEx(FAILED, "UIDs must include 10 HEX symbols");
free(uidBlock); free(uidBlock);
fclose(f); fclose(f);
return 1; return 1;
@ -535,11 +535,12 @@ int CmdEM410xBrute(const char *Cmd) {
fclose(f); fclose(f);
if (uidcnt == 0) { if (uidcnt == 0) {
PrintAndLogEx(NORMAL, "No UIDs found in file"); PrintAndLogEx(FAILED, "No UIDs found in file");
free(uidBlock); free(uidBlock);
return 1; return 1;
} }
PrintAndLogEx(NORMAL, "Loaded %d UIDs from %s, pause delay: %d ms", uidcnt, filename, delay);
PrintAndLogEx(SUCCESS, "Loaded %d UIDs from %s, pause delay: %d ms", uidcnt, filename, delay);
// loop // loop
for(uint32_t c = 0; c < uidcnt; ++c ) { for(uint32_t c = 0; c < uidcnt; ++c ) {
@ -599,7 +600,7 @@ int CmdEM410xWatchnSpoof(const char *Cmd) {
// loops if the captured ID was in XL-format. // loops if the captured ID was in XL-format.
CmdEM410xWatch(Cmd); CmdEM410xWatch(Cmd);
PrintAndLogEx(NORMAL, "# Replaying captured ID: %010" PRIx64 , g_em410xid); PrintAndLogEx(SUCCESS, "# Replaying captured ID: %010" PRIx64 , g_em410xid);
CmdLFaskSim(""); CmdLFaskSim("");
return 0; return 0;
} }
@ -645,17 +646,17 @@ int CmdEM410xWrite(const char *Cmd) {
} }
if (card == 1) { if (card == 1) {
PrintAndLogEx(NORMAL, "Writing %s tag with UID 0x%010" PRIx64 " (clock rate: %d)", "T55x7", id, clock); PrintAndLogEx(SUCCESS, "Writing %s tag with UID 0x%010" PRIx64 " (clock rate: %d)", "T55x7", id, clock);
// NOTE: We really should pass the clock in as a separate argument, but to // NOTE: We really should pass the clock in as a separate argument, but to
// provide for backwards-compatibility for older firmware, and to avoid // provide for backwards-compatibility for older firmware, and to avoid
// having to add another argument to CMD_EM410X_WRITE_TAG, we just store // having to add another argument to CMD_EM410X_WRITE_TAG, we just store
// the clock rate in bits 8-15 of the card value // the clock rate in bits 8-15 of the card value
card = (card & 0xFF) | ((clock << 8) & 0xFF00); card = (card & 0xFF) | ((clock << 8) & 0xFF00);
} else if (card == 0) { } else if (card == 0) {
PrintAndLogEx(NORMAL, "Writing %s tag with UID 0x%010" PRIx64, "T5555", id, clock); PrintAndLogEx(SUCCESS, "Writing %s tag with UID 0x%010" PRIx64, "T5555", id, clock);
card = (card & 0xFF) | ((clock << 8) & 0xFF00); card = (card & 0xFF) | ((clock << 8) & 0xFF00);
} else { } else {
PrintAndLogEx(WARNING, "Error! Bad card type selected.\n"); PrintAndLogEx(FAILED, "Error! Bad card type selected.\n");
return 0; return 0;
} }

View file

@ -82,11 +82,11 @@ int detectFDXB(uint8_t *dest, size_t *size) {
static void verify_values(uint32_t countryid, uint64_t animalid){ static void verify_values(uint32_t countryid, uint64_t animalid){
if ((animalid & 0x3FFFFFFFFF) != animalid) { if ((animalid & 0x3FFFFFFFFF) != animalid) {
animalid &= 0x3FFFFFFFFF; animalid &= 0x3FFFFFFFFF;
PrintAndLogEx(NORMAL, "Animal ID Truncated to 38bits: %"PRIx64, animalid); PrintAndLogEx(INFO, "Animal ID Truncated to 38bits: %"PRIx64, animalid);
} }
if ( (countryid & 0x3ff) != countryid ) { if ( (countryid & 0x3ff) != countryid ) {
countryid &= 0x3ff; countryid &= 0x3ff;
PrintAndLogEx(NORMAL, "Country ID Truncated to 10bits: %03d", countryid); PrintAndLogEx(INFO, "Country ID Truncated to 10bits: %03d", countryid);
} }
} }
@ -159,26 +159,24 @@ int getFDXBits(uint64_t national_id, uint16_t country, uint8_t isanimal, uint8_t
*/ */
int CmdFDXBdemodBI(const char *Cmd){ int CmdFDXBdemodBI(const char *Cmd){
int invert = 1;
int clk = 32; int clk = 32;
int errCnt = 0; int invert = 1, errCnt = 0, offset = 0, maxErr = 0;
int offset = 0, maxErr = 0; uint8_t bs[MAX_DEMOD_BUF_LEN];
uint8_t BitStream[MAX_DEMOD_BUF_LEN]; size_t size = getFromGraphBuf(bs);
size_t size = getFromGraphBuf(BitStream);
errCnt = askdemod(BitStream, &size, &clk, &invert, maxErr, 0, 0); errCnt = askdemod(bs, &size, &clk, &invert, maxErr, 0, 0);
if ( errCnt < 0 || errCnt > maxErr ) { if ( errCnt < 0 || errCnt > maxErr ) {
PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB no data or error found %d, clock: %d", errCnt, clk); PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB no data or error found %d, clock: %d", errCnt, clk);
return 0; return 0;
} }
errCnt = BiphaseRawDecode(BitStream, &size, &offset, 1); errCnt = BiphaseRawDecode(bs, &size, &offset, 1);
if (errCnt < 0 || errCnt > maxErr ) { if (errCnt < 0 || errCnt > maxErr ) {
PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB BiphaseRawDecode: %d", errCnt); PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB BiphaseRawDecode: %d", errCnt);
return 0; return 0;
} }
int preambleIndex = detectFDXB(BitStream, &size); int preambleIndex = detectFDXB(bs, &size);
if (preambleIndex < 0){ if (preambleIndex < 0){
PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB preamble not found :: %d",preambleIndex); PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB preamble not found :: %d",preambleIndex);
return 0; return 0;
@ -188,44 +186,44 @@ int CmdFDXBdemodBI(const char *Cmd){
return 0; return 0;
} }
setDemodBuf(BitStream, 128, preambleIndex); setDemodBuf(bs, 128, preambleIndex);
// remove marker bits (1's every 9th digit after preamble) (pType = 2) // 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 ) { if ( size != 104 ) {
PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB error removeParity:: %d", size); PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB error removeParity:: %d", size);
return 0; 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 //got a good demod
uint64_t NationalCode = ((uint64_t)(bytebits_to_byteLSBF(BitStream+32,6)) << 32) | bytebits_to_byteLSBF(BitStream,32); uint64_t NationalCode = ((uint64_t)(bytebits_to_byteLSBF(bs+32, 6)) << 32) | bytebits_to_byteLSBF(bs, 32);
uint32_t countryCode = bytebits_to_byteLSBF(BitStream+38,10); uint32_t countryCode = bytebits_to_byteLSBF(bs+38, 10);
uint8_t dataBlockBit = BitStream[48]; uint8_t dataBlockBit = bs[48];
uint32_t reservedCode = bytebits_to_byteLSBF(BitStream+49,14); uint32_t reservedCode = bytebits_to_byteLSBF(bs+49, 14);
uint8_t animalBit = BitStream[63]; uint8_t animalBit = bs[63];
uint32_t crc16 = bytebits_to_byteLSBF(BitStream+64,16); uint32_t crc16 = bytebits_to_byteLSBF(bs+64, 16);
uint32_t extended = bytebits_to_byteLSBF(BitStream+80,24); 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]; uint8_t raw[8];
num_to_bytes(rawid, 8, raw); 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); uint16_t calcCrc = crc16_kermit(raw, 8);
PrintAndLogEx(NORMAL, "Animal ID: %04u-%012" PRIu64, countryCode, NationalCode); PrintAndLogEx(SUCCESS, "Animal ID: %04u-%012" PRIu64, countryCode, NationalCode);
PrintAndLogEx(NORMAL, "National Code: %012" PRIu64, NationalCode); PrintAndLogEx(SUCCESS, "National Code: %012" PRIu64, NationalCode);
PrintAndLogEx(NORMAL, "CountryCode: %04u", countryCode); PrintAndLogEx(SUCCESS, "CountryCode: %04u", countryCode);
PrintAndLogEx(NORMAL, "Reserved/RFU: %u", reservedCode); PrintAndLogEx(SUCCESS, "Reserved/RFU: %u", reservedCode);
PrintAndLogEx(NORMAL, "Animal Tag: %s", animalBit ? "True" : "False"); PrintAndLogEx(SUCCESS, "Animal Tag: %s", animalBit ? _YELLOW_(True) : "False");
PrintAndLogEx(NORMAL, "Has extended data: %s [0x%X]", dataBlockBit ? "True" : "False", extended); PrintAndLogEx(SUCCESS, "Has extended data: %s [0x%X]", dataBlockBit ? _YELLOW_(True) : "False", extended);
PrintAndLogEx(NORMAL, "CRC: 0x%04X - [%04X] - %s", crc16, calcCrc, (calcCrc == crc16) ? "Passed" : "Failed"); PrintAndLogEx(SUCCESS, "CRC: 0x%04X - [%04X] - %s", crc16, calcCrc, (calcCrc == crc16) ? _GREEN_(Passed) : "Failed");
if (g_debugMode) { if (g_debugMode) {
PrintAndLogEx(DEBUG, "Start marker %d; Size %d", preambleIndex, size); 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); PrintAndLogEx(DEBUG, "DEBUG BinStream:\n%s",bin);
} }
return 1; return 1;
@ -282,14 +280,14 @@ int CmdFdxDemod(const char *Cmd) {
uint16_t calcCrc = crc16_kermit(raw, 8); 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(SUCCESS, "\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(SUCCESS, "Animal ID %04u-%012" PRIu64, countryCode, NationalCode);
PrintAndLogEx(NORMAL, "National Code %012" PRIu64 " (0x%" PRIx64 ")", NationalCode, NationalCode); PrintAndLogEx(SUCCESS, "National Code %012" PRIu64 " (0x%" PRIx64 ")", NationalCode, NationalCode);
PrintAndLogEx(NORMAL, "Country Code %04u", countryCode); PrintAndLogEx(SUCCESS, "Country Code %04u", countryCode);
PrintAndLogEx(NORMAL, "Reserved/RFU %u (0x04%X)", reservedCode, reservedCode); PrintAndLogEx(SUCCESS, "Reserved/RFU %u (0x04%X)", reservedCode, reservedCode);
PrintAndLogEx(NORMAL, "Animal Tag %s", animalBit ? "True" : "False"); PrintAndLogEx(SUCCESS, "Animal Tag %s", animalBit ? _YELLOW_(True) : "False");
PrintAndLogEx(NORMAL, "Has extended data %s [0x%X]", dataBlockBit ? "True" : "False", extended); PrintAndLogEx(SUCCESS, "Has extended data %s [0x%X]", dataBlockBit ? _YELLOW_(True) : "False", extended);
PrintAndLogEx(NORMAL, "CRC-16 0x%04X - 0x%04X [%s]", crc16, calcCrc, (calcCrc == crc16) ? "Ok" : "Failed"); PrintAndLogEx(SUCCESS, "CRC-16 0x%04X - 0x%04X [%s]", crc16, calcCrc, (calcCrc == crc16) ? _GREEN_(Ok) : "Failed");
if (g_debugMode) { if (g_debugMode) {
PrintAndLogEx(DEBUG, "Start marker %d; Size %d", preambleIndex, size); 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[3] = bytebits_to_byte(bs + 64, 32);
blocks[4] = bytebits_to_byte(bs + 96, 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); print_blocks(blocks, 5);
UsbCommand resp; UsbCommand resp;
@ -379,7 +377,7 @@ int CmdFdxSim(const char *Cmd) {
arg1 = clk << 8 | encoding; arg1 = clk << 8 | encoding;
arg2 = invert << 8 | separator; 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}}; UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};

View file

@ -107,21 +107,21 @@ int GetGuardBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits) {
for (i = 0; i < 4; ++i) for (i = 0; i < 4; ++i)
rawbytes[i+4] = bytebits_to_byte( pre + (i*8), 8); 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) // XOR (only works on wiegand stuff)
for (i = 1; i < 12; ++i) for (i = 1; i < 12; ++i)
rawbytes[i] ^= xorKey ; 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 // convert rawbytes to bits in pre
for (i = 0; i < 12; ++i) for (i = 0; i < 12; ++i)
num_to_bytebitsLSBF( rawbytes[i], 8, pre + (i*8)); num_to_bytebitsLSBF( rawbytes[i], 8, pre + (i*8));
if (g_debugMode) PrintAndLogEx(NORMAL, "\n Raw | %s \n", sprint_hex(rawbytes, sizeof(rawbytes))); PrintAndLogEx(DEBUG, "\n Raw | %s \n", sprint_hex(rawbytes, sizeof(rawbytes)));
if (g_debugMode) PrintAndLogEx(NORMAL, " Raw | %s\n", sprint_bin(pre, 64) ); PrintAndLogEx(DEBUG, " Raw | %s\n", sprint_bin(pre, 64) );
// add spacer bit 0 every 4 bits, starting with index 0, // 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) // 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[4] = 1;
guardBits[5] = 0; 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; return 1;
} }
@ -192,7 +192,7 @@ int CmdGuardDemod(const char *Cmd) {
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII preamble not found"); PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII preamble not found");
else if (preambleIndex == -3) else if (preambleIndex == -3)
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII size not correct: %d", size); 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"); PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII wrong spacerbits");
else else
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII ans: %d", preambleIndex); PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII ans: %d", preambleIndex);
@ -246,9 +246,9 @@ int CmdGuardDemod(const char *Cmd) {
break; break;
} }
if ( !unknown) 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 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; return 1;
} }
@ -290,7 +290,7 @@ int CmdGuardClone(const char *Cmd) {
blocks[2] = bytebits_to_byte(bs + 32, 32); blocks[2] = bytebits_to_byte(bs + 32, 32);
blocks[3] = bytebits_to_byte(bs + 64, 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); print_blocks(blocks, 4);
UsbCommand resp; UsbCommand resp;
@ -333,7 +333,7 @@ int CmdGuardSim(const char *Cmd) {
return 1; 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; uint64_t arg1, arg2;
arg1 = (clock << 8) | encoding; arg1 = (clock << 8) | encoding;

View file

@ -106,7 +106,7 @@ static bool sendTry(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint32_t delay, ui
// this should be optional. // this should be optional.
if ( verbose ) 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); calcWiegand( fmtlen, fc, cn, bits);
@ -164,7 +164,7 @@ int CmdHIDDemod(const char *Cmd) {
} }
if (hi2 != 0){ //extra large HID tags 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 } else { //standard HID tags <38 bits
uint8_t fmtLen = 0; uint8_t fmtLen = 0;
uint32_t cc = 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 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{ }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 hi = 0, lo = 0;
uint32_t n = 0, i = 0; uint32_t n = 0, i = 0;
uint8_t ctmp = param_getchar(Cmd, 0); uint8_t ctmp = tolower(param_getchar(Cmd, 0));
if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_hid_sim(); if ( strlen(Cmd) == 0 || ctmp == 'h' ) return usage_lf_hid_sim();
while (sscanf(&Cmd[i++], "%1x", &n ) == 1) { while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
hi = (hi << 4) | (lo >> 28); hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (n & 0xf); lo = (lo << 4) | (n & 0xf);
} }
PrintAndLogEx(NORMAL, "Emulating tag with ID %x%08x", hi, lo); PrintAndLogEx(SUCCESS, "Simulating HID tag with ID %x%08x", hi, lo);
PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation"); PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation");
UsbCommand c = {CMD_HID_SIM_TAG, {hi, lo, 0}}; UsbCommand c = {CMD_HID_SIM_TAG, {hi, lo, 0}};
clearCommandBuffer(); clearCommandBuffer();
@ -277,7 +277,7 @@ int CmdHIDClone(const char *Cmd) {
lo = (lo << 4) | (n & 0xf); 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; c.d.asBytes[0] = 1;
} else { } else {
@ -285,7 +285,7 @@ int CmdHIDClone(const char *Cmd) {
hi = (hi << 4) | (lo >> 28); hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (n & 0xf); 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; hi2 = 0;
c.d.asBytes[0] = 0; c.d.asBytes[0] = 0;
} }
@ -492,33 +492,28 @@ int CmdHIDBrute(const char *Cmd){
memset(bits, 0, sizeof(bits)); memset(bits, 0, sizeof(bits));
uint8_t cmdp = 0; uint8_t cmdp = 0;
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch(param_getchar(Cmd, cmdp)) { switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
case 'H':
return usage_lf_hid_brute(); return usage_lf_hid_brute();
case 'f': case 'f':
case 'F':
fc = param_get32ex(Cmd ,cmdp+1, 0, 10); fc = param_get32ex(Cmd ,cmdp+1, 0, 10);
if ( !fc ) if ( !fc )
errors = true; errors = true;
cmdp += 2; cmdp += 2;
break; break;
case 'd': case 'd':
case 'D':
// delay between attemps, defaults to 1000ms. // delay between attemps, defaults to 1000ms.
delay = param_get32ex(Cmd, cmdp+1, 1000, 10); delay = param_get32ex(Cmd, cmdp+1, 1000, 10);
cmdp += 2; cmdp += 2;
break; break;
case 'c': case 'c':
case 'C':
cn = param_get32ex(Cmd, cmdp+1, 0, 10); cn = param_get32ex(Cmd, cmdp+1, 0, 10);
// truncate cardnumber. // truncate cardnumber.
cn &= 0xFFFF; cn &= 0xFFFF;
cmdp += 2; cmdp += 2;
break; break;
case 'a': case 'a':
case 'A':
fmtlen = param_get8(Cmd, cmdp+1); fmtlen = param_get8(Cmd, cmdp+1);
cmdp += 2; cmdp += 2;
bool is_ftm_ok = false; bool is_ftm_ok = false;
@ -532,7 +527,6 @@ int CmdHIDBrute(const char *Cmd){
errors = !is_ftm_ok; errors = !is_ftm_ok;
break; break;
case 'v': case 'v':
case 'V':
verbose = true; verbose = true;
cmdp++; cmdp++;
break; break;
@ -545,8 +539,8 @@ int CmdHIDBrute(const char *Cmd){
if ( fc == 0 ) errors = true; if ( fc == 0 ) errors = true;
if ( errors ) return usage_lf_hid_brute(); if ( errors ) return usage_lf_hid_brute();
PrintAndLogEx(NORMAL, "Brute-forcing HID reader"); PrintAndLogEx(INFO, "Brute-forcing HID reader");
PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or run another command"); PrintAndLogEx(INFO, "Press pm3-button to abort simulation or run another command");
uint16_t up = cn; uint16_t up = cn;
uint16_t down = cn; uint16_t down = cn;

View file

@ -136,7 +136,7 @@ int CmdIndalaDemod(const char *Cmd) {
idx = indala224decode(DemodBuffer, &size, &invert); idx = indala224decode(DemodBuffer, &size, &invert);
if (idx < 0 || size != 224) { if (idx < 0 || size != 224) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Indala wrong size, expected [64|224] got: %d (startindex %i)", size, idx); 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){ if (rawbit > 0){
PrintAndLogEx(NORMAL, "Recovered %d raw bits, expected: %d", rawbit, GraphTraceLen/32); PrintAndLogEx(INFO, "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, "worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);
} else { } else {
return 0; return 0;
} }
@ -262,7 +262,7 @@ int CmdIndalaDemodAlt(const char *Cmd) {
} }
if (start == rawbit - uidlen + 1) { if (start == rawbit - uidlen + 1) {
PrintAndLogEx(NORMAL, "nothing to wait for"); PrintAndLogEx(FAILED, "nothing to wait for");
return 0; return 0;
} }
@ -288,7 +288,7 @@ int CmdIndalaDemodAlt(const char *Cmd) {
showbits[bit] = '.' + bits[bit]; showbits[bit] = '.' + bits[bit];
} }
showbits[bit+1]='\0'; showbits[bit+1]='\0';
PrintAndLogEx(NORMAL, "Partial UID=%s", showbits); PrintAndLogEx(SUCCESS, "Partial UID | %s", showbits);
return 0; return 0;
} else { } else {
for (bit = 0; bit < uidlen; bit++) { for (bit = 0; bit < uidlen; bit++) {
@ -313,7 +313,7 @@ int CmdIndalaDemodAlt(const char *Cmd) {
uid2 = (uid2<<1) | 1; uid2 = (uid2<<1) | 1;
} }
} }
PrintAndLogEx(NORMAL, "UID=%s (%x%08x)", showbits, uid1, uid2); PrintAndLogEx(SUCCESS, "UID | %s (%x%08x)", showbits, uid1, uid2);
} }
else { else {
uid3 = uid4 = uid5 = uid6 = uid7 = 0; uid3 = uid4 = uid5 = uid6 = uid7 = 0;
@ -331,7 +331,7 @@ int CmdIndalaDemodAlt(const char *Cmd) {
else else
uid7 = (uid7<<1) | 1; 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 // Checking UID against next occurrences
@ -350,7 +350,7 @@ int CmdIndalaDemodAlt(const char *Cmd) {
times += 1; 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 // Remodulating for tag cloning
// HACK: 2015-01-04 this will have an impact on our new way of seening lf commands (demod) // 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) { int CmdIndalaSim(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_indala_sim(); if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_indala_sim();
uint8_t bits[224]; uint8_t bits[224];
size_t size = sizeof(bits); size_t size = sizeof(bits);
@ -392,9 +392,9 @@ int CmdIndalaSim(const char *Cmd) {
return usage_lf_indala_sim(); return usage_lf_indala_sim();
// convert to binarray // convert to binarray
uint8_t counter = 224; uint8_t counter = 223;
for (uint8_t i=0; i< len; i++) { for (uint8_t i = 0; i < len; i++) {
for(uint8_t j=0; j<8; j++) { for(uint8_t j = 0; j < 8; j++) {
bits[counter--] = hexuid[i] & 1; bits[counter--] = hexuid[i] & 1;
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. // It has to send either 64bits (8bytes) or 224bits (28bytes). Zero padding needed if not.
// lf simpsk 1 c 32 r 2 d 0102030405060708 // lf simpsk 1 c 32 r 2 d 0102030405060708
// PrintAndLogEx(NORMAL, "Emulating Indala UID: %u \n", cn); PrintAndLogEx(SUCCESS, "Simulating Indala UID: %s", sprint_hex(hexuid, len));
// PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or run another command"); PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command");
UsbCommand c = {CMD_PSK_SIM_TAG, {arg1, arg2, size}}; UsbCommand c = {CMD_PSK_SIM_TAG, {arg1, arg2, size}};
memcpy(c.d.asBytes, bits, size); memcpy(c.d.asBytes, bits, size);
@ -427,6 +427,7 @@ int CmdIndalaClone(const char *Cmd) {
uint32_t n = 0, i = 0; uint32_t n = 0, i = 0;
if (strchr(Cmd,'l') != 0) { if (strchr(Cmd,'l') != 0) {
while (sscanf(&Cmd[i++], "%1x", &n ) == 1) { while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
uid1 = (uid1 << 4) | (uid2 >> 28); uid1 = (uid1 << 4) | (uid2 >> 28);
uid2 = (uid2 << 4) | (uid3 >> 28); uid2 = (uid2 << 4) | (uid3 >> 28);
@ -436,7 +437,8 @@ int CmdIndalaClone(const char *Cmd) {
uid6 = (uid6 << 4) | (uid7 >> 28); uid6 = (uid6 << 4) | (uid7 >> 28);
uid7 = (uid7 << 4) | (n & 0xf); 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.cmd = CMD_INDALA_CLONE_TAG_L;
c.d.asDwords[0] = uid1; c.d.asDwords[0] = uid1;
c.d.asDwords[1] = uid2; c.d.asDwords[1] = uid2;
@ -450,7 +452,7 @@ int CmdIndalaClone(const char *Cmd) {
uid1 = (uid1 << 4) | (uid2 >> 28); uid1 = (uid1 << 4) | (uid2 >> 28);
uid2 = (uid2 << 4) | (n & 0xf); 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.cmd = CMD_INDALA_CLONE_TAG;
c.arg[0] = uid1; c.arg[0] = uid1;
c.arg[1] = uid2; c.arg[1] = uid2;

View file

@ -86,15 +86,15 @@ int CmdIOProxDemod(const char *Cmd) {
uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0}; uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0};
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
if (size < 65) { 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; return 0;
} }
//get binary from fsk wave //get binary from fsk wave
int waveIdx = 0; int waveIdx = 0;
idx = detectIOProx(bits, &size, &waveIdx); idx = detectIOProx(bits, &size, &waveIdx);
if (idx < 0){ if (idx < 0) {
if (g_debugMode){ if (g_debugMode) {
if (idx == -1){ if (idx == -1) {
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox not enough samples"); PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox not enough samples");
} else if (idx == -2) { } else if (idx == -2) {
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox just noise detected"); PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox just noise detected");
@ -115,10 +115,10 @@ int CmdIOProxDemod(const char *Cmd) {
setDemodBuf(bits, size, idx); setDemodBuf(bits, size, idx);
setClockGrid(64, waveIdx + (idx*64)); setClockGrid(64, waveIdx + (idx*64));
if (idx==0){ if (idx == 0) {
if (g_debugMode){ if (g_debugMode) {
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox data not found - FSK Bits: %d", size); 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; return retval;
} }
@ -132,15 +132,13 @@ int CmdIOProxDemod(const char *Cmd) {
// //
//XSF(version)facility:codeone+codetwo (raw) //XSF(version)facility:codeone+codetwo (raw)
if (g_debugMode) { 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(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(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(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(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(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(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(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(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(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(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(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(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]);
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]);
}
uint32_t code = bytebits_to_byte(bits+idx,32); uint32_t code = bytebits_to_byte(bits+idx,32);
uint32_t code2 = bytebits_to_byte(bits+idx+32,32); uint32_t code2 = bytebits_to_byte(bits+idx+32,32);
@ -163,13 +161,13 @@ int CmdIOProxDemod(const char *Cmd) {
snprintf(crcStr, 3, "ok"); snprintf(crcStr, 3, "ok");
retval = 1; retval = 1;
} else { } 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); snprintf(crcStr, sizeof(crcStr), "failed 0x%02X != 0x%02X", crc, calccrc);
retval = 0; 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){ if (g_debugMode){
PrintAndLogEx(DEBUG, "DEBUG: IO prox idx: %d, Len: %d, Printing demod buffer:", idx, size); 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)); 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; return 1;
} }
@ -252,8 +250,8 @@ int CmdIOProxSim(const char *Cmd) {
size_t size = sizeof(bits); size_t size = sizeof(bits);
memset(bits, 0x00, size); memset(bits, 0x00, size);
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_io_sim(); if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_io_sim();
version = param_get8(Cmd, 0); version = param_get8(Cmd, 0);
fc = param_get8(Cmd, 1); fc = param_get8(Cmd, 1);
@ -263,7 +261,7 @@ int CmdIOProxSim(const char *Cmd) {
if ((cn & 0xFFFF) != cn) { if ((cn & 0xFFFF) != cn) {
cn &= 0xFFFF; 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 // clock 64, FSK2a fcHIGH 10 | fcLOW 8
@ -272,8 +270,8 @@ int CmdIOProxSim(const char *Cmd) {
arg1 = high << 8 | low; arg1 = high << 8 | low;
arg2 = invert << 8 | clk; arg2 = invert << 8 | clk;
PrintAndLogEx(NORMAL, "Emulating IOProx Version: %u FC: %u; CN: %u\n", version, fc, cn); PrintAndLogEx(SUCCESS, "Simulating 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, "Press pm3-button to abort simulation or run another command");
if ( !getIOProxBits(version, fc, cn, bits)) { if ( !getIOProxBits(version, fc, cn, bits)) {
PrintAndLogEx(WARNING, "Error with tag bitstream generation."); PrintAndLogEx(WARNING, "Error with tag bitstream generation.");
@ -309,7 +307,7 @@ int CmdIOProxClone(const char *Cmd) {
if ((cn & 0xFFFF) != cn) { if ((cn & 0xFFFF) != cn) {
cn &= 0xFFFF; 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)) { if ( !getIOProxBits(version, fc, cn, bits)) {
@ -323,7 +321,7 @@ int CmdIOProxClone(const char *Cmd) {
blocks[1] = bytebits_to_byte(bits, 32); blocks[1] = bytebits_to_byte(bits, 32);
blocks[2] = bytebits_to_byte(bits + 32, 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); print_blocks(blocks, 3);
//UsbCommand c = {CMD_T55XX_WRITE_BLOCK, {0,0,0}}; //UsbCommand c = {CMD_T55XX_WRITE_BLOCK, {0,0,0}};

View file

@ -130,14 +130,14 @@ int CmdJablotronDemod(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Jablotron Tag Found: Card ID: %"PRIx64" :: Raw: %08X%08X", id, raw1, raw2); PrintAndLogEx(SUCCESS, "Jablotron Tag Found: Card ID: %"PRIx64" :: Raw: %08X%08X", id, raw1, raw2);
uint8_t chksum = raw2 & 0xFF; uint8_t chksum = raw2 & 0xFF;
PrintAndLogEx(NORMAL, "Checksum: %02X [%s]", PrintAndLogEx(INFO, "Checksum: %02X [%s]",
chksum, chksum,
(chksum == jablontron_chksum(DemodBuffer)) ? "OK":"FAIL" (chksum == jablontron_chksum(DemodBuffer)) ? _GREEN_(OK) : _RED_(FAIL)
); );
id = DEC2BCD(id); id = DEC2BCD(id);
// Printed format: 1410-nn-nnnn-nnnn // 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, (uint8_t)(id >> 32) & 0xFF,
(uint16_t)(id >> 16) & 0xFFFF, (uint16_t)(id >> 16) & 0xFFFF,
(uint16_t)id & 0xFFFF (uint16_t)id & 0xFFFF
@ -158,8 +158,8 @@ int CmdJablotronClone(const char *Cmd) {
uint8_t bits[64]; uint8_t bits[64];
memset(bits, 0, sizeof(bits)); memset(bits, 0, sizeof(bits));
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_jablotron_clone(); if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_jablotron_clone();
fullcode = param_get64ex(Cmd, 0, 0, 16); fullcode = param_get64ex(Cmd, 0, 0, 16);
@ -170,7 +170,7 @@ int CmdJablotronClone(const char *Cmd) {
// clearing the topbit needed for the preambl detection. // clearing the topbit needed for the preambl detection.
if ((fullcode & 0x7FFFFFFFFF) != fullcode) { if ((fullcode & 0x7FFFFFFFFF) != fullcode) {
fullcode &= 0x7FFFFFFFFF; fullcode &= 0x7FFFFFFFFF;
PrintAndLogEx(NORMAL, "Card Number Truncated to 39bits: %"PRIx64, fullcode); PrintAndLogEx(INFO, "Card Number Truncated to 39bits: %"PRIx64, fullcode);
} }
if ( !getJablotronBits(fullcode, bits)) { if ( !getJablotronBits(fullcode, bits)) {
@ -181,13 +181,13 @@ int CmdJablotronClone(const char *Cmd) {
blocks[1] = bytebits_to_byte(bits, 32); blocks[1] = bytebits_to_byte(bits, 32);
blocks[2] = bytebits_to_byte(bits + 32, 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); print_blocks(blocks, 3);
UsbCommand resp; UsbCommand resp;
UsbCommand c = {CMD_T55XX_WRITE_BLOCK, {0,0,0}}; 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[0] = blocks[i];
c.arg[1] = i; c.arg[1] = i;
clearCommandBuffer(); clearCommandBuffer();
@ -203,15 +203,15 @@ int CmdJablotronClone(const char *Cmd) {
int CmdJablotronSim(const char *Cmd) { int CmdJablotronSim(const char *Cmd) {
uint64_t fullcode = 0; uint64_t fullcode = 0;
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_jablotron_sim(); if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_jablotron_sim();
fullcode = param_get64ex(Cmd, 0, 0, 16); fullcode = param_get64ex(Cmd, 0, 0, 16);
// clearing the topbit needed for the preambl detection. // clearing the topbit needed for the preambl detection.
if ((fullcode & 0x7FFFFFFFFF) != fullcode) { if ((fullcode & 0x7FFFFFFFFF) != fullcode) {
fullcode &= 0x7FFFFFFFFF; 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; uint8_t clk = 64, encoding = 2, separator = 0, invert = 1;
@ -220,7 +220,7 @@ int CmdJablotronSim(const char *Cmd) {
arg1 = clk << 8 | encoding; arg1 = clk << 8 | encoding;
arg2 = invert << 8 | separator; 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}}; UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
getJablotronBits(fullcode, c.d.asBytes); getJablotronBits(fullcode, c.d.asBytes);

243
client/cmdlfkeri.c Normal file
View file

@ -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] <id> <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <id> : Keri Internal ID");
PrintAndLogEx(NORMAL, " <Q5> : 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] <id>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <id> : 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;
}

36
client/cmdlfkeri.h Normal file
View file

@ -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 <string.h>
#include <inttypes.h>
#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

View file

@ -194,15 +194,15 @@ int CmdLFNedapDemod(const char *Cmd) {
chksum2 = bytebits_to_byte(DemodBuffer+110, 8); chksum2 = bytebits_to_byte(DemodBuffer+110, 8);
chksum2 |= bytebits_to_byte(DemodBuffer+119, 8) << 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(SUCCESS, "NEDAP ID Found - Raw: %08x%08x%08x%08x", raw[3], raw[2], raw[1], raw[0]);
PrintAndLogEx(NORMAL, " - UID: %06X", uid); PrintAndLogEx(SUCCESS, " - UID: %06X", uid);
PrintAndLogEx(NORMAL, " - i: %04X", two); PrintAndLogEx(SUCCESS, " - i: %04X", two);
PrintAndLogEx(NORMAL, " - Checksum2 %04X", chksum2); PrintAndLogEx(SUCCESS, " - Checksum2 %04X", chksum2);
if (g_debugMode){ if (g_debugMode){
PrintAndLogEx(DEBUG, "DEBUG: idx: %d, Len: %d, Printing Demod Buffer:", idx, 128); PrintAndLogEx(DEBUG, "DEBUG: idx: %d, Len: %d, Printing Demod Buffer:", idx, 128);
printDemodBuff(); 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; return 1;
@ -268,7 +268,7 @@ int CmdLFNedapClone(const char *Cmd) {
blocks[3] = bytebits_to_byte(bits + 64, 32); blocks[3] = bytebits_to_byte(bits + 64, 32);
blocks[4] = bytebits_to_byte(bits + 96, 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); print_blocks(blocks, 5);
UsbCommand resp; UsbCommand resp;
@ -314,8 +314,8 @@ int CmdLFNedapSim(const char *Cmd) {
return 1; return 1;
} }
PrintAndLogEx(NORMAL, "bin %s", sprint_bin_break(bs, 128, 32)); PrintAndLogEx(SUCCESS, "bin %s", sprint_bin_break(bs, 128, 32));
PrintAndLogEx(NORMAL, "Simulating Nedap - CardNumber: %u", cardnumber ); PrintAndLogEx(SUCCESS, "Simulating Nedap - CardNumber: %u", cardnumber );
UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
memcpy(c.d.asBytes, bs, size); memcpy(c.d.asBytes, bs, size);
@ -332,7 +332,7 @@ int CmdLFNedapChk(const char *Cmd){
len = ( len == 0 ) ? 5 : len>>1; 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); //uint8_t last = GetParity(data, EVEN, 62);
//PrintAndLogEx(NORMAL, "TEST PARITY:: %d | %d ", DemodBuffer[62], last); //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; return 0;
} }

View file

@ -34,14 +34,13 @@ int detectNexWatch(uint8_t *dest, size_t *size, bool *invert) {
int CmdNexWatchDemod(const char *Cmd) { int CmdNexWatchDemod(const char *Cmd) {
if (!PSKDemod("", false)) { 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; return 0;
} }
bool invert = false; bool invert = false;
size_t size = DemodBufferLen; size_t size = DemodBufferLen;
int idx = detectNexWatch(DemodBuffer, &size, &invert); int idx = detectNexWatch(DemodBuffer, &size, &invert);
if (idx <= 0){ if (idx <= 0) {
if (g_debugMode){
if (idx == -1) if (idx == -1)
PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch not enough samples"); PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch not enough samples");
// else if (idx == -2) // else if (idx == -2)
@ -54,7 +53,7 @@ int CmdNexWatchDemod(const char *Cmd) {
// PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch size not correct: %d", size); // PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch size not correct: %d", size);
else else
PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch error %d",idx); PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch error %d",idx);
}
return 0; return 0;
} }
@ -101,6 +100,7 @@ static command_t CommandTable[] = {
}; };
int CmdLFNEXWATCH(const char *Cmd) { int CmdLFNEXWATCH(const char *Cmd) {
clearCommandBuffer();
CmdsParse(CommandTable, Cmd); CmdsParse(CommandTable, Cmd);
return 0; return 0;
} }

View file

@ -161,10 +161,10 @@ int CmdNoralsyDemod(const char *Cmd) {
return 0; 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) { if (raw1 != 0xBB0214FF) {
PrintAndLogEx(NORMAL, "Unknown bits set in first block! Expected 0xBB0214FF, Found: 0x%08X", raw1); PrintAndLogEx(WARNING, "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, "Please post this output in forum to further research on this format");
} }
return 1; return 1;
} }
@ -202,7 +202,7 @@ int CmdNoralsyClone(const char *Cmd) {
blocks[2] = bytebits_to_byte(bits + 32, 32); blocks[2] = bytebits_to_byte(bits + 32, 32);
blocks[3] = bytebits_to_byte(bits + 64, 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); print_blocks(blocks, 4);
UsbCommand resp; UsbCommand resp;
@ -247,7 +247,7 @@ int CmdNoralsySim(const char *Cmd) {
return 1; 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}}; UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
memcpy(c.d.asBytes, bs, size); memcpy(c.d.asBytes, bs, size);

View file

@ -12,11 +12,11 @@ static int CmdHelp(const char *Cmd);
int usage_lf_presco_clone(void){ int usage_lf_presco_clone(void){
PrintAndLogEx(NORMAL, "clone a Presco tag to a T55x7 tag."); PrintAndLogEx(NORMAL, "clone a Presco tag to a T55x7 tag.");
PrintAndLogEx(NORMAL, "Usage: lf presco clone [h] d <Card-ID> H <hex-ID> <Q5>"); PrintAndLogEx(NORMAL, "Usage: lf presco clone [h] d <Card-ID> c <hex-ID> <Q5>");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " d <Card-ID> : 9 digit presco card ID"); PrintAndLogEx(NORMAL, " d <Card-ID> : 9 digit presco card ID");
PrintAndLogEx(NORMAL, " H <hex-ID> : 8 digit hex card number"); PrintAndLogEx(NORMAL, " c <hex-ID> : 8 digit hex card number");
PrintAndLogEx(NORMAL, " <Q5> : specify write to Q5 (t5555 instead of t55x7)"); PrintAndLogEx(NORMAL, " <Q5> : specify write to Q5 (t5555 instead of t55x7)");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); 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, "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, "Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated.");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf presco sim [h] d <Card-ID> or H <hex-ID>"); PrintAndLogEx(NORMAL, "Usage: lf presco sim [h] d <Card-ID> or c <hex-ID>");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " d <Card-ID> : 9 digit presco card number"); PrintAndLogEx(NORMAL, " d <Card-ID> : 9 digit presco card number");
PrintAndLogEx(NORMAL, " H <hex-ID> : 8 digit hex card number"); PrintAndLogEx(NORMAL, " c <hex-ID> : 8 digit hex card number");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf presco sim d 123456789"); 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; int stringlen = 0;
memset(id, 0x00, sizeof(id)); memset(id, 0x00, sizeof(id));
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch(param_getchar(Cmd, cmdp)) { switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
return -1; return -1;
case 'H': case 'c':
hex = true; hex = true;
//get hex //get hex
*fullcode = param_get32ex(Cmd, cmdp+1, 0, 16); *fullcode = param_get32ex(Cmd, cmdp+1, 0, 16);
cmdp+=2; cmdp+=2;
break; break;
case 'D':
case 'd': case 'd':
//param get string int param_getstr(const char *line, int paramnum, char * str) //param get string int param_getstr(const char *line, int paramnum, char * str)
stringlen = param_getstr(Cmd, cmdp+1, id, sizeof(id)); stringlen = param_getstr(Cmd, cmdp+1, id, sizeof(id));
if (stringlen < 2) return -1; if (stringlen < 2) return -1;
cmdp += 2; cmdp += 2;
break; break;
case 'Q':
case 'q': case 'q':
*Q5 = true; *Q5 = true;
cmdp++; cmdp++;
@ -136,7 +134,6 @@ int CmdPrescoDemod(const char *Cmd) {
size_t size = DemodBufferLen; size_t size = DemodBufferLen;
int ans = detectPresco(DemodBuffer, &size); int ans = detectPresco(DemodBuffer, &size);
if (ans < 0) { if (ans < 0) {
if (ans == -1) if (ans == -1)
PrintAndLogEx(DEBUG, "DEBUG: Error - Presco: too few bits found"); PrintAndLogEx(DEBUG, "DEBUG: Error - Presco: too few bits found");
else if (ans == -2) else if (ans == -2)
@ -163,7 +160,7 @@ int CmdPrescoDemod(const char *Cmd) {
char cmd[12] = {0}; char cmd[12] = {0};
sprintf(cmd, "H %08X", cardid); sprintf(cmd, "H %08X", cardid);
GetWiegandFromPresco(cmd, &sitecode, &usercode, &fullcode, &Q5); 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; return 1;
} }
@ -190,12 +187,12 @@ int CmdPrescoClone(const char *Cmd) {
if ((sitecode & 0xFF) != sitecode) { if ((sitecode & 0xFF) != sitecode) {
sitecode &= 0xFF; 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) { if ((usercode & 0xFFFF) != usercode) {
usercode &= 0xFFFF; 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 blocks[1] = 0x10D00000; //preamble
@ -203,7 +200,7 @@ int CmdPrescoClone(const char *Cmd) {
blocks[3] = 0x00000000; blocks[3] = 0x00000000;
blocks[4] = fullcode; 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); print_blocks(blocks, 5);
UsbCommand resp; UsbCommand resp;
@ -236,7 +233,7 @@ int CmdPrescoSim(const char *Cmd) {
arg1 = clk << 8 | encoding; arg1 = clk << 8 | encoding;
arg2 = invert << 8 | separator; 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}}; UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
GetPrescoBits(fullcode, c.d.asBytes); GetPrescoBits(fullcode, c.d.asBytes);

View file

@ -285,7 +285,7 @@ int CmdPyramidClone(const char *Cmd) {
blocks[3] = bytebits_to_byte(bs + 64, 32); blocks[3] = bytebits_to_byte(bs + 64, 32);
blocks[4] = bytebits_to_byte(bs + 96, 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); print_blocks(blocks, 5);
UsbCommand resp; UsbCommand resp;
@ -331,7 +331,7 @@ int CmdPyramidSim(const char *Cmd) {
return 1; 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}}; UsbCommand c = {CMD_FSK_SIM_TAG, {arg1, arg2, size}};
memcpy(c.d.asBytes, bs, size); memcpy(c.d.asBytes, bs, size);

View file

@ -97,12 +97,12 @@ int CmdSecurakeyDemod(const char *Cmd) {
// test parities - evenparity32 looks to add an even parity returns 0 if already even... // test parities - evenparity32 looks to add an even parity returns 0 if already even...
bool parity = !evenparity32(lWiegand) && !oddparity32(rWiegand); 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) if (bitLen <= 32)
PrintAndLogEx(NORMAL, "Wiegand: %08X, Parity: %s", (lWiegand<<(bitLen/2)) | rWiegand, parity ? "Passed" : "Failed"); PrintAndLogEx(SUCCESS, "Wiegand: %08X, Parity: %s", (lWiegand<<(bitLen/2)) | rWiegand, parity ? "Passed" : "Failed");
PrintAndLogEx(NORMAL, "\nHow the FC translates to printed FC is unknown"); PrintAndLogEx(INFO, "\nHow the FC translates to printed FC is unknown");
PrintAndLogEx(NORMAL, "How the checksum is calculated is unknown"); PrintAndLogEx(INFO, "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(INFO, "Help the community identify this format further\n by sharing your tag on the pm3 forum or with forum members");
return 1; return 1;
} }

View file

@ -141,21 +141,33 @@ int usage_t55xx_wakup(){
PrintAndLogEx(NORMAL, " lf t55xx wakeup p 11223344 - send wakeup password"); PrintAndLogEx(NORMAL, " lf t55xx wakeup p 11223344 - send wakeup password");
return 0; return 0;
} }
int usage_t55xx_bruteforce(){ int usage_t55xx_chk(){
PrintAndLogEx(NORMAL, "This command uses A) bruteforce to scan a number range"); PrintAndLogEx(NORMAL, "This command uses a dictionary attack");
PrintAndLogEx(NORMAL, " B) a dictionary attack");
PrintAndLogEx(NORMAL, "press 'enter' to cancel the command"); PrintAndLogEx(NORMAL, "press 'enter' to cancel the command");
PrintAndLogEx(NORMAL, "Usage: lf t55xx bruteforce [h] <start password> <end password> [i <*.dic>]"); PrintAndLogEx(NORMAL, "Usage: lf t55xx bruteforce [h] <m> [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] <start password> <end password>");
PrintAndLogEx(NORMAL, " password must be 4 bytes (8 hex symbols)"); PrintAndLogEx(NORMAL, " password must be 4 bytes (8 hex symbols)");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " <start_pwd> - 4 byte hex value to start pwd search at"); PrintAndLogEx(NORMAL, " <start_pwd> - 4 byte hex value to start pwd search at");
PrintAndLogEx(NORMAL, " <end_pwd> - 4 byte hex value to end pwd search at"); PrintAndLogEx(NORMAL, " <end_pwd> - 4 byte hex value to end pwd search at");
PrintAndLogEx(NORMAL, " i <*.dic> - loads a default keys dictionary file <*.dic>");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf t55xx bruteforce aaaaaaaa bbbbbbbb"); PrintAndLogEx(NORMAL, " lf t55xx bruteforce aaaaaaaa bbbbbbbb");
PrintAndLogEx(NORMAL, " lf t55xx bruteforce i default_pwd.dic");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return 0; return 0;
} }
@ -224,10 +236,9 @@ int CmdT55xxSetConfig(const char *Cmd) {
uint8_t cmdp = 0; uint8_t cmdp = 0;
bool errors = false; bool errors = false;
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
tmp = param_getchar(Cmd, cmdp); tmp = tolower(param_getchar(Cmd, cmdp));
switch(tmp) { switch(tmp) {
case 'h': case 'h':
case 'H':
return usage_t55xx_config(); return usage_t55xx_config();
case 'b': case 'b':
errors |= param_getdec(Cmd, cmdp+1, &bitRate); errors |= param_getdec(Cmd, cmdp+1, &bitRate);
@ -292,12 +303,10 @@ int CmdT55xxSetConfig(const char *Cmd) {
config.offset = offset; config.offset = offset;
cmdp+=2; cmdp+=2;
break; break;
case 'Q':
case 'q': case 'q':
config.Q5 = true; config.Q5 = true;
cmdp++; cmdp++;
break; break;
case 'S':
case 's': case 's':
config.ST = true; config.ST = true;
cmdp++; 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 (!AquireData(page1, block, usepwd, password) ) return 0;
if (!DecodeT55xxBlock()) return 0; if (!DecodeT55xxBlock()) return 0;
char blk[10]={0}; char blk[10] = {0};
sprintf(blk,"%02d", block); sprintf(blk, "%02d", block);
printT55xxBlock(blk); printT55xxBlock(blk);
return 1; return 1;
} }
@ -358,22 +367,18 @@ int CmdT55xxReadBlock(const char *Cmd) {
bool errors = false; bool errors = false;
uint8_t cmdp = 0; uint8_t cmdp = 0;
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch(param_getchar(Cmd, cmdp)) { switch ( tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
case 'H':
return usage_t55xx_read(); return usage_t55xx_read();
case 'b': case 'b':
case 'B':
errors |= param_getdec(Cmd, cmdp+1, &block); errors |= param_getdec(Cmd, cmdp+1, &block);
cmdp += 2; cmdp += 2;
break; break;
case 'o': case 'o':
case 'O':
override = true; override = true;
cmdp++; cmdp++;
break; break;
case 'p': case 'p':
case 'P':
password = param_get32ex(Cmd, cmdp+1, 0, 16); password = param_get32ex(Cmd, cmdp+1, 0, 16);
usepwd = true; usepwd = true;
cmdp += 2; cmdp += 2;
@ -686,7 +691,7 @@ bool tryDetectModulation(){
bool retval = false; bool retval = false;
if ( hits > 1) { 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<hits; ++i){ for(int i=0; i<hits; ++i){
retval = testKnownConfigBlock(tests[i].block0); retval = testKnownConfigBlock(tests[i].block0);
if ( retval ) { if ( retval ) {
@ -937,9 +942,9 @@ int printConfiguration( t55xx_conf_block_t b){
PrintAndLogEx(NORMAL, "Chip Type : %s", (b.Q5) ? "T5555(Q5)" : "T55x7"); PrintAndLogEx(NORMAL, "Chip Type : %s", (b.Q5) ? "T5555(Q5)" : "T55x7");
PrintAndLogEx(NORMAL, "Modulation : %s", GetSelectedModulationStr(b.modulation) ); PrintAndLogEx(NORMAL, "Modulation : %s", GetSelectedModulationStr(b.modulation) );
PrintAndLogEx(NORMAL, "Bit Rate : %s", GetBitRateStr(b.bitrate, (b.block0 & T55x7_X_MODE && (b.block0>>28==6 || b.block0>>28==9))) ); PrintAndLogEx(NORMAL, "Bit Rate : %s", GetBitRateStr(b.bitrate, (b.block0 & T55x7_X_MODE && (b.block0>>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, "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, "Block0 : 0x%08X", b.block0);
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return 0; return 0;
@ -949,13 +954,11 @@ int CmdT55xxWakeUp(const char *Cmd) {
uint32_t password = 0; uint32_t password = 0;
uint8_t cmdp = 0; uint8_t cmdp = 0;
bool errors = false; bool errors = false;
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch(param_getchar(Cmd, cmdp)) { switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
case 'H':
return usage_t55xx_wakup(); return usage_t55xx_wakup();
case 'p': case 'p':
case 'P':
password = param_get32ex(Cmd, cmdp+1, 0, 16); password = param_get32ex(Cmd, cmdp+1, 0, 16);
cmdp += 2; cmdp += 2;
errors = false; errors = false;
@ -971,7 +974,7 @@ int CmdT55xxWakeUp(const char *Cmd) {
UsbCommand c = {CMD_T55XX_WAKEUP, {password, 0, 0}}; UsbCommand c = {CMD_T55XX_WAKEUP, {password, 0, 0}};
clearCommandBuffer(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
PrintAndLogEx(NORMAL, "Wake up command sent. Try read now"); PrintAndLogEx(SUCCESS, "Wake up command sent. Try read now");
return 0; return 0;
} }
@ -985,30 +988,25 @@ int CmdT55xxWriteBlock(const char *Cmd) {
bool testMode = false; bool testMode = false;
bool errors = false; bool errors = false;
uint8_t cmdp = 0; uint8_t cmdp = 0;
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch(param_getchar(Cmd, cmdp)) { switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
case 'H':
return usage_t55xx_write(); return usage_t55xx_write();
case 'b': case 'b':
case 'B':
errors |= param_getdec(Cmd, cmdp+1, &block); errors |= param_getdec(Cmd, cmdp+1, &block);
cmdp += 2; cmdp += 2;
break; break;
case 'd': case 'd':
case 'D':
data = param_get32ex(Cmd, cmdp+1, 0, 16); data = param_get32ex(Cmd, cmdp+1, 0, 16);
gotdata = true; gotdata = true;
cmdp += 2; cmdp += 2;
break; break;
case 'p': case 'p':
case 'P':
password = param_get32ex(Cmd, cmdp+1, 0, 16); password = param_get32ex(Cmd, cmdp+1, 0, 16);
usepwd = true; usepwd = true;
cmdp += 2; cmdp += 2;
break; break;
case 't': case 't':
case 'T':
testMode = true; testMode = true;
cmdp++; cmdp++;
break; break;
@ -1025,7 +1023,7 @@ int CmdT55xxWriteBlock(const char *Cmd) {
if (errors || !gotdata) return usage_t55xx_write(); if (errors || !gotdata) return usage_t55xx_write();
if (block > 7) { 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; return 0;
} }
@ -1037,7 +1035,7 @@ int CmdT55xxWriteBlock(const char *Cmd) {
char pwdStr[16] = {0}; char pwdStr[16] = {0};
snprintf(pwdStr, sizeof(pwdStr), "pwd: 0x%08X", password); 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 //Password mode
if (usepwd) { if (usepwd) {
@ -1054,12 +1052,13 @@ int CmdT55xxWriteBlock(const char *Cmd) {
} }
int CmdT55xxReadTrace(const char *Cmd) { int CmdT55xxReadTrace(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) > 1 || cmdp == 'h') return usage_t55xx_trace();
bool pwdmode = false; bool pwdmode = false;
uint32_t password = 0; uint32_t password = 0;
if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') return usage_t55xx_trace();
if (strlen(Cmd)==0) { if (strlen(Cmd) == 0) {
// sanity check. // sanity check.
if (!SanityOfflineCheck(false)) return 1; if (!SanityOfflineCheck(false)) return 1;
@ -1086,7 +1085,7 @@ int CmdT55xxReadTrace(const char *Cmd) {
uint32_t hdr = PackBits(si, 9, DemodBuffer); si += 9; uint32_t hdr = PackBits(si, 9, DemodBuffer); si += 9;
if (hdr != 0x1FF) { 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; return 1;
} }
@ -1125,7 +1124,7 @@ int CmdT55xxReadTrace(const char *Cmd) {
data.acl = PackBits(si, 8, DemodBuffer); si += 8; data.acl = PackBits(si, 8, DemodBuffer); si += 8;
if ( data.acl != 0xE0 ) { 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; return 1;
} }
@ -1222,11 +1221,11 @@ int CmdT55xxInfo(const char *Cmd){
*/ */
bool pwdmode = false; bool pwdmode = false;
uint32_t password = 0; 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. // sanity check.
if (!SanityOfflineCheck(false)) return 1; 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 inv = PackBits(si, 1, DemodBuffer); si += 1;
uint32_t por = 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, "");
PrintAndLogEx(NORMAL, "-- T55x7 Configuration & Tag Information --------------------"); PrintAndLogEx(NORMAL, "-- T55x7 Configuration & Tag Information --------------------");
PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
PrintAndLogEx(NORMAL, " Safer key : %s", GetSaferStr(safer)); PrintAndLogEx(NORMAL, " Safer key : %s", GetSaferStr(safer));
PrintAndLogEx(NORMAL, " reserved : %d", resv); PrintAndLogEx(NORMAL, " reserved : %d", resv);
PrintAndLogEx(NORMAL, " Data bit rate : %s", GetBitRateStr(dbr, extend)); 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, " Modulation : %s", GetModulationStr(datamod));
PrintAndLogEx(NORMAL, " PSK clock frequency : %d", pskcf); PrintAndLogEx(NORMAL, " PSK clock frequency : %d", pskcf);
PrintAndLogEx(NORMAL, " AOR - Answer on Request : %s", (aor) ? "Yes":"No"); PrintAndLogEx(NORMAL, " AOR - Answer on Request : %s", (aor) ? _GREEN_(Yes) : "No");
PrintAndLogEx(NORMAL, " OTP - One Time Pad : %s", (otp) ? "Yes - Warning":"No" ); PrintAndLogEx(NORMAL, " OTP - One Time Pad : %s", (otp) ? _YELLOW_(Yes - Warning) : "No" );
PrintAndLogEx(NORMAL, " Max block : %d", maxblk); PrintAndLogEx(NORMAL, " Max block : %d", maxblk);
PrintAndLogEx(NORMAL, " Password mode : %s", (pwd) ? "Yes":"No"); PrintAndLogEx(NORMAL, " Password mode : %s", (pwd) ? _GREEN_(Yes) : "No");
PrintAndLogEx(NORMAL, " Sequence Start Terminator : %s", (sst) ? "Yes":"No"); PrintAndLogEx(NORMAL, " Sequence Start Terminator : %s", (sst) ? _GREEN_(Yes) : "No");
PrintAndLogEx(NORMAL, " Fast Write : %s", (fw) ? "Yes":"No"); PrintAndLogEx(NORMAL, " Fast Write : %s", (fw) ? _GREEN_(Yes) : "No");
PrintAndLogEx(NORMAL, " Inverse data : %s", (inv) ? "Yes":"No"); PrintAndLogEx(NORMAL, " Inverse data : %s", (inv) ? _GREEN_(Yes) : "No");
PrintAndLogEx(NORMAL, " POR-Delay : %s", (por) ? "Yes":"No"); PrintAndLogEx(NORMAL, " POR-Delay : %s", (por) ? _GREEN_(Yes) : "No");
PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
PrintAndLogEx(NORMAL, " Raw Data - Page 0"); PrintAndLogEx(NORMAL, " Raw Data - Page 0");
PrintAndLogEx(NORMAL, " Block 0 : 0x%08X %s", block0, sprint_bin(DemodBuffer + config.offset, 32) ); 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; uint32_t password = 0;
bool override = false; bool override = false;
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if ( cmdp == 'h' || cmdp == 'H') return usage_t55xx_dump(); if ( cmdp == 'h') return usage_t55xx_dump();
bool usepwd = ( strlen(Cmd) > 0); bool usepwd = ( strlen(Cmd) > 0);
if ( usepwd ){ if ( usepwd ){
@ -1474,7 +1475,7 @@ int CmdT55xxWipe(const char *Cmd) {
// Try with the default password to reset block 0 // Try with the default password to reset block 0
// With a pwd should work even if pwd bit not set // 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 ) if ( Q5 )
snprintf(ptrData,sizeof(writeData),"b 0 d 6001F004 p 0"); 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); if (!CmdT55xxWriteBlock(ptrData)) PrintAndLogEx(WARNING, "Error writing blk %d", blk);
memset(writeData,0x00, sizeof(writeData)); memset(writeData, 0x00, sizeof(writeData));
} }
return 0; return 0;
} }
@ -1503,22 +1504,67 @@ bool IsCancelled(void) {
return false; return false;
} }
int CmdT55xxBruteForce(const char *Cmd) { int CmdT55xxChkPwds(const char *Cmd) {
// load a default pwd file. // load a default pwd file.
char line[9]; char line[9];
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
int keycnt = 0; int keycnt = 0;
uint8_t stKeyBlock = 20; uint8_t stKeyBlock = 20;
uint8_t *keyBlock = NULL, *p = NULL; uint8_t *keyBlock = NULL, *p = NULL;
uint32_t start_password = 0x00000000; //start password
uint32_t end_password = 0xFFFFFFFF; //end password
bool found = false; bool found = false;
uint8_t timeout = 0;
memset(line, 0, sizeof(line)); memset(line, 0, sizeof(line));
char cmdp = tolower(param_getchar(Cmd, 0)); 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); keyBlock = calloc(stKeyBlock, 4);
if (keyBlock == NULL) return 1; if (keyBlock == NULL) return 1;
@ -1531,7 +1577,7 @@ int CmdT55xxBruteForce(const char *Cmd) {
FILE * f = fopen( filename , "r"); FILE * f = fopen( filename , "r");
if ( !f ) { if ( !f ) {
PrintAndLogEx(NORMAL, "File: %s: not found or locked.", filename); PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename);
free(keyBlock); free(keyBlock);
return 1; return 1;
} }
@ -1546,7 +1592,7 @@ int CmdT55xxBruteForce(const char *Cmd) {
if( line[0]=='#' ) continue; if( line[0]=='#' ) continue;
if (!isxdigit(line[0])) { 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; continue;
} }
@ -1569,19 +1615,20 @@ int CmdT55xxBruteForce(const char *Cmd) {
num_to_bytes( strtoll(line, NULL, 16), 4, keyBlock + 4*keycnt); 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++; keycnt++;
memset(line, 0, sizeof(line)); memset(line, 0, sizeof(line));
} }
if (f) if (f)
fclose(f); fclose(f);
if (keycnt == 0) { if (keycnt == 0) {
PrintAndLogEx(NORMAL, "No keys found in file"); PrintAndLogEx(WARNING, "No keys found in file");
free(keyBlock); free(keyBlock);
return 1; return 1;
} }
PrintAndLogEx(NORMAL, "Loaded %d keys", keycnt); PrintAndLogEx(SUCCESS, "Loaded %d keys", keycnt);
// loop // loop
uint64_t testpwd = 0x00; uint64_t testpwd = 0x00;
@ -1600,74 +1647,92 @@ int CmdT55xxBruteForce(const char *Cmd) {
testpwd = bytes_to_num(keyBlock + 4*c, 4); 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)) { 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); free(keyBlock);
return 0; return 0;
} }
found = tryDetectModulation(); found = tryDetectModulation();
if ( found ) { if ( found )
PrintAndLogEx(NORMAL, "Found valid password: [%08X]", testpwd); break;
//free(keyBlock);
//return 0;
}
} }
PrintAndLogEx(NORMAL, "Password NOT found."); if ( found )
free(keyBlock); PrintAndLogEx(SUCCESS, "Found valid password: [ %08X ]", testpwd);
return 0; 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 :) // Try to read Block 7, first :)
// incremental pwd range search // incremental pwd range search
start_password = param_get32ex(Cmd, 0, 0, 16); start_password = param_get32ex(Cmd, 0, 0, 16);
end_password = param_get32ex(Cmd, 1, 0, 16); end_password = param_get32ex(Cmd, 1, 0, 16);
curr = start_password;
if ( start_password >= end_password ) { if ( start_password >= end_password ) {
free(keyBlock);
return usage_t55xx_bruteforce(); return usage_t55xx_bruteforce();
} }
PrintAndLogEx(NORMAL, "Search password range [%08X -> %08X]", start_password, end_password); PrintAndLogEx(INFO, "Search password range [%08X -> %08X]", start_password, end_password);
uint32_t i = start_password; while ( !found || (curr <= end_password)){
while ((!found) && (i <= end_password)){
printf("."); fflush(stdout); printf("."); fflush(stdout);
if (IsCancelled()) { if (IsCancelled()) {
free(keyBlock);
return 0; return 0;
} }
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i)) { if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, curr)) {
PrintAndLogEx(NORMAL, "Aquireing data from device failed. Quitting"); PrintAndLogEx(WARNING, "Aquireing data from device failed. Quitting");
free(keyBlock);
return 0; return 0;
} }
found = tryDetectModulation(); found = tryDetectModulation();
if (found) break; ++curr;
i++;
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
if (found) if (found)
PrintAndLogEx(NORMAL, "Found valid password: [%08x]", i); PrintAndLogEx(SUCCESS, "Found valid password: [ %08X ]", curr);
else 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; return 0;
} }
int tryOnePassword(uint32_t password) { 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)) { if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, password)) {
PrintAndLogEx(NORMAL, "Acquire data from device failed. Quitting"); PrintAndLogEx(NORMAL, "Acquire data from device failed. Quitting");
return -1; return -1;
@ -1686,8 +1751,8 @@ int CmdT55xxRecoverPW(const char *Cmd) {
uint32_t prev_password = 0xffffffff; uint32_t prev_password = 0xffffffff;
uint32_t mask = 0x0; uint32_t mask = 0x0;
int found = 0; int found = 0;
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h' || cmdp == 'H') return usage_t55xx_recoverpw(); if (cmdp == 'h' ) return usage_t55xx_recoverpw();
orig_password = param_get32ex(Cmd, 0, 0x51243648, 16); //password used by handheld cloners orig_password = param_get32ex(Cmd, 0, 0x51243648, 16); //password used by handheld cloners
@ -1746,9 +1811,9 @@ int CmdT55xxRecoverPW(const char *Cmd) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
if (found == 1) if (found == 1)
PrintAndLogEx(NORMAL, "Found valid password: [%08x]", curr_password); PrintAndLogEx(SUCCESS, "Found valid password: [%08x]", curr_password);
else else
PrintAndLogEx(NORMAL, "Password NOT found."); PrintAndLogEx(WARNING, "Password NOT found.");
return 0; return 0;
} }
@ -1870,13 +1935,11 @@ int CmdT55xxDetectPage1(const char *Cmd){
uint32_t password = 0; uint32_t password = 0;
uint8_t cmdp = 0; uint8_t cmdp = 0;
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch(param_getchar(Cmd, cmdp)) { switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
case 'H':
return usage_t55xx_detectP1(); return usage_t55xx_detectP1();
case 'p': case 'p':
case 'P':
password = param_get32ex(Cmd, cmdp+1, 0, 16); password = param_get32ex(Cmd, cmdp+1, 0, 16);
usepwd = true; usepwd = true;
cmdp += 2; cmdp += 2;
@ -1899,7 +1962,7 @@ int CmdT55xxDetectPage1(const char *Cmd){
return false; return false;
} }
bool success = tryDetectP1(false); bool success = tryDetectP1(false);
if (success) PrintAndLogEx(NORMAL, "T55xx chip found!"); if (success) PrintAndLogEx(SUCCESS, "T55xx chip found!");
return success; return success;
} }
@ -1959,6 +2022,7 @@ static command_t CommandTable[] = {
{"help", CmdHelp, 1, "This help"}, {"help", CmdHelp, 1, "This help"},
{"bruteforce", CmdT55xxBruteForce,0, "<start password> <end password> [i <*.dic>] Simple bruteforce attack to find password"}, {"bruteforce", CmdT55xxBruteForce,0, "<start password> <end password> [i <*.dic>] Simple bruteforce attack to find password"},
{"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, {"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."}, {"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"}, {"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"}, {"p1detect", CmdT55xxDetectPage1,1, "[1] Try detecting if this is a t55xx tag by reading page 1"},

View file

@ -133,6 +133,7 @@ t55xx_conf_block_t Get_t55xx_Config(void);
void Set_t55xx_Config(t55xx_conf_block_t conf); void Set_t55xx_Config(t55xx_conf_block_t conf);
extern int CmdLFT55XX(const char *Cmd); extern int CmdLFT55XX(const char *Cmd);
extern int CmdT55xxChk(const char *Cmd);
extern int CmdT55xxBruteForce(const char *Cmd); extern int CmdT55xxBruteForce(const char *Cmd);
extern int CmdT55xxSetConfig(const char *Cmd); extern int CmdT55xxSetConfig(const char *Cmd);
extern int CmdT55xxReadBlock(const char *Cmd); extern int CmdT55xxReadBlock(const char *Cmd);

View file

@ -118,7 +118,7 @@ int CmdVikingClone(const char *Cmd) {
rawID = getVikingBits(id); 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}}; UsbCommand c = {CMD_VIKING_CLONE_TAG, {rawID >> 32, rawID & 0xFFFFFFFF, Q5}};
clearCommandBuffer(); clearCommandBuffer();
@ -149,7 +149,7 @@ int CmdVikingSim(const char *Cmd) {
arg1 = clk << 8 | encoding; arg1 = clk << 8 | encoding;
arg2 = invert << 8 | separator; 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}}; UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
num_to_bytebits(rawID, size, c.d.asBytes); num_to_bytebits(rawID, size, c.d.asBytes);

View file

@ -165,8 +165,8 @@ int CmdVisa2kClone(const char *Cmd) {
uint64_t id = 0; uint64_t id = 0;
uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_64 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, BL0CK1, 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); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_visa2k_clone(); if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_visa2k_clone();
id = param_get32ex(Cmd, 0, 0, 10); id = param_get32ex(Cmd, 0, 0, 10);
@ -210,7 +210,7 @@ int CmdVisa2kSim(const char *Cmd) {
arg1 = clk << 8 | encoding; arg1 = clk << 8 | encoding;
arg2 = invert << 8 | separator; 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}}; UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};

View file

@ -24,14 +24,14 @@ static command_t CommandTable[] = {
{"lf", CmdLF, 1, "{ Low Frequency commands... }"}, {"lf", CmdLF, 1, "{ Low Frequency commands... }"},
{"emv", CmdEMV, 1, "{ EMV iso14443 and iso7816... }"}, {"emv", CmdEMV, 1, "{ EMV iso14443 and iso7816... }"},
{"rem", CmdRem, 1, "{ Add text to row in log file }"}, {"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 }"}, {"script", CmdScript, 1, "{ Scripting commands }"},
{"trace", CmdTrace, 1, "{ Trace manipulation... }"}, {"trace", CmdTrace, 1, "{ Trace manipulation... }"},
#ifdef WITH_FLASH #ifdef WITH_FLASH
{"mem", CmdFlashMem, 1, "{ RDV40, Flash Memory manipulation... }"}, {"mem", CmdFlashMem, 1, "{ Flash Memory manipulation... }"},
#endif #endif
#ifdef WITH_SMARTCARD #ifdef WITH_SMARTCARD
{"sc", CmdSmartcard, 1, "{ RDV40, Smart card ISO7816 commands... }"}, {"sc", CmdSmartcard, 1, "{ Smart card ISO7816 commands... }"},
#endif #endif
{"quit", CmdQuit, 1, ""}, {"quit", CmdQuit, 1, ""},
{"exit", CmdQuit, 1, "Exit program"}, {"exit", CmdQuit, 1, "Exit program"},

View file

@ -8,6 +8,7 @@
// Proxmark3 RDV40 Smartcard module commands // Proxmark3 RDV40 Smartcard module commands
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdsmartcard.h" #include "cmdsmartcard.h"
#include "../emv/emvjson.h"
static int CmdHelp(const char *Cmd); 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, "Usage: sc raw [h|r|c] d <0A 0B 0C ... hex>");
PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " r : do not read response"); PrintAndLogEx(NORMAL, " r : do not read response");
PrintAndLogEx(NORMAL, " a : active smartcard without select"); PrintAndLogEx(NORMAL, " a : active smartcard without select (reset sc module)");
PrintAndLogEx(NORMAL, " s : active smartcard with select"); PrintAndLogEx(NORMAL, " s : active smartcard with select (get ATR)");
PrintAndLogEx(NORMAL, " t : executes TLV decoder if it possible"); PrintAndLogEx(NORMAL, " t : executes TLV decoder if it possible");
PrintAndLogEx(NORMAL, " 0 : use protocol T=0");
PrintAndLogEx(NORMAL, " d <bytes> : bytes to send"); PrintAndLogEx(NORMAL, " d <bytes> : bytes to send");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " sc raw d 00a404000e315041592e5359532e444446303100 - `1PAY.SYS.DDF01` PPSE directory"); PrintAndLogEx(NORMAL, " sc raw s 0 d 00a404000e315041592e5359532e4444463031 - `1PAY.SYS.DDF01` PPSE directory with get ATR");
PrintAndLogEx(NORMAL, " sc raw d 00a404000e325041592e5359532e444446303100 - `2PAY.SYS.DDF01` PPSE directory"); 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; return 0;
} }
int usage_sm_reader(void) { int usage_sm_reader(void) {
@ -63,15 +68,48 @@ int usage_sm_setclock(void) {
return 0; return 0;
} }
int usage_sm_brute(void) { 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, "Usage: sc brute [h]");
PrintAndLogEx(NORMAL, " h : this help"); 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, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " sc brute"); PrintAndLogEx(NORMAL, " sc brute t");
return 0; 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) { uint8_t GetATRTA1(uint8_t *atr, size_t atrlen) {
if (atrlen > 2) { if (atrlen > 2) {
uint8_t T0 = atr[1]; uint8_t T0 = atr[1];
@ -79,7 +117,7 @@ uint8_t GetATRTA1(uint8_t *atr, size_t atrlen) {
return atr[2]; 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[] = { int DiArray[] = {
@ -141,75 +179,60 @@ float FArray[] = {
int GetATRDi(uint8_t *atr, size_t atrlen) { int GetATRDi(uint8_t *atr, size_t atrlen) {
uint8_t TA1 = GetATRTA1(atr, 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) { int GetATRFi(uint8_t *atr, size_t atrlen) {
uint8_t TA1 = GetATRTA1(atr, 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 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) { float GetATRF(uint8_t *atr, size_t atrlen) {
uint8_t TA1 = GetATRTA1(atr, 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 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) { 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 T0 = atr[1];
uint8_t K = T0 & 0x0F; uint8_t K = T0 & 0x0F;
uint8_t TD1 = 0; uint8_t TD1 = 0, T1len = 0, TD1len = 0, TDilen = 0;
uint8_t T1len = 0;
uint8_t TD1len = 0;
uint8_t TDilen = 0;
if (T0 & 0x10) { 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++; T1len++;
} }
if (T0 & 0x20) { 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++; T1len++;
} }
if (T0 & 0x40) { 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++; T1len++;
} }
if (T0 & 0x80) { if (T0 & 0x80) {
TD1 = atr[2 + T1len]; 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++; T1len++;
if (TD1 & 0x10) { 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++; TD1len++;
} }
if (TD1 & 0x20) { 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++; TD1len++;
} }
if (TD1 & 0x40) { 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++; TD1len++;
} }
if (TD1 & 0x80) { if (TD1 & 0x80) {
uint8_t TDi = atr[2 + T1len + TD1len]; 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++; TD1len++;
bool nextCycle = true; bool nextCycle = true;
@ -217,20 +240,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
while (nextCycle) { while (nextCycle) {
nextCycle = false; nextCycle = false;
if (TDi & 0x10) { 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++; TDilen++;
} }
if (TDi & 0x20) { 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++; TDilen++;
} }
if (TDi & 0x40) { 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++; TDilen++;
} }
if (TDi & 0x80) { if (TDi & 0x80) {
TDi = atr[2 + T1len + TD1len + TDilen]; 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++; TDilen++;
nextCycle = true; nextCycle = true;
@ -240,26 +263,39 @@ 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; uint8_t calen = 2 + T1len + TD1len + TDilen + K;
if (atrlen != calen && atrlen != calen + 1) // may be CRC 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); 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) 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) { if (K > 1) {
PrintAndLog("Historical bytes:"); PrintAndLogEx(INFO, "\tHistorical bytes");
dump_buffer(&atr[2 + T1len + TD1len + TDilen], K, NULL, 1); dump_buffer(&atr[2 + T1len + TD1len + TDilen], K, NULL, 1);
} }
return 0; 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}}; UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}};
clearCommandBuffer(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
@ -275,40 +311,43 @@ static bool smart_select(bool silent) {
return false; return false;
} }
if (!silent) { smart_card_atr_t card;
smart_card_atr_t card; memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t));
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)); PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
}
return true; return true;
} }
static int smart_wait(uint8_t *data) { static int smart_wait(uint8_t *data, bool silent) {
UsbCommand resp; UsbCommand resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
PrintAndLogEx(WARNING, "smart card response failed"); if (!silent) PrintAndLogEx(WARNING, "smart card response timeout");
return -1; return -1;
} }
uint32_t len = resp.arg[0]; uint32_t len = resp.arg[0];
if ( !len ) { if ( !len ) {
PrintAndLogEx(WARNING, "smart card response failed"); if (!silent) PrintAndLogEx(WARNING, "smart card response failed");
return -2; return -2;
} }
memcpy(data, resp.d.asBytes, len); memcpy(data, resp.d.asBytes, len);
PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 32));
if (len >= 2) { 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; 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; bool needGetData = false;
if (datalen < 2 ) { if (datalen < 2 ) {
@ -321,14 +360,14 @@ static int smart_response(uint8_t *data) {
if (needGetData) { if (needGetData) {
int len = data[datalen - 1]; int len = data[datalen - 1];
PrintAndLogEx(INFO, "Requesting response. len=0x%x", len); if (!silent) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len);
uint8_t getstatus[] = {0x00, ISO7816_GETSTATUS, 0x00, 0x00, len}; uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len};
UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}}; UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}};
memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) ); memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) );
clearCommandBuffer(); clearCommandBuffer();
SendCommand(&cStatus); SendCommand(&cStatus);
datalen = smart_wait(data); datalen = smart_wait(data, silent);
if (datalen < 2 ) { if (datalen < 2 ) {
goto out; goto out;
@ -338,8 +377,10 @@ static int smart_response(uint8_t *data) {
if (datalen != len + 2) { if (datalen != len + 2) {
// data with ACK // data with ACK
if (datalen == len + 2 + 1) { // 2 - response, 1 - ACK if (datalen == len + 2 + 1) { // 2 - response, 1 - ACK
if (data[0] != ISO7816_GETSTATUS) { if (data[0] != ISO7816_GET_RESPONSE) {
PrintAndLogEx(ERR, "GetResponse ACK error. len=0x%x data[0]=%02x", len, data[0]); if (!silent) {
PrintAndLogEx(ERR, "GetResponse ACK error. len 0x%x | data[0] %02X", len, data[0]);
}
datalen = 0; datalen = 0;
goto out; goto out;
} }
@ -348,7 +389,9 @@ static int smart_response(uint8_t *data) {
memmove(data, &data[1], datalen); memmove(data, &data[1], datalen);
} else { } else {
// wrong length // 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; return datalen;
} }
static int smart_response(uint8_t *data) {
return smart_responseEx(data, false);
}
int CmdSmartRaw(const char *Cmd) { int CmdSmartRaw(const char *Cmd) {
int hexlen = 0; int hexlen = 0;
bool active = false; bool active = false;
bool active_select = false; bool active_select = false;
bool useT0 = false;
uint8_t cmdp = 0; uint8_t cmdp = 0;
bool errors = false, reply = true, decodeTLV = false, breakloop = false; bool errors = false, reply = true, decodeTLV = false, breakloop = false;
uint8_t data[USB_CMD_DATA_SIZE] = {0x00}; uint8_t data[USB_CMD_DATA_SIZE] = {0x00};
@ -385,6 +433,10 @@ int CmdSmartRaw(const char *Cmd) {
decodeTLV = true; decodeTLV = true;
cmdp++; cmdp++;
break; break;
case '0':
useT0 = true;
cmdp++;
break;
case 'd': { case 'd': {
switch (param_gethex_to_eol(Cmd, cmdp+1, data, sizeof(data), &hexlen)) { switch (param_gethex_to_eol(Cmd, cmdp+1, data, sizeof(data), &hexlen)) {
case 1: case 1:
@ -425,7 +477,10 @@ int CmdSmartRaw(const char *Cmd) {
} }
if (hexlen > 0) { 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 ); memcpy(c.d.asBytes, data, hexlen );
@ -457,7 +512,7 @@ int CmdSmartRaw(const char *Cmd) {
} }
if (decodeTLV && len > 4) if (decodeTLV && len > 4)
TLVPrintFromBuffer(buf+1, len-3); TLVPrintFromBuffer(buf, len-2);
free(buf); free(buf);
} }
@ -468,8 +523,9 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
*dataoutlen = 0; *dataoutlen = 0;
if (activateCard) if (activateCard)
smart_select(false); smart_select(false, NULL);
printf("* APDU SC\n");
PrintAndLogEx(DEBUG, "APDU SC");
UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, datainlen, 0}}; UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, datainlen, 0}};
if (activateCard) { if (activateCard) {
@ -479,10 +535,10 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
clearCommandBuffer(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
int len = smart_response(dataout); int len = smart_responseEx(dataout, true);
if ( len < 0 ) { if ( len < 0 ) {
return 2; return 1;
} }
// retry // retry
@ -496,15 +552,13 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
clearCommandBuffer(); clearCommandBuffer();
SendCommand(&c2); SendCommand(&c2);
len = smart_response(dataout); len = smart_responseEx(dataout, true);
} }
*dataoutlen = len; *dataoutlen = len;
return 0; return 0;
} }
int CmdSmartUpgrade(const char *Cmd) { int CmdSmartUpgrade(const char *Cmd) {
PrintAndLogEx(WARNING, "WARNING - Smartcard socket firmware upgrade."); PrintAndLogEx(WARNING, "WARNING - Smartcard socket firmware upgrade.");
@ -541,7 +595,7 @@ int CmdSmartUpgrade(const char *Cmd) {
// load file // load file
f = fopen(filename, "rb"); f = fopen(filename, "rb");
if ( !f ){ if ( !f ){
PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename); PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename);
return 1; return 1;
} }
@ -652,32 +706,36 @@ int CmdSmartInfo(const char *Cmd){
memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t));
// print header // print header
PrintAndLogEx(INFO, "\n--- Smartcard Information ---------"); PrintAndLogEx(INFO, "--- Smartcard Information ---------");
PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(INFO, "ISO76183 ATR : %s", sprint_hex(card.atr, card.atr_len)); PrintAndLogEx(INFO, "ISO7618-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
PrintAndLogEx(INFO, "look up ATR"); PrintAndLogEx(INFO, "\nhttp://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) );
PrintAndLogEx(INFO, "http://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) );
// print ATR // print ATR
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "* ATR:"); PrintAndLogEx(INFO, "ATR");
PrintATR(card.atr, card.atr_len); PrintATR(card.atr, card.atr_len);
// print D/F (brom byte TA1 or defaults) // print D/F (brom byte TA1 or defaults)
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "* D/F (TA1):"); PrintAndLogEx(INFO, "D/F (TA1)");
int Di = GetATRDi(card.atr, card.atr_len); int Di = GetATRDi(card.atr, card.atr_len);
int Fi = GetATRFi(card.atr, card.atr_len); int Fi = GetATRFi(card.atr, card.atr_len);
float F = GetATRF(card.atr, card.atr_len); float F = GetATRF(card.atr, card.atr_len);
if (GetATRTA1(card.atr, card.atr_len) == 0x11) if (GetATRTA1(card.atr, card.atr_len) == 0x11)
PrintAndLogEx(INFO, "Using default values..."); PrintAndLogEx(INFO, "Using default values...");
PrintAndLogEx(NORMAL, "Di=%d", Di); PrintAndLogEx(NORMAL, "\t- Di %d", Di);
PrintAndLogEx(NORMAL, "Fi=%d", Fi); PrintAndLogEx(NORMAL, "\t- Fi %d", Fi);
PrintAndLogEx(NORMAL, "F=%.1f MHz", F); PrintAndLogEx(NORMAL, "\t- F %.1f MHz", F);
PrintAndLogEx(NORMAL, "Cycles/ETU=%d", Fi/Di);
PrintAndLogEx(NORMAL, "%.1f bits/sec at 4MHz", (float)4000000 / (Fi/Di)); if (Di && Fi) {
PrintAndLogEx(NORMAL, "%.1f bits/sec at Fmax=%.1fMHz", (F * 1000000) / (Fi/Di), F); 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; return 0;
} }
@ -784,55 +842,102 @@ int CmdSmartList(const char *Cmd) {
return 0; return 0;
} }
int CmdSmartBruteforceSFI(const char *Cmd) { static void smart_brute_prim(){
char ctmp = tolower(param_getchar(Cmd, 0)); uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t));
if (ctmp == 'h') return usage_sm_brute(); 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
};
PrintAndLogEx(INFO, "Selecting card"); UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, 5, 0}};
if ( !smart_select(false) ) {
return 1; PrintAndLogEx(INFO, "Reading primitives");
for (int i = 0; i < sizeof(get_card_data); i += 5) {
memcpy(c.d.asBytes, get_card_data+i, 5 );
clearCommandBuffer();
SendCommand(&c);
len = smart_responseEx(buf, true);
if ( len > 2 ) {
//if ( decodeTLV ) {
//if (!TLVPrintFromBuffer(buf, len-2)) {
PrintAndLogEx(SUCCESS, "\tHEX %d |: %s", len, sprint_hex(buf, len));
//}
//}
}
len = 0;
} }
free(buf);
}
PrintAndLogEx(INFO, "Selecting PPSE aid"); static int smart_brute_sfi(bool decodeTLV){
CmdSmartRaw("d 00a404000e325041592e5359532e444446303100");
CmdSmartRaw("d 00a4040007a000000004101000");
PrintAndLogEx(INFO, "starting"); uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t));
UsbCommand c = {CMD_SMART_RAW, {SC_RAW, sizeof(data), 0}};
uint8_t* buf = malloc(USB_CMD_DATA_SIZE);
if ( !buf ) if ( !buf )
return 1; return 1;
for (uint8_t i=1; i < 4; i++) { int len = 0;
for (int p1=1; p1 < 5; p1++) { // READ RECORD
uint8_t READ_RECORD[] = {0x00, 0xB2, 0x00, 0x00, 0x00};
UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, sizeof(READ_RECORD), 0}};
data[2] = p1; PrintAndLogEx(INFO, "Start SFI brute forcing");
data[3] = (i << 3) + 4;
memcpy(c.d.asBytes, data, sizeof(data) ); 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(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
smart_response(buf); len = smart_responseEx(buf, true);
// if 0x6C
if ( buf[0] == 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(); clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
uint8_t len = smart_response(buf); len = smart_responseEx(buf, true);
// TLV decoder READ_RECORD[4] = 0;
if (len > 4) }
TLVPrintFromBuffer(buf+1, len-3);
data[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); memset(buf, 0x00, USB_CMD_DATA_SIZE);
} }
@ -841,6 +946,175 @@ int CmdSmartBruteforceSFI(const char *Cmd) {
return 0; 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[] = { static command_t CommandTable[] = {
{"help", CmdHelp, 1, "This help"}, {"help", CmdHelp, 1, "This help"},
{"list", CmdSmartList, 0, "List ISO 7816 history"}, {"list", CmdSmartList, 0, "List ISO 7816 history"},

View file

@ -33,6 +33,7 @@ extern int CmdSmartUpgrade(const char* cmd);
extern int CmdSmartInfo(const char* cmd); extern int CmdSmartInfo(const char* cmd);
extern int CmdSmartReader(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 ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
extern int usage_sm_raw(void); extern int usage_sm_raw(void);

View file

@ -14,7 +14,6 @@ static int CmdHelp(const char *Cmd);
// trace pointer // trace pointer
static uint8_t *trace; static uint8_t *trace;
long traceLen = 0; long traceLen = 0;
bool preRDV40 = true;
int usage_trace_list(){ int usage_trace_list(){
PrintAndLogEx(NORMAL, "List protocol data in trace buffer."); PrintAndLogEx(NORMAL, "List protocol data in trace buffer.");
@ -167,6 +166,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
break; break;
case PROTO_MIFARE: case PROTO_MIFARE:
crcStatus = mifare_CRC_check(isResponse, frame, data_len); crcStatus = mifare_CRC_check(isResponse, frame, data_len);
break;
case ISO_14443A: case ISO_14443A:
case MFDES: case MFDES:
crcStatus = iso14443A_CRC_check(isResponse, frame, data_len); 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) { 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, " Gap | Src | Data | CRC | Annotation |");
PrintAndLogEx(NORMAL, "--------|-----|---------------------------------|----------|-------------------|"); PrintAndLogEx(NORMAL, "--------|-----|---------------------------------|----------|-------------------|");
uint16_t tracepos = 0; uint16_t tracepos = 0;
@ -297,8 +298,9 @@ void printFelica(uint16_t traceLen, uint8_t *trace) {
if (tracepos + 3 >= traceLen) break; 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; tracepos += 3;
if (tracepos + 3 >= traceLen) break; if (tracepos + 3 >= traceLen) break;
@ -511,8 +513,8 @@ int CmdTraceList(const char *Cmd) {
} }
} }
PrintAndLogEx(NORMAL, "Recorded Activity (TraceLen = %d bytes)", traceLen); PrintAndLogEx(SUCCESS, "Recorded Activity (TraceLen = %d bytes)", traceLen);
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "");
if (protocol == FELICA) { if (protocol == FELICA) {
printFelica(traceLen, trace); printFelica(traceLen, trace);
} else { } else {
@ -526,8 +528,6 @@ int CmdTraceList(const char *Cmd) {
" Tag Mode: Timings are in sub carrier periods (1/212 kHz == 4.7us)"); " Tag Mode: Timings are in sub carrier periods (1/212 kHz == 4.7us)");
if ( protocol == ISO_15693 ) if ( protocol == ISO_15693 )
PrintAndLogEx(NORMAL, "ISO15693 - Timings are not as accurate"); 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 ) if ( protocol == ISO_7816_4 )
PrintAndLogEx(NORMAL, "ISO7816-4 / Smartcard - Timings N/A yet"); PrintAndLogEx(NORMAL, "ISO7816-4 / Smartcard - Timings N/A yet");

View file

@ -155,41 +155,30 @@ static void UsbCommandReceived(UsbCommand* c) {
memset(s, 0x00, sizeof(s)); memset(s, 0x00, sizeof(s));
size_t len = MIN(c->arg[0], USB_CMD_DATA_SIZE); size_t len = MIN(c->arg[0], USB_CMD_DATA_SIZE);
memcpy(s, c->d.asBytes, len); 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
uint64_t flag = c->arg[1]; 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 switch (flag) {
if ( c->arg[1] == CMD_MEASURE_ANTENNA_TUNING_HF) { case FLAG_RAWPRINT:
PrintAndLogEx(NORMAL, "\r#db# %s", s); printf("%s", s);
} else { break;
PrintAndLogEx(NORMAL, "#db# %s", s); 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); fflush(stdout);
break; break;
} }
case CMD_DEBUG_PRINT_INTEGERS: { 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; break;
} }
// iceman: hw status - down the path on device, runs printusbspeed which starts sending a lot of // iceman: hw status - down the path on device, runs printusbspeed which starts sending a lot of

View file

@ -24,7 +24,9 @@
#include "util.h" #include "util.h"
#include "proxmark3.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 { enum asn1_tag_t {
ASN1_TAG_GENERIC, ASN1_TAG_GENERIC,
@ -235,10 +237,13 @@ static char *asn1_oid_description(const char *oid, bool with_group_desc) {
static char res[300]; static char res[300];
memset(res, 0x00, sizeof(res)); 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"); strcat(fname, "crypto/oids.json");
if (access(fname, F_OK) < 0) { if (access(fname, F_OK) < 0) {
strcpy(fname, get_my_executable_directory()); strncpy(fname, get_my_executable_directory(), len);
strcat(fname, "oids.json"); strcat(fname, "oids.json");
if (access(fname, F_OK) < 0) { if (access(fname, F_OK) < 0) {
goto error; // file not found goto error; // file not found

View file

@ -8,3 +8,4 @@ AEA684A6DAB23278 -- AA1
5b7c62c491c11b39 -- from loclass demo file. 5b7c62c491c11b39 -- from loclass demo file.
F0E1D2C3B4A59687 -- Kd from PicoPass 2k documentation F0E1D2C3B4A59687 -- Kd from PicoPass 2k documentation
5CBCF1DA45D5FB4F -- PicoPass Default Exchange Key 5CBCF1DA45D5FB4F -- PicoPass Default Exchange Key
31ad7ebd2f282168 -- From HID multiclassSE reader

View file

@ -98,6 +98,7 @@ fc00018778f7,--VästtrafikenKeyA, RKFÖstgötaTrafikenKeyA
314B49474956,--VIGIK1KeyA 314B49474956,--VIGIK1KeyA
564c505f4d41,--VIGIK1KeyB 564c505f4d41,--VIGIK1KeyB
ba5b895da162,--VIGIK1KeyB ba5b895da162,--VIGIK1KeyB
4143414F5250,
# #
# Data from: http://irq5.io/2013/04/13/decoding-bcard-conference-badges/ # Data from: http://irq5.io/2013/04/13/decoding-bcard-conference-badges/
f4a9ef2afc6d,--BCARD KeyB f4a9ef2afc6d,--BCARD KeyB
@ -709,3 +710,49 @@ EA0FD73CB149,
FC0001877BF7, FC0001877BF7,
FD8705E721B0, FD8705E721B0,
00ada2cd516d, 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,

View file

@ -96,6 +96,7 @@ FABADA11, //china?
69696969, 69696969,
12121212, 12121212,
12344321, 12344321,
1234ABCD,
11112222, 11112222,
13131313, 13131313,
10041004, 10041004,
@ -104,8 +105,8 @@ FABADA11, //china?
abcd1234, abcd1234,
20002000, 20002000,
19721972, 19721972,
aa55aa55, //amiboo aa55aa55, // amiboo
55aa55aa, //rev amiboo 55aa55aa, // rev amiboo
4f271149, // seeds ul-ev1 4f271149, // seeds ul-ev1
07d7bb0b, // seeds ul-ev1 07d7bb0b, // seeds ul-ev1
9636ef8f, // seeds ul-ev1 9636ef8f, // seeds ul-ev1
@ -113,4 +114,4 @@ b5f44686, // seeds ul-ev1
9E3779B9, // TEA 9E3779B9, // TEA
C6EF3720, // TEA C6EF3720, // TEA
7854794A, // xbox tea constant :) 7854794A, // xbox tea constant :)
F1EA5EED, //burtle F1EA5EED, // burtle

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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,

View file

@ -38,6 +38,20 @@ void ParamLoadDefaults(struct tlvdb *tlvRoot) {
TLV_ADD(0x9F6A, "\x01\x02\x03\x04"); TLV_ADD(0x9F6A, "\x01\x02\x03\x04");
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4 //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC 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) { int CmdEMVSelect(const char *cmd) {
@ -67,6 +81,7 @@ int CmdEMVSelect(const char *cmd) {
EMVCommandChannel channel = ECC_CONTACTLESS; EMVCommandChannel channel = ECC_CONTACTLESS;
if (arg_get_lit(5)) if (arg_get_lit(5))
channel = ECC_CONTACT; channel = ECC_CONTACT;
PrintChannel(channel);
CLIGetHexWithReturn(6, data, &datalen); CLIGetHexWithReturn(6, data, &datalen);
CLIParserFree(); CLIParserFree();
@ -114,6 +129,7 @@ int CmdEMVSearch(const char *cmd) {
EMVCommandChannel channel = ECC_CONTACTLESS; EMVCommandChannel channel = ECC_CONTACTLESS;
if (arg_get_lit(5)) if (arg_get_lit(5))
channel = ECC_CONTACT; channel = ECC_CONTACT;
PrintChannel(channel);
CLIParserFree(); CLIParserFree();
SetAPDULogging(APDULogging); SetAPDULogging(APDULogging);
@ -170,6 +186,7 @@ int CmdEMVPPSE(const char *cmd) {
EMVCommandChannel channel = ECC_CONTACTLESS; EMVCommandChannel channel = ECC_CONTACTLESS;
if (arg_get_lit(7)) if (arg_get_lit(7))
channel = ECC_CONTACT; channel = ECC_CONTACT;
PrintChannel(channel);
CLIParserFree(); CLIParserFree();
SetAPDULogging(APDULogging); SetAPDULogging(APDULogging);
@ -224,6 +241,7 @@ int CmdEMVGPO(const char *cmd) {
EMVCommandChannel channel = ECC_CONTACTLESS; EMVCommandChannel channel = ECC_CONTACTLESS;
if (arg_get_lit(6)) if (arg_get_lit(6))
channel = ECC_CONTACT; channel = ECC_CONTACT;
PrintChannel(channel);
CLIGetHexWithReturn(7, data, &datalen); CLIGetHexWithReturn(7, data, &datalen);
CLIParserFree(); CLIParserFree();
@ -235,6 +253,7 @@ int CmdEMVGPO(const char *cmd) {
// calc PDOL // calc PDOL
struct tlv *pdol_data_tlv = NULL; struct tlv *pdol_data_tlv = NULL;
struct tlvdb *tmp_ext = NULL;
struct tlv data_tlv = { struct tlv data_tlv = {
.tag = 0x83, .tag = 0x83,
.len = datalen, .len = datalen,
@ -248,9 +267,11 @@ int CmdEMVGPO(const char *cmd) {
ParamLoadFromJson(tlvRoot); 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){ if (!pdol_data_tlv){
PrintAndLogEx(ERR, "Can't create PDOL TLV."); PrintAndLogEx(ERR, "Can't create PDOL TLV.");
tlvdb_free(tmp_ext);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
return 4; 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); unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len);
if (!pdol_data_tlv_data) { if (!pdol_data_tlv_data) {
PrintAndLogEx(ERR, "Can't create PDOL data."); PrintAndLogEx(ERR, "Can't create PDOL data.");
tlvdb_free(tmp_ext);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
return 4; return 4;
} }
@ -278,6 +300,8 @@ int CmdEMVGPO(const char *cmd) {
if (pdol_data_tlv != &data_tlv) if (pdol_data_tlv != &data_tlv)
free(pdol_data_tlv); free(pdol_data_tlv);
tlvdb_free(tmp_ext);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
if (sw) if (sw)
@ -306,7 +330,7 @@ int CmdEMVReadRecord(const char *cmd) {
arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("aA", "apdu", "show APDU reqests and responses"),
arg_lit0("tT", "tlv", "TLV decode results of selected applets"), 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_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
arg_strx1(NULL, NULL, "<SFI 1byte HEX><SFIrec 1byte HEX>", NULL), arg_strx1(NULL, NULL, "<SFI 1byte HEX><SFIrecord 1byte HEX>", NULL),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(cmd, argtable, true); CLIExecWithReturn(cmd, argtable, true);
@ -317,6 +341,7 @@ int CmdEMVReadRecord(const char *cmd) {
EMVCommandChannel channel = ECC_CONTACTLESS; EMVCommandChannel channel = ECC_CONTACTLESS;
if (arg_get_lit(4)) if (arg_get_lit(4))
channel = ECC_CONTACT; channel = ECC_CONTACT;
PrintChannel(channel);
CLIGetHexWithReturn(5, data, &datalen); CLIGetHexWithReturn(5, data, &datalen);
CLIParserFree(); CLIParserFree();
@ -399,6 +424,7 @@ int CmdEMVAC(const char *cmd) {
EMVCommandChannel channel = ECC_CONTACTLESS; EMVCommandChannel channel = ECC_CONTACTLESS;
if (arg_get_lit(8)) if (arg_get_lit(8))
channel = ECC_CONTACT; channel = ECC_CONTACT;
PrintChannel(channel);
CLIGetHexWithReturn(9, data, &datalen); CLIGetHexWithReturn(9, data, &datalen);
CLIParserFree(); CLIParserFree();
@ -410,6 +436,7 @@ int CmdEMVAC(const char *cmd) {
// calc CDOL // calc CDOL
struct tlv *cdol_data_tlv = NULL; struct tlv *cdol_data_tlv = NULL;
struct tlvdb *tmp_ext = NULL;
struct tlv data_tlv = { struct tlv data_tlv = {
.tag = 0x01, .tag = 0x01,
.len = datalen, .len = datalen,
@ -424,9 +451,11 @@ int CmdEMVAC(const char *cmd) {
ParamLoadFromJson(tlvRoot); 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){ if (!cdol_data_tlv){
PrintAndLogEx(ERR, "Can't create CDOL TLV."); PrintAndLogEx(ERR, "Can't create CDOL TLV.");
tlvdb_free(tmp_ext);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
return 4; return 4;
} }
@ -447,6 +476,8 @@ int CmdEMVAC(const char *cmd) {
if (cdol_data_tlv != &data_tlv) if (cdol_data_tlv != &data_tlv)
free(cdol_data_tlv); free(cdol_data_tlv);
tlvdb_free(tmp_ext);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
if (sw) if (sw)
@ -481,6 +512,7 @@ int CmdEMVGenerateChallenge(const char *cmd) {
EMVCommandChannel channel = ECC_CONTACTLESS; EMVCommandChannel channel = ECC_CONTACTLESS;
if (arg_get_lit(3)) if (arg_get_lit(3))
channel = ECC_CONTACT; channel = ECC_CONTACT;
PrintChannel(channel);
CLIParserFree(); CLIParserFree();
SetAPDULogging(APDULogging); SetAPDULogging(APDULogging);
@ -510,8 +542,11 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
int datalen = 0; int datalen = 0;
CLIParserInit("emv intauth", 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.", "Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\n"
"Usage:\n\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\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 -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"); "\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; EMVCommandChannel channel = ECC_CONTACTLESS;
if (arg_get_lit(6)) if (arg_get_lit(6))
channel = ECC_CONTACT; channel = ECC_CONTACT;
PrintChannel(channel);
CLIGetHexWithReturn(7, data, &datalen); CLIGetHexWithReturn(7, data, &datalen);
CLIParserFree(); CLIParserFree();
@ -547,6 +583,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
// calc DDOL // calc DDOL
struct tlv *ddol_data_tlv = NULL; struct tlv *ddol_data_tlv = NULL;
struct tlvdb *tmp_ext = NULL;
struct tlv data_tlv = { struct tlv data_tlv = {
.tag = 0x01, .tag = 0x01,
.len = datalen, .len = datalen,
@ -561,9 +598,11 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
ParamLoadFromJson(tlvRoot); 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){ if (!ddol_data_tlv){
PrintAndLogEx(ERR, "Can't create DDOL TLV."); PrintAndLogEx(ERR, "Can't create DDOL TLV.");
tlvdb_free(tmp_ext);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
return 4; return 4;
} }
@ -584,6 +623,8 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
if (ddol_data_tlv != &data_tlv) if (ddol_data_tlv != &data_tlv)
free(ddol_data_tlv); free(ddol_data_tlv);
tlvdb_free(tmp_ext);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
if (sw) if (sw)
@ -598,7 +639,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
return 0; 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) { 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) { int CmdEMVExec(const char *cmd) {
uint8_t buf[APDU_RES_LEN] = {0}; uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0; size_t len = 0;
@ -680,7 +765,8 @@ int CmdEMVExec(const char *cmd) {
CLIParserInit("emv exec", CLIParserInit("emv exec",
"Executes EMV contactless transaction", "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"); "\temv exec -satc -> select card, execute CDA transaction, show APDU and TLV\n");
void* argtable[] = { void* argtable[] = {
@ -708,9 +794,9 @@ int CmdEMVExec(const char *cmd) {
enum TransactionType TrType = TT_MSD; enum TransactionType TrType = TT_MSD;
if (arg_get_lit(7)) if (arg_get_lit(7))
TrType = TT_QVSDCMCHIP; TrType = TT_QVSDCMCHIP;
if (arg_get_lit(8)) if (arg_get_lit(8))
TrType = TT_CDA; TrType = TT_CDA;
if (arg_get_lit(9)) if (arg_get_lit(9))
TrType = TT_VSDC; TrType = TT_VSDC;
@ -718,8 +804,18 @@ int CmdEMVExec(const char *cmd) {
EMVCommandChannel channel = ECC_CONTACTLESS; EMVCommandChannel channel = ECC_CONTACTLESS;
if (arg_get_lit(11)) if (arg_get_lit(11))
channel = ECC_CONTACT; channel = ECC_CONTACT;
PrintChannel(channel);
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
CLIParserFree(); 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); SetAPDULogging(showAPDU);
// init applets list tree // init applets list tree
@ -732,7 +828,7 @@ int CmdEMVExec(const char *cmd) {
// PPSE // PPSE
PrintAndLogEx(NORMAL, "\n* PPSE."); PrintAndLogEx(NORMAL, "\n* PPSE.");
SetAPDULogging(showAPDU); SetAPDULogging(showAPDU);
res = EMVSearchPSE(channel, activateField, true, decodeTLV, tlvSelect); res = EMVSearchPSE(channel, activateField, true, psenum, decodeTLV, tlvSelect);
// check PPSE and select application id // check PPSE and select application id
if (!res) { if (!res) {
@ -845,7 +941,7 @@ int CmdEMVExec(const char *cmd) {
uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIend = AFL->value[i * 4 + 2];
uint8_t SFIoffline = AFL->value[i * 4 + 3]; 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) { if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) {
PrintAndLogEx(NORMAL, "SFI ERROR! Skipped..."); PrintAndLogEx(NORMAL, "SFI ERROR! Skipped...");
continue; continue;
@ -867,7 +963,7 @@ int CmdEMVExec(const char *cmd) {
// Build Input list for Offline Data Authentication // Build Input list for Offline Data Authentication
// EMV 4.3 book3 10.3, page 96 // EMV 4.3 book3 10.3, page 96
if (SFIoffline) { if (SFIoffline > 0) {
if (SFI < 11) { if (SFI < 11) {
const unsigned char *abuf = buf; const unsigned char *abuf = buf;
size_t elmlen = len; size_t elmlen = len;
@ -882,6 +978,8 @@ int CmdEMVExec(const char *cmd) {
memcpy(&ODAiList[ODAiListLen], buf, len); memcpy(&ODAiList[ODAiListLen], buf, len);
ODAiListLen += len; ODAiListLen += len;
} }
SFIoffline--;
} }
} }
} }
@ -921,7 +1019,7 @@ int CmdEMVExec(const char *cmd) {
// transaction check // transaction check
// qVSDC // qVSDC
if (TrType == TT_QVSDCMCHIP|| TrType == TT_CDA){ if (TrType == TT_QVSDCMCHIP || TrType == TT_CDA){
// 9F26: Application Cryptogram // 9F26: Application Cryptogram
const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL); const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL);
if (AC) { if (AC) {
@ -938,7 +1036,7 @@ int CmdEMVExec(const char *cmd) {
// print AC data // print AC data
PrintAndLogEx(NORMAL, "ATC: %s", sprint_hex(ATC->value, ATC->len)); PrintAndLogEx(NORMAL, "ATC: %s", sprint_hex(ATC->value, ATC->len));
PrintAndLogEx(NORMAL, "AC: %s", sprint_hex(AC->value, AC->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)); PrintAndLogEx(NORMAL, "IAD: %s", sprint_hex(IAD->value, IAD->len));
if (IAD->len >= IAD->value[0] + 1) { if (IAD->len >= IAD->value[0] + 1) {
@ -978,17 +1076,18 @@ int CmdEMVExec(const char *cmd) {
// ICC Dynamic Number // ICC Dynamic Number
struct tlvdb * ICCDynN = tlvdb_fixed(0x9f4c, len, buf); struct tlvdb * ICCDynN = tlvdb_fixed(0x9f4c, len, buf);
tlvdb_add(tlvRoot, ICCDynN); tlvdb_add(tlvRoot, ICCDynN);
if (decodeTLV){ if (decodeTLV) {
PrintAndLogEx(NORMAL, "\n* * ICC Dynamic Number:"); PrintAndLogEx(NORMAL, "\n* * ICC Dynamic Number:");
TLVPrintFromTLV(ICCDynN); TLVPrintFromTLV(ICCDynN);
} }
PrintAndLogEx(NORMAL, "* * Calc CDOL1"); PrintAndLogEx(NORMAL, "* * Calc CDOL1");
struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag 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."); PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV.");
dreturn(6); dreturn(6);
} }
PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len)); PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
PrintAndLogEx(NORMAL, "* * AC1"); PrintAndLogEx(NORMAL, "* * AC1");
@ -1010,6 +1109,7 @@ int CmdEMVExec(const char *cmd) {
if (res) { if (res) {
PrintAndLogEx(NORMAL, "CDA error (%d)", res); PrintAndLogEx(NORMAL, "CDA error (%d)", res);
} }
free(ac_tlv); free(ac_tlv);
free(cdol_data_tlv); free(cdol_data_tlv);
@ -1073,7 +1173,7 @@ int CmdEMVExec(const char *cmd) {
PrintAndLogEx(NORMAL, "Use default UDOL."); PrintAndLogEx(NORMAL, "Use default UDOL.");
struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag 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."); PrintAndLogEx(WARNING, "Error: can't create UDOL TLV.");
dreturn(8); 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 // Destroy TLV's
free(pdol_data_tlv); free(pdol_data_tlv);
@ -1164,19 +1397,23 @@ int CmdEMVScan(const char *cmd) {
EMVCommandChannel channel = ECC_CONTACTLESS; EMVCommandChannel channel = ECC_CONTACTLESS;
if (arg_get_lit(11)) if (arg_get_lit(11))
channel = ECC_CONTACT; channel = ECC_CONTACT;
PrintChannel(channel);
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
uint8_t relfname[250] ={0}; uint8_t relfname[250] ={0};
char *crelfname = (char *)relfname; char *crelfname = (char *)relfname;
int relfnamelen = 0; int relfnamelen = 0;
CLIGetStrWithReturn(12, relfname, &relfnamelen); CLIGetStrWithReturn(12, relfname, &relfnamelen);
CLIParserFree(); CLIParserFree();
SetAPDULogging(showAPDU); #ifndef WITH_SMARTCARD
// not compiled with smartcard functionality, we need to exit
// TODO if ( channel == ECC_CONTACT ) {
if (channel == ECC_CONTACT) { PrintAndLogEx(WARNING, "PM3 Client is not compiled with support for SMARTCARD. Exiting.");
PrintAndLogEx(ERR, "Do not use contact interface. Exit."); return 0;
return 1;
} }
#endif
SetAPDULogging(showAPDU);
// current path + file name // current path + file name
if (!strstr(crelfname, ".json")) if (!strstr(crelfname, ".json"))
@ -1201,23 +1438,37 @@ int CmdEMVScan(const char *cmd) {
} }
// drop field at start // drop field at start
DropField(); DropFieldEx( channel );
// iso 14443 select
PrintAndLogEx(NORMAL, "--> GET UID, ATS.");
iso14a_card_select_t card;
if (Hf14443_4aGetCardData(&card)) {
return 2;
}
JsonSaveStr(root, "$.File.Created", "proxmark3 `emv scan`"); JsonSaveStr(root, "$.File.Created", "proxmark3 `emv scan`");
JsonSaveStr(root, "$.Card.Communication", "iso14443-4a"); if (channel == ECC_CONTACTLESS) {
JsonSaveBufAsHex(root, "$.Card.UID", (uint8_t *)&card.uid, card.uidlen); // iso 14443 select
JsonSaveHex(root, "$.Card.ATQA", card.atqa[0] + (card.atqa[1] << 2), 2); PrintAndLogEx(NORMAL, "--> GET UID, ATS.");
JsonSaveHex(root, "$.Card.SAK", card.sak, 0);
JsonSaveBufAsHex(root, "$.Card.ATS", (uint8_t *)card.ats, card.ats_len); 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 // init applets list tree
const char *al = "Applets list"; const char *al = "Applets list";
@ -1242,7 +1493,7 @@ int CmdEMVScan(const char *cmd) {
tlvdb_free(fci); tlvdb_free(fci);
} }
res = EMVSearchPSE(channel, false, true, decodeTLV, tlvSelect); res = EMVSearchPSE(channel, false, true, psenum, decodeTLV, tlvSelect);
// check PPSE and select application id // check PPSE and select application id
if (!res) { if (!res) {
@ -1254,7 +1505,7 @@ int CmdEMVScan(const char *cmd) {
if (EMVSearch(channel, false, true, decodeTLV, tlvSelect)) { if (EMVSearch(channel, false, true, decodeTLV, tlvSelect)) {
PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit..."); PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit...");
tlvdb_free(tlvSelect); tlvdb_free(tlvSelect);
DropField(); DropFieldEx( channel );
return 3; return 3;
} }
@ -1270,7 +1521,7 @@ int CmdEMVScan(const char *cmd) {
if (!AIDlen) { if (!AIDlen) {
PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit..."); PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit...");
DropField(); DropFieldEx( channel );
return 4; return 4;
} }
@ -1289,7 +1540,7 @@ int CmdEMVScan(const char *cmd) {
if (res) { if (res) {
PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res); PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
DropField(); DropFieldEx( channel );
return 5; return 5;
} }
@ -1317,7 +1568,7 @@ int CmdEMVScan(const char *cmd) {
if (!pdol_data_tlv){ if (!pdol_data_tlv){
PrintAndLogEx(ERR, "Can't create PDOL TLV."); PrintAndLogEx(ERR, "Can't create PDOL TLV.");
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
DropField(); DropFieldEx( channel );
return 6; return 6;
} }
@ -1326,7 +1577,7 @@ int CmdEMVScan(const char *cmd) {
if (!pdol_data_tlv_data) { if (!pdol_data_tlv_data) {
PrintAndLogEx(ERR, "Can't create PDOL data."); PrintAndLogEx(ERR, "Can't create PDOL data.");
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
DropField(); DropFieldEx( channel );
return 6; 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, "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) { if (res) {
PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw); PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
DropField(); DropFieldEx( channel );
return 7; return 7;
} }
ProcessGPOResponseFormat1(tlvRoot, buf, len, decodeTLV); ProcessGPOResponseFormat1(tlvRoot, buf, len, decodeTLV);
@ -1382,7 +1633,7 @@ int CmdEMVScan(const char *cmd) {
uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIend = AFL->value[i * 4 + 2];
uint8_t SFIoffline = AFL->value[i * 4 + 3]; 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) { if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) {
PrintAndLogEx(ERR, "SFI ERROR! Skipped..."); PrintAndLogEx(ERR, "SFI ERROR! Skipped...");
continue; continue;
@ -1432,8 +1683,7 @@ int CmdEMVScan(const char *cmd) {
// free tlv object // free tlv object
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
// DropField DropFieldEx( channel );
DropField();
res = json_dump_file(root, fname, JSON_INDENT(2)); res = json_dump_file(root, fname, JSON_INDENT(2));
if (res) { if (res) {
@ -1448,25 +1698,6 @@ int CmdEMVScan(const char *cmd) {
return 0; 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) { int CmdEMVList(const char *Cmd) {
return CmdTraceList("7816"); return CmdTraceList("7816");
} }
@ -1475,6 +1706,237 @@ int CmdEMVTest(const char *cmd) {
return ExecuteCryptoTests(true); 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[] = { static command_t CommandTable[] = {
{"help", CmdHelp, 1, "This help"}, {"help", CmdHelp, 1, "This help"},
{"exec", CmdEMVExec, 0, "Executes EMV contactless transaction."}, {"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."}, {"scan", CmdEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."},
{"test", CmdEMVTest, 0, "Crypto logic test."}, {"test", CmdEMVTest, 0, "Crypto logic test."},
/* /*
{"getrng", CmdEMVGetrng, 0, "get random number from terminal"}, {"getrng", CmdEMVGetrng, 0, "get random number from terminal"},
{"eload", CmdEmvELoad, 0, "load EMV tag into device"}, {"eload", CmdEmvELoad, 0, "load EMV tag into device"},
{"dump", CmdEmvDump, 0, "dump EMV tag values"}, {"dump", CmdEmvDump, 0, "dump EMV tag values"},
{"sim", CmdEmvSim, 0, "simulate EMV tag"}, {"sim", CmdEmvSim, 0, "simulate EMV tag"},
{"clone", CmdEmvClone, 0, "clone an 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} {NULL, NULL, 0, NULL}
}; };

View file

@ -25,6 +25,7 @@
#include "cmdmain.h" #include "cmdmain.h"
#include "emvcore.h" #include "emvcore.h"
#include "apduinfo.h" #include "apduinfo.h"
#include "emv_roca.h"
int CmdEMV(const char *Cmd); int CmdEMV(const char *Cmd);
@ -34,5 +35,6 @@ extern int CmdEMVPPSE(const char *cmd);
extern int CmdEMVExec(const char *cmd); extern int CmdEMVExec(const char *cmd);
extern int CmdEMVGetrng(const char *Cmd); extern int CmdEMVGetrng(const char *Cmd);
extern int CmdEMVList(const char *Cmd); extern int CmdEMVList(const char *Cmd);
extern int CmdEMVRoca(const char *Cmd);
#endif #endif

Some files were not shown because too many files have changed in this diff Show more