mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-08-29 05:28:22 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -3,6 +3,20 @@ All notable changes to this project will be documented in this file.
|
||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Chg 'data autocorrelate' - better visual representation and added extra peak detection (@iceman)
|
||||
- Fix 'lf search' - false positive indala identification fixed (@iceman)
|
||||
- Add 'lf keri' - basic support for Keri tags (@iceman)
|
||||
- Add 'hf mf list' - re-added it again (@iceman)
|
||||
- Fix - A lot of bugfixes, like memory leaks (@iceman)
|
||||
- Change 'hf 14a antifuzz' - original implementation (@asfabw), reworked a bit
|
||||
- Fix 'hf mf fchk' (@iceman)
|
||||
- Fix 'usb slow on posix based systems' (@fl0-0)
|
||||
- Change 'lf pcf7931' - improved read code (@sguerrini97)
|
||||
- Change 'hf felica list' - started with some FeliCa annotations (@iceman)
|
||||
- Fix 'hf tune' - now works as expected (@iceman)
|
||||
- Add 'option to use flash memory to upload dictionary files' (RDV40) (@iceman)
|
||||
- Fix 'printing percentage now standard compliant' (@fabled)
|
||||
- Add 'emv roca' - command to test for ROCA vuln in public RSA modulus (@merlokk / @iceman)
|
||||
- Added TCP ports support (on linux) (@phcoder)
|
||||
- Added HF sniff standalone mode with optional storing of ULC/NTAG/ULEV1 authentication attempts (@bogiton)
|
||||
- Fix 'Lining up plot and control window' (@anticat)
|
||||
@@ -88,6 +102,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||
- Added `hf emv` `gpo`, `readrec`, `genac`, `challenge`, `intauth` - separate commands from `hf emc exec` (@merlokk)
|
||||
- Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (@merlokk)
|
||||
- Added trailer block decoding to `hf mf rdbl` and `hf mf cgetbl` (@merlokk)
|
||||
- Added `hf mf mad` and `hf mfp mad` MAD decode, check and print commands (@merlokk)
|
||||
|
||||
### Fixed
|
||||
- Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi)
|
||||
|
||||
@@ -5,6 +5,33 @@ Proxmark3 RDV40 dedicated repo, based on iceman fork
|
||||
## Notice
|
||||
This repo is based on iceman fork for proxmark3. It is dedicated to bring the most out of the new features for proxmark3 RDV40 device.
|
||||
|
||||
# Donations
|
||||
Nothing says thank you as much as a donation, https://www.patreon.com/iceman1001
|
||||
|
||||
## ToC
|
||||
|
||||
- Coverity Scan Config & Run
|
||||
- Whats changed?
|
||||
- Why didn't you based it on offical PM3 Master?
|
||||
- Why don't you add this or that functionality?
|
||||
- PM3 GUI
|
||||
- Development
|
||||
- KALI and ARCHLINUX users
|
||||
- Setup and build for UBUNTU
|
||||
- Setup and build for ArchLinux
|
||||
- Homebrew (Mac OS X)
|
||||
- Upgrading HomeBrew tap formula
|
||||
- Building on Windows
|
||||
- Gator96100 distro
|
||||
- Build and run
|
||||
- Validating proxmark client functionality
|
||||
- Run the following commands
|
||||
- Quit client
|
||||
- First things on your RDV40
|
||||
- Verify sim module firmware version
|
||||
|
||||
- The end
|
||||
|
||||
## Coverity Scan Config & Run
|
||||
Download the Coverity Scan Self-buld and install it.
|
||||
You will need to configure ARM-NON-EABI- Compiler for it to use:
|
||||
@@ -37,19 +64,29 @@ The separation from offical pm3 repo gives us very much freedom to create a firm
|
||||
Give us a hint, and we'll see if we can't merge in the stuff you have.
|
||||
|
||||
## PM3 GUI
|
||||
The official PM3-GUI from Gaucho will not work.
|
||||
The new universial GUI will work.
|
||||
The official PM3-GUI from Gaucho will not work.
|
||||
The new universial GUI will work. [Proxmark3 Univerisal GUI](https://github.com/burma69/PM3UniversalGUI)
|
||||
|
||||
## Development
|
||||
This fork now compiles just fine on
|
||||
- Windows/mingw environment with Qt5.6.1 & GCC 4.8
|
||||
- Ubuntu 1404, 1510, 1604
|
||||
- Ubuntu 1404, 1510, 1604, 1804
|
||||
- Mac OS X / Homebrew
|
||||
- ParrotOS
|
||||
- WSL (Windows subsystem linux) on Windows 10
|
||||
- Docker container
|
||||
|
||||
## KALI and ARCHLINUX users
|
||||
Kali and ArchLinux users usually must kill their modem manager in order for the proxmark3 to enumerate properly.
|
||||
|
||||
```sh
|
||||
sudo apt remove modemmanager
|
||||
```
|
||||
or
|
||||
```sh
|
||||
systemctl stop ModemManager
|
||||
systemctl disable ModemManager
|
||||
```
|
||||
|
||||
## Setup and build for UBUNTU
|
||||
GC made updates to allow this to build easily on Ubuntu 14.04.2 LTS, 15.10 or 16.04
|
||||
See https://github.com/Proxmark/proxmark3/wiki/Ubuntu%20Linux
|
||||
@@ -60,7 +97,7 @@ I have also added this script to the fork.
|
||||
https://github.com/RfidResearchGroup/proxmark3/blob/master/install.sh
|
||||
|
||||
- Run
|
||||
`sudo apt-get install p7zip git build-essential libreadline5 libreadline-dev libusb-0.1-4 libusb-dev libqt4-dev perl pkg-config wget libncurses5-dev gcc-arm-none-eabi libjansson-dev`
|
||||
`sudo apt-get install p7zip git build-essential libreadline5 libreadline-dev libusb-0.1-4 libusb-dev libqt4-dev perl pkg-config wget libncurses5-dev gcc-arm-none-eabi`
|
||||
|
||||
- Clone fork
|
||||
`git clone https://github.com/RfidResearchGroup/proxmark3.git`
|
||||
@@ -85,9 +122,12 @@ https://github.com/RfidResearchGroup/proxmark3/blob/master/install.sh
|
||||
|
||||
## Setup and build for ArchLinux
|
||||
- Run
|
||||
`sudo pacman -Sy base-devel p7zip libusb readline ncurses libjansson-dev arm-none-eabi-newlib --needed`
|
||||
`sudo pacman -Sy base-devel p7zip libusb readline ncurses arm-none-eabi-newlib --needed`
|
||||
`yaourt -S termcap`
|
||||
|
||||
- Remove modemmanager
|
||||
`sudo apt remove modemmanager`
|
||||
|
||||
- Clone fork
|
||||
`git clone https://github.com/RfidResearchGroup/proxmark3.git`
|
||||
|
||||
@@ -155,7 +195,7 @@ Links
|
||||
- https://github.com/Gator96100/ProxSpace/releases/tag/v2.2 (release v2.2 with gcc v5.3.0 arm-none-eabi-gcc v7.1.0)
|
||||
|
||||
|
||||
### 7. Build and run
|
||||
### Build and run
|
||||
|
||||
- Clone fork
|
||||
`git clone https://github.com/RfidResearchGroup/proxmark3.git`
|
||||
@@ -177,5 +217,106 @@ Assuming you have Proxmark3 Windows drivers installed you can run the Proxmark s
|
||||
- Run the client
|
||||
`proxmark3.exe comX`
|
||||
|
||||
iceman at host iuse.se
|
||||
July 2018, Sweden
|
||||
|
||||
## Validating proxmark client functionality
|
||||
|
||||
If all went well you should get some information about the firmware and memory usage as well as the prompt, something like this.
|
||||
|
||||
>[=] UART Setting serial baudrate 460800
|
||||
>
|
||||
>Proxmark3 RFID instrument
|
||||
>
|
||||
> [ CLIENT ]
|
||||
>
|
||||
> client: iceman build for RDV40 with flashmem; smartcard;
|
||||
>
|
||||
> [ ARM ]
|
||||
>
|
||||
> bootrom: iceman/master/4517531c-dirty-unclean 2018-12-13 15:42:24
|
||||
>
|
||||
> os: iceman/master/5a34550a-dirty-unclean 2019-01-07 23:04:07
|
||||
>
|
||||
> [ FPGA ]
|
||||
>
|
||||
> LF image built for 2s30vq100 on 2018/ 9/ 8 at 13:57:51
|
||||
>
|
||||
> HF image built for 2s30vq100 on 2018/ 9/ 3 at 21:40:23
|
||||
>
|
||||
> [ Hardware ]
|
||||
>
|
||||
>--= uC: AT91SAM7S512 Rev B
|
||||
>
|
||||
>--= Embedded Processor: ARM7TDMI
|
||||
>
|
||||
>--= Nonvolatile Program Memory Size: 512K bytes, Used: 247065 bytes (47%) Free: 277223 bytes (53%)
|
||||
>
|
||||
>--= Second Nonvolatile Program Memory Size: None
|
||||
>
|
||||
>--= Internal SRAM Size: 64K bytes
|
||||
>
|
||||
>--= Architecture Identifier: AT91SAM7Sxx Series
|
||||
>
|
||||
>--= Nonvolatile Program Memory Type: Embedded Flash Memory
|
||||
>
|
||||
> pm3 -->
|
||||
|
||||
### Run the following commands
|
||||
pm3 --> hw status
|
||||
pm3 --> hw version
|
||||
pm3 --> hw tune
|
||||
|
||||
You are now ready to use your newly upgraded proxmark3 device. Many commands uses the **h** parameter to show a help text. The client uses a arcaic command structure which will be hard to grasp at first. Here are some commands to start off with.
|
||||
|
||||
pm3 --> hf
|
||||
pm3 --> hf 14a info
|
||||
pm3 --> lf
|
||||
pm3 --> lf search
|
||||
|
||||
### Quit client
|
||||
pm3 --> quit
|
||||
|
||||
|
||||
### First things on your RDV40
|
||||
You will need to run these commands to make sure your rdv4 is prepared
|
||||
|
||||
pm3 --> mem load f default_keys m
|
||||
pm3 --> mem load f default_pwd t
|
||||
pm3 --> mem load f default_iclass_keys i
|
||||
pm3 --> lf t55xx deviceconfig a 29 b 17 c 15 d 47 e 15 p
|
||||
|
||||
### Verify sim module firmware version
|
||||
To make sure you got the latest sim module firmware.
|
||||
_Lastest version is v3.10_
|
||||
|
||||
pm3 --> hw status
|
||||
|
||||
Find version in the long output, look for these two lines
|
||||
|
||||
#db# Smart card module (ISO 7816)
|
||||
#db# version.................v2.06
|
||||
|
||||
This version is obselete. The following command upgrades your device sim module firmware.
|
||||
Don't not turn of your device during the execution of this command.
|
||||
|
||||
pm3 --> sc upgrade f ../tools/simmodule/SIM010.BIN
|
||||
|
||||
You get the following output, this is a successful execution.
|
||||
|
||||
[!] WARNING - Smartcard socket firmware upgrade.
|
||||
[!] A dangerous command, do wrong and you will brick the smart card socket
|
||||
[+] Smartcard socket firmware uploading to PM3
|
||||
..
|
||||
[+] Smartcard socket firmware updating, don't turn off your PM3!
|
||||
#db# FW 0000
|
||||
#db# FW 0080
|
||||
#db# FW 0100
|
||||
#db# FW 0180
|
||||
#db# FW 0200
|
||||
#db# FW 0280
|
||||
[+] Smartcard socket firmware upgraded successful
|
||||
|
||||
|
||||
## the end
|
||||
|
||||
`iceman at host iuse.se`
|
||||
`July 2018, Sweden`
|
||||
|
||||
+7
-7
@@ -30,8 +30,8 @@ static uint16_t BigBuf_hi = BIGBUF_SIZE;
|
||||
static uint8_t *emulator_memory = NULL;
|
||||
|
||||
// trace related variables
|
||||
static uint16_t traceLen = 0;
|
||||
int tracing = 1; //Last global one.. todo static?
|
||||
static uint32_t traceLen = 0;
|
||||
static bool tracing = true; //todo static?
|
||||
|
||||
// get the address of BigBuf
|
||||
uint8_t *BigBuf_get_addr(void) {
|
||||
@@ -112,7 +112,7 @@ uint16_t BigBuf_max_traceLen(void) {
|
||||
void clear_trace(void) {
|
||||
traceLen = 0;
|
||||
}
|
||||
void set_tracelen(uint16_t value) {
|
||||
void set_tracelen(uint32_t value) {
|
||||
traceLen = value;
|
||||
}
|
||||
void set_tracing(bool enable) {
|
||||
@@ -127,7 +127,7 @@ bool get_tracing(void) {
|
||||
* Get the number of bytes traced
|
||||
* @return
|
||||
*/
|
||||
uint16_t BigBuf_get_traceLen(void) {
|
||||
uint32_t BigBuf_get_traceLen(void) {
|
||||
return traceLen;
|
||||
}
|
||||
|
||||
@@ -142,8 +142,8 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_
|
||||
|
||||
uint8_t *trace = BigBuf_get_addr();
|
||||
|
||||
uint16_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity
|
||||
uint16_t duration = timestamp_end - timestamp_start;
|
||||
uint32_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity
|
||||
uint32_t duration = timestamp_end - timestamp_start;
|
||||
|
||||
// Return when trace is full
|
||||
if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= BigBuf_max_traceLen()) {
|
||||
@@ -204,7 +204,7 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP
|
||||
if (!tracing) return false;
|
||||
|
||||
uint8_t *trace = BigBuf_get_addr();
|
||||
uint16_t iLen = nbytes(iBits);
|
||||
uint32_t iLen = nbytes(iBits);
|
||||
// Return when trace is full
|
||||
if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) return false;
|
||||
|
||||
|
||||
+2
-2
@@ -36,10 +36,10 @@ extern uint8_t *BigBuf_malloc(uint16_t);
|
||||
extern void BigBuf_free(void);
|
||||
extern void BigBuf_free_keep_EM(void);
|
||||
extern void BigBuf_print_status(void);
|
||||
extern uint16_t BigBuf_get_traceLen(void);
|
||||
extern uint32_t BigBuf_get_traceLen(void);
|
||||
extern void clear_trace(void);
|
||||
extern void set_tracing(bool enable);
|
||||
extern void set_tracelen(uint16_t value);
|
||||
extern void set_tracelen(uint32_t value);
|
||||
extern bool get_tracing(void);
|
||||
extern bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
|
||||
extern int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int bReader);
|
||||
|
||||
+5
-4
@@ -21,7 +21,7 @@ APP_CFLAGS = -DWITH_CRC \
|
||||
-DWITH_ISO14443a \
|
||||
-DWITH_ICLASS \
|
||||
-DWITH_FELICA \
|
||||
-DWITH_FLASH \
|
||||
-DWITH_FLASH \
|
||||
-DWITH_SMARTCARD \
|
||||
-DWITH_FPC \
|
||||
-DWITH_HFSNOOP \
|
||||
@@ -122,8 +122,9 @@ APP_CFLAGS += $(ZLIB_CFLAGS)
|
||||
# zlib includes:
|
||||
APP_CFLAGS += -I../zlib
|
||||
|
||||
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
|
||||
APP_CFLAGS += -I.
|
||||
# stdint.h provided locally until GCC 4.5 becomes C99 compliant,
|
||||
# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc
|
||||
APP_CFLAGS += -I. -fno-stack-protector -fno-pie
|
||||
|
||||
# Compile these in thumb mode (small size)
|
||||
THUMBSRC = start.c \
|
||||
@@ -190,7 +191,7 @@ $(OBJDIR)/fpga_all.bit.z: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR)
|
||||
$(FPGA_COMPRESSOR) $(filter %.bit,$^) $@
|
||||
|
||||
$(FPGA_COMPRESSOR):
|
||||
make -C ../client $(notdir $(FPGA_COMPRESSOR))
|
||||
$(MAKE) -C ../client $(notdir $(FPGA_COMPRESSOR))
|
||||
|
||||
$(OBJDIR)/fullimage.stage1.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ)
|
||||
$(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS)
|
||||
|
||||
@@ -271,6 +271,11 @@ void RAMFUNC SniffAndStore(uint8_t param) {
|
||||
uint16_t writelen = Flash_WriteData(0, total_data, memoffset + 4 * auth_attempts);
|
||||
if (MF_DBGLEVEL > 1) Dbprintf("[!] Wrote %u bytes into flash mem", writelen);
|
||||
|
||||
// If pwd saved successfully, blink led A three times
|
||||
if (writelen > 0) {
|
||||
SpinErr(0, 200, 5); // blink led A
|
||||
}
|
||||
|
||||
SpinDelay(100);
|
||||
|
||||
// Reset the SPI Baudrate to the default value (24MHz)
|
||||
|
||||
+21
-7
@@ -113,7 +113,7 @@ void print_result(char *name, uint8_t *buf, size_t len) {
|
||||
void DbpStringEx(char *str, uint32_t cmd) {
|
||||
#if DEBUG
|
||||
uint8_t len = strlen(str);
|
||||
cmd_send(CMD_DEBUG_PRINT_STRING, len, cmd, 0, (byte_t*)str, len);
|
||||
cmd_send(CMD_DEBUG_PRINT_STRING, len, cmd, 0, (uint8_t*)str, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -307,10 +307,10 @@ void MeasureAntennaTuningHf(void) {
|
||||
} else {
|
||||
volt = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10;
|
||||
}
|
||||
DbprintfEx(CMD_MEASURE_ANTENNA_TUNING_HF, "%u mV / %5u V", volt, (uint16_t)(volt/1000));
|
||||
DbprintfEx(FLAG_NONEWLINE, "%u mV / %5u V", volt, (uint16_t)(volt/1000));
|
||||
}
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
DbpString("\n[+] cancelled");
|
||||
DbprintfEx(FLAG_NOOPT, "\n[+] cancelled", 1);
|
||||
}
|
||||
|
||||
void ReadMem(int addr) {
|
||||
@@ -724,6 +724,9 @@ void UsbPacketReceived(uint8_t *packet, int len) {
|
||||
case CMD_T55XX_RESET_READ:
|
||||
T55xxResetRead();
|
||||
break;
|
||||
case CMD_T55XX_CHKPWDS:
|
||||
T55xx_ChkPwds();
|
||||
break;
|
||||
case CMD_PCF7931_READ:
|
||||
ReadPCF7931();
|
||||
break;
|
||||
@@ -1250,11 +1253,11 @@ void UsbPacketReceived(uint8_t *packet, int len) {
|
||||
|
||||
size_t size = MIN(USB_CMD_DATA_SIZE, len);
|
||||
|
||||
uint8_t *mem = BigBuf_malloc(size);
|
||||
|
||||
if (!FlashInit()) {
|
||||
if (!FlashInit()) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t *mem = BigBuf_malloc(size);
|
||||
|
||||
for(size_t i = 0; i < len; i += size) {
|
||||
len = MIN((len - i), size);
|
||||
@@ -1268,6 +1271,7 @@ void UsbPacketReceived(uint8_t *packet, int len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
BigBuf_free();
|
||||
FlashStop();
|
||||
LED_B_OFF();
|
||||
break;
|
||||
@@ -1285,10 +1289,20 @@ void UsbPacketReceived(uint8_t *packet, int len) {
|
||||
if (!FlashInit()) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
Flash_WriteEnable();
|
||||
|
||||
if ( startidx == DEFAULT_T55XX_KEYS_OFFSET )
|
||||
Flash_Erase4k(3, 0xC);
|
||||
else if (startidx == DEFAULT_MF_KEYS_OFFSET )
|
||||
Flash_Erase4k(3, 0xB);
|
||||
else if (startidx == DEFAULT_ICLASS_KEYS_OFFSET)
|
||||
Flash_Erase4k(3, 0xA);
|
||||
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
Flash_WriteEnable();
|
||||
|
||||
// inside 256b page?
|
||||
if ( (tmp & 0xFF) != 0) {
|
||||
|
||||
|
||||
+2
-1
@@ -34,7 +34,6 @@ extern "C" {
|
||||
|
||||
extern const uint8_t OddByteParity[256];
|
||||
extern int rsamples; // = 0;
|
||||
extern int tracing; // = TRUE;
|
||||
extern uint8_t trigger;
|
||||
|
||||
// This may be used (sparingly) to declare a function to be copied to
|
||||
@@ -104,6 +103,8 @@ void T55xxWriteBlock(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t PwdMode
|
||||
void T55xxWriteBlockExt(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t PwdMode);
|
||||
void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd);
|
||||
void T55xxWakeUp(uint32_t Pwd);
|
||||
void T55xx_ChkPwds(void);
|
||||
|
||||
void TurnReadLFOn(uint32_t delay);
|
||||
void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd);
|
||||
void EM4xWriteWord(uint32_t flag, uint32_t data, uint32_t pwd);
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response)
|
||||
switch(iso_type)
|
||||
{
|
||||
case 'a':
|
||||
return iso14_apdu(apdu, (uint16_t) length, response, NULL);
|
||||
return iso14_apdu(apdu, (uint16_t) length, false, response, NULL);
|
||||
break;
|
||||
case 'b':
|
||||
return iso14443b_apdu(apdu, length, response);
|
||||
|
||||
+112
-114
@@ -29,27 +29,25 @@ static uint32_t felica_timeout;
|
||||
static uint32_t felica_nexttransfertime;
|
||||
static uint32_t felica_lasttime_prox2air_start;
|
||||
|
||||
static void felica_setup(uint8_t fpga_minor_mode);
|
||||
static void iso18092_setup(uint8_t fpga_minor_mode);
|
||||
static uint8_t felica_select_card(felica_card_select_t *card);
|
||||
static void TransmitFor18092_AsReader(uint8_t * frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed);
|
||||
bool WaitForFelicaReply(uint16_t maxbytes);
|
||||
|
||||
void felica_set_timeout(uint32_t timeout) {
|
||||
void iso18092_set_timeout(uint32_t timeout) {
|
||||
felica_timeout = timeout + (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) + 2;
|
||||
}
|
||||
|
||||
uint32_t felica_get_timeout(void) {
|
||||
uint32_t iso18092_get_timeout(void) {
|
||||
return felica_timeout - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) - 2;
|
||||
}
|
||||
|
||||
//random service RW: 0x0009
|
||||
//random service RO: 0x000B
|
||||
#ifndef NFC_MAX_FRAME_SIZE
|
||||
#define NFC_MAX_FRAME_SIZE 260
|
||||
#ifndef FELICA_MAX_FRAME_SIZE
|
||||
#define FELICA_MAX_FRAME_SIZE 260
|
||||
#endif
|
||||
|
||||
//structure to hold outgoing NFC frame
|
||||
static uint8_t frameSpace[NFC_MAX_FRAME_SIZE+4];
|
||||
static uint8_t frameSpace[FELICA_MAX_FRAME_SIZE+4];
|
||||
|
||||
//structure to hold incoming NFC frame, used for ISO/IEC 18092-compatible frames
|
||||
static struct {
|
||||
@@ -71,114 +69,114 @@ static struct {
|
||||
uint8_t *framebytes;
|
||||
//should be enough. maxlen is 255, 254 for data, 2 for sync, 2 for crc
|
||||
// 0,1 -> SYNC, 2 - len, 3-(len+1)->data, then crc
|
||||
} NFCFrame;
|
||||
} FelicaFrame;
|
||||
|
||||
//b2 4d is SYNC, 45645 in 16-bit notation, 10110010 01001101 binary. Frame will not start filling until this is shifted in
|
||||
//bit order in byte -reverse, I guess? [((bt>>0)&1),((bt>>1)&1),((bt>>2)&1),((bt>>3)&1),((bt>>4)&1),((bt>>5)&1),((bt>>6)&1),((bt>>7)&1)] -at least in the mode that I read those in
|
||||
#ifndef SYNC_16BIT
|
||||
# define SYNC_16BIT 0x4DB2
|
||||
# define SYNC_16BIT 0xB24D
|
||||
#endif
|
||||
|
||||
static void NFCFrameReset() {
|
||||
NFCFrame.state = STATE_UNSYNCD;
|
||||
NFCFrame.posCnt = 0;
|
||||
NFCFrame.crc_ok = false;
|
||||
NFCFrame.byte_offset = 0;
|
||||
static void FelicaFrameReset() {
|
||||
FelicaFrame.state = STATE_UNSYNCD;
|
||||
FelicaFrame.posCnt = 0;
|
||||
FelicaFrame.crc_ok = false;
|
||||
FelicaFrame.byte_offset = 0;
|
||||
}
|
||||
static void NFCInit(uint8_t *data) {
|
||||
NFCFrame.framebytes = data;
|
||||
NFCFrameReset();
|
||||
static void FelicaFrameinit(uint8_t *data) {
|
||||
FelicaFrame.framebytes = data;
|
||||
FelicaFrameReset();
|
||||
}
|
||||
|
||||
//shift byte into frame, reversing it at the same time
|
||||
static void shiftInByte(uint8_t bt) {
|
||||
uint8_t j;
|
||||
for(j=0; j < NFCFrame.byte_offset; j++) {
|
||||
NFCFrame.framebytes[NFCFrame.posCnt] = ( NFCFrame.framebytes[NFCFrame.posCnt]<<1 ) + (bt & 1);
|
||||
for(j=0; j < FelicaFrame.byte_offset; j++) {
|
||||
FelicaFrame.framebytes[FelicaFrame.posCnt] = ( FelicaFrame.framebytes[FelicaFrame.posCnt]<<1 ) + (bt & 1);
|
||||
bt >>= 1;
|
||||
}
|
||||
NFCFrame.posCnt++;
|
||||
NFCFrame.rem_len--;
|
||||
for(j = NFCFrame.byte_offset; j<8; j++) {
|
||||
NFCFrame.framebytes[NFCFrame.posCnt] = (NFCFrame.framebytes[NFCFrame.posCnt]<<1 ) + (bt & 1);
|
||||
FelicaFrame.posCnt++;
|
||||
FelicaFrame.rem_len--;
|
||||
for(j = FelicaFrame.byte_offset; j<8; j++) {
|
||||
FelicaFrame.framebytes[FelicaFrame.posCnt] = (FelicaFrame.framebytes[FelicaFrame.posCnt]<<1 ) + (bt & 1);
|
||||
bt >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ProcessNFCByte(uint8_t bt) {
|
||||
switch (NFCFrame.state) {
|
||||
static void Process18092Byte(uint8_t bt) {
|
||||
switch (FelicaFrame.state) {
|
||||
case STATE_UNSYNCD: {
|
||||
//almost any nonzero byte can be start of SYNC. SYNC should be preceded by zeros, but that is not alsways the case
|
||||
if (bt > 0) {
|
||||
NFCFrame.shiftReg = reflect8(bt);
|
||||
NFCFrame.state = STATE_TRYING_SYNC;
|
||||
FelicaFrame.shiftReg = reflect8(bt);
|
||||
FelicaFrame.state = STATE_TRYING_SYNC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_TRYING_SYNC: {
|
||||
if (bt == 0) {
|
||||
//desync
|
||||
NFCFrame.shiftReg = bt;
|
||||
NFCFrame.state = STATE_UNSYNCD;
|
||||
FelicaFrame.shiftReg = bt;
|
||||
FelicaFrame.state = STATE_UNSYNCD;
|
||||
} else {
|
||||
for (uint8_t i=0; i<8; i++) {
|
||||
|
||||
if (NFCFrame.shiftReg == SYNC_16BIT) {
|
||||
if (FelicaFrame.shiftReg == SYNC_16BIT) {
|
||||
//SYNC done!
|
||||
NFCFrame.state = STATE_GET_LENGTH;
|
||||
NFCFrame.framebytes[0] = 0xb2;
|
||||
NFCFrame.framebytes[1] = 0x4d; //write SYNC
|
||||
NFCFrame.byte_offset = i;
|
||||
FelicaFrame.state = STATE_GET_LENGTH;
|
||||
FelicaFrame.framebytes[0] = 0xb2;
|
||||
FelicaFrame.framebytes[1] = 0x4d;
|
||||
FelicaFrame.byte_offset = i;
|
||||
//shift in remaining byte, slowly...
|
||||
for(uint8_t j=i; j<8; j++) {
|
||||
NFCFrame.framebytes[2] = (NFCFrame.framebytes[2] << 1) + (bt & 1);
|
||||
FelicaFrame.framebytes[2] = (FelicaFrame.framebytes[2] << 1) + (bt & 1);
|
||||
bt >>= 1;
|
||||
}
|
||||
|
||||
NFCFrame.posCnt = 2;
|
||||
FelicaFrame.posCnt = 2;
|
||||
if (i==0)
|
||||
break;
|
||||
}
|
||||
NFCFrame.shiftReg = (NFCFrame.shiftReg << 1) + (bt & 1);
|
||||
FelicaFrame.shiftReg = (FelicaFrame.shiftReg << 1) + (bt & 1);
|
||||
bt >>= 1;
|
||||
}
|
||||
|
||||
//that byte was last byte of sync
|
||||
if (NFCFrame.shiftReg == SYNC_16BIT) {
|
||||
if (FelicaFrame.shiftReg == SYNC_16BIT) {
|
||||
//Force SYNC on next byte
|
||||
NFCFrame.state = STATE_GET_LENGTH;
|
||||
NFCFrame.framebytes[0] = 0xb2;
|
||||
NFCFrame.framebytes[1] = 0x4d;
|
||||
NFCFrame.byte_offset = 0;
|
||||
NFCFrame.posCnt = 1;
|
||||
FelicaFrame.state = STATE_GET_LENGTH;
|
||||
FelicaFrame.framebytes[0] = 0xb2;
|
||||
FelicaFrame.framebytes[1] = 0x4d;
|
||||
FelicaFrame.byte_offset = 0;
|
||||
FelicaFrame.posCnt = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_GET_LENGTH: {
|
||||
shiftInByte(bt);
|
||||
NFCFrame.rem_len = NFCFrame.framebytes[2] - 1;
|
||||
NFCFrame.len = NFCFrame.framebytes[2] + 4; //with crc and sync
|
||||
NFCFrame.state = STATE_GET_DATA;
|
||||
FelicaFrame.rem_len = FelicaFrame.framebytes[2] - 1;
|
||||
FelicaFrame.len = FelicaFrame.framebytes[2] + 4; //with crc and sync
|
||||
FelicaFrame.state = STATE_GET_DATA;
|
||||
break;
|
||||
}
|
||||
case STATE_GET_DATA: {
|
||||
shiftInByte(bt);
|
||||
if (NFCFrame.rem_len <= 0) {
|
||||
NFCFrame.state = STATE_GET_CRC;
|
||||
NFCFrame.rem_len = 2;
|
||||
if (FelicaFrame.rem_len <= 0) {
|
||||
FelicaFrame.state = STATE_GET_CRC;
|
||||
FelicaFrame.rem_len = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_GET_CRC: {
|
||||
shiftInByte(bt);
|
||||
|
||||
if ( NFCFrame.rem_len <= 0 ) {
|
||||
if ( FelicaFrame.rem_len <= 0 ) {
|
||||
// skip sync 2bytes. IF ok, residue should be 0x0000
|
||||
NFCFrame.crc_ok = check_crc(CRC_FELICA, NFCFrame.framebytes+2, NFCFrame.len-2);
|
||||
NFCFrame.state = STATE_FULL;
|
||||
NFCFrame.rem_len = 0;
|
||||
if (MF_DBGLEVEL > 3) Dbprintf("[+] got 2 crc bytes [%s]", (NFCFrame.crc_ok) ? "OK" : "No" );
|
||||
FelicaFrame.crc_ok = check_crc(CRC_FELICA, FelicaFrame.framebytes+2, FelicaFrame.len-2);
|
||||
FelicaFrame.state = STATE_FULL;
|
||||
FelicaFrame.rem_len = 0;
|
||||
if (MF_DBGLEVEL > 3) Dbprintf("[+] got 2 crc bytes [%s]", (FelicaFrame.crc_ok) ? "OK" : "No" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -207,7 +205,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
||||
// b0 = fc/64 (212kbps)
|
||||
// 0x00 = timeslot
|
||||
// 0x09 0x21 = crc
|
||||
static uint8_t poll[10] = {0xb2,0x4d,0x06,0x00,0xFF,0xFF,0x00,0x00,0x09,0x21};
|
||||
static uint8_t poll[10] = {0xb2,0x4d,0x06,FELICA_POLL_REQ,0xFF,0xFF,0x00,0x00,0x09,0x21};
|
||||
|
||||
int len = 20;
|
||||
|
||||
@@ -219,7 +217,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
||||
TransmitFor18092_AsReader(poll, sizeof(poll), NULL, 1, 0);
|
||||
|
||||
// polling card, break if success
|
||||
if (WaitForFelicaReply(512) && NFCFrame.framebytes[3] == FELICA_POLL_ACK)
|
||||
if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK)
|
||||
break;
|
||||
|
||||
WDT_HIT();
|
||||
@@ -231,19 +229,19 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
||||
return 1;
|
||||
|
||||
// wrong answer
|
||||
if (NFCFrame.framebytes[3] != FELICA_POLL_ACK)
|
||||
if (FelicaFrame.framebytes[3] != FELICA_POLL_ACK)
|
||||
return 2;
|
||||
|
||||
// VALIDATE CRC residue is 0, hence if crc is a value it failed.
|
||||
if (!check_crc(CRC_FELICA, NFCFrame.framebytes+2, NFCFrame.len-2))
|
||||
if (!check_crc(CRC_FELICA, FelicaFrame.framebytes+2, FelicaFrame.len-2))
|
||||
return 3;
|
||||
|
||||
// copy UID
|
||||
// idm 8
|
||||
if (card) {
|
||||
memcpy(card->IDm, NFCFrame.framebytes + 4, 8);
|
||||
memcpy(card->PMm, NFCFrame.framebytes + 4 + 8, 8);
|
||||
//memcpy(card->servicecode, NFCFrame.framebytes + 4 + 8 + 8, 2);
|
||||
memcpy(card->IDm, FelicaFrame.framebytes + 4, 8);
|
||||
memcpy(card->PMm, FelicaFrame.framebytes + 4 + 8, 8);
|
||||
//memcpy(card->servicecode, FelicaFrame.framebytes + 4 + 8 + 8, 2);
|
||||
memcpy(card->code, card->IDm, 2);
|
||||
memcpy(card->uid, card->IDm + 2, 6);
|
||||
memcpy(card->iccode, card->PMm, 2);
|
||||
@@ -269,7 +267,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
||||
static void BuildFliteRdblk(uint8_t* idm, int blocknum, uint16_t *blocks ) {
|
||||
|
||||
if (blocknum > 4 || blocknum <= 0)
|
||||
Dbprintf("Invalid number of blocks, %d. Up to 4 are allowed.", blocknum);
|
||||
Dbprintf("Invalid number of blocks, %d != 4", blocknum);
|
||||
|
||||
uint8_t c = 0, i = 0;
|
||||
|
||||
@@ -389,19 +387,19 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
|
||||
// power, no modulation
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
|
||||
NFCFrameReset();
|
||||
FelicaFrameReset();
|
||||
|
||||
// clear RXRDY:
|
||||
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
uint32_t timeout = felica_get_timeout();
|
||||
uint32_t timeout = iso18092_get_timeout();
|
||||
for(;;) {
|
||||
WDT_HIT();
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
b = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
|
||||
ProcessNFCByte(b);
|
||||
if (NFCFrame.state == STATE_FULL) {
|
||||
Process18092Byte(b);
|
||||
if (FelicaFrame.state == STATE_FULL) {
|
||||
felica_nexttransfertime =
|
||||
MAX(
|
||||
felica_nexttransfertime,
|
||||
@@ -410,19 +408,19 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
|
||||
;
|
||||
|
||||
LogTrace(
|
||||
NFCFrame.framebytes,
|
||||
NFCFrame.len,
|
||||
FelicaFrame.framebytes,
|
||||
FelicaFrame.len,
|
||||
((GetCountSspClk() & 0xfffffff8)<<4) - DELAY_AIR2ARM_AS_READER - timeout,
|
||||
((GetCountSspClk() & 0xfffffff8)<<4) - DELAY_AIR2ARM_AS_READER,
|
||||
NULL,
|
||||
false
|
||||
);
|
||||
return true;
|
||||
} else if (c++ > timeout && NFCFrame.state == STATE_UNSYNCD) {
|
||||
} else if (c++ > timeout && FelicaFrame.state == STATE_UNSYNCD) {
|
||||
return false;
|
||||
} else if (NFCFrame.state == STATE_GET_CRC) {
|
||||
} else if (FelicaFrame.state == STATE_GET_CRC) {
|
||||
Dbprintf(" Frame: ");
|
||||
Dbhexdump(16, NFCFrame.framebytes, 0);
|
||||
Dbhexdump(16, FelicaFrame.framebytes, 0);
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
@@ -432,7 +430,7 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
|
||||
|
||||
// Set up FeliCa communication (similar to iso14443a_setup)
|
||||
// field is setup for "Sending as Reader"
|
||||
static void felica_setup(uint8_t fpga_minor_mode) {
|
||||
static void iso18092_setup(uint8_t fpga_minor_mode) {
|
||||
|
||||
LEDsoff();
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
@@ -442,11 +440,13 @@ static void felica_setup(uint8_t fpga_minor_mode) {
|
||||
|
||||
// Initialize Demod and Uart structs
|
||||
//DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
|
||||
NFCInit(BigBuf_malloc(NFC_MAX_FRAME_SIZE));
|
||||
FelicaFrameinit(BigBuf_malloc(FELICA_MAX_FRAME_SIZE));
|
||||
|
||||
felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER;
|
||||
felica_set_timeout(2120); // 106 * 20ms maximum start-up time of card
|
||||
iso18092_set_timeout(2120); // 106 * 20ms maximum start-up time of card
|
||||
|
||||
init_table(CRC_FELICA);
|
||||
|
||||
// connect Demodulated Signal to ADC:
|
||||
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
|
||||
|
||||
@@ -455,8 +455,6 @@ static void felica_setup(uint8_t fpga_minor_mode) {
|
||||
|
||||
// LSB transfer. Remember to set it back to MSB with
|
||||
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
|
||||
|
||||
init_table(CRC_FELICA);
|
||||
|
||||
// Signal field is on with the appropriate LED
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | fpga_minor_mode);
|
||||
@@ -492,7 +490,7 @@ void felica_sendraw(UsbCommand *c) {
|
||||
set_tracing(true);
|
||||
|
||||
if ((param & FELICA_CONNECT)) {
|
||||
felica_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
|
||||
// notify client selecting status.
|
||||
// if failed selecting, turn off antenna and quite.
|
||||
@@ -526,7 +524,7 @@ void felica_sendraw(UsbCommand *c) {
|
||||
|
||||
TransmitFor18092_AsReader(buf, buf[2]+4, NULL, 1, 0);
|
||||
arg0 = !WaitForFelicaReply(1024);
|
||||
cmd_send(CMD_ACK, arg0, 0, 0, NFCFrame.framebytes+2, NFCFrame.len-2);
|
||||
cmd_send(CMD_ACK, arg0, 0, 0, FelicaFrame.framebytes+2, FelicaFrame.len-2);
|
||||
}
|
||||
|
||||
if ((param & FELICA_NO_DISCONNECT))
|
||||
@@ -547,7 +545,7 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) {
|
||||
|
||||
Dbprintf("Snoop FelicaLiteS: Getting first %d frames, Skipping %d triggers.\n", samplesToSkip, triggersToSkip);
|
||||
|
||||
felica_setup( FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
iso18092_setup( FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
|
||||
//the frame bits are slow enough.
|
||||
int n = BigBuf_max_traceLen() / sizeof(uint8_t); // take all memory
|
||||
@@ -563,24 +561,24 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) {
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
|
||||
ProcessNFCByte(dist);
|
||||
Process18092Byte(dist);
|
||||
|
||||
//to be sure we are in frame
|
||||
if (NFCFrame.state == STATE_GET_LENGTH) {
|
||||
if (FelicaFrame.state == STATE_GET_LENGTH) {
|
||||
//length is after 48 (PRE)+16 (SYNC) - 64 ticks +maybe offset? not 100%
|
||||
uint16_t distance = GetCountSspClk() - endframe - 64 + (NFCFrame.byte_offset > 0 ? (8-NFCFrame.byte_offset) : 0);
|
||||
uint16_t distance = GetCountSspClk() - endframe - 64 + (FelicaFrame.byte_offset > 0 ? (8-FelicaFrame.byte_offset) : 0);
|
||||
*dest = distance >> 8;
|
||||
dest++;
|
||||
*dest = (distance & 0xff);
|
||||
dest++;
|
||||
}
|
||||
//crc NOT checked
|
||||
if (NFCFrame.state == STATE_FULL) {
|
||||
if (FelicaFrame.state == STATE_FULL) {
|
||||
endframe = GetCountSspClk();
|
||||
//*dest = NFCFrame.crc_ok; //kind of wasteful
|
||||
//*dest = FelicaFrame.crc_ok; //kind of wasteful
|
||||
dest++;
|
||||
for(int i=0; i < NFCFrame.len; i++) {
|
||||
*dest = NFCFrame.framebytes[i];
|
||||
for(int i=0; i < FelicaFrame.len; i++) {
|
||||
*dest = FelicaFrame.framebytes[i];
|
||||
dest++;
|
||||
if (dest >= destend ) break;
|
||||
|
||||
@@ -590,9 +588,9 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) {
|
||||
if (remFrames <= 0) break;
|
||||
if (dest >= destend ) break;
|
||||
|
||||
numbts += NFCFrame.len;
|
||||
numbts += FelicaFrame.len;
|
||||
|
||||
NFCFrameReset();
|
||||
FelicaFrameReset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -621,9 +619,9 @@ void felica_sim_lite(uint64_t nfcid) {
|
||||
num_to_bytes(nfcid, 8, ndef);
|
||||
|
||||
//prepare our 3 responses...
|
||||
uint8_t resp_poll0[R_POLL0_LEN] = { 0xb2,0x4d,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00,0xb3,0x7f};
|
||||
uint8_t resp_poll1[R_POLL1_LEN] = { 0xb2,0x4d,0x14,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00, 0x88,0xb4,0xb3,0x7f};
|
||||
uint8_t resp_readblk[R_READBLK_LEN] = { 0xb2,0x4d,0x1d,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x04,0x01,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x23,0xcb,0x6e};
|
||||
uint8_t resp_poll0[R_POLL0_LEN] = { 0xb2,0x4d,0x12,FELICA_POLL_ACK,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00,0xb3,0x7f};
|
||||
uint8_t resp_poll1[R_POLL1_LEN] = { 0xb2,0x4d,0x14,FELICA_POLL_ACK,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00, 0x88,0xb4,0xb3,0x7f};
|
||||
uint8_t resp_readblk[R_READBLK_LEN] = { 0xb2,0x4d,0x1d,FELICA_RDBLK_ACK,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x04,0x01,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x23,0xcb,0x6e};
|
||||
|
||||
//NFC tag 3/ ISo technically. Many overlapping standards
|
||||
DbpString("Felica Lite-S sim start");
|
||||
@@ -643,7 +641,7 @@ void felica_sim_lite(uint64_t nfcid) {
|
||||
AddCrc(resp_poll1, resp_poll1[2]);
|
||||
AddCrc(resp_readblk, resp_readblk[2]);
|
||||
|
||||
felica_setup( FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
iso18092_setup( FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
|
||||
bool listenmode = true;
|
||||
//uint32_t frtm = GetCountSspClk();
|
||||
@@ -657,28 +655,28 @@ void felica_sim_lite(uint64_t nfcid) {
|
||||
|
||||
uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
|
||||
//frtm = GetCountSspClk();
|
||||
ProcessNFCByte(dist);
|
||||
Process18092Byte(dist);
|
||||
|
||||
if (NFCFrame.state == STATE_FULL) {
|
||||
if (FelicaFrame.state == STATE_FULL) {
|
||||
|
||||
if (NFCFrame.crc_ok) {
|
||||
if (FelicaFrame.crc_ok) {
|
||||
|
||||
if (NFCFrame.framebytes[2] == 6 && NFCFrame.framebytes[3] == 0) {
|
||||
if (FelicaFrame.framebytes[2] == 6 && FelicaFrame.framebytes[3] == 0) {
|
||||
|
||||
//polling... there are two types of polling we answer to
|
||||
if (NFCFrame.framebytes[6] == 0) {
|
||||
if (FelicaFrame.framebytes[6] == 0) {
|
||||
curresp = resp_poll0;
|
||||
curlen = R_POLL0_LEN;
|
||||
listenmode = false;
|
||||
}
|
||||
if (NFCFrame.framebytes[6] == 1) {
|
||||
if (FelicaFrame.framebytes[6] == 1) {
|
||||
curresp = resp_poll1;
|
||||
curlen = R_POLL1_LEN;
|
||||
listenmode = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (NFCFrame.framebytes[2] > 5 && NFCFrame.framebytes[3] == 0x06) {
|
||||
if (FelicaFrame.framebytes[2] > 5 && FelicaFrame.framebytes[3] == 0x06) {
|
||||
//we should rebuild it depending on page size, but...
|
||||
//Let's see first
|
||||
curresp = resp_readblk;
|
||||
@@ -686,10 +684,10 @@ void felica_sim_lite(uint64_t nfcid) {
|
||||
listenmode = false;
|
||||
}
|
||||
//clear frame
|
||||
NFCFrameReset();
|
||||
FelicaFrameReset();
|
||||
} else {
|
||||
//frame invalid, clear it out to allow for the next one
|
||||
NFCFrameReset();
|
||||
FelicaFrameReset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -703,7 +701,7 @@ void felica_sim_lite(uint64_t nfcid) {
|
||||
//switch back
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
|
||||
NFCFrameReset();
|
||||
FelicaFrameReset();
|
||||
listenmode = true;
|
||||
curlen = 0;
|
||||
curresp = NULL;
|
||||
@@ -721,11 +719,11 @@ void felica_sim_lite(uint64_t nfcid) {
|
||||
void felica_dump_lite_s() {
|
||||
|
||||
uint8_t ndef[8];
|
||||
uint8_t poll[10] = { 0xb2,0x4d,0x06,0x00,0xff,0xff,0x00,0x00,0x09,0x21};
|
||||
uint16_t liteblks[28] = {0x00, 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x90,0x91,0x92,0xa0};
|
||||
uint8_t poll[10] = { 0xb2,0x4d,0x06,FELICA_POLL_REQ,0xff,0xff,0x00,0x00,0x09,0x21};
|
||||
uint16_t liteblks[28] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x90,0x91,0x92,0xa0};
|
||||
|
||||
// setup device.
|
||||
felica_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
|
||||
uint8_t blknum;
|
||||
bool isOK = false;
|
||||
@@ -740,12 +738,12 @@ void felica_dump_lite_s() {
|
||||
//TransmitFor18092_AsReader(poll, 10, GetCountSspClk()+512, 1, 0);
|
||||
TransmitFor18092_AsReader(poll, 10, NULL, 1, 0);
|
||||
|
||||
if (WaitForFelicaReply(512) && NFCFrame.framebytes[3] == FELICA_POLL_ACK) {
|
||||
if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK) {
|
||||
|
||||
// copy 8bytes to ndef.
|
||||
memcpy(ndef, NFCFrame.framebytes + 4, 8);
|
||||
memcpy(ndef, FelicaFrame.framebytes + 4, 8);
|
||||
// for (c=0; c < 8; c++)
|
||||
// ndef[c] = NFCFrame.framebytes[c+4];
|
||||
// ndef[c] = FelicaFrame.framebytes[c+4];
|
||||
|
||||
for (blknum=0; blknum < sizeof(liteblks); ) {
|
||||
|
||||
@@ -756,15 +754,15 @@ void felica_dump_lite_s() {
|
||||
TransmitFor18092_AsReader(frameSpace, frameSpace[2]+4, NULL, 1, 0);
|
||||
|
||||
// read block
|
||||
if (WaitForFelicaReply(1024) && NFCFrame.framebytes[3] == FELICA_RDBLK_ACK) {
|
||||
if (WaitForFelicaReply(1024) && FelicaFrame.framebytes[3] == FELICA_RDBLK_ACK) {
|
||||
|
||||
dest[cnt++] = liteblks[blknum];
|
||||
|
||||
uint8_t *fb = NFCFrame.framebytes;
|
||||
uint8_t *fb = FelicaFrame.framebytes;
|
||||
dest[cnt++] = fb[12];
|
||||
dest[cnt++] = fb[13];
|
||||
|
||||
//memcpy(dest+cnt, NFCFrame.framebytes + 15, 16);
|
||||
//memcpy(dest+cnt, FelicaFrame.framebytes + 15, 16);
|
||||
//cnt += 16;
|
||||
for(uint8_t j=0; j < 16; j++)
|
||||
dest[cnt++] = fb[15+j];
|
||||
@@ -773,8 +771,8 @@ void felica_dump_lite_s() {
|
||||
cntfails = 0;
|
||||
|
||||
// // print raw log.
|
||||
// Dbprintf("LEN %u | Dump bytes count %u ", NFCFrame.len, cnt);
|
||||
Dbhexdump(NFCFrame.len, NFCFrame.framebytes+15, 0);
|
||||
// Dbprintf("LEN %u | Dump bytes count %u ", FelicaFrame.len, cnt);
|
||||
Dbhexdump(FelicaFrame.len, FelicaFrame.framebytes+15, 0);
|
||||
} else {
|
||||
cntfails++;
|
||||
if (cntfails > 12) {
|
||||
|
||||
+116
-104
@@ -14,7 +14,10 @@
|
||||
#define MAX_ISO14A_TIMEOUT 524288
|
||||
static uint32_t iso14a_timeout;
|
||||
|
||||
uint8_t colpos = 0;
|
||||
int rsamples = 0;
|
||||
//int ReqCount;
|
||||
//char CollisionIndicators[10*8];
|
||||
|
||||
uint8_t trigger = 0;
|
||||
// the block number for the ISO14443-4 PCB
|
||||
@@ -103,6 +106,8 @@ static uint32_t LastProxToAirDuration;
|
||||
// Sequence D: 11110000 modulation with subcarrier during first half
|
||||
// Sequence E: 00001111 modulation with subcarrier during second half
|
||||
// Sequence F: 00000000 no modulation with subcarrier
|
||||
// Sequence COLL: 11111111 load modulation over the full bitlenght.
|
||||
// Tricks the reader to think that multiple cards answer (at least one card with 1 and at least one card with 0).
|
||||
// READER TO CARD - miller
|
||||
// Sequence X: 00001100 drop after half a period
|
||||
// Sequence Y: 00000000 no drop
|
||||
@@ -110,6 +115,7 @@ static uint32_t LastProxToAirDuration;
|
||||
#define SEC_D 0xf0
|
||||
#define SEC_E 0x0f
|
||||
#define SEC_F 0x00
|
||||
#define SEC_COLL 0xff
|
||||
#define SEC_X 0x0c
|
||||
#define SEC_Y 0x00
|
||||
#define SEC_Z 0xc0
|
||||
@@ -643,7 +649,9 @@ void RAMFUNC SniffIso14443a(uint8_t param) {
|
||||
//-----------------------------------------------------------------------------
|
||||
// Prepare tag messages
|
||||
//-----------------------------------------------------------------------------
|
||||
static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *parity) {
|
||||
static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *parity, bool collision) {
|
||||
|
||||
//uint8_t localCol = 0;
|
||||
ToSendReset();
|
||||
|
||||
// Correction bit, might be removed when not needed
|
||||
@@ -651,7 +659,7 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par
|
||||
ToSendStuffBit(0);
|
||||
ToSendStuffBit(0);
|
||||
ToSendStuffBit(0);
|
||||
ToSendStuffBit(1); // 1
|
||||
ToSendStuffBit(1); // <-----
|
||||
ToSendStuffBit(0);
|
||||
ToSendStuffBit(0);
|
||||
ToSendStuffBit(0);
|
||||
@@ -665,21 +673,32 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par
|
||||
|
||||
// Data bits
|
||||
for(uint16_t j = 0; j < 8; j++) {
|
||||
if(b & 1) {
|
||||
ToSend[++ToSendMax] = SEC_D;
|
||||
} else {
|
||||
ToSend[++ToSendMax] = SEC_E;
|
||||
//if (collision && (localCol >= colpos)){
|
||||
if (collision) {
|
||||
ToSend[++ToSendMax] = SEC_COLL;
|
||||
//localCol++;
|
||||
} else {
|
||||
if (b & 1) {
|
||||
ToSend[++ToSendMax] = SEC_D;
|
||||
} else {
|
||||
ToSend[++ToSendMax] = SEC_E;
|
||||
}
|
||||
b >>= 1;
|
||||
}
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
// Get the parity bit
|
||||
if (parity[i>>3] & (0x80>>(i&0x0007))) {
|
||||
ToSend[++ToSendMax] = SEC_D;
|
||||
LastProxToAirDuration = 8 * ToSendMax - 4;
|
||||
if (collision) {
|
||||
ToSend[++ToSendMax] = SEC_COLL;
|
||||
LastProxToAirDuration = 8 * ToSendMax;
|
||||
} else {
|
||||
ToSend[++ToSendMax] = SEC_E;
|
||||
LastProxToAirDuration = 8 * ToSendMax;
|
||||
// Get the parity bit
|
||||
if (parity[i>>3] & (0x80>>(i&0x0007))) {
|
||||
ToSend[++ToSendMax] = SEC_D;
|
||||
LastProxToAirDuration = 8 * ToSendMax - 4;
|
||||
} else {
|
||||
ToSend[++ToSendMax] = SEC_E;
|
||||
LastProxToAirDuration = 8 * ToSendMax;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -690,10 +709,13 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par
|
||||
ToSendMax++;
|
||||
}
|
||||
|
||||
static void CodeIso14443aAsTag(const uint8_t *cmd, uint16_t len) {
|
||||
static void CodeIso14443aAsTagEx(const uint8_t *cmd, uint16_t len, bool collision) {
|
||||
uint8_t par[MAX_PARITY_SIZE] = {0};
|
||||
GetParity(cmd, len, par);
|
||||
CodeIso14443aAsTagPar(cmd, len, par);
|
||||
CodeIso14443aAsTagPar(cmd, len, par, collision);
|
||||
}
|
||||
static void CodeIso14443aAsTag(const uint8_t *cmd, uint16_t len) {
|
||||
CodeIso14443aAsTagEx(cmd, len, false);
|
||||
}
|
||||
|
||||
static void Code4bitAnswerAsTag(uint8_t cmd) {
|
||||
@@ -781,12 +803,12 @@ bool prepare_tag_modulation(tag_response_info_t* response_info, size_t max_buffe
|
||||
// Make sure we do not exceed the free buffer space
|
||||
if (ToSendMax > max_buffer_size) {
|
||||
Dbprintf("Out of memory, when modulating bits for tag answer:");
|
||||
Dbhexdump(response_info->response_n,response_info->response,false);
|
||||
Dbhexdump(response_info->response_n, response_info->response, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy the byte array, used for this modulation to the buffer position
|
||||
memcpy(response_info->modulation,ToSend,ToSendMax);
|
||||
memcpy(response_info->modulation, ToSend, ToSendMax);
|
||||
|
||||
// Store the number of bytes that were used for encoding/modulation and the time needed to transfer them
|
||||
response_info->modulation_n = ToSendMax;
|
||||
@@ -1033,7 +1055,7 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t* data) {
|
||||
|
||||
// Clean receive command buffer
|
||||
if (!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) {
|
||||
Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen());
|
||||
Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen());
|
||||
break;
|
||||
}
|
||||
p_response = NULL;
|
||||
@@ -1680,9 +1702,11 @@ int EmSend4bit(uint8_t resp){
|
||||
par);
|
||||
return res;
|
||||
}
|
||||
|
||||
int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){
|
||||
CodeIso14443aAsTagPar(resp, respLen, par);
|
||||
int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par) {
|
||||
return EmSendCmdParEx(resp, respLen, par, false);
|
||||
}
|
||||
int EmSendCmdParEx(uint8_t *resp, uint16_t respLen, uint8_t *par, bool collision){
|
||||
CodeIso14443aAsTagPar(resp, respLen, par, collision);
|
||||
int res = EmSendCmd14443aRaw(ToSend, ToSendMax);
|
||||
// do the tracing for the previous reader request and this tag answer:
|
||||
EmLogTrace(Uart.output,
|
||||
@@ -1697,11 +1721,13 @@ int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){
|
||||
par);
|
||||
return res;
|
||||
}
|
||||
|
||||
int EmSendCmd(uint8_t *resp, uint16_t respLen){
|
||||
return EmSendCmdEx(resp, respLen, false);
|
||||
}
|
||||
int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool collision){
|
||||
uint8_t par[MAX_PARITY_SIZE] = {0x00};
|
||||
GetParity(resp, respLen, par);
|
||||
return EmSendCmdPar(resp, respLen, par);
|
||||
return EmSendCmdParEx(resp, respLen, par, collision);
|
||||
}
|
||||
|
||||
bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity,
|
||||
@@ -1805,44 +1831,22 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) {
|
||||
// by fooling the reader there is a collision and forceing the reader to
|
||||
// increase the uid bytes. The might be an overflow, DoS will occure.
|
||||
void iso14443a_antifuzz(uint32_t flags){
|
||||
/*
|
||||
uint8_t uidlen = 4+1+1+2;
|
||||
if (( flags & 2 ) == 2 )
|
||||
uidlen = 7+1+1+2;
|
||||
if (( flags & 4 ) == 4 )
|
||||
uidlen = 10+1+1+2;
|
||||
|
||||
uint8_t *uid = BigBuf_malloc(uidlen);
|
||||
|
||||
// The first response contains the ATQA (note: bytes are transmitted in reverse order).
|
||||
// Mifare Classic 1K
|
||||
uint8_t atqa[] = {0x04, 0};
|
||||
|
||||
if ( (flags & 2) == 2 ) {
|
||||
uid[0] = 0x88; // Cascade Tag marker
|
||||
uid[1] = 0x01;
|
||||
|
||||
// Configure the ATQA accordingly
|
||||
atqa[0] |= 0x40;
|
||||
} else {
|
||||
memcpy(response2, data, 4);
|
||||
// Configure the ATQA accordingly
|
||||
atqa[0] &= 0xBF;
|
||||
}
|
||||
|
||||
// We need to listen to the high-frequency, peak-detected path.
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
|
||||
|
||||
BigBuf_free_keep_EM();
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
int len = 0;
|
||||
|
||||
// allocate buffers:
|
||||
uint8_t *received = BigBuf_malloc(MAX_FRAME_SIZE);
|
||||
uint8_t *receivedPar = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint16_t counter = 0;
|
||||
|
||||
int len = 0;
|
||||
|
||||
BigBuf_free();
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
uint8_t *resp = BigBuf_malloc(20);
|
||||
|
||||
memset(resp, 0xFF , 20);
|
||||
|
||||
LED_A_ON();
|
||||
for (;;) {
|
||||
@@ -1850,50 +1854,53 @@ void iso14443a_antifuzz(uint32_t flags){
|
||||
|
||||
// Clean receive command buffer
|
||||
if (!GetIso14443aCommandFromReader(received, receivedPar, &len)) {
|
||||
Dbprintf("Anti-fuzz stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen());
|
||||
Dbprintf("Anti-fuzz stopped. Trace length: %d ", BigBuf_get_traceLen());
|
||||
break;
|
||||
}
|
||||
p_response = NULL;
|
||||
if ( received[0] == ISO14443A_CMD_WUPA || received[0] == ISO14443A_CMD_REQA) {
|
||||
resp[0] = 0x04;
|
||||
resp[1] = 0x00;
|
||||
|
||||
if ( (flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA ) {
|
||||
resp[0] = 0x44;
|
||||
}
|
||||
|
||||
EmSendCmd(resp, 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
// look at the command now.
|
||||
if (received[0] == ISO14443A_CMD_REQA) { // Received a REQUEST
|
||||
p_response = &responses[0];
|
||||
} else if (received[0] == ISO14443A_CMD_WUPA) { // Received a WAKEUP
|
||||
p_response = &responses[0];
|
||||
} else if (received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { // Received request for UID (cascade 1)
|
||||
p_response = &responses[1];
|
||||
} else if (received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received request for UID (cascade 2)
|
||||
p_response = &responses[2];
|
||||
} else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { // Received a SELECT (cascade 1)
|
||||
p_response = &responses[3];
|
||||
} else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received a SELECT (cascade 2)
|
||||
p_response = &responses[4];
|
||||
}
|
||||
if (p_response != NULL) {
|
||||
// Received request for UID (cascade 1)
|
||||
//if (received[1] >= 0x20 && received[1] <= 0x57 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) {
|
||||
if (received[1] >= 0x20 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) {
|
||||
resp[0] = 0xFF;
|
||||
resp[1] = 0xFF;
|
||||
resp[2] = 0xFF;
|
||||
resp[3] = 0xFF;
|
||||
resp[4] = resp[0] ^ resp[1] ^ resp[2] ^ resp[3];
|
||||
colpos = 0;
|
||||
|
||||
EmSendCmd14443aRaw(p_response->modulation, p_response->modulation_n);
|
||||
// do the tracing for the previous reader request and this tag answer:
|
||||
uint8_t par[MAX_PARITY_SIZE] = {0x00};
|
||||
GetParity(p_response->response, p_response->response_n, par);
|
||||
if ( (flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA ) {
|
||||
resp[0] = 0x88;
|
||||
colpos = 8;
|
||||
}
|
||||
|
||||
EmSendCmdEx(resp, 5, true);
|
||||
if (MF_DBGLEVEL >= 4) Dbprintf("ANTICOLL or SELECT %x", received[1]);
|
||||
LED_D_INV();
|
||||
|
||||
EmLogTrace(Uart.output,
|
||||
Uart.len,
|
||||
Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG,
|
||||
Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG,
|
||||
Uart.parity,
|
||||
p_response->response,
|
||||
p_response->response_n,
|
||||
LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG,
|
||||
(LastTimeProxToAirStart + p_response->ProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG,
|
||||
par);
|
||||
continue;
|
||||
} else if (received[1] == 0x20 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received request for UID (cascade 2)
|
||||
if (MF_DBGLEVEL >= 4) Dbprintf("ANTICOLL or SELECT_2");
|
||||
} else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { // Received a SELECT (cascade 1)
|
||||
} else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received a SELECT (cascade 2)
|
||||
} else {
|
||||
Dbprintf("unknown command %x", received[0]);
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
cmd_send(CMD_ACK,1,0,0,0,0);
|
||||
switch_off();
|
||||
Dbprintf("-[ UID until no response [%d]", counter);
|
||||
*/
|
||||
switch_off();
|
||||
BigBuf_free_keep_EM();
|
||||
}
|
||||
|
||||
static void iso14a_set_ATS_times(uint8_t *ats) {
|
||||
@@ -2212,13 +2219,16 @@ b8 b7 b6 b5 b4 b3 b2 b1
|
||||
b5,b6 = 00 - DESELECT
|
||||
11 - WTX
|
||||
*/
|
||||
int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res) {
|
||||
int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res) {
|
||||
uint8_t parity[MAX_PARITY_SIZE] = {0x00};
|
||||
uint8_t real_cmd[cmd_len + 4];
|
||||
|
||||
if (cmd_len) {
|
||||
// ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02
|
||||
real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00)
|
||||
if (send_chaining) {
|
||||
real_cmd[0] |= 0x10;
|
||||
}
|
||||
// put block number into the PCB
|
||||
real_cmd[0] |= iso14_pcb_blocknum;
|
||||
memcpy(real_cmd + 1, cmd, cmd_len);
|
||||
@@ -2238,7 +2248,7 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res) {
|
||||
return 0; //DATA LINK ERROR
|
||||
} else{
|
||||
// S-Block WTX
|
||||
while((data_bytes[0] & 0xF2) == 0xF2) {
|
||||
while(len && ((data_bytes[0] & 0xF2) == 0xF2)) {
|
||||
uint32_t save_iso14a_timeout = iso14a_get_timeout();
|
||||
// temporarily increase timeout
|
||||
iso14a_set_timeout( MAX((data_bytes[1] & 0x3f) * save_iso14a_timeout, MAX_ISO14A_TIMEOUT) );
|
||||
@@ -2256,32 +2266,34 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res) {
|
||||
iso14a_set_timeout(save_iso14a_timeout);
|
||||
}
|
||||
|
||||
// if we received an I- or R(ACK)-Block with a block number equal to the
|
||||
// current block number, toggle the current block number
|
||||
// if we received an I- or R(ACK)-Block with a block number equal to the
|
||||
// current block number, toggle the current block number
|
||||
if (len >= 3 // PCB+CRC = 3 bytes
|
||||
&& ((data_bytes[0] & 0xC0) == 0 // I-Block
|
||||
|| (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0
|
||||
&& (data_bytes[0] & 0x01) == iso14_pcb_blocknum) // equal block numbers
|
||||
{
|
||||
iso14_pcb_blocknum ^= 1;
|
||||
}
|
||||
{
|
||||
iso14_pcb_blocknum ^= 1;
|
||||
}
|
||||
|
||||
// if we received I-block with chaining we need to send ACK and receive another block of data
|
||||
if (res)
|
||||
*res = data_bytes[0];
|
||||
|
||||
// crc check
|
||||
if (len >=3 && !check_crc(CRC_14443_A, data_bytes, len)) {
|
||||
if (len >= 3 && !check_crc(CRC_14443_A, data_bytes, len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// cut frame byte
|
||||
len -= 1;
|
||||
// memmove(data_bytes, data_bytes + 1, len);
|
||||
for (int i = 0; i < len; i++)
|
||||
data_bytes[i] = data_bytes[i + 1];
|
||||
if (len) {
|
||||
// cut frame byte
|
||||
len -= 1;
|
||||
// memmove(data_bytes, data_bytes + 1, len);
|
||||
for (int i = 0; i < len; i++)
|
||||
data_bytes[i] = data_bytes[i + 1];
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -2331,7 +2343,7 @@ void ReaderIso14443a(UsbCommand *c) {
|
||||
|
||||
if ((param & ISO14A_APDU)) {
|
||||
uint8_t res;
|
||||
arg0 = iso14_apdu(cmd, len, buf, &res);
|
||||
arg0 = iso14_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, &res);
|
||||
cmd_send(CMD_ACK, arg0, res, 0, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
@@ -3495,7 +3507,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
|
||||
}
|
||||
|
||||
if (MF_DBGLEVEL >= 1)
|
||||
Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen());
|
||||
Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen());
|
||||
|
||||
cmd_send(CMD_ACK,1,0,0,0,0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
|
||||
+3
-1
@@ -114,7 +114,7 @@ extern void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32
|
||||
extern int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par);
|
||||
|
||||
extern void iso14443a_setup(uint8_t fpga_minor_mode);
|
||||
extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res);
|
||||
extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res);
|
||||
extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats);
|
||||
extern int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades);
|
||||
extern void iso14a_set_trigger(bool enable);
|
||||
@@ -122,8 +122,10 @@ extern void iso14a_set_trigger(bool enable);
|
||||
extern int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen);
|
||||
extern int EmSend4bit(uint8_t resp);
|
||||
extern int EmSendCmd(uint8_t *resp, uint16_t respLen);
|
||||
extern int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool collision);
|
||||
extern int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity);
|
||||
extern int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par);
|
||||
extern int EmSendCmdParEx(uint8_t *resp, uint16_t respLen, uint8_t *par, bool collision);
|
||||
extern int EmSendPrecompiledCmd(tag_response_info_t *response_info);
|
||||
|
||||
bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity,
|
||||
|
||||
+1
-1
@@ -710,7 +710,7 @@ void SimulateIso14443bTag(uint32_t pupi) {
|
||||
++cmdsReceived;
|
||||
}
|
||||
if (MF_DBGLEVEL >= 2)
|
||||
Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen());
|
||||
Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen());
|
||||
switch_off(); //simulate
|
||||
}
|
||||
|
||||
|
||||
+31
-31
@@ -61,7 +61,7 @@ static inline uint8_t rx_byte_from_fpga() {
|
||||
WDT_HIT();
|
||||
|
||||
// wait for byte be become available in rx holding register
|
||||
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
return AT91C_BASE_SSC->SSC_RHR;
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ static inline uint8_t rx_byte_from_fpga() {
|
||||
// To reduce CPU time the amplitude is approximated by using linear functions:
|
||||
// am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq))
|
||||
//
|
||||
// Note: The SSC receiver is never synchronized the calculation my be performed
|
||||
// Note: The SSC receiver is never synchronized the calculation may be performed
|
||||
// on a i/q pair from two subsequent correlations, but does not matter.
|
||||
static inline int32_t sample_power() {
|
||||
int32_t q = (int8_t)rx_byte_from_fpga(); q = ABS(q);
|
||||
@@ -100,7 +100,7 @@ static inline int32_t sample_power() {
|
||||
static inline bool rx_bit() {
|
||||
int32_t power;
|
||||
|
||||
for(size_t i = 0; i<5; ++i) {
|
||||
for (size_t i = 0; i<5; ++i) {
|
||||
power = sample_power();
|
||||
}
|
||||
|
||||
@@ -120,12 +120,12 @@ static inline void tx_bit(bool bit) {
|
||||
// insert pause
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
last_frame_end += RWD_TIME_PAUSE;
|
||||
while(GET_TICKS < last_frame_end) { };
|
||||
while (GET_TICKS < last_frame_end) { };
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
|
||||
// return to high, wait for bit periode to end
|
||||
last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE;
|
||||
while(GET_TICKS < last_frame_end) { };
|
||||
while (GET_TICKS < last_frame_end) { };
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -143,13 +143,13 @@ static void tx_frame(uint32_t frame, uint8_t len) {
|
||||
|
||||
// wait for next tx timeslot
|
||||
last_frame_end += RWD_FRAME_WAIT;
|
||||
while(GET_TICKS < last_frame_end) { };
|
||||
while (GET_TICKS < last_frame_end) { };
|
||||
|
||||
// backup ts for trace log
|
||||
uint32_t last_frame_start = last_frame_end;
|
||||
|
||||
// transmit frame, MSB first
|
||||
for(uint8_t i = 0; i < len; ++i) {
|
||||
for (uint8_t i = 0; i < len; ++i) {
|
||||
bool bit = (frame >> i) & 0x01;
|
||||
tx_bit(bit ^ legic_prng_get_bit());
|
||||
legic_prng_forward(1);
|
||||
@@ -158,7 +158,7 @@ static void tx_frame(uint32_t frame, uint8_t len) {
|
||||
// add pause to mark end of the frame
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
last_frame_end += RWD_TIME_PAUSE;
|
||||
while(GET_TICKS < last_frame_end) { };
|
||||
while (GET_TICKS < last_frame_end) { };
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
|
||||
// log
|
||||
@@ -173,19 +173,19 @@ static uint32_t rx_frame(uint8_t len) {
|
||||
|
||||
// hold sampling until card is expected to respond
|
||||
last_frame_end += TAG_FRAME_WAIT;
|
||||
while(GET_TICKS < last_frame_end) { };
|
||||
while (GET_TICKS < last_frame_end) { };
|
||||
|
||||
// backup ts for trace log
|
||||
uint32_t last_frame_start = last_frame_end;
|
||||
|
||||
uint32_t frame = 0;
|
||||
for(uint8_t i = 0; i < len; ++i) {
|
||||
for (uint8_t i = 0; i < len; ++i) {
|
||||
frame |= (rx_bit() ^ legic_prng_get_bit()) << i;
|
||||
legic_prng_forward(1);
|
||||
|
||||
// rx_bit runs only 95us, resync to TAG_BIT_PERIOD
|
||||
last_frame_end += TAG_BIT_PERIOD;
|
||||
while(GET_TICKS < last_frame_end) { };
|
||||
while (GET_TICKS < last_frame_end) { };
|
||||
}
|
||||
|
||||
// log
|
||||
@@ -203,23 +203,23 @@ static bool rx_ack() {
|
||||
|
||||
// hold sampling until card is expected to respond
|
||||
last_frame_end += TAG_FRAME_WAIT;
|
||||
while(GET_TICKS < last_frame_end) { };
|
||||
while (GET_TICKS < last_frame_end) { };
|
||||
|
||||
// backup ts for trace log
|
||||
uint32_t last_frame_start = last_frame_end;
|
||||
|
||||
uint32_t ack = 0;
|
||||
for(uint8_t i = 0; i < TAG_WRITE_TIMEOUT; ++i) {
|
||||
for (uint8_t i = 0; i < TAG_WRITE_TIMEOUT; ++i) {
|
||||
// sample bit
|
||||
ack = rx_bit();
|
||||
legic_prng_forward(1);
|
||||
|
||||
// rx_bit runs only 95us, resync to TAG_BIT_PERIOD
|
||||
last_frame_end += TAG_BIT_PERIOD;
|
||||
while(GET_TICKS < last_frame_end) { };
|
||||
while (GET_TICKS < last_frame_end) { };
|
||||
|
||||
// check if it was an ACK
|
||||
if(ack) {
|
||||
if (ack) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -282,7 +282,7 @@ static void init_reader(bool clear_mem) {
|
||||
|
||||
// reserve a cardmem, meaning we can use the tracelog function in bigbuff easier.
|
||||
legic_mem = BigBuf_get_EM_addr();
|
||||
if(legic_mem) {
|
||||
if (legic_mem) {
|
||||
memset(legic_mem, 0x00, LEGIC_CARD_MEMSIZE);
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ static uint32_t setup_phase(uint8_t iv) {
|
||||
|
||||
// Switch on carrier and let the card charge for 5ms.
|
||||
last_frame_end += 7500;
|
||||
while(GET_TICKS < last_frame_end) { };
|
||||
while (GET_TICKS < last_frame_end) { };
|
||||
|
||||
legic_prng_init(0);
|
||||
tx_frame(iv, 7);
|
||||
@@ -359,7 +359,7 @@ static int16_t read_byte(uint16_t index, uint8_t cmd_sz) {
|
||||
|
||||
// check received against calculated crc
|
||||
uint8_t calc_crc = calc_crc4(cmd, cmd_sz, byte);
|
||||
if(calc_crc != crc) {
|
||||
if (calc_crc != crc) {
|
||||
Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc);
|
||||
return -1;
|
||||
}
|
||||
@@ -399,15 +399,15 @@ void LegicRfInfo(void) {
|
||||
|
||||
// establish shared secret and detect card type
|
||||
uint8_t card_type = setup_phase(0x01);
|
||||
if(init_card(card_type, &card) != 0) {
|
||||
if (init_card(card_type, &card) != 0) {
|
||||
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
// read UID
|
||||
for(uint8_t i = 0; i < sizeof(card.uid); ++i) {
|
||||
for (uint8_t i = 0; i < sizeof(card.uid); ++i) {
|
||||
int16_t byte = read_byte(i, card.cmdsize);
|
||||
if(byte == -1) {
|
||||
if (byte == -1) {
|
||||
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
goto OUT;
|
||||
}
|
||||
@@ -417,7 +417,7 @@ void LegicRfInfo(void) {
|
||||
// read MCC and check against UID
|
||||
int16_t mcc = read_byte(4, card.cmdsize);
|
||||
int16_t calc_mcc = CRC8Legic(card.uid, 4);;
|
||||
if(mcc != calc_mcc) {
|
||||
if (mcc != calc_mcc) {
|
||||
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
goto OUT;
|
||||
}
|
||||
@@ -436,19 +436,19 @@ void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) {
|
||||
|
||||
// establish shared secret and detect card type
|
||||
uint8_t card_type = setup_phase(iv);
|
||||
if(init_card(card_type, &card) != 0) {
|
||||
if (init_card(card_type, &card) != 0) {
|
||||
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
// do not read beyond card memory
|
||||
if(len + offset > card.cardsize) {
|
||||
if (len + offset > card.cardsize) {
|
||||
len = card.cardsize - offset;
|
||||
}
|
||||
|
||||
for(uint16_t i = 0; i < len; ++i) {
|
||||
for (uint16_t i = 0; i < len; ++i) {
|
||||
int16_t byte = read_byte(offset + i, card.cmdsize);
|
||||
if(byte == -1) {
|
||||
if (byte == -1) {
|
||||
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
goto OUT;
|
||||
}
|
||||
@@ -468,26 +468,26 @@ void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) {
|
||||
init_reader(false);
|
||||
|
||||
// uid is not writeable
|
||||
if(offset <= WRITE_LOWERLIMIT) {
|
||||
if (offset <= WRITE_LOWERLIMIT) {
|
||||
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
// establish shared secret and detect card type
|
||||
uint8_t card_type = setup_phase(iv);
|
||||
if(init_card(card_type, &card) != 0) {
|
||||
if (init_card(card_type, &card) != 0) {
|
||||
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
// do not write beyond card memory
|
||||
if(len + offset > card.cardsize) {
|
||||
if (len + offset > card.cardsize) {
|
||||
len = card.cardsize - offset;
|
||||
}
|
||||
|
||||
// write in reverse order, only then is DCF (decremental field) writable
|
||||
while(len-- > 0 && !BUTTON_PRESS()) {
|
||||
if(!write_byte(len + offset, data[len], card.addrsize)) {
|
||||
while (len-- > 0 && !BUTTON_PRESS()) {
|
||||
if (!write_byte(len + offset, data[len], card.addrsize)) {
|
||||
Dbprintf("operation failed | %02X | %02X | %02X", len + offset, len, data[len]);
|
||||
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
goto OUT;
|
||||
|
||||
+30
-31
@@ -46,7 +46,7 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
|
||||
#define RWD_TIME_PAUSE 4 /* 18.9us */
|
||||
#define RWD_TIME_1 21 /* RWD_TIME_PAUSE 18.9us off + 80.2us on = 99.1us */
|
||||
#define RWD_TIME_0 13 /* RWD_TIME_PAUSE 18.9us off + 42.4us on = 61.3us */
|
||||
#define RWD_CMD_TIMEOUT 40 /* 40 * 99.1us (arbitrary value) */
|
||||
#define RWD_CMD_TIMEOUT 120 /* 120 * 99.1us (arbitrary value) */
|
||||
#define RWD_MIN_FRAME_LEN 6 /* Shortest frame is 6 bits */
|
||||
#define RWD_MAX_FRAME_LEN 23 /* Longest frame is 23 bits */
|
||||
|
||||
@@ -59,8 +59,8 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
|
||||
|
||||
// Returns true if a pulse/pause is received within timeout
|
||||
static inline bool wait_for(bool value, const uint32_t timeout) {
|
||||
while((bool)(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN) != value) {
|
||||
if(GetCountSspClk() > timeout) {
|
||||
while ((bool)(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN) != value) {
|
||||
if (GetCountSspClk() > timeout) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -81,12 +81,12 @@ static inline int8_t rx_bit() {
|
||||
uint32_t bit_start = last_frame_end;
|
||||
|
||||
// wait for pause to end
|
||||
if(!wait_for(RWD_PULSE, bit_start + RWD_TIME_1*3/2)) {
|
||||
if (!wait_for(RWD_PULSE, bit_start + RWD_TIME_1*3/2)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// wait for next pause
|
||||
if(!wait_for(RWD_PAUSE, bit_start + RWD_TIME_1*3/2)) {
|
||||
if (!wait_for(RWD_PAUSE, bit_start + RWD_TIME_1*3/2)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ static inline int8_t rx_bit() {
|
||||
last_frame_end = GetCountSspClk();
|
||||
|
||||
// check for code violation (bit to short)
|
||||
if(last_frame_end - bit_start < RWD_TIME_PAUSE) {
|
||||
if (last_frame_end - bit_start < RWD_TIME_PAUSE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ static inline int8_t rx_bit() {
|
||||
static inline void tx_bit(bool bit) {
|
||||
LED_C_ON();
|
||||
|
||||
if(bit) {
|
||||
if (bit) {
|
||||
// modulate subcarrier
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
} else {
|
||||
@@ -132,7 +132,7 @@ static inline void tx_bit(bool bit) {
|
||||
|
||||
// wait for tx timeslot to end
|
||||
last_frame_end += TAG_BIT_PERIOD;
|
||||
while(GetCountSspClk() < last_frame_end) { };
|
||||
while (GetCountSspClk() < last_frame_end) { };
|
||||
LED_C_OFF();
|
||||
}
|
||||
|
||||
@@ -150,13 +150,13 @@ static void tx_frame(uint32_t frame, uint8_t len) {
|
||||
// wait for next tx timeslot
|
||||
last_frame_end += TAG_FRAME_WAIT;
|
||||
legic_prng_forward(TAG_FRAME_WAIT/TAG_BIT_PERIOD - 1);
|
||||
while(GetCountSspClk() < last_frame_end) { };
|
||||
while (GetCountSspClk() < last_frame_end) { };
|
||||
|
||||
// backup ts for trace log
|
||||
uint32_t last_frame_start = last_frame_end;
|
||||
|
||||
// transmit frame, MSB first
|
||||
for(uint8_t i = 0; i < len; ++i) {
|
||||
for (uint8_t i = 0; i < len; ++i) {
|
||||
bool bit = (frame >> i) & 0x01;
|
||||
tx_bit(bit ^ legic_prng_get_bit());
|
||||
legic_prng_forward(1);
|
||||
@@ -174,7 +174,7 @@ static void tx_ack() {
|
||||
// wait for ack timeslot
|
||||
last_frame_end += TAG_ACK_WAIT;
|
||||
legic_prng_forward(TAG_ACK_WAIT/TAG_BIT_PERIOD - 1);
|
||||
while(GetCountSspClk() < last_frame_end) { };
|
||||
while (GetCountSspClk() < last_frame_end) { };
|
||||
|
||||
// backup ts for trace log
|
||||
uint32_t last_frame_start = last_frame_end;
|
||||
@@ -206,19 +206,19 @@ static int32_t rx_frame(uint8_t *len) {
|
||||
last_frame_end -= 2;
|
||||
|
||||
// wait for first pause (start of frame)
|
||||
for(uint8_t i = 0; true; ++i) {
|
||||
for (uint8_t i = 0; true; ++i) {
|
||||
// increment prng every TAG_BIT_PERIOD
|
||||
last_frame_end += TAG_BIT_PERIOD;
|
||||
legic_prng_forward(1);
|
||||
|
||||
// if start of frame was received exit delay loop
|
||||
if(wait_for(RWD_PAUSE, last_frame_end)) {
|
||||
if (wait_for(RWD_PAUSE, last_frame_end)) {
|
||||
last_frame_end = GetCountSspClk();
|
||||
break;
|
||||
}
|
||||
|
||||
// check for code violation
|
||||
if(i > RWD_CMD_TIMEOUT) {
|
||||
if (i > RWD_CMD_TIMEOUT) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -227,19 +227,19 @@ static int32_t rx_frame(uint8_t *len) {
|
||||
uint32_t last_frame_start = last_frame_end;
|
||||
|
||||
// receive frame
|
||||
for(*len = 0; true; ++(*len)) {
|
||||
for (*len = 0; true; ++(*len)) {
|
||||
// receive next bit
|
||||
LED_B_ON();
|
||||
int8_t bit = rx_bit();
|
||||
LED_B_OFF();
|
||||
|
||||
// check for code violation and to short / long frame
|
||||
if((bit < 0) && ((*len < RWD_MIN_FRAME_LEN) || (*len > RWD_MAX_FRAME_LEN))) {
|
||||
if ((bit < 0) && ((*len < RWD_MIN_FRAME_LEN) || (*len > RWD_MAX_FRAME_LEN))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check for code violation caused by end of frame
|
||||
if(bit < 0) {
|
||||
if (bit < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -256,7 +256,6 @@ static int32_t rx_frame(uint8_t *len) {
|
||||
// log
|
||||
uint8_t cmdbytes[] = {*len, BYTEx(frame, 0), BYTEx(frame, 1), BYTEx(frame, 2)};
|
||||
LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, true);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
@@ -267,7 +266,7 @@ static int32_t rx_frame(uint8_t *len) {
|
||||
static int32_t init_card(uint8_t cardtype, legic_card_select_t *p_card) {
|
||||
p_card->tagtype = cardtype;
|
||||
|
||||
switch(p_card->tagtype) {
|
||||
switch (p_card->tagtype) {
|
||||
case 0:
|
||||
p_card->cmdsize = 6;
|
||||
p_card->addrsize = 5;
|
||||
@@ -338,7 +337,7 @@ static int32_t setup_phase(legic_card_select_t *p_card) {
|
||||
|
||||
// wait for iv
|
||||
int32_t iv = rx_frame(&len);
|
||||
if((len != 7) || (iv < 0)) {
|
||||
if ((len != 7) || (iv < 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -346,7 +345,7 @@ static int32_t setup_phase(legic_card_select_t *p_card) {
|
||||
legic_prng_init(iv);
|
||||
|
||||
// reply with card type
|
||||
switch(p_card->tagtype) {
|
||||
switch (p_card->tagtype) {
|
||||
case 0:
|
||||
tx_frame(0x0D, 6);
|
||||
break;
|
||||
@@ -360,12 +359,12 @@ static int32_t setup_phase(legic_card_select_t *p_card) {
|
||||
|
||||
// wait for ack
|
||||
int32_t ack = rx_frame(&len);
|
||||
if((len != 6) || (ack < 0)) {
|
||||
if ((len != 6) || (ack < 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// validate data
|
||||
switch(p_card->tagtype) {
|
||||
switch (p_card->tagtype) {
|
||||
case 0:
|
||||
if(ack != 0x19) return -1;
|
||||
break;
|
||||
@@ -399,12 +398,12 @@ static int32_t connected_phase(legic_card_select_t *p_card) {
|
||||
|
||||
// wait for command
|
||||
int32_t cmd = rx_frame(&len);
|
||||
if(cmd < 0) {
|
||||
if (cmd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check if command is LEGIC_READ
|
||||
if(len == p_card->cmdsize) {
|
||||
if (len == p_card->cmdsize) {
|
||||
// prepare data
|
||||
uint8_t byte = legic_mem[cmd >> 1];
|
||||
uint8_t crc = calc_crc4(cmd, p_card->cmdsize, byte);
|
||||
@@ -416,7 +415,7 @@ static int32_t connected_phase(legic_card_select_t *p_card) {
|
||||
}
|
||||
|
||||
// check if command is LEGIC_WRITE
|
||||
if(len == p_card->cmdsize + 8 + 4) {
|
||||
if (len == p_card->cmdsize + 8 + 4) {
|
||||
// decode data
|
||||
uint16_t mask = (1 << p_card->addrsize) - 1;
|
||||
uint16_t addr = (cmd >> 1) & mask;
|
||||
@@ -425,7 +424,7 @@ static int32_t connected_phase(legic_card_select_t *p_card) {
|
||||
|
||||
// check received against calculated crc
|
||||
uint8_t calc_crc = calc_crc4(addr << 1, p_card->cmdsize, byte);
|
||||
if(calc_crc != crc) {
|
||||
if (calc_crc != crc) {
|
||||
Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc);
|
||||
return -1;
|
||||
}
|
||||
@@ -453,7 +452,7 @@ void LegicRfSimulate(uint8_t cardtype) {
|
||||
init_tag();
|
||||
|
||||
// verify command line input
|
||||
if(init_card(cardtype, &card) != 0) {
|
||||
if (init_card(cardtype, &card) != 0) {
|
||||
DbpString("Unknown tagtype.");
|
||||
goto OUT;
|
||||
}
|
||||
@@ -464,17 +463,17 @@ void LegicRfSimulate(uint8_t cardtype) {
|
||||
WDT_HIT();
|
||||
|
||||
// wait for carrier, restart after timeout
|
||||
if(!wait_for(RWD_PULSE, GetCountSspClk() + TAG_BIT_PERIOD)) {
|
||||
if (!wait_for(RWD_PULSE, GetCountSspClk() + TAG_BIT_PERIOD)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// wait for connection, restart on error
|
||||
if(setup_phase(&card)) {
|
||||
if (setup_phase(&card)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// conection is established, process commands until one fails
|
||||
while(!connected_phase(&card)) {
|
||||
while (!connected_phase(&card)) {
|
||||
WDT_HIT();
|
||||
}
|
||||
}
|
||||
|
||||
+146
-42
@@ -80,7 +80,7 @@ void setT55xxConfig(uint8_t arg0, t55xx_config *c) {
|
||||
|
||||
printT55xxConfig();
|
||||
|
||||
#if WITH_FLASH
|
||||
#ifdef WITH_FLASH
|
||||
// shall persist to flashmem
|
||||
if (arg0 == 0) {
|
||||
return;
|
||||
@@ -103,7 +103,7 @@ void setT55xxConfig(uint8_t arg0, t55xx_config *c) {
|
||||
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
Flash_WriteEnable();
|
||||
Flash_Erase4k(3, 0xD);
|
||||
Flash_Erase4k(3, 0xD);
|
||||
res = Flash_Write(T55XX_CONFIG_OFFSET, buf, T55XX_CONFIG_LEN);
|
||||
|
||||
if ( res == T55XX_CONFIG_LEN && MF_DBGLEVEL > 1) {
|
||||
@@ -119,7 +119,7 @@ t55xx_config* getT55xxConfig(void) {
|
||||
}
|
||||
|
||||
void loadT55xxConfig(void) {
|
||||
#if WITH_FLASH
|
||||
#ifdef WITH_FLASH
|
||||
if (!FlashInit()) {
|
||||
return;
|
||||
}
|
||||
@@ -598,9 +598,11 @@ void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycle
|
||||
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK;
|
||||
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
|
||||
AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK;
|
||||
|
||||
uint8_t check = 1;
|
||||
|
||||
for(;;) {
|
||||
|
||||
|
||||
if ( numcycles > -1 ) {
|
||||
if ( x != numcycles ) {
|
||||
++x;
|
||||
@@ -616,9 +618,11 @@ void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycle
|
||||
// used as a simple detection of a reader field?
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) {
|
||||
WDT_HIT();
|
||||
if ( usb_poll_validate_length() || BUTTON_PRESS() )
|
||||
goto OUT;
|
||||
}
|
||||
if ( !check ) {
|
||||
if ( usb_poll_validate_length() || BUTTON_PRESS() )
|
||||
goto OUT;
|
||||
}
|
||||
++check; }
|
||||
|
||||
if (buf[i])
|
||||
OPEN_COIL();
|
||||
@@ -628,9 +632,11 @@ void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycle
|
||||
//wait until SSC_CLK goes LOW
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) {
|
||||
WDT_HIT();
|
||||
//if ( usb_poll_validate_length() || BUTTON_PRESS() )
|
||||
if ( BUTTON_PRESS() )
|
||||
goto OUT;
|
||||
if ( !check ) {
|
||||
if ( usb_poll_validate_length() || BUTTON_PRESS() )
|
||||
goto OUT;
|
||||
}
|
||||
++check;
|
||||
}
|
||||
|
||||
i++;
|
||||
@@ -1489,11 +1495,22 @@ void T55xxWriteBlock(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t arg) {
|
||||
// Read one card block in page [page]
|
||||
void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) {
|
||||
LED_A_ON();
|
||||
bool PwdMode = arg0 & 0x1;
|
||||
uint8_t Page = (arg0 & 0x2) >> 1;
|
||||
uint32_t i = 0;
|
||||
bool RegReadMode = (Block == 0xFF);//regular read mode
|
||||
bool PwdMode = arg0 & 0x1;
|
||||
uint8_t Page = ( arg0 & 0x2 ) >> 1;
|
||||
bool brute_mem = arg0 & 0x4;
|
||||
|
||||
uint32_t i = 0;
|
||||
|
||||
// regular read mode
|
||||
bool RegReadMode = (Block == 0xFF);
|
||||
|
||||
uint8_t start_wait = 4;
|
||||
size_t samples = 12000;
|
||||
if ( brute_mem ) {
|
||||
start_wait = 0;
|
||||
samples = 1024;
|
||||
}
|
||||
|
||||
//clear buffer now so it does not interfere with timing later
|
||||
BigBuf_Clear_keep_EM();
|
||||
|
||||
@@ -1505,7 +1522,8 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) {
|
||||
// Set up FPGA, 125kHz to power up the tag
|
||||
LFSetupFPGAForADC(95, true);
|
||||
// make sure tag is fully powered up...
|
||||
WaitMS(4);
|
||||
WaitMS(start_wait);
|
||||
|
||||
// Trigger T55x7 Direct Access Mode with start gap
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
WaitUS(t_config.start_gap);
|
||||
@@ -1529,17 +1547,118 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) {
|
||||
|
||||
// Turn field on to read the response
|
||||
// 137*8 seems to get to the start of data pretty well...
|
||||
// but we want to go past the start and let the repeating data settle in...
|
||||
TurnReadLFOn(210*8);
|
||||
// but we want to go past the start and let the repeating data settle in...
|
||||
TurnReadLFOn(200*8);
|
||||
|
||||
// Acquisition
|
||||
// Now do the acquisition
|
||||
DoPartialAcquisition(0, true, 12000, 0);
|
||||
DoPartialAcquisition(0, true, samples, 0);
|
||||
|
||||
// Turn the field off
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
|
||||
cmd_send(CMD_ACK,0,0,0,0,0);
|
||||
LED_A_OFF();
|
||||
if ( !brute_mem ) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
cmd_send(CMD_ACK,0,0,0,0,0);
|
||||
LED_A_OFF();
|
||||
}
|
||||
}
|
||||
|
||||
void T55xx_ChkPwds() {
|
||||
|
||||
DbpString("[+] T55XX Check pwds using flashmemory starting");
|
||||
|
||||
uint8_t ret = 0;
|
||||
// First get baseline and setup LF mode.
|
||||
// tends to mess up BigBuf
|
||||
uint8_t *buf = BigBuf_get_addr();
|
||||
|
||||
uint32_t b1, baseline = 0;
|
||||
|
||||
// collect baseline for failed attempt
|
||||
uint8_t x = 32;
|
||||
while (x--) {
|
||||
b1 = 0;
|
||||
T55xxReadBlock(4, 1, 0);
|
||||
for (uint16_t j=0; j < 1024; ++j)
|
||||
b1 += buf[j];
|
||||
|
||||
b1 *= b1;
|
||||
b1 >>= 8;
|
||||
baseline += b1;
|
||||
}
|
||||
|
||||
baseline >>= 5;
|
||||
Dbprintf("[=] Baseline determined [%u]", baseline);
|
||||
|
||||
|
||||
uint8_t *pwds = BigBuf_get_EM_addr();
|
||||
uint16_t pwdCount = 0;
|
||||
uint32_t candidate = 0;
|
||||
|
||||
#ifdef WITH_FLASH
|
||||
bool use_flashmem = true;
|
||||
if ( use_flashmem ) {
|
||||
BigBuf_Clear_EM();
|
||||
uint16_t isok = 0;
|
||||
uint8_t counter[2] = {0x00, 0x00};
|
||||
isok = Flash_ReadData(DEFAULT_T55XX_KEYS_OFFSET, counter, sizeof(counter) );
|
||||
if ( isok != sizeof(counter) )
|
||||
goto OUT;
|
||||
|
||||
pwdCount = counter[1] << 8 | counter[0];
|
||||
|
||||
if ( pwdCount == 0 && pwdCount == 0xFFFF)
|
||||
goto OUT;
|
||||
|
||||
isok = Flash_ReadData(DEFAULT_T55XX_KEYS_OFFSET+2, pwds, pwdCount * 4);
|
||||
if ( isok != pwdCount * 4 )
|
||||
goto OUT;
|
||||
|
||||
Dbprintf("[=] Password dictionary count %d ", pwdCount);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t pwd = 0, curr = 0, prev = 0;
|
||||
for (uint16_t i =0; i< pwdCount; ++i) {
|
||||
|
||||
if (BUTTON_PRESS() && !usb_poll_validate_length()) {
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
pwd = bytes_to_num(pwds + i * 4, 4);
|
||||
|
||||
|
||||
T55xxReadBlock(5, 0, pwd);
|
||||
|
||||
// calc mean of BigBuf 1024 samples.
|
||||
uint32_t sum = 0;
|
||||
for (uint16_t j=0; j<1024; ++j) {
|
||||
sum += buf[j];
|
||||
}
|
||||
|
||||
sum *= sum;
|
||||
sum >>= 8;
|
||||
|
||||
int32_t tmp = (sum - baseline);
|
||||
curr = ABS(tmp);
|
||||
|
||||
Dbprintf("[=] Pwd %08X | ABS %u", pwd, curr );
|
||||
|
||||
if ( curr > prev ) {
|
||||
|
||||
|
||||
Dbprintf("[=] --> ABS %u Candidate %08X <--", curr, pwd );
|
||||
candidate = pwd;
|
||||
prev = curr;
|
||||
}
|
||||
}
|
||||
|
||||
if ( candidate )
|
||||
ret = 1;
|
||||
|
||||
OUT:
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
cmd_send(CMD_ACK,ret,candidate,0,0,0);
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
void T55xxWakeUp(uint32_t Pwd){
|
||||
@@ -1970,7 +2089,6 @@ void EM4xWriteWord(uint32_t flag, uint32_t data, uint32_t pwd) {
|
||||
//Wait 20ms for write to complete?
|
||||
WaitMS(7);
|
||||
|
||||
//Capture response if one exists
|
||||
DoPartialAcquisition(20, true, 6000, 1000);
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
@@ -1994,7 +2112,7 @@ This triggers a COTAG tag to response
|
||||
*/
|
||||
void Cotag(uint32_t arg0) {
|
||||
#ifndef OFF
|
||||
# define OFF { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(2035); }
|
||||
# define OFF(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS((x)); }
|
||||
#endif
|
||||
#ifndef ON
|
||||
# define ON(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); WaitUS((x)); }
|
||||
@@ -2003,29 +2121,15 @@ void Cotag(uint32_t arg0) {
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
// Switching to LF image on FPGA. This might empty BigBuff
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
|
||||
LFSetupFPGAForADC(89, true);
|
||||
|
||||
//clear buffer now so it does not interfere with timing later
|
||||
BigBuf_Clear_ext(false);
|
||||
|
||||
// Set up FPGA, 132kHz to power up the tag
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 89);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
|
||||
|
||||
// Connect the A/D to the peak-detected low-frequency path.
|
||||
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
|
||||
|
||||
// Now set up the SSC to get the ADC samples that are now streaming at us.
|
||||
FpgaSetupSsc();
|
||||
|
||||
// start clock - 1.5ticks is 1us
|
||||
StartTicks();
|
||||
|
||||
//send COTAG start pulse
|
||||
ON(740) OFF
|
||||
ON(3330) OFF
|
||||
ON(740) OFF
|
||||
ON(740) OFF(2035)
|
||||
ON(3330) OFF(2035)
|
||||
ON(740) OFF(2035)
|
||||
ON(1000)
|
||||
|
||||
switch(rawsignal) {
|
||||
|
||||
+22
-31
@@ -117,21 +117,21 @@ void LFSetupFPGAForADC(int divisor, bool lf_field) {
|
||||
* @return the number of bits occupied by the samples.
|
||||
*/
|
||||
uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, uint32_t cancel_after) {
|
||||
//bigbuf, to hold the aquired raw data signal
|
||||
|
||||
uint8_t *dest = BigBuf_get_addr();
|
||||
bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen();
|
||||
|
||||
|
||||
if (bits_per_sample < 1) bits_per_sample = 1;
|
||||
if (bits_per_sample > 8) bits_per_sample = 8;
|
||||
|
||||
if (decimation < 1) decimation = 1;
|
||||
|
||||
// Use a bit stream to handle the output
|
||||
// use a bit stream to handle the output
|
||||
BitstreamOut data = { dest , 0, 0};
|
||||
int sample_counter = 0;
|
||||
uint8_t sample = 0;
|
||||
//If we want to do averaging
|
||||
|
||||
// if we want to do averaging
|
||||
uint32_t sample_sum =0 ;
|
||||
uint32_t sample_total_numbers = 0;
|
||||
uint32_t sample_total_saved = 0;
|
||||
@@ -139,13 +139,13 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
|
||||
|
||||
while (!BUTTON_PRESS() && !usb_poll_validate_length() ) {
|
||||
WDT_HIT();
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
|
||||
AT91C_BASE_SSC->SSC_THR = 0x43;
|
||||
LED_D_ON();
|
||||
}
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
// Testpoint 8 (TP8) can be used to trigger oscilliscope
|
||||
LED_D_OFF();
|
||||
|
||||
// threshold either high or low values 128 = center 0. if trigger = 178
|
||||
if ((trigger_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) {
|
||||
if (cancel_after > 0) {
|
||||
@@ -162,24 +162,26 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
|
||||
if (averaging)
|
||||
sample_sum += sample;
|
||||
|
||||
//Check decimation
|
||||
// check decimation
|
||||
if (decimation > 1) {
|
||||
sample_counter++;
|
||||
if (sample_counter < decimation) continue;
|
||||
sample_counter = 0;
|
||||
}
|
||||
|
||||
//Averaging
|
||||
// averaging
|
||||
if (averaging && decimation > 1) {
|
||||
sample = sample_sum / decimation;
|
||||
sample_sum =0;
|
||||
}
|
||||
|
||||
//Store the sample
|
||||
// store the sample
|
||||
sample_total_saved ++;
|
||||
if (bits_per_sample == 8){
|
||||
if (bits_per_sample == 8) {
|
||||
dest[sample_total_saved-1] = sample;
|
||||
data.numbits = sample_total_saved << 3;//Get the return value correct
|
||||
|
||||
// Get the return value correct
|
||||
data.numbits = sample_total_saved << 3;
|
||||
if (sample_total_saved >= bufsize) break;
|
||||
|
||||
} else {
|
||||
@@ -190,9 +192,8 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
|
||||
if (bits_per_sample > 4) pushBit(&data, sample & 0x08);
|
||||
if (bits_per_sample > 5) pushBit(&data, sample & 0x04);
|
||||
if (bits_per_sample > 6) pushBit(&data, sample & 0x02);
|
||||
//Not needed, 8bps is covered above
|
||||
//if (bits_per_sample > 7) pushBit(&data, sample & 0x01);
|
||||
if ((data.numbits >> 3) +1 >= bufsize) break;
|
||||
|
||||
if ((data.numbits >> 3) + 1 >= bufsize) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,10 +286,8 @@ void doT55x7Acquisition(size_t sample_size) {
|
||||
|
||||
while(!BUTTON_PRESS() && !usb_poll_validate_length() && skipCnt < 1000 && (i < bufsize) ) {
|
||||
WDT_HIT();
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
|
||||
AT91C_BASE_SSC->SSC_THR = 0x43; //43
|
||||
LED_D_ON();
|
||||
}
|
||||
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
curSample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
LED_D_OFF();
|
||||
@@ -352,11 +351,7 @@ void doCotagAcquisition(size_t sample_size) {
|
||||
|
||||
while (!BUTTON_PRESS() && !usb_poll_validate_length() && (i < bufsize) && (noise_counter < (COTAG_T1 << 1)) ) {
|
||||
WDT_HIT();
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
|
||||
AT91C_BASE_SSC->SSC_THR = 0x43;
|
||||
LED_D_ON();
|
||||
}
|
||||
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
LED_D_OFF();
|
||||
@@ -406,12 +401,8 @@ uint32_t doCotagAcquisitionManchester() {
|
||||
uint16_t noise_counter = 0;
|
||||
|
||||
while (!BUTTON_PRESS() && !usb_poll_validate_length() && (sample_counter < bufsize) && (noise_counter < (COTAG_T1 << 1)) ) {
|
||||
WDT_HIT();
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
|
||||
AT91C_BASE_SSC->SSC_THR = 0x43;
|
||||
LED_D_ON();
|
||||
}
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
LED_D_OFF();
|
||||
|
||||
+108
-38
@@ -17,7 +17,7 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifndef HARDNESTED_AUTHENTICATION_TIMEOUT
|
||||
# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 //848 // card times out 1ms after wrong authentication (according to NXP documentation)
|
||||
# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
|
||||
#endif
|
||||
#ifndef HARDNESTED_PRE_AUTHENTICATION_LEADTIME
|
||||
# define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication
|
||||
@@ -1122,7 +1122,6 @@ uint8_t chkKey_readb(struct chk_t *c, uint8_t *keyb) {
|
||||
}
|
||||
|
||||
void chkKey_scanA(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, uint8_t *sectorcnt, uint8_t *foundkeys) {
|
||||
uint8_t status;
|
||||
for (uint8_t s = 0; s < *sectorcnt; s++) {
|
||||
|
||||
// skip already found A keys
|
||||
@@ -1130,8 +1129,7 @@ void chkKey_scanA(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, ui
|
||||
continue;
|
||||
|
||||
c->block = FirstBlockOfSector( s );
|
||||
status = chkKey( c );
|
||||
if ( status == 0 ) {
|
||||
if ( chkKey( c ) == 0 ) {
|
||||
num_to_bytes(c->key, 6, k_sector[s].keyA);
|
||||
found[(s*2)] = 1;
|
||||
++*foundkeys;
|
||||
@@ -1142,7 +1140,6 @@ void chkKey_scanA(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, ui
|
||||
}
|
||||
|
||||
void chkKey_scanB(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, uint8_t *sectorcnt, uint8_t *foundkeys) {
|
||||
uint8_t status;
|
||||
for (uint8_t s = 0; s < *sectorcnt; s++) {
|
||||
|
||||
// skip already found B keys
|
||||
@@ -1150,8 +1147,7 @@ void chkKey_scanB(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, ui
|
||||
continue;
|
||||
|
||||
c->block = FirstBlockOfSector( s );
|
||||
status = chkKey( c );
|
||||
if ( status == 0 ) {
|
||||
if ( chkKey( c ) == 0 ) {
|
||||
num_to_bytes(c->key, 6, k_sector[s].keyB);
|
||||
found[(s*2)+1] = 1;
|
||||
++*foundkeys;
|
||||
@@ -1167,7 +1163,12 @@ void chkKey_loopBonly(struct chk_t *c, struct sector_t *k_sector, uint8_t *found
|
||||
|
||||
// read Block B, if A is found.
|
||||
for (uint8_t s = 0; s < *sectorcnt; ++s) {
|
||||
|
||||
if ( found[(s*2)] && found[(s*2)+1] )
|
||||
continue;
|
||||
|
||||
c->block = (FirstBlockOfSector( s ) + NumBlocksPerSector( s ) - 1);
|
||||
|
||||
// A but not B
|
||||
if ( found[(s*2)] && !found[(s*2)+1] ){
|
||||
c->key = bytes_to_num(k_sector[s].keyA, 6);
|
||||
@@ -1187,6 +1188,9 @@ void chkKey_loopBonly(struct chk_t *c, struct sector_t *k_sector, uint8_t *found
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// get Chunks of keys, to test authentication against card.
|
||||
// arg0 = antal sectorer
|
||||
// arg0 = first time
|
||||
@@ -1200,7 +1204,8 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
||||
uint8_t firstchunk = (arg0 >> 8) & 0xF;
|
||||
uint8_t lastchunk = (arg0 >> 12) & 0xF;
|
||||
uint8_t strategy = arg1 & 0xFF;
|
||||
uint8_t keyCount = arg2 & 0xFF;
|
||||
uint8_t use_flashmem = (arg1 >> 8) & 0xFF;
|
||||
uint16_t keyCount = arg2 & 0xFF;
|
||||
uint8_t status = 0;
|
||||
|
||||
struct Crypto1State mpcs = {0, 0};
|
||||
@@ -1217,33 +1222,56 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
||||
static uint8_t found[80];
|
||||
static uint8_t *uid;
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
#ifdef WITH_FLASH
|
||||
if ( use_flashmem ) {
|
||||
BigBuf_free();
|
||||
uint16_t isok = 0;
|
||||
uint8_t size[2] = {0x00, 0x00};
|
||||
isok = Flash_ReadData(DEFAULT_MF_KEYS_OFFSET, size, 2);
|
||||
if ( isok != 2 )
|
||||
goto OUT;
|
||||
|
||||
keyCount = size[1] << 8 | size[0];
|
||||
|
||||
if ( keyCount == 0 && keyCount == 0xFFFF)
|
||||
goto OUT;
|
||||
|
||||
datain = BigBuf_malloc( keyCount * 6);
|
||||
if (datain == NULL )
|
||||
goto OUT;
|
||||
|
||||
isok = Flash_ReadData(DEFAULT_MF_KEYS_OFFSET+2, datain, keyCount * 6);
|
||||
if ( isok != keyCount * 6 )
|
||||
goto OUT;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
if (uid == NULL || firstchunk) {
|
||||
uid = BigBuf_malloc(10);
|
||||
if (uid == NULL ) {
|
||||
if (MF_DBGLEVEL >= 3) Dbprintf("ChkKeys: uid malloc failed");
|
||||
if (uid == NULL )
|
||||
goto OUT;
|
||||
}
|
||||
}
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
|
||||
LEDsoff();
|
||||
LED_A_ON();
|
||||
|
||||
if ( firstchunk ) {
|
||||
|
||||
clear_trace();
|
||||
set_tracing(false);
|
||||
|
||||
memset(k_sector, 0x00, 480+10);
|
||||
memset(found, 0x00, sizeof(found));
|
||||
foundkeys = 0;
|
||||
|
||||
|
||||
iso14a_card_select_t card_info;
|
||||
if ( !iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
|
||||
if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (ALL)");
|
||||
if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys_fast: Can't select card (ALL)");
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
switch (card_info.uidlen) {
|
||||
case 4 : cascade_levels = 1; break;
|
||||
case 7 : cascade_levels = 2; break;
|
||||
@@ -1262,19 +1290,23 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
||||
chk_data.block = 0;
|
||||
|
||||
// keychunk loop - depth first one sector.
|
||||
if ( strategy == 1 ) {
|
||||
if ( strategy == 1 || use_flashmem) {
|
||||
|
||||
uint8_t newfound = foundkeys;
|
||||
|
||||
uint16_t lastpos = 0;
|
||||
uint16_t s_point = 0;
|
||||
// Sector main loop
|
||||
// keep track of how many sectors on card.
|
||||
for (uint8_t s = 0; s < sectorcnt; ++s) {
|
||||
|
||||
if ( found[(s*2)] && found[(s*2)+1] )
|
||||
if ( found[(s*2)] && found[(s*2)+1] )
|
||||
continue;
|
||||
|
||||
for (uint8_t i = 0; i < keyCount; ++i) {
|
||||
|
||||
for (uint16_t i = s_point; i < keyCount; ++i) {
|
||||
|
||||
//if ( i % 100 == 0) Dbprintf("ChkKeys_fast: sector %d | checking %d | %d found | s_point %d", s, i, foundkeys, s_point);
|
||||
|
||||
// Allow button press / usb cmd to interrupt device
|
||||
if (BUTTON_PRESS() && !usb_poll_validate_length()) {
|
||||
goto OUT;
|
||||
@@ -1292,8 +1324,6 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
||||
// new key
|
||||
chk_data.key = bytes_to_num(datain + i * 6, 6);
|
||||
|
||||
// assume: block0,1,2 has more read rights in accessbits than the sectortrailer. authenticating against block0 in each sector
|
||||
|
||||
// skip already found A keys
|
||||
if( !found[(s*2)] ) {
|
||||
chk_data.keyType = 0;
|
||||
@@ -1303,12 +1333,26 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
||||
found[(s*2)] = 1;
|
||||
++foundkeys;
|
||||
|
||||
chkKey_scanA(&chk_data, k_sector, found, §orcnt, &foundkeys);
|
||||
chkKey_scanA(&chk_data, k_sector, found, §orcnt, &foundkeys);
|
||||
|
||||
// read Block B, if A is found.
|
||||
chkKey_loopBonly( &chk_data, k_sector, found, §orcnt, &foundkeys);
|
||||
|
||||
chk_data.keyType = 1;
|
||||
chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys);
|
||||
|
||||
chk_data.keyType = 0;
|
||||
chk_data.block = FirstBlockOfSector( s );
|
||||
|
||||
if ( use_flashmem ) {
|
||||
if ( lastpos != i && lastpos != 0) {
|
||||
if ( i - lastpos < 0xF) {
|
||||
s_point = i & 0xFFF0;
|
||||
}
|
||||
} else {
|
||||
lastpos = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1322,25 +1366,46 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
||||
++foundkeys;
|
||||
|
||||
chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys);
|
||||
|
||||
if ( use_flashmem ) {
|
||||
if ( lastpos != i && lastpos != 0) {
|
||||
|
||||
if ( i - lastpos < 0xF)
|
||||
s_point = i & 0xFFF0;
|
||||
} else {
|
||||
lastpos = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( found[(s*2)] && found[(s*2)+1] )
|
||||
break;
|
||||
|
||||
} // end keys test loop - depth first
|
||||
|
||||
// assume1. if no keys found in first sector, get next keychunk from client
|
||||
if ( newfound-foundkeys == 0 )
|
||||
if ( !use_flashmem && (newfound-foundkeys == 0) )
|
||||
goto OUT;
|
||||
|
||||
} // end loop - sector
|
||||
} // end strategy 1
|
||||
|
||||
if ( foundkeys == allkeys )
|
||||
goto OUT;
|
||||
|
||||
if ( strategy == 2 ) {
|
||||
if ( strategy == 2 || use_flashmem ) {
|
||||
|
||||
// Keychunk loop
|
||||
for (uint8_t i = 0; i < keyCount; i++) {
|
||||
|
||||
for (uint16_t i = 0; i < keyCount; i++) {
|
||||
|
||||
// Allow button press / usb cmd to interrupt device
|
||||
if (BUTTON_PRESS() && !usb_poll_validate_length()) break;
|
||||
|
||||
// found all keys?
|
||||
if ( foundkeys == allkeys )
|
||||
goto OUT;
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
// new key
|
||||
@@ -1349,7 +1414,9 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
||||
// Sector main loop
|
||||
// keep track of how many sectors on card.
|
||||
for (uint8_t s = 0; s < sectorcnt; ++s) {
|
||||
|
||||
|
||||
if ( found[(s*2)] && found[(s*2)+1] ) continue;
|
||||
|
||||
// found all keys?
|
||||
if ( foundkeys == allkeys )
|
||||
goto OUT;
|
||||
@@ -1387,36 +1454,39 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
||||
chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // end loop sectors
|
||||
} // end loop keys
|
||||
} // end loop strategy 2
|
||||
OUT:
|
||||
OUT:
|
||||
LEDsoff();
|
||||
|
||||
crypto1_destroy(pcs);
|
||||
|
||||
// All keys found, send to client, or last keychunk from client
|
||||
if (foundkeys == allkeys || lastchunk ) {
|
||||
|
||||
|
||||
uint64_t foo = 0;
|
||||
for (uint8_t m = 0; m < 64; m++) {
|
||||
foo |= ((uint64_t)(found[m] & 1) << m);
|
||||
}
|
||||
|
||||
uint16_t bar = 0;
|
||||
for (uint8_t m = 0; m < 64; ++m)
|
||||
foo |= (found[m] << m);
|
||||
for (uint8_t m=64; m < sizeof(found); ++m)
|
||||
bar |= (found[m] << (m-64));
|
||||
|
||||
uint8_t j = 0;
|
||||
for (uint8_t m=64; m < sizeof(found); m++) {
|
||||
bar |= ((uint16_t)(found[m] & 1) << j++);
|
||||
}
|
||||
|
||||
uint8_t *tmp = BigBuf_malloc(480+10);
|
||||
memcpy(tmp, k_sector, sectorcnt * sizeof(sector_t) );
|
||||
num_to_bytes(foo, 8, tmp+480);
|
||||
tmp[488] = bar & 0xFF;
|
||||
tmp[489] = bar >> 8 & 0xFF;
|
||||
|
||||
cmd_send(CMD_ACK, foundkeys, 0, 0, tmp, 480+10);
|
||||
|
||||
set_tracing(false);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
BigBuf_free(); BigBuf_Clear_ext(false);
|
||||
BigBuf_free(); BigBuf_Clear_ext(false);
|
||||
} else {
|
||||
// partial/none keys found
|
||||
cmd_send(CMD_ACK, foundkeys, 0, 0, 0, 0);
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
* by the Free Software Foundation, or, at your option, any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|
||||
+198
-173
@@ -3,8 +3,7 @@
|
||||
#define T0_PCF 8 //period for the pcf7931 in us
|
||||
#define ALLOC 16
|
||||
|
||||
int DemodPCF7931(uint8_t **outBlocks) {
|
||||
|
||||
size_t DemodPCF7931(uint8_t **outBlocks) {
|
||||
uint8_t bits[256] = {0x00};
|
||||
uint8_t blocks[8][16];
|
||||
uint8_t *dest = BigBuf_get_addr();
|
||||
@@ -18,7 +17,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
|
||||
int tolerance = clock / 8;
|
||||
int pmc, block_done;
|
||||
int lc, warnings = 0;
|
||||
int num_blocks = 0;
|
||||
size_t num_blocks = 0;
|
||||
int lmin=128, lmax=128;
|
||||
uint8_t dir;
|
||||
//clear read buffer
|
||||
@@ -40,8 +39,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
|
||||
i++;
|
||||
}
|
||||
dir = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
while(i < GraphTraceLen) {
|
||||
if( !(dest[i] < dest[i-1]) && dest[i] < lmin)
|
||||
break;
|
||||
@@ -55,10 +53,8 @@ int DemodPCF7931(uint8_t **outBlocks) {
|
||||
pmc = 0;
|
||||
block_done = 0;
|
||||
|
||||
for (bitidx = 0; i < GraphTraceLen; i++)
|
||||
{
|
||||
if ( (dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin))
|
||||
{
|
||||
for (bitidx = 0; i < GraphTraceLen; i++) {
|
||||
if ((dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin)) {
|
||||
lc = i - lastval;
|
||||
lastval = i;
|
||||
|
||||
@@ -72,8 +68,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
|
||||
lastval = i;
|
||||
pmc = 0;
|
||||
block_done = 1;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pmc = i;
|
||||
}
|
||||
} else if (ABS(lc-clock/2) < tolerance) {
|
||||
@@ -84,8 +79,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
|
||||
lastval = i;
|
||||
pmc = 0;
|
||||
block_done = 1;
|
||||
}
|
||||
else if(half_switch == 1) {
|
||||
} else if(half_switch == 1) {
|
||||
bits[bitidx++] = 0;
|
||||
half_switch = 0;
|
||||
}
|
||||
@@ -96,26 +90,25 @@ int DemodPCF7931(uint8_t **outBlocks) {
|
||||
bits[bitidx++] = 1;
|
||||
} else {
|
||||
// Error
|
||||
warnings++;
|
||||
if (warnings > 10)
|
||||
{
|
||||
Dbprintf("Error: too many detection errors, aborting...");
|
||||
if (++warnings > 10) {
|
||||
Dbprintf("Error: too many detection errors, aborting.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(block_done == 1) {
|
||||
if(bitidx == 128) {
|
||||
for(j=0; j<16; j++) {
|
||||
blocks[num_blocks][j] = 128*bits[j*8+7]+
|
||||
for(j = 0; j < 16; ++j) {
|
||||
blocks[num_blocks][j] =
|
||||
128 * bits[j*8 + 7]+
|
||||
64*bits[j*8+6]+
|
||||
32*bits[j*8+5]+
|
||||
16*bits[j*8+4]+
|
||||
8*bits[j*8+3]+
|
||||
4*bits[j*8+2]+
|
||||
2*bits[j*8+1]+
|
||||
bits[j*8];
|
||||
|
||||
bits[j*8]
|
||||
;
|
||||
}
|
||||
num_blocks++;
|
||||
}
|
||||
@@ -135,185 +128,209 @@ int DemodPCF7931(uint8_t **outBlocks) {
|
||||
return num_blocks;
|
||||
}
|
||||
|
||||
int IsBlock0PCF7931(uint8_t *Block) {
|
||||
// Assume RFU means 0 :)
|
||||
if((memcmp(Block, "\x00\x00\x00\x00\x00\x00\x00\x01", 8) == 0) && memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) // PAC enabled
|
||||
return 1;
|
||||
if((memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) && Block[7] == 0) // PAC disabled, can it *really* happen ?
|
||||
return 1;
|
||||
return 0;
|
||||
bool IsBlock0PCF7931(uint8_t *block) {
|
||||
// assuming all RFU bits are set to 0
|
||||
// if PAC is enabled password is set to 0
|
||||
if (block[7] == 0x01)
|
||||
{
|
||||
if (!memcmp(block, "\x00\x00\x00\x00\x00\x00\x00", 7) && !memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7))
|
||||
return true;
|
||||
}
|
||||
else if (block[7] == 0x00)
|
||||
{
|
||||
if (!memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int IsBlock1PCF7931(uint8_t *Block) {
|
||||
// Assume RFU means 0 :)
|
||||
if( Block[10] == 0 &&
|
||||
Block[11] == 0 &&
|
||||
Block[12] == 0 &&
|
||||
Block[13] == 0)
|
||||
if ( (Block[14] & 0x7f) <= 9 && Block[15] <= 9)
|
||||
return 1;
|
||||
return 0;
|
||||
bool IsBlock1PCF7931(uint8_t *block) {
|
||||
// assuming all RFU bits are set to 0
|
||||
if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0)
|
||||
if((block[14] & 0x7f) <= 9 && block[15] <= 9)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReadPCF7931() {
|
||||
uint8_t Blocks[8][17];
|
||||
uint8_t tmpBlocks[4][16];
|
||||
int i, j, ind, ind2, n;
|
||||
int num_blocks = 0;
|
||||
int max_blocks = 8;
|
||||
int ident = 0;
|
||||
int error = 0;
|
||||
int tries = 0;
|
||||
int found_blocks = 0; // successfully read blocks
|
||||
int max_blocks = 8; // readable blocks
|
||||
uint8_t memory_blocks[8][17]; // PCF content
|
||||
|
||||
uint8_t single_blocks[8][17]; // PFC blocks with unknown position
|
||||
int single_blocks_cnt = 0;
|
||||
|
||||
memset(Blocks, 0, 8*17*sizeof(uint8_t));
|
||||
size_t n = 0; // transmitted blocks
|
||||
uint8_t tmp_blocks[4][16]; // temporary read buffer
|
||||
|
||||
uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found
|
||||
int errors = 0; // error counter
|
||||
int tries = 0; // tries counter
|
||||
|
||||
memset(memory_blocks, 0, 8*17*sizeof(uint8_t));
|
||||
memset(single_blocks, 0, 8*17*sizeof(uint8_t));
|
||||
|
||||
int i = 0, j = 0;
|
||||
|
||||
do {
|
||||
memset(tmpBlocks, 0, 4*16*sizeof(uint8_t));
|
||||
n = DemodPCF7931((uint8_t**)tmpBlocks);
|
||||
i = 0;
|
||||
|
||||
memset(tmp_blocks, 0, 4*16*sizeof(uint8_t));
|
||||
n = DemodPCF7931((uint8_t**)tmp_blocks);
|
||||
if(!n)
|
||||
error++;
|
||||
if(error==10 && num_blocks == 0) {
|
||||
++errors;
|
||||
|
||||
// exit if no block is received
|
||||
if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) {
|
||||
Dbprintf("Error, no tag or bad tag");
|
||||
return;
|
||||
}
|
||||
else if (tries==20 || error==10) {
|
||||
// exit if too many errors during reading
|
||||
if (tries > 50 && (2*errors > tries)) {
|
||||
Dbprintf("Error reading the tag");
|
||||
Dbprintf("Here is the partial content");
|
||||
goto end;
|
||||
}
|
||||
|
||||
for(i=0; i<n; i++)
|
||||
Dbprintf("(dbg) %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
tmpBlocks[i][0], tmpBlocks[i][1], tmpBlocks[i][2], tmpBlocks[i][3], tmpBlocks[i][4], tmpBlocks[i][5], tmpBlocks[i][6], tmpBlocks[i][7],
|
||||
tmpBlocks[i][8], tmpBlocks[i][9], tmpBlocks[i][10], tmpBlocks[i][11], tmpBlocks[i][12], tmpBlocks[i][13], tmpBlocks[i][14], tmpBlocks[i][15]);
|
||||
if(!ident) {
|
||||
for(i=0; i<n; i++) {
|
||||
if(IsBlock0PCF7931(tmpBlocks[i])) {
|
||||
// Found block 0 ?
|
||||
if(i < n-1 && IsBlock1PCF7931(tmpBlocks[i+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;
|
||||
}
|
||||
// our logic breaks if we don't get at least two blocks
|
||||
if (n < 2) {
|
||||
if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
|
||||
continue;
|
||||
|
||||
if (single_blocks_cnt < max_blocks) {
|
||||
for (i = 0; i < single_blocks_cnt; ++i) {
|
||||
if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) {
|
||||
j = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j != 1) {
|
||||
memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16);
|
||||
single_blocks_cnt++;
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
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++) {
|
||||
if(Blocks[j][ALLOC] == 1 && !memcmp(tmpBlocks[i], Blocks[j], 16)) {
|
||||
// Found an identical block
|
||||
for(ind=i-1,ind2=j-1; ind >= 0; ind--,ind2--) {
|
||||
if(ind2 < 0)
|
||||
ind2 = max_blocks;
|
||||
if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found
|
||||
// Dbprintf("Tmp %d -> Block %d", ind, ind2);
|
||||
memcpy(Blocks[ind2], tmpBlocks[ind], 16);
|
||||
Blocks[ind2][ALLOC] = 1;
|
||||
num_blocks++;
|
||||
if(num_blocks == max_blocks) goto end;
|
||||
}
|
||||
}
|
||||
for(ind=i+1,ind2=j+1; ind < n; ind++,ind2++) {
|
||||
if(ind2 > max_blocks)
|
||||
ind2 = 0;
|
||||
if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found
|
||||
// Dbprintf("Tmp %d -> Block %d", ind, ind2);
|
||||
memcpy(Blocks[ind2], tmpBlocks[ind], 16);
|
||||
Blocks[ind2][ALLOC] = 1;
|
||||
num_blocks++;
|
||||
if(num_blocks == max_blocks) goto end;
|
||||
}
|
||||
}
|
||||
++tries;
|
||||
continue;
|
||||
}
|
||||
|
||||
Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors);
|
||||
|
||||
i = 0;
|
||||
if(!found_0_1) {
|
||||
while (i < n - 1) {
|
||||
if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i+1])) {
|
||||
found_0_1 = 1;
|
||||
memcpy(memory_blocks[0], tmp_blocks[i], 16);
|
||||
memcpy(memory_blocks[1], tmp_blocks[i+1], 16);
|
||||
memory_blocks[0][ALLOC] = memory_blocks[1][ALLOC] = 1;
|
||||
// block 1 tells how many blocks are going to be sent
|
||||
max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1;
|
||||
found_blocks = 2;
|
||||
|
||||
Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks);
|
||||
|
||||
// handle the following blocks
|
||||
for (j = i + 2; j < n; ++j) {
|
||||
memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16);
|
||||
memory_blocks[found_blocks][ALLOC] = 1;
|
||||
++found_blocks;
|
||||
}
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
} else {
|
||||
// Trying to re-order blocks
|
||||
// Look for identical block in memory blocks
|
||||
while (i < n-1) {
|
||||
// skip all zeroes blocks
|
||||
if (memcmp(tmp_blocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) {
|
||||
for (j = 1; j < max_blocks - 1; ++j) {
|
||||
if (!memcmp(tmp_blocks[i], memory_blocks[j], 16) && !memory_blocks[j+1][ALLOC]) {
|
||||
memcpy(memory_blocks[j+1], tmp_blocks[i+1], 16);
|
||||
memory_blocks[j+1][ALLOC] = 1;
|
||||
if (++found_blocks >= max_blocks) goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (memcmp(tmp_blocks[i+1], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) {
|
||||
for (j = 0; j < max_blocks; ++j) {
|
||||
if (!memcmp(tmp_blocks[i+1], memory_blocks[j], 16) && !memory_blocks[(j == 0 ? max_blocks : j) -1][ALLOC]) {
|
||||
if (j == 0) {
|
||||
memcpy(memory_blocks[max_blocks - 1], tmp_blocks[i], 16);
|
||||
memory_blocks[max_blocks - 1][ALLOC] = 1;
|
||||
} else {
|
||||
memcpy(memory_blocks[j-1], tmp_blocks[i], 16);
|
||||
memory_blocks[j-1][ALLOC] = 1;
|
||||
}
|
||||
if (++found_blocks >= max_blocks) goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
tries++;
|
||||
if (BUTTON_PRESS()) return;
|
||||
} while (num_blocks != max_blocks);
|
||||
++tries;
|
||||
if (BUTTON_PRESS()) {
|
||||
Dbprintf("Button pressed, stopping.");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
while (found_blocks != max_blocks);
|
||||
|
||||
end:
|
||||
Dbprintf("-----------------------------------------");
|
||||
Dbprintf("Memory content:");
|
||||
Dbprintf("-----------------------------------------");
|
||||
for(i=0; i<max_blocks; i++) {
|
||||
if(Blocks[i][ALLOC]==1)
|
||||
Dbprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
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]);
|
||||
for (i = 0; i < max_blocks; ++i) {
|
||||
if (memory_blocks[i][ALLOC])
|
||||
print_result("Block", memory_blocks[i], 16);
|
||||
else
|
||||
Dbprintf("<missing block %d>", i);
|
||||
}
|
||||
Dbprintf("-----------------------------------------");
|
||||
|
||||
if (found_blocks < max_blocks) {
|
||||
Dbprintf("-----------------------------------------");
|
||||
Dbprintf("Blocks with unknown position:");
|
||||
Dbprintf("-----------------------------------------");
|
||||
for (i = 0; i < single_blocks_cnt; ++i)
|
||||
print_result("Block", single_blocks[i], 16);
|
||||
|
||||
Dbprintf("-----------------------------------------");
|
||||
}
|
||||
cmd_send(CMD_ACK,0,0,0,0,0);
|
||||
}
|
||||
|
||||
|
||||
/* Write on a byte of a PCF7931 tag
|
||||
* @param address : address of the block to write
|
||||
@param byte : address of the byte to write
|
||||
@param data : data to write
|
||||
*/
|
||||
void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data)
|
||||
{
|
||||
static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) {
|
||||
uint32_t tab[1024] = {0}; // data times frame
|
||||
uint32_t u = 0;
|
||||
uint8_t parity = 0;
|
||||
bool comp = 0;
|
||||
|
||||
//BUILD OF THE DATA FRAME
|
||||
|
||||
//alimentation of the tag (time for initializing)
|
||||
AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab);
|
||||
|
||||
//PMC
|
||||
Dbprintf("Initialization delay : %d us", init_delay);
|
||||
AddPatternPCF7931(8192/2*T0_PCF + 319*T0_PCF+70, 3*T0_PCF, 29*T0_PCF, tab);
|
||||
|
||||
Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p);
|
||||
|
||||
//password indication bit
|
||||
AddBitPCF7931(1, tab, l, p);
|
||||
|
||||
//password (on 56 bits)
|
||||
Dbprintf("Password (LSB first on each byte) : %02x %02x %02x %02x %02x %02x %02x", pass1,pass2,pass3,pass4,pass5,pass6,pass7);
|
||||
AddBytePCF7931(pass1, tab, l, p);
|
||||
AddBytePCF7931(pass2, tab, l, p);
|
||||
AddBytePCF7931(pass3, tab, l, p);
|
||||
AddBytePCF7931(pass4, tab, l, p);
|
||||
AddBytePCF7931(pass5, tab, l, p);
|
||||
AddBytePCF7931(pass6, tab, l, p);
|
||||
AddBytePCF7931(pass7, tab, l, p);
|
||||
|
||||
|
||||
AddBytePCF7931(pass[0], tab, l, p);
|
||||
AddBytePCF7931(pass[1], tab, l, p);
|
||||
AddBytePCF7931(pass[2], tab, l, p);
|
||||
AddBytePCF7931(pass[3], tab, l, p);
|
||||
AddBytePCF7931(pass[4], tab, l, p);
|
||||
AddBytePCF7931(pass[5], tab, l, p);
|
||||
AddBytePCF7931(pass[6], tab, l, p);
|
||||
//programming mode (0 or 1)
|
||||
AddBitPCF7931(0, tab, l, p);
|
||||
|
||||
//block adress on 6 bits
|
||||
Dbprintf("Block address : %02x", address);
|
||||
for (u=0; u<6; u++)
|
||||
{
|
||||
for (u = 0; u < 6; ++u) {
|
||||
if (address&(1<<u)) { // bit 1
|
||||
parity++;
|
||||
++parity;
|
||||
AddBitPCF7931(1, tab, l, p);
|
||||
} else{ // bit 0
|
||||
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
|
||||
Dbprintf("Byte address : %02x", byte);
|
||||
for (u=0; u<4; u++)
|
||||
for (u = 0; u < 4; ++u)
|
||||
{
|
||||
if (byte&(1<<u)) { // bit 1
|
||||
parity++;
|
||||
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
|
||||
Dbprintf("Data : %02x", data);
|
||||
for (u=0; u<8; u++)
|
||||
{
|
||||
if (data&(1<<u)) { // bit 1
|
||||
parity++;
|
||||
AddBitPCF7931(1, tab, l, p);
|
||||
} else{ //bit 0
|
||||
}
|
||||
else //bit 0
|
||||
AddBitPCF7931(0, tab, l, p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//parity bit
|
||||
if((parity%2)==0){
|
||||
if ((parity % 2) == 0)
|
||||
AddBitPCF7931(0, tab, l, p); //even parity
|
||||
}else{
|
||||
else
|
||||
AddBitPCF7931(1, tab, l, p);//odd parity
|
||||
}
|
||||
|
||||
//time access memory
|
||||
AddPatternPCF7931(5120+2680, 0, 0, tab);
|
||||
|
||||
//conversion of the scale time
|
||||
for(u=0;u<500;u++){
|
||||
for (u = 0; u < 500; ++u)
|
||||
tab[u]=(tab[u] * 3)/2;
|
||||
}
|
||||
|
||||
//compensation of the counter reload
|
||||
while (!comp){
|
||||
comp = 1;
|
||||
for(u=0;tab[u]!=0;u++){
|
||||
for (u = 0; tab[u] != 0; ++u)
|
||||
if(tab[u] > 0xFFFF){
|
||||
tab[u] -= 0xFFFF;
|
||||
comp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SendCmdPCF7931(tab);
|
||||
}
|
||||
|
||||
/* Write on a byte of a PCF7931 tag
|
||||
* @param address : address of the block to write
|
||||
@param byte : address of the byte to write
|
||||
@param data : data to write
|
||||
*/
|
||||
void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) {
|
||||
Dbprintf("Initialization delay : %d us", init_delay);
|
||||
Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p);
|
||||
Dbprintf("Password (LSB first on each byte): %02x %02x %02x %02x %02x %02x %02x", pass1, pass2, pass3, pass4, pass5, pass6, pass7);
|
||||
Dbprintf("Block address : %02x", address);
|
||||
Dbprintf("Byte address : %02x", byte);
|
||||
Dbprintf("Data : %02x", data);
|
||||
|
||||
uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7};
|
||||
|
||||
RealWritePCF7931 (password, init_delay, l, p, address, byte, data);
|
||||
}
|
||||
|
||||
|
||||
/* Send a trame to a PCF7931 tags
|
||||
@@ -386,9 +414,7 @@ void SendCmdPCF7931(uint32_t * tab){
|
||||
Dbprintf("Sending data frame...");
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU );
|
||||
|
||||
LED_A_ON();
|
||||
@@ -405,21 +431,22 @@ void SendCmdPCF7931(uint32_t * tab){
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
|
||||
AT91C_BASE_TCB->TCB_BCR = 1;
|
||||
|
||||
|
||||
tempo = AT91C_BASE_TC0->TC_CV;
|
||||
for( u = 0; tab[u] != 0; u += 3){
|
||||
|
||||
// modulate antenna
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
while(tempo != tab[u]) tempo = AT91C_BASE_TC0->TC_CV;
|
||||
while (tempo != tab[u])
|
||||
tempo = AT91C_BASE_TC0->TC_CV;
|
||||
|
||||
// stop modulating antenna
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
while(tempo != tab[u+1]) tempo = AT91C_BASE_TC0->TC_CV;
|
||||
while (tempo != tab[u+1])
|
||||
tempo = AT91C_BASE_TC0->TC_CV;
|
||||
|
||||
// modulate antenna
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
while(tempo != tab[u+2]) tempo = AT91C_BASE_TC0->TC_CV;
|
||||
while (tempo != tab[u+2])
|
||||
tempo = AT91C_BASE_TC0->TC_CV;
|
||||
}
|
||||
|
||||
LED_A_OFF();
|
||||
@@ -437,18 +464,16 @@ void SendCmdPCF7931(uint32_t * tab){
|
||||
* @param l : offset on low pulse width
|
||||
* @param p : offset on low pulse positioning
|
||||
*/
|
||||
|
||||
bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p){
|
||||
|
||||
uint32_t u;
|
||||
for ( u=0; u<8; u++)
|
||||
{
|
||||
if (byte&(1<<u)) { //bit à 1
|
||||
for (u = 0; u < 8; ++u) {
|
||||
if (byte & (1 << u)) { //bit is 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;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -7,9 +7,9 @@
|
||||
#include "pcf7931.h"
|
||||
#include "string.h"
|
||||
|
||||
int DemodPCF7931(uint8_t **outBlocks);
|
||||
int IsBlock0PCF7931(uint8_t *Block);
|
||||
int IsBlock1PCF7931(uint8_t *Block);
|
||||
size_t DemodPCF7931(uint8_t **outBlocks);
|
||||
bool IsBlock0PCF7931(uint8_t *Block);
|
||||
bool IsBlock1PCF7931(uint8_t *Block);
|
||||
void ReadPCF7931();
|
||||
void SendCmdPCF7931(uint32_t * tab);
|
||||
bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -25,6 +25,10 @@ VERSIONSRC = version.c
|
||||
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
|
||||
APP_CFLAGS = -I. -fno-strict-aliasing -ffunction-sections -fdata-sections
|
||||
|
||||
# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc
|
||||
APP_CFLAGS += -fno-stack-protector -fno-pie
|
||||
|
||||
|
||||
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
|
||||
include ../common/Makefile.common
|
||||
|
||||
|
||||
+14
-11
@@ -108,7 +108,7 @@ CORESRCS = uart_posix.c \
|
||||
|
||||
CMDSRCS = crapto1/crapto1.c \
|
||||
crapto1/crypto1.c \
|
||||
mfkey.c \
|
||||
mifare/mfkey.c \
|
||||
tea.c \
|
||||
fido/additional_ca.c \
|
||||
fido/cose.c \
|
||||
@@ -126,7 +126,7 @@ CMDSRCS = crapto1/crapto1.c \
|
||||
loclass/elite_crack.c \
|
||||
loclass/fileutils.c \
|
||||
whereami.c \
|
||||
mifarehost.c \
|
||||
mifare/mifarehost.c \
|
||||
parity.c \
|
||||
crc.c \
|
||||
crc16.c \
|
||||
@@ -155,7 +155,9 @@ CMDSRCS = crapto1/crapto1.c \
|
||||
emv/test/dda_test.c\
|
||||
emv/test/cda_test.c\
|
||||
emv/cmdemv.c \
|
||||
mifare4.c \
|
||||
emv/emv_roca.c \
|
||||
mifare/mifare4.c \
|
||||
mifare/mad.c \
|
||||
cmdanalyse.c \
|
||||
cmdhf.c \
|
||||
cmdhflist.c \
|
||||
@@ -186,6 +188,7 @@ CMDSRCS = crapto1/crapto1.c \
|
||||
cmdlfio.c \
|
||||
cmdlfindala.c \
|
||||
cmdlfjablotron.c \
|
||||
cmdlfkeri.c \
|
||||
cmdlfnexwatch.c \
|
||||
cmdlfnedap.c \
|
||||
cmdlfnoralsy.c \
|
||||
@@ -298,29 +301,29 @@ lualibs/mf_default_keys.lua : default_keys.dic
|
||||
|
||||
clean:
|
||||
$(RM) $(CLEAN)
|
||||
cd ../liblua && make clean
|
||||
cd $(JANSSONLIBPATH) && make clean
|
||||
cd $(MBEDTLSLIBPATH) && make clean
|
||||
cd $(CBORLIBPATH) && make clean
|
||||
cd ../liblua && $(MAKE) clean
|
||||
cd $(JANSSONLIBPATH) && $(MAKE) clean
|
||||
cd $(MBEDTLSLIBPATH) && $(MAKE) clean
|
||||
cd $(CBORLIBPATH) && $(MAKE) clean
|
||||
|
||||
tarbin: $(BINS)
|
||||
$(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%)
|
||||
|
||||
lua_build:
|
||||
@echo Compiling liblua, using platform $(LUAPLATFORM)
|
||||
cd ../liblua && make $(LUAPLATFORM)
|
||||
cd ../liblua && $(MAKE) $(LUAPLATFORM)
|
||||
|
||||
jansson_build:
|
||||
@echo Compiling jansson
|
||||
cd $(JANSSONLIBPATH) && make all
|
||||
cd $(JANSSONLIBPATH) && $(MAKE) all
|
||||
|
||||
mbedtls_build:
|
||||
@echo Compiling mbedtls
|
||||
cd $(MBEDTLSLIBPATH) && make all
|
||||
cd $(MBEDTLSLIBPATH) && $(MAKE) all
|
||||
|
||||
cbor_build:
|
||||
@echo Compiling tinycbor
|
||||
cd $(CBORLIBPATH) && make all
|
||||
cd $(CBORLIBPATH) && $(MAKE) all
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -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.
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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.
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
+3
-3
@@ -16,15 +16,15 @@
|
||||
#include <unistd.h>
|
||||
#include "cmdmain.h"
|
||||
#include "proxmark3.h"
|
||||
#include "ui.h" // PrintAndLog
|
||||
#include "ui.h" // PrintAndLog
|
||||
#include "util.h"
|
||||
#include "crc.h"
|
||||
#include "crc16.h" // crc16 ccitt
|
||||
#include "tea.h"
|
||||
#include "legic_prng.h"
|
||||
#include "loclass/elite_crack.h"
|
||||
#include "mfkey.h" //nonce2key
|
||||
#include "util_posix.h" // msclock
|
||||
#include "mifare/mfkey.h" //nonce2key
|
||||
#include "util_posix.h" // msclock
|
||||
|
||||
|
||||
int usage_analyse_lcr(void);
|
||||
|
||||
+11
-6
@@ -39,8 +39,7 @@ int split(char *str, char *arr[MAX_ARGS]){
|
||||
return wordCnt;
|
||||
}
|
||||
|
||||
int CmdCrc(const char *Cmd)
|
||||
{
|
||||
int CmdCrc(const char *Cmd) {
|
||||
char name[] = {"reveng "};
|
||||
char Cmd2[100 + 7];
|
||||
memcpy(Cmd2, name, 7);
|
||||
@@ -198,6 +197,11 @@ int GetModels(char *Models[], int *count, uint8_t *width){
|
||||
pfree(qptr);
|
||||
}
|
||||
}
|
||||
if(uflags & C_NOBFS && ~rflags & R_HAVEP) {
|
||||
PrintAndLogEx(WARNING, "no models found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(model.flags & P_REFIN) != !(model.flags & P_REFOUT)){
|
||||
PrintAndLogEx(WARNING, "cannot search for crossed-endian models");
|
||||
return 0;
|
||||
@@ -259,8 +263,9 @@ int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *res
|
||||
|
||||
SETBMP();
|
||||
//set model
|
||||
if (!(c = mbynam(&model, inModel))) {
|
||||
PrintAndLogEx(WARNING, "error: preset model '%s' not found. Use reveng -D to list presets.", inModel);
|
||||
c = mbynam(&model, inModel);
|
||||
if (!c) {
|
||||
PrintAndLogEx(WARNING, "error: preset model '%s' not found. Use reveng -D to list presets. [%d]", inModel, c);
|
||||
return 0;
|
||||
}
|
||||
if (c < 0){
|
||||
@@ -396,7 +401,7 @@ char *SwapEndianStr(const char *inStr, const size_t len, const uint8_t blockSize
|
||||
// takes hex string in and searches for a matching result (hex string must include checksum)
|
||||
int CmdrevengSearch(const char *Cmd){
|
||||
|
||||
#define NMODELS 103
|
||||
#define NMODELS 105
|
||||
|
||||
char inHexStr[100] = {0x00};
|
||||
int dataLen = param_getstr(Cmd, 0, inHexStr, sizeof(inHexStr));
|
||||
@@ -432,7 +437,7 @@ int CmdrevengSearch(const char *Cmd){
|
||||
char *outHex = calloc(dataLen-crcChars+1, sizeof(char));
|
||||
memcpy(outHex, inHexStr, dataLen-crcChars);
|
||||
|
||||
// PrintAndLogEx(DEBUG, "DEBUG: dataLen: %d, crcChars: %d, Model: %s, CRC: %s, width: %d, outHex: %s",dataLen, crcChars, Models[i], inCRC, width[i], outHex);
|
||||
PrintAndLogEx(DEBUG, "DEBUG: dataLen: %d, crcChars: %d, Model: %s, CRC: %s, width: %d, outHex: %s",dataLen, crcChars, Models[i], inCRC, width[i], outHex);
|
||||
ans = RunModel(Models[i], outHex, false, 0, result);
|
||||
if (ans) {
|
||||
// test for match
|
||||
|
||||
+50
-8
@@ -754,19 +754,53 @@ int AutoCorrelate(const int *in, int *out, size_t len, int window, bool SaveGrph
|
||||
lastmax = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose && ( correlation > 1 ) ) {
|
||||
PrintAndLogEx(SUCCESS, "possible correlation %4d samples", correlation);
|
||||
} else {
|
||||
PrintAndLogEx(FAILED, "no repeating pattern found");
|
||||
|
||||
//
|
||||
int hi = 0, idx = 0;
|
||||
int distance = 0, hi_1 = 0, idx_1 = 0;
|
||||
for (int i = 0; i <= len; ++i){
|
||||
if ( CorrelBuffer[i] > hi) {
|
||||
hi = CorrelBuffer[i];
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (SaveGrph){
|
||||
for (int i = idx+1; i <= window; ++i){
|
||||
if ( CorrelBuffer[i] > hi_1 ) {
|
||||
hi_1 = CorrelBuffer[i];
|
||||
idx_1 = i;
|
||||
}
|
||||
}
|
||||
|
||||
int foo = ABS(hi-hi_1);
|
||||
int bar = (int)(((hi+hi_1) / 2) * 0.03);
|
||||
if ( verbose && foo < bar ) {
|
||||
distance = idx_1 - idx;
|
||||
PrintAndLogEx(SUCCESS, "possible 3% visible correlation %4d samples", distance);
|
||||
} else if (verbose && ( correlation > 1 ) ) {
|
||||
PrintAndLogEx(SUCCESS, "possible correlation %4d samples", correlation);
|
||||
} else {
|
||||
PrintAndLogEx(FAILED, "no repeating pattern found, try increasing window size");
|
||||
}
|
||||
|
||||
int retval = correlation;
|
||||
if (SaveGrph) {
|
||||
//GraphTraceLen = GraphTraceLen - window;
|
||||
memcpy(out, CorrelBuffer, len * sizeof(int));
|
||||
if ( distance > 0) {
|
||||
setClockGrid(distance, idx);
|
||||
retval = distance;
|
||||
}
|
||||
else
|
||||
setClockGrid(correlation, idx);
|
||||
|
||||
CursorCPos = idx_1;
|
||||
CursorDPos = idx_1+retval;
|
||||
DemodBufferLen = 0;
|
||||
RepaintGraphWindow();
|
||||
}
|
||||
return correlation;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int CmdAutoCorr(const char *Cmd) {
|
||||
@@ -1461,6 +1495,13 @@ int CmdTuneSamples(const char *Cmd) {
|
||||
#define HF_UNUSABLE_V 3000
|
||||
#define HF_MARGINAL_V 5000
|
||||
#define ANTENNA_ERROR 1.03 // current algo has 3% error margin.
|
||||
|
||||
// hide demod plot line
|
||||
DemodBufferLen = 0;
|
||||
setClockGrid(0, 0);
|
||||
RepaintGraphWindow();
|
||||
|
||||
|
||||
int timeout = 0;
|
||||
PrintAndLogEx(INFO, "\nmeasuring antenna characteristics, please wait...");
|
||||
|
||||
@@ -1541,6 +1582,7 @@ int CmdTuneSamples(const char *Cmd) {
|
||||
|
||||
PrintAndLogEx(FAILED, "\nNot showing LF tuning graph since all values is zero.\n\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1786,7 +1828,7 @@ int Cmdbin2hex(const char *Cmd) {
|
||||
//Number of digits supplied as argument
|
||||
size_t length = en - bg + 1;
|
||||
size_t bytelen = (length+7) / 8;
|
||||
uint8_t* arr = (uint8_t *) malloc(bytelen);
|
||||
uint8_t* arr = (uint8_t *) calloc(bytelen, sizeof(uint8_t));
|
||||
memset(arr, 0, bytelen);
|
||||
BitstreamOut bout = { arr, 0, 0 };
|
||||
|
||||
|
||||
+79
-15
@@ -7,10 +7,13 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Proxmark3 RDV40 Flash memory commands
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef WITH_FLASH
|
||||
|
||||
#include "cmdflashmem.h"
|
||||
|
||||
#include "mbedtls/rsa.h"
|
||||
#include "mbedtls/sha1.h"
|
||||
#include "mbedtls/base64.h"
|
||||
|
||||
#define MCK 48000000
|
||||
//#define FLASH_BAUD 24000000
|
||||
@@ -50,13 +53,19 @@ int usage_flashmem_read(void){
|
||||
}
|
||||
int usage_flashmem_load(void){
|
||||
PrintAndLogEx(NORMAL, "Loads binary file into flash memory on device");
|
||||
PrintAndLogEx(NORMAL, "Usage: mem load o <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, " 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, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " mem load f myfile"); // upload file myfile at default offset 0
|
||||
PrintAndLogEx(NORMAL, " mem load f myfile o 1024"); // upload file myfile at offset 1024
|
||||
PrintAndLogEx(NORMAL, " mem load f default_keys m");
|
||||
PrintAndLogEx(NORMAL, " mem load f default_pwd t");
|
||||
PrintAndLogEx(NORMAL, " mem load f default_iclass_keys i");
|
||||
return 0;
|
||||
}
|
||||
int usage_flashmem_save(void){
|
||||
@@ -154,7 +163,8 @@ int CmdFlashMemLoad(const char *Cmd){
|
||||
uint32_t start_index = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
uint8_t cmdp = 0;
|
||||
Dictionary_t d = DICTIONARY_NONE;
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
@@ -171,7 +181,19 @@ int CmdFlashMemLoad(const char *Cmd){
|
||||
case 'o':
|
||||
start_index = param_get32ex(Cmd, cmdp+1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
break;
|
||||
case 'm':
|
||||
d = DICTIONARY_MIFARE;
|
||||
cmdp++;
|
||||
break;
|
||||
case 't':
|
||||
d = DICTIONARY_T55XX;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'i':
|
||||
d = DICTIONARY_ICLASS;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
@@ -181,20 +203,60 @@ int CmdFlashMemLoad(const char *Cmd){
|
||||
|
||||
//Validations
|
||||
if (errors || cmdp == 0 ) return usage_flashmem_load();
|
||||
|
||||
uint8_t *data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t));
|
||||
|
||||
size_t datalen = 0;
|
||||
int res = loadFile(filename, "bin", data, &datalen);
|
||||
//int res = loadFileEML( filename, "eml", data, &datalen);
|
||||
if ( res ) {
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
uint16_t keycount = 0;
|
||||
int res = 0;
|
||||
uint8_t *data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t));
|
||||
|
||||
if (datalen > FLASH_MEM_MAX_SIZE) {
|
||||
PrintAndLogDevice(WARNING, "error, filesize is larger than available memory");
|
||||
free(data);
|
||||
return 1;
|
||||
switch (d) {
|
||||
case DICTIONARY_MIFARE:
|
||||
start_index = DEFAULT_MF_KEYS_OFFSET;
|
||||
res = loadFileDICTIONARY(filename, "dic", data+2, &datalen, 6, &keycount );
|
||||
if ( res || !keycount) {
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
data[0] = (keycount >> 0) & 0xFF;
|
||||
data[1] = (keycount >> 8) & 0xFF;
|
||||
datalen += 2;
|
||||
break;
|
||||
case DICTIONARY_T55XX:
|
||||
start_index = DEFAULT_T55XX_KEYS_OFFSET;
|
||||
res = loadFileDICTIONARY(filename, "dic", data+2, &datalen, 4, &keycount );
|
||||
if ( res || !keycount) {
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
data[0] = (keycount >> 0) & 0xFF;
|
||||
data[1] = (keycount >> 8) & 0xFF;
|
||||
datalen += 2;
|
||||
break;
|
||||
case DICTIONARY_ICLASS:
|
||||
start_index = DEFAULT_ICLASS_KEYS_OFFSET;
|
||||
res = loadFileDICTIONARY(filename, "dic", data+2, &datalen, 8, &keycount );
|
||||
if ( res || !keycount) {
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
data[0] = (keycount >> 0) & 0xFF;
|
||||
data[1] = (keycount >> 8) & 0xFF;
|
||||
datalen += 2;
|
||||
break;
|
||||
default:
|
||||
|
||||
res = loadFile(filename, "bin", data, &datalen);
|
||||
//int res = loadFileEML( filename, "eml", data, &datalen);
|
||||
if ( res ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (datalen > FLASH_MEM_MAX_SIZE) {
|
||||
PrintAndLogDevice(WARNING, "error, filesize is larger than available memory");
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
data = realloc(data, datalen);
|
||||
@@ -544,3 +606,5 @@ int CmdHelp(const char *Cmd) {
|
||||
CmdsHelp(CommandTable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -8,6 +8,8 @@
|
||||
// Proxmark3 RDV40 Flash memory commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef WITH_FLASH
|
||||
|
||||
#ifndef CMDFLASHMEM_H__
|
||||
#define CMDFLASHMEM_H__
|
||||
|
||||
@@ -24,6 +26,13 @@
|
||||
#include "loclass/fileutils.h" //saveFile
|
||||
#include "comms.h" //getfromdevice
|
||||
|
||||
typedef enum {
|
||||
DICTIONARY_NONE = 0,
|
||||
DICTIONARY_MIFARE,
|
||||
DICTIONARY_T55XX,
|
||||
DICTIONARY_ICLASS
|
||||
} Dictionary_t;
|
||||
|
||||
extern int CmdFlashMem(const char *Cmd);
|
||||
|
||||
extern int CmdFlashMemRead(const char* cmd);
|
||||
@@ -31,4 +40,6 @@ extern int CmdFlashMemLoad(const char* cmd);
|
||||
extern int CmdFlashMemSave(const char* cmd);
|
||||
extern int CmdFlashMemWipe(const char *Cmd);
|
||||
extern int CmdFlashMemInfo(const char *Cmd);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+203
-42
@@ -1,6 +1,6 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
|
||||
// 2011, 2017 Merlok
|
||||
// 2011, 2017 - 2019 Merlok
|
||||
// 2014, Peter Fillmore
|
||||
// 2015, 2016, 2017 Iceman
|
||||
//
|
||||
@@ -12,6 +12,8 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdhf14a.h"
|
||||
|
||||
bool APDUInFramingEnable = true;
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
static int waitCmd(uint8_t iLen);
|
||||
|
||||
@@ -147,6 +149,10 @@ char* getTagInfo(uint8_t uid) {
|
||||
return manufactureMapping[len-1].desc;
|
||||
}
|
||||
|
||||
// iso14a apdu input frame length
|
||||
static uint16_t frameLength = 0;
|
||||
uint16_t atsFSC[] = {16, 24, 32, 40, 48, 64, 96, 128, 256};
|
||||
|
||||
int usage_hf_14a_sim(void) {
|
||||
// PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n");
|
||||
PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 byte UID\n");
|
||||
@@ -213,11 +219,6 @@ int usage_hf_14a_info(void){
|
||||
PrintAndLogEx(NORMAL, " n test for nack bug");
|
||||
return 0;
|
||||
}
|
||||
int usage_hf_14a_antifuzz(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14a antifuzz [4|7|10]");
|
||||
PrintAndLogEx(NORMAL, " <len> determine which anticollision phase the command will target.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdHF14AList(const char *Cmd) {
|
||||
//PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list 14a' instead");
|
||||
@@ -491,10 +492,7 @@ int CmdHF14AInfo(const char *Cmd) {
|
||||
(tb1 ? "" : " NOT"),
|
||||
(tc1 ? "" : " NOT"),
|
||||
fsci,
|
||||
fsci < 5 ? (fsci - 2) * 8 :
|
||||
fsci < 8 ? (fsci - 3) * 32 :
|
||||
fsci == 8 ? 256 :
|
||||
-1
|
||||
fsci < sizeof(atsFSC) ? atsFSC[fsci] : -1
|
||||
);
|
||||
}
|
||||
pos = 2;
|
||||
@@ -581,11 +579,11 @@ int CmdHF14AInfo(const char *Cmd) {
|
||||
if (isMifareClassic) {
|
||||
int res = detect_classic_prng();
|
||||
if ( res == 1 )
|
||||
PrintAndLogEx(SUCCESS, "Prng detection: WEAK");
|
||||
PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_(WEAK));
|
||||
else if (res == 0 )
|
||||
PrintAndLogEx(SUCCESS, "Prng detection: HARD");
|
||||
PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_(HARD));
|
||||
else
|
||||
PrintAndLogEx(FAILED, "prng detection: failed");
|
||||
PrintAndLogEx(FAILED, "prng detection: " _RED_(failed));
|
||||
|
||||
if ( do_nack_test )
|
||||
detect_classic_nackbug(silent);
|
||||
@@ -841,15 +839,90 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chaining) {
|
||||
uint16_t cmdc = 0;
|
||||
int SelectCard14443_4(bool disconnect, iso14a_card_select_t *card) {
|
||||
UsbCommand resp;
|
||||
|
||||
*chaining = false;
|
||||
frameLength = 0;
|
||||
|
||||
if (card)
|
||||
memset(card, 0, sizeof(iso14a_card_select_t));
|
||||
|
||||
if (activateField) {
|
||||
cmdc |= ISO14A_CONNECT;
|
||||
DropField();
|
||||
|
||||
// Anticollision + SELECT card
|
||||
UsbCommand ca = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
|
||||
SendCommand(&ca);
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
PrintAndLogEx(ERR, "Proxmark connection timeout.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// check result
|
||||
if (resp.arg[0] == 0) {
|
||||
PrintAndLogEx(ERR, "No card in field.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (resp.arg[0] != 1 && resp.arg[0] != 2) {
|
||||
PrintAndLogEx(ERR, "Card not in iso14443-4. res=%d.", resp.arg[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (resp.arg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
|
||||
// get ATS
|
||||
UsbCommand cr = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0}};
|
||||
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
|
||||
memcpy(cr.d.asBytes, rats, 2);
|
||||
SendCommand(&cr);
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
PrintAndLogEx(ERR, "Proxmark connection timeout.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (resp.arg[0] <= 0) { // ats_len
|
||||
PrintAndLogEx(ERR, "Can't get ATS.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// get frame length from ATS in data field
|
||||
if (resp.arg[0] > 1) {
|
||||
uint8_t fsci = resp.d.asBytes[1] & 0x0f;
|
||||
if (fsci < sizeof(atsFSC))
|
||||
frameLength = atsFSC[fsci];
|
||||
}
|
||||
} else {
|
||||
// get frame length from ATS in card data structure
|
||||
iso14a_card_select_t *vcard = (iso14a_card_select_t *) resp.d.asBytes;
|
||||
if (vcard->ats_len > 1) {
|
||||
uint8_t fsci = vcard->ats[1] & 0x0f;
|
||||
if (fsci < sizeof(atsFSC))
|
||||
frameLength = atsFSC[fsci];
|
||||
}
|
||||
|
||||
if (card)
|
||||
memcpy(card, vcard, sizeof(iso14a_card_select_t));
|
||||
}
|
||||
|
||||
if (disconnect)
|
||||
DropField();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout) {
|
||||
*chainingout = false;
|
||||
|
||||
if (activateField) {
|
||||
// select with no disconnect and set frameLength
|
||||
int selres = SelectCard14443_4(false, NULL);
|
||||
if (selres)
|
||||
return selres;
|
||||
}
|
||||
|
||||
uint16_t cmdc = 0;
|
||||
if (chainingin)
|
||||
cmdc = ISO14A_SEND_CHAINING;
|
||||
|
||||
// "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes
|
||||
// https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size
|
||||
// here length USB_CMD_DATA_SIZE=512
|
||||
@@ -861,18 +934,6 @@ int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t
|
||||
uint8_t *recv;
|
||||
UsbCommand resp;
|
||||
|
||||
if (activateField) {
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
PrintAndLogEx(ERR, "APDU: Proxmark connection timeout.");
|
||||
return 1;
|
||||
}
|
||||
if (resp.arg[0] != 1) {
|
||||
PrintAndLogEx(ERR, "APDU: Proxmark error %d.", resp.arg[0]);
|
||||
DropField();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
recv = resp.d.asBytes;
|
||||
int iLen = resp.arg[0];
|
||||
@@ -888,13 +949,20 @@ int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t
|
||||
return 2;
|
||||
}
|
||||
|
||||
// I-block ACK
|
||||
if ((res & 0xf2) == 0xa2) {
|
||||
*dataoutlen = 0;
|
||||
*chainingout = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!iLen) {
|
||||
PrintAndLogEx(ERR, "APDU: No APDU response.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// check apdu length
|
||||
if (iLen < 4 && iLen >= 0) {
|
||||
if (iLen < 2 && iLen >= 0) {
|
||||
PrintAndLogEx(ERR, "APDU: Small APDU response. Len=%d", iLen);
|
||||
return 2;
|
||||
}
|
||||
@@ -909,7 +977,7 @@ int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t
|
||||
|
||||
// chaining
|
||||
if ((res & 0x10) != 0) {
|
||||
*chaining = true;
|
||||
*chainingout = true;
|
||||
}
|
||||
|
||||
// CRC Check
|
||||
@@ -928,12 +996,57 @@ int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t
|
||||
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
*dataoutlen = 0;
|
||||
bool chaining = false;
|
||||
|
||||
int res = CmdExchangeAPDU(datain, datainlen, activateField, dataout, maxdataoutlen, dataoutlen, &chaining);
|
||||
int res;
|
||||
|
||||
// 3 byte here - 1b framing header, 2b crc16
|
||||
if (APDUInFramingEnable &&
|
||||
( (frameLength && (datainlen > frameLength - 3)) || (datainlen > USB_CMD_DATA_SIZE - 3)) ) {
|
||||
int clen = 0;
|
||||
|
||||
bool vActivateField = activateField;
|
||||
|
||||
do {
|
||||
int vlen = MIN(frameLength - 3, datainlen - clen);
|
||||
bool chainBlockNotLast = ((clen + vlen) < datainlen);
|
||||
|
||||
*dataoutlen = 0;
|
||||
res = CmdExchangeAPDU(chainBlockNotLast, &datain[clen], vlen, vActivateField, dataout, maxdataoutlen, dataoutlen, &chaining);
|
||||
if (res) {
|
||||
if (!leaveSignalON)
|
||||
DropField();
|
||||
|
||||
return 200;
|
||||
}
|
||||
|
||||
// check R-block ACK
|
||||
if ((*dataoutlen == 0) && (*dataoutlen != 0 || chaining != chainBlockNotLast)) {
|
||||
if (!leaveSignalON)
|
||||
DropField();
|
||||
|
||||
return 201;
|
||||
}
|
||||
|
||||
clen += vlen;
|
||||
vActivateField = false;
|
||||
if (*dataoutlen) {
|
||||
if (clen != datainlen)
|
||||
PrintAndLogEx(WARNING, "APDU: I-block/R-block sequence error. Data len=%d, Sent=%d, Last packet len=%d", datainlen, clen, *dataoutlen);
|
||||
break;
|
||||
}
|
||||
} while (clen < datainlen);
|
||||
} else {
|
||||
res = CmdExchangeAPDU(false, datain, datainlen, activateField, dataout, maxdataoutlen, dataoutlen, &chaining);
|
||||
if (res) {
|
||||
if (!leaveSignalON)
|
||||
DropField();
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
while (chaining) {
|
||||
// I-block with chaining
|
||||
res = CmdExchangeAPDU(NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining);
|
||||
res = CmdExchangeAPDU(false, NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining);
|
||||
|
||||
if (res) {
|
||||
if (!leaveSignalON)
|
||||
@@ -1183,27 +1296,75 @@ static int waitCmd(uint8_t iSelect) {
|
||||
|
||||
int CmdHF14AAntiFuzz(const char *cmd) {
|
||||
|
||||
if (strlen(cmd) < 1) return usage_hf_14a_antifuzz();
|
||||
CLIParserInit("hf 14a antifuzz",
|
||||
"Tries to fuzz the ISO14443a anticollision phase",
|
||||
"Usage:\n"
|
||||
"\thf 14a antifuzz -4\n");
|
||||
|
||||
// read param length
|
||||
uint8_t arg0 = 4;
|
||||
|
||||
void* argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("4", NULL, "4 byte uid"),
|
||||
arg_lit0("7", NULL, "7 byte uid"),
|
||||
arg_lit0(NULL, "10", "10 byte uid"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(cmd, argtable, false);
|
||||
|
||||
uint8_t arg0 = FLAG_4B_UID_IN_DATA;
|
||||
if (arg_get_lit(2))
|
||||
arg0 = FLAG_7B_UID_IN_DATA;
|
||||
if (arg_get_lit(3))
|
||||
arg0 = FLAG_10B_UID_IN_DATA;
|
||||
|
||||
CLIParserFree();
|
||||
UsbCommand c = {CMD_ANTIFUZZ_ISO_14443a, {arg0, 0, 0}};
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdHF14AChaining(const char *cmd) {
|
||||
|
||||
CLIParserInit("hf 14a chaining",
|
||||
"Enable/Disable ISO14443a input chaining. Maximum input length goes from ATS.",
|
||||
"Usage:\n"
|
||||
"\thf 14a chaining disable -> disable chaining\n"
|
||||
"\thf 14a chaining -> show chaining enable/disable state\n");
|
||||
|
||||
void* argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0(NULL, NULL, "<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[] = {
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
{"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443-a history"},
|
||||
{"info", CmdHF14AInfo, 0, "Tag information"},
|
||||
{"reader", CmdHF14AReader, 0, "Act like an ISO14443-a reader"},
|
||||
{"reader", CmdHF14AReader, 0, "Act like an ISO14443-a reader"},
|
||||
{"cuids", CmdHF14ACUIDs, 0, "<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"},
|
||||
{"apdu", CmdHF14AAPDU, 0, "Send ISO 14443-4 APDU to tag"},
|
||||
{"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"},
|
||||
{"chaining", CmdHF14AChaining, 0, "Control ISO 14443-4 input chaining"},
|
||||
{"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"},
|
||||
{"antifuzz", CmdHF14AAntiFuzz, 0, "Fuzzing the anticollision phase. Warning! Readers may react strange"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
#include "cmdhfmf.h"
|
||||
#include "cmdhfmfu.h"
|
||||
#include "cmdhf.h" // list cmd
|
||||
#include "mifarehost.h"
|
||||
#include "mifare/mifarehost.h"
|
||||
#include "emv/apduinfo.h"
|
||||
#include "emv/emvcore.h"
|
||||
|
||||
|
||||
+3
-2
@@ -246,7 +246,7 @@ static bool get_14b_UID(iso14b_card_select_t *card) {
|
||||
if (!card)
|
||||
return false;
|
||||
|
||||
uint8_t retry = 3;
|
||||
int8_t retry = 3;
|
||||
UsbCommand resp;
|
||||
UsbCommand c = {CMD_ISO_14443B_COMMAND, {ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0}};
|
||||
|
||||
@@ -283,7 +283,7 @@ static bool get_14b_UID(iso14b_card_select_t *card) {
|
||||
}
|
||||
} // retry
|
||||
|
||||
if ( !retry )
|
||||
if ( retry <= 0 )
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
|
||||
return false;
|
||||
@@ -461,6 +461,7 @@ bool HF14B_Std_Info(bool verbose){
|
||||
PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid);
|
||||
print_atqb_resp(card.atqb, card.cid);
|
||||
isSuccess = true;
|
||||
break;
|
||||
case 2:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail");
|
||||
break;
|
||||
|
||||
+47
-42
@@ -519,21 +519,21 @@ int CmdHF15Info(const char *Cmd) {
|
||||
SendCommand(&c);
|
||||
|
||||
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) {
|
||||
PrintAndLogEx(NORMAL, "iso15693 card select failed");
|
||||
PrintAndLogEx(WARNING, "iso15693 card select failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t status = resp.arg[0];
|
||||
|
||||
if ( status < 2 ) {
|
||||
PrintAndLogEx(NORMAL, "iso15693 card doesn't answer to systeminfo command");
|
||||
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command");
|
||||
return 1;
|
||||
}
|
||||
|
||||
recv = resp.d.asBytes;
|
||||
|
||||
if ( recv[0] & ISO15_RES_ERROR ) {
|
||||
PrintAndLogEx(NORMAL, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
||||
PrintAndLogEx(WARNING, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
||||
return 3;
|
||||
}
|
||||
|
||||
@@ -575,8 +575,8 @@ int CmdHF15Info(const char *Cmd) {
|
||||
// Record Activity without enabeling carrier
|
||||
//helptext
|
||||
int CmdHF15Record(const char *Cmd) {
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (cmdp == 'h' || cmdp == 'H') return usage_15_record();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_15_record();
|
||||
|
||||
UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693, {0,0,0}};
|
||||
clearCommandBuffer();
|
||||
@@ -598,8 +598,8 @@ int HF15Reader(const char *Cmd, bool verbose) {
|
||||
}
|
||||
|
||||
int CmdHF15Reader(const char *Cmd) {
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (cmdp == 'h' || cmdp == 'H') return usage_15_reader();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_15_reader();
|
||||
|
||||
HF15Reader(Cmd, true);
|
||||
return 0;
|
||||
@@ -608,16 +608,16 @@ int CmdHF15Reader(const char *Cmd) {
|
||||
// Simulation is still not working very good
|
||||
// helptext
|
||||
int CmdHF15Sim(const char *Cmd) {
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') return usage_15_sim();
|
||||
char cmdp =tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_sim();
|
||||
|
||||
uint8_t uid[8] = {0,0,0,0,0,0,0,0};
|
||||
if (param_gethex(Cmd, 0, uid, 16)) {
|
||||
PrintAndLogEx(NORMAL, "UID must include 16 HEX symbols");
|
||||
PrintAndLogEx(WARNING, "UID must include 16 HEX symbols");
|
||||
return 0;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid)) );
|
||||
PrintAndLogEx(SUCCESS, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid)) );
|
||||
|
||||
UsbCommand c = {CMD_SIMTAG_ISO_15693, {0, 0, 0}};
|
||||
memcpy(c.d.asBytes, uid, 8);
|
||||
@@ -630,10 +630,10 @@ int CmdHF15Sim(const char *Cmd) {
|
||||
// (There is no standard way of reading the AFI, allthough some tags support this)
|
||||
// helptext
|
||||
int CmdHF15Afi(const char *Cmd) {
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (cmdp == 'h' || cmdp == 'H') return usage_15_findafi();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_15_findafi();
|
||||
|
||||
PrintAndLogEx(NORMAL, "press pm3-button to cancel");
|
||||
PrintAndLogEx(SUCCESS, "press pm3-button to cancel");
|
||||
|
||||
UsbCommand c = {CMD_ISO_15693_FIND_AFI, {strtol(Cmd, NULL, 0), 0, 0}};
|
||||
clearCommandBuffer();
|
||||
@@ -689,7 +689,7 @@ int CmdHF15Dump(const char*Cmd) {
|
||||
}
|
||||
// detect blocksize from card :)
|
||||
|
||||
PrintAndLogEx(NORMAL, "Reading memory from tag UID %s", sprintUID(NULL, uid));
|
||||
PrintAndLogEx(NORMAL, "Reading memory from tag UID " _YELLOW_(%s), sprintUID(NULL, uid));
|
||||
|
||||
int blocknum = 0;
|
||||
uint8_t *recv = NULL;
|
||||
@@ -764,7 +764,7 @@ int CmdHF15Dump(const char*Cmd) {
|
||||
}
|
||||
|
||||
int CmdHF15Restore(const char*Cmd) {
|
||||
FILE *file;
|
||||
FILE *f;
|
||||
|
||||
uint8_t uid[8]={0x00};
|
||||
char filename[FILE_PATH_SIZE] = {0x00};
|
||||
@@ -774,10 +774,10 @@ int CmdHF15Restore(const char*Cmd) {
|
||||
char newCmdPrefix[255] = {0x00}, tmpCmd[255] = {0x00};
|
||||
char param[FILE_PATH_SIZE]="";
|
||||
char hex[255]="";
|
||||
uint8_t retries = 3, tried = 0;
|
||||
uint8_t retries = 3, tried = 0, i = 0;
|
||||
int retval=0;
|
||||
size_t bytes_read;
|
||||
uint8_t i=0;
|
||||
|
||||
while(param_getchar(Cmd, cmdp) != 0x00) {
|
||||
switch(tolower(param_getchar(Cmd, cmdp))) {
|
||||
case '-':
|
||||
@@ -785,7 +785,8 @@ int CmdHF15Restore(const char*Cmd) {
|
||||
switch(param[1])
|
||||
{
|
||||
case '2':
|
||||
case 'o': strncpy(newCmdPrefix, " ",sizeof(newCmdPrefix)-1);
|
||||
case 'o':
|
||||
strncpy(newCmdPrefix, " ", sizeof(newCmdPrefix)-1);
|
||||
strncat(newCmdPrefix, param, sizeof(newCmdPrefix)-1);
|
||||
break;
|
||||
default:
|
||||
@@ -815,60 +816,64 @@ int CmdHF15Restore(const char*Cmd) {
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
return usage_15_restore();
|
||||
break;
|
||||
}
|
||||
cmdp++;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO,"Blocksize: %u",blocksize);
|
||||
if(filename[0]=='\0')
|
||||
{
|
||||
|
||||
if ( !strlen(filename)) {
|
||||
PrintAndLogEx(WARNING,"Please provide a filename");
|
||||
return 1;
|
||||
return usage_15_restore();
|
||||
}
|
||||
|
||||
if ((file = fopen(filename,"rb")) == NULL) {
|
||||
if ((f = fopen(filename, "rb")) == NULL) {
|
||||
PrintAndLogEx(WARNING, "Could not find file %s", filename);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (!getUID(uid)) {
|
||||
PrintAndLogEx(WARNING, "No tag found");
|
||||
fclose(f);
|
||||
return 3;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
tried=0;
|
||||
hex[0]=0x00;
|
||||
tmpCmd[0]=0x00;
|
||||
tried = 0;
|
||||
hex[0] = 0x00;
|
||||
tmpCmd[0] = 0x00;
|
||||
|
||||
bytes_read = fread( buff, 1, blocksize, file );
|
||||
bytes_read = fread( buff, 1, blocksize, f );
|
||||
if ( bytes_read == 0) {
|
||||
PrintAndLogEx(SUCCESS, "File reading done (%s).", filename);
|
||||
fclose(file);
|
||||
PrintAndLogEx(SUCCESS, "File reading done `%s`", filename);
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
else if ( bytes_read != blocksize) {
|
||||
} else if ( bytes_read != blocksize) {
|
||||
PrintAndLogEx(WARNING, "File reading error (%s), %u bytes read instead of %u bytes.", filename, bytes_read, blocksize);
|
||||
fclose(file);
|
||||
fclose(f);
|
||||
return 2;
|
||||
}
|
||||
for(int j=0;j<blocksize;j++)
|
||||
snprintf(hex+j*2,3,"%02X", (unsigned char)buff[j]);
|
||||
for(int j=0;j<sizeof(uid)/sizeof(uid[0]);j++)
|
||||
|
||||
for(int j=0; j < blocksize; 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]);
|
||||
|
||||
//TODO: Addressed mode currently not work
|
||||
//snprintf(tmpCmd, sizeof(tmpCmd), "%s %s %d %s", newCmdPrefix, buff, i, hex);
|
||||
snprintf(tmpCmd, sizeof(tmpCmd), "%s u %d %s", newCmdPrefix, i, hex);
|
||||
PrintAndLogEx(DEBUG, "Command to be sent: %s", tmpCmd);
|
||||
snprintf(tmpCmd, sizeof(tmpCmd), "%s u %u %s", newCmdPrefix, i, hex);
|
||||
PrintAndLogEx(DEBUG, "Command to be sent| %s", tmpCmd);
|
||||
|
||||
for(tried=0;tried<retries;tried++)
|
||||
if(!(retval=CmdHF15Write(tmpCmd)))
|
||||
for(tried=0; tried < retries; tried++)
|
||||
if(!(retval = CmdHF15Write(tmpCmd)))
|
||||
break;
|
||||
if(tried >= retries)
|
||||
return retval;
|
||||
|
||||
i++;
|
||||
}
|
||||
fclose(file);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
int CmdHF15List(const char *Cmd) {
|
||||
@@ -1241,7 +1246,7 @@ int CmdHF15Write(const char *Cmd) {
|
||||
AddCrc(req, reqlen);
|
||||
c.arg[0] = reqlen+2;
|
||||
|
||||
PrintAndLogEx(NORMAL, "iso15693 writing to page %02d (0x&02X) | data ", pagenum, pagenum);
|
||||
PrintAndLogEx(NORMAL, "iso15693 writing to page %02d (0x%02X) | data ", pagenum, pagenum);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
+1
-1
@@ -43,7 +43,7 @@ int CmdHFEPACollectPACENonces(const char *Cmd)
|
||||
PrintAndLogEx(FAILED, "Error in step %d, Return code: %d",resp.arg[0],(int)resp.arg[1]);
|
||||
} else {
|
||||
size_t nonce_length = resp.arg[1];
|
||||
char *nonce = (char *) malloc(2 * nonce_length + 1);
|
||||
char *nonce = (char *) calloc(2 * nonce_length + 1, sizeof(uint8_t));
|
||||
for(int j = 0; j < nonce_length; j++) {
|
||||
sprintf(nonce + (2 * j), "%02X", resp.d.asBytes[j]);
|
||||
}
|
||||
|
||||
+11
-10
@@ -66,7 +66,7 @@ int usage_hf_felica_raw(void){
|
||||
|
||||
int CmdHFFelicaList(const char *Cmd) {
|
||||
//PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list felica' instead");
|
||||
CmdTraceList("raw");
|
||||
CmdTraceList("felica");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ static void printSep() {
|
||||
PrintAndLogEx(NORMAL, "------------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) {
|
||||
uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace, uint16_t tracelen) {
|
||||
if (tracepos+19 >= tracelen)
|
||||
return tracelen;
|
||||
|
||||
@@ -253,7 +253,7 @@ uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) {
|
||||
|
||||
char line[110] = {0};
|
||||
for (int j = 0; j < 16; j++) {
|
||||
snprintf(line+( j * 4),110, "%02x ", trace[j+3]);
|
||||
snprintf(line + (j * 4), sizeof(line) - 1 - (j*4) , "%02x ", trace[j+3]);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "block number %02x, status: %02x %02x",blocknum,status1, status2);
|
||||
@@ -273,11 +273,12 @@ uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) {
|
||||
case 0x0c: PrintAndLogEx(NORMAL, "S_PAD12: %s",line);break;
|
||||
case 0x0d: PrintAndLogEx(NORMAL, "S_PAD13: %s",line);break;
|
||||
case 0x0E: {
|
||||
uint32_t regA = trace[3] + (trace[4]>>8) + (trace[5]>>16) + (trace[6]>>24);
|
||||
uint32_t regB = trace[7] + (trace[8]>>8) + (trace[9]>>16) + (trace[10]>>24);
|
||||
uint32_t regA = trace[3] | trace[4] << 8 | trace[5] << 16 | trace[ 6] << 24;
|
||||
uint32_t regB = trace[7] | trace[8] << 8 | trace[9] << 16 | trace[10] << 24;
|
||||
line[0] = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
snprintf(line+( j * 2),110, "%02x", trace[j+11]);
|
||||
snprintf(line + (j*2), sizeof(line)-1-(j*2), "%02x", trace[j+11]);
|
||||
|
||||
PrintAndLogEx(NORMAL, "REG: regA: %d regB: %d regC: %s ", regA, regB, line);
|
||||
}
|
||||
break;
|
||||
@@ -287,10 +288,10 @@ uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) {
|
||||
char idd[20];
|
||||
char idm[20];
|
||||
for (int j = 0; j < 8; j++)
|
||||
snprintf(idd+( j * 2),20, "%02x", trace[j+3]);
|
||||
snprintf(idd + (j*2), sizeof(idd)-1-(j*2), "%02x", trace[j+3]);
|
||||
|
||||
for (int j = 0; j < 6; j++)
|
||||
snprintf(idm+( j * 2),20, "%02x", trace[j+13]);
|
||||
snprintf(idm + (j*2), sizeof(idm)-1-(j*2), "%02x", trace[j+13]);
|
||||
|
||||
PrintAndLogEx(NORMAL, "ID Block, IDd: 0x%s DFC: 0x%02x%02x Arb: %s ", idd, trace[11], trace [12], idm);
|
||||
}
|
||||
@@ -299,10 +300,10 @@ uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) {
|
||||
char idm[20];
|
||||
char pmm[20];
|
||||
for (int j = 0; j < 8; j++)
|
||||
snprintf(idm+( j * 2),20, "%02x", trace[j+3]);
|
||||
snprintf(idm + (j*2), sizeof(idm)-1-(j*2), "%02x", trace[j+3]);
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
snprintf(pmm+( j * 2),20, "%02x", trace[j+11]);
|
||||
snprintf(pmm + (j*2), sizeof(pmm)-1-(j*2), "%02x", trace[j+11]);
|
||||
|
||||
PrintAndLogEx(NORMAL, "DeviceId: IDm: 0x%s PMm: 0x%s ", idm, pmm);
|
||||
}
|
||||
|
||||
+1
-1
@@ -914,7 +914,7 @@ static command_t CommandTable[] =
|
||||
};
|
||||
|
||||
int CmdHFFido(const char *Cmd) {
|
||||
(void)WaitForResponseTimeout(CMD_ACK,NULL,100);
|
||||
(void)WaitForResponseTimeout(CMD_ACK, NULL, 100);
|
||||
CmdsParse(CommandTable, Cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+14
-13
@@ -404,7 +404,7 @@ int CmdHFiClassSim(const char *Cmd) {
|
||||
break;
|
||||
|
||||
size_t datalen = NUM_CSNS * 24;
|
||||
void* dump = malloc(datalen);
|
||||
void* dump = calloc(datalen, sizeof(uint8_t));
|
||||
if ( !dump ) {
|
||||
PrintAndLogEx(WARNING, "Failed to allocate memory");
|
||||
return 2;
|
||||
@@ -456,7 +456,7 @@ int CmdHFiClassSim(const char *Cmd) {
|
||||
break;
|
||||
|
||||
size_t datalen = NUM_CSNS * 24;
|
||||
void* dump = malloc(datalen);
|
||||
void* dump = calloc(datalen, sizeof(uint8_t));
|
||||
if ( !dump ) {
|
||||
PrintAndLogEx(WARNING, "Failed to allocate memory");
|
||||
return 2;
|
||||
@@ -626,7 +626,7 @@ int CmdHFiClassELoad(const char *Cmd) {
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if ( !f ){
|
||||
PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename);
|
||||
PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2162,10 +2162,10 @@ static int cmp_uint32( const void *a, const void *b) {
|
||||
int CmdHFiClassLookUp(const char *Cmd) {
|
||||
|
||||
uint8_t CSN[8];
|
||||
uint8_t EPURSE[8];
|
||||
uint8_t MACS[8];
|
||||
uint8_t EPURSE[8] = { 0,0,0,0,0,0,0,0 };
|
||||
uint8_t MACS[8]= { 0,0,0,0,0,0,0,0 };
|
||||
uint8_t CCNR[12];
|
||||
uint8_t MAC_TAG[4] = {0x00,0x00,0x00,0x00};
|
||||
uint8_t MAC_TAG[4] = { 0,0,0,0 };
|
||||
|
||||
// elite key, raw key, standard key
|
||||
bool use_elite = false;
|
||||
@@ -2304,7 +2304,7 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) {
|
||||
int keyitems = 0;
|
||||
|
||||
if ( !(f = fopen( filename , "r")) ) {
|
||||
PrintAndLogEx(ERR, "file: %s: not found or locked.", filename);
|
||||
PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2316,7 +2316,8 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) {
|
||||
while (fgetc(f) != '\n' && !feof(f)) {};
|
||||
|
||||
//The line start with # is comment, skip
|
||||
if( buf[0]=='#' ) continue;
|
||||
if( buf[0]=='#' )
|
||||
continue;
|
||||
|
||||
// doesn't this only test first char only?
|
||||
if (!isxdigit(buf[0])){
|
||||
@@ -2329,7 +2330,7 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) {
|
||||
|
||||
p = realloc(*keys, 8 * (keyitems += 64));
|
||||
if (!p) {
|
||||
PrintAndLogEx(NORMAL, _RED_([!])" cannot allocate memory for default keys");
|
||||
PrintAndLogEx(ERR, "cannot allocate memory for default keys");
|
||||
fclose(f);
|
||||
return 2;
|
||||
}
|
||||
@@ -2341,7 +2342,7 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
}
|
||||
fclose(f);
|
||||
PrintAndLogEx(NORMAL, _BLUE_([+]) "Loaded " _GREEN_(%2d) " keys from %s", *keycnt, filename);
|
||||
PrintAndLogEx(SUCCESS, "Loaded " _GREEN_(%2d) " keys from %s", *keycnt, filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2462,7 +2463,7 @@ static void shave(uint8_t *data, uint8_t len){
|
||||
data[i] &= 0xFE;
|
||||
}
|
||||
static void generate_rev(uint8_t *data, uint8_t len) {
|
||||
uint8_t *key = calloc(len,1);
|
||||
uint8_t *key = calloc(len, sizeof(uint8_t));
|
||||
PrintAndLogEx(SUCCESS, "input permuted key | %s \n", sprint_hex(data, len));
|
||||
permute_rev(data, len, key);
|
||||
PrintAndLogEx(SUCCESS, " unpermuted key | %s \n", sprint_hex(key, len));
|
||||
@@ -2471,8 +2472,8 @@ static void generate_rev(uint8_t *data, uint8_t len) {
|
||||
free(key);
|
||||
}
|
||||
static void generate(uint8_t *data, uint8_t len) {
|
||||
uint8_t *key = calloc(len,1);
|
||||
uint8_t *pkey = calloc(len,1);
|
||||
uint8_t *key = calloc(len, sizeof(uint8_t));
|
||||
uint8_t *pkey = calloc(len, sizeof(uint8_t));
|
||||
PrintAndLogEx(SUCCESS, " input key | %s \n", sprint_hex(data, len));
|
||||
permute(data, len, pkey);
|
||||
PrintAndLogEx(SUCCESS, "permuted key | %s \n", sprint_hex(pkey, len));
|
||||
|
||||
+109
-73
@@ -180,15 +180,14 @@ int CmdLegicInfo(const char *Cmd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Reading tag memory %d b...", card.cardsize);
|
||||
PrintAndLogEx(SUCCESS, "Reading tag memory %d b...", card.cardsize);
|
||||
|
||||
// allocate receiver buffer
|
||||
uint8_t *data = malloc(card.cardsize);
|
||||
uint8_t *data = calloc(card.cardsize, sizeof(uint8_t));
|
||||
if (!data) {
|
||||
PrintAndLogEx(WARNING, "Cannot allocate memory");
|
||||
return 2;
|
||||
}
|
||||
memset(data, 0, card.cardsize);
|
||||
|
||||
int status = legic_read_mem(0, card.cardsize, 0x55, data, &datalen);
|
||||
if ( status > 0 ) {
|
||||
@@ -480,15 +479,20 @@ int CmdLegicRdmem(const char *Cmd) {
|
||||
uint16_t datalen = 0;
|
||||
sscanf(Cmd, "%x %x %x", &offset, &len, &iv);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Reading %d bytes, from offset %d", len, offset);
|
||||
// sanity checks
|
||||
if ( len + offset >= MAX_LENGTH ) {
|
||||
PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", MAX_LENGTH, len + offset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Reading %d bytes, from offset %d", len, offset);
|
||||
|
||||
// allocate receiver buffer
|
||||
uint8_t *data = malloc(len);
|
||||
uint8_t *data = calloc(len, sizeof(uint8_t));
|
||||
if ( !data ){
|
||||
PrintAndLogEx(WARNING, "Cannot allocate memory");
|
||||
return 2;
|
||||
return -2;
|
||||
}
|
||||
memset(data, 0, len);
|
||||
|
||||
int status = legic_read_mem(offset, len, iv, data, &datalen);
|
||||
if ( status == 0 ) {
|
||||
@@ -540,9 +544,9 @@ int CmdLegicRfWrite(const char *Cmd) {
|
||||
}
|
||||
|
||||
// limit number of bytes to write. This is not a 'restore' command.
|
||||
if ( (len>>1) > 100 ){
|
||||
PrintAndLogEx(NORMAL, "Max bound on 100bytes to write a one time.");
|
||||
PrintAndLogEx(NORMAL, "Use the 'hf legic restore' command if you want to write the whole tag at once");
|
||||
if ( (len >> 1) > 100 ){
|
||||
PrintAndLogEx(WARNING, "Max bound on 100bytes to write a one time.");
|
||||
PrintAndLogEx(WARNING, "Use the 'hf legic restore' command if you want to write the whole tag at once");
|
||||
errors = true;
|
||||
}
|
||||
|
||||
@@ -551,7 +555,7 @@ int CmdLegicRfWrite(const char *Cmd) {
|
||||
if (data)
|
||||
free(data);
|
||||
|
||||
data = malloc(len >> 1);
|
||||
data = calloc(len >> 1, sizeof(uint8_t));
|
||||
if ( data == NULL ) {
|
||||
PrintAndLogEx(WARNING, "Can't allocate memory. exiting");
|
||||
errors = true;
|
||||
@@ -598,12 +602,12 @@ int CmdLegicRfWrite(const char *Cmd) {
|
||||
// OUT-OF-BOUNDS checks
|
||||
// UID 4+1 bytes can't be written to.
|
||||
if ( offset < 5 ) {
|
||||
PrintAndLogEx(NORMAL, "Out-of-bounds, bytes 0-1-2-3-4 can't be written to. Offset = %d", offset);
|
||||
PrintAndLogEx(WARNING, "Out-of-bounds, bytes 0-1-2-3-4 can't be written to. Offset = %d", offset);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if ( len + offset >= card.cardsize ) {
|
||||
PrintAndLogEx(NORMAL, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", card.cardsize, len + offset);
|
||||
PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", card.cardsize, len + offset);
|
||||
return -2;
|
||||
}
|
||||
|
||||
@@ -622,7 +626,7 @@ int CmdLegicRfWrite(const char *Cmd) {
|
||||
|
||||
legic_chk_iv(&IV);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Writing to tag");
|
||||
PrintAndLogEx(SUCCESS, "Writing to tag");
|
||||
|
||||
UsbCommand c = {CMD_WRITER_LEGIC_RF, {offset, len, IV}};
|
||||
memcpy(c.d.asBytes, data, len);
|
||||
@@ -630,10 +634,18 @@ int CmdLegicRfWrite(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t timeout = 0;
|
||||
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
++timeout;
|
||||
printf("."); fflush(stdout);
|
||||
if (timeout > 7) {
|
||||
PrintAndLogEx(WARNING, "\ncommand execution time out");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "\n");
|
||||
|
||||
uint8_t isOK = resp.arg[0] & 0xFF;
|
||||
if ( !isOK ) {
|
||||
PrintAndLogEx(WARNING, "Failed writing tag");
|
||||
@@ -673,7 +685,7 @@ int CmdLegicCalcCrc(const char *Cmd){
|
||||
// it's possible for user to accidentally enter "b" parameter
|
||||
// more than once - we have to clean previous malloc
|
||||
if (data) free(data);
|
||||
data = malloc(len >> 1);
|
||||
data = calloc(len >> 1, sizeof(uint8_t) );
|
||||
if ( data == NULL ) {
|
||||
PrintAndLogEx(WARNING, "Can't allocate memory. exiting");
|
||||
errors = true;
|
||||
@@ -714,10 +726,10 @@ int CmdLegicCalcCrc(const char *Cmd){
|
||||
switch (type){
|
||||
case 16:
|
||||
init_table(CRC_LEGIC);
|
||||
PrintAndLogEx(NORMAL, "Legic crc16: %X", crc16_legic(data, len, uidcrc));
|
||||
PrintAndLogEx(SUCCESS, "Legic crc16: %X", crc16_legic(data, len, uidcrc));
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(NORMAL, "Legic crc8: %X", CRC8Legic(data, len) );
|
||||
PrintAndLogEx(SUCCESS, "Legic crc8: %X", CRC8Legic(data, len) );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -733,11 +745,18 @@ int legic_read_mem(uint32_t offset, uint32_t len, uint32_t iv, uint8_t *out, uin
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
UsbCommand resp;
|
||||
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 3000) ) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
uint8_t timeout = 0;
|
||||
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
++timeout;
|
||||
printf("."); fflush(stdout);
|
||||
if (timeout > 7) {
|
||||
PrintAndLogEx(WARNING, "\ncommand execution time out");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "\n");
|
||||
|
||||
uint8_t isOK = resp.arg[0] & 0xFF;
|
||||
*outlen = resp.arg[1];
|
||||
if ( !isOK ) {
|
||||
@@ -762,13 +781,13 @@ int legic_print_type(uint32_t tagtype, uint8_t spaces){
|
||||
char *spacer = spc + (10-spaces);
|
||||
|
||||
if ( tagtype == 22 )
|
||||
PrintAndLogEx(NORMAL, "%sTYPE : MIM%d card (outdated)", spacer, tagtype);
|
||||
PrintAndLogEx(SUCCESS, "%sTYPE : MIM%d card (outdated)", spacer, tagtype);
|
||||
else if ( tagtype == 256 )
|
||||
PrintAndLogEx(NORMAL, "%sTYPE : MIM%d card (234 bytes)", spacer, tagtype);
|
||||
PrintAndLogEx(SUCCESS, "%sTYPE : MIM%d card (234 bytes)", spacer, tagtype);
|
||||
else if ( tagtype == 1024 )
|
||||
PrintAndLogEx(NORMAL, "%sTYPE : MIM%d card (1002 bytes)", spacer, tagtype);
|
||||
PrintAndLogEx(SUCCESS, "%sTYPE : MIM%d card (1002 bytes)", spacer, tagtype);
|
||||
else
|
||||
PrintAndLogEx(NORMAL, "%sTYPE : Unknown %06x", spacer, tagtype);
|
||||
PrintAndLogEx(INFO, "%sTYPE : Unknown %06x", spacer, tagtype);
|
||||
return 0;
|
||||
}
|
||||
int legic_get_type(legic_card_select_t *card){
|
||||
@@ -792,12 +811,12 @@ int legic_get_type(legic_card_select_t *card){
|
||||
void legic_chk_iv(uint32_t *iv){
|
||||
if ( (*iv & 0x7F) != *iv ){
|
||||
*iv &= 0x7F;
|
||||
PrintAndLogEx(NORMAL, "Truncating IV to 7bits, %u", *iv);
|
||||
PrintAndLogEx(INFO, "Truncating IV to 7bits, %u", *iv);
|
||||
}
|
||||
// IV must be odd
|
||||
if ( (*iv & 1) == 0 ){
|
||||
*iv |= 0x01;
|
||||
PrintAndLogEx(NORMAL, "LSB of IV must be SET %u", *iv);
|
||||
PrintAndLogEx(INFO, "LSB of IV must be SET %u", *iv);
|
||||
}
|
||||
}
|
||||
void legic_seteml(uint8_t *src, uint32_t offset, uint32_t numofbytes) {
|
||||
@@ -828,11 +847,11 @@ int HFLegicReader(const char *Cmd, bool verbose) {
|
||||
if ( verbose ) PrintAndLogEx(WARNING, "command execution time out");
|
||||
return 1;
|
||||
case 3:
|
||||
if ( verbose ) PrintAndLogEx(NORMAL, "legic card select failed");
|
||||
if ( verbose ) PrintAndLogEx(WARNING, "legic card select failed");
|
||||
return 2;
|
||||
default: break;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, sizeof(card.uid)));
|
||||
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, sizeof(card.uid)));
|
||||
legic_print_type(card.cardsize, 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -882,16 +901,23 @@ int CmdLegicDump(const char *Cmd){
|
||||
dumplen = card.cardsize;
|
||||
|
||||
legic_print_type(dumplen, 0);
|
||||
PrintAndLogEx(NORMAL, "Reading tag memory %d b...", dumplen);
|
||||
PrintAndLogEx(SUCCESS, "Reading tag memory %d b...", dumplen);
|
||||
|
||||
UsbCommand c = {CMD_READER_LEGIC_RF, {0x00, dumplen, 0x55}};
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
UsbCommand resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
|
||||
PrintAndLogEx(NORMAL, "Command execute time-out");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t timeout = 0;
|
||||
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
++timeout;
|
||||
printf("."); fflush(stdout);
|
||||
if (timeout > 7) {
|
||||
PrintAndLogEx(WARNING, "\ncommand execution time out");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "\n");
|
||||
|
||||
uint8_t isOK = resp.arg[0] & 0xFF;
|
||||
if ( !isOK ) {
|
||||
@@ -900,12 +926,11 @@ int CmdLegicDump(const char *Cmd){
|
||||
}
|
||||
|
||||
uint16_t readlen = resp.arg[1];
|
||||
uint8_t *data = malloc(readlen);
|
||||
uint8_t *data = calloc(readlen, sizeof(uint8_t));
|
||||
if (!data) {
|
||||
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
|
||||
return 3;
|
||||
}
|
||||
memset(data, 0, readlen);
|
||||
|
||||
if ( readlen != dumplen )
|
||||
PrintAndLogEx(WARNING, "Fail, only managed to read 0x%02X bytes of 0x%02X", readlen, dumplen);
|
||||
@@ -923,7 +948,7 @@ int CmdLegicDump(const char *Cmd){
|
||||
else
|
||||
sprintf(fnameptr + fileNlen,".bin");
|
||||
|
||||
f = fopen(filename,"wb");
|
||||
f = fopen(filename, "wb");
|
||||
if (!f) {
|
||||
PrintAndLogEx(WARNING, "Could not create file name %s", filename);
|
||||
if (data)
|
||||
@@ -934,7 +959,7 @@ int CmdLegicDump(const char *Cmd){
|
||||
fflush(f);
|
||||
fclose(f);
|
||||
free(data);
|
||||
PrintAndLogEx(NORMAL, "Wrote %d bytes to %s", readlen, filename);
|
||||
PrintAndLogEx(SUCCESS, "Wrote %d bytes to %s", readlen, filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -982,12 +1007,11 @@ int CmdLegicRestore(const char *Cmd){
|
||||
numofbytes = card.cardsize;
|
||||
|
||||
// set up buffer
|
||||
uint8_t *data = malloc(numofbytes);
|
||||
uint8_t *data = calloc(numofbytes, sizeof(uint8_t) );
|
||||
if (!data) {
|
||||
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
|
||||
return 2;
|
||||
}
|
||||
memset(data, 0, numofbytes);
|
||||
|
||||
legic_print_type(numofbytes, 0);
|
||||
|
||||
@@ -997,7 +1021,8 @@ int CmdLegicRestore(const char *Cmd){
|
||||
|
||||
f = fopen(filename,"rb");
|
||||
if (!f) {
|
||||
PrintAndLogEx(NORMAL, "File %s not found or locked", filename);
|
||||
PrintAndLogEx(WARNING, "File %s not found or locked", filename);
|
||||
free(data);
|
||||
return 3;
|
||||
}
|
||||
|
||||
@@ -1018,12 +1043,12 @@ int CmdLegicRestore(const char *Cmd){
|
||||
fclose(f);
|
||||
|
||||
if ( bytes_read == 0){
|
||||
PrintAndLogEx(NORMAL, "File reading error");
|
||||
PrintAndLogEx(WARNING, "File reading error");
|
||||
free(data);
|
||||
return 2;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Restoring to card");
|
||||
PrintAndLogEx(SUCCESS, "Restoring to card");
|
||||
|
||||
// transfer to device
|
||||
size_t len = 0;
|
||||
@@ -1038,22 +1063,29 @@ int CmdLegicRestore(const char *Cmd){
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
uint8_t timeout = 0;
|
||||
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
++timeout;
|
||||
printf("."); fflush(stdout);
|
||||
if (timeout > 7) {
|
||||
PrintAndLogEx(WARNING, "\ncommand execution time out");
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "\n");
|
||||
|
||||
uint8_t isOK = resp.arg[0] & 0xFF;
|
||||
if ( !isOK ) {
|
||||
PrintAndLogEx(WARNING, "Failed writing tag [msg = %u]", resp.arg[1] & 0xFF);
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "Wrote chunk [offset %d | len %d | total %d", i, len, i+len);
|
||||
PrintAndLogEx(SUCCESS, "Wrote chunk [offset %d | len %d | total %d", i, len, i+len);
|
||||
}
|
||||
|
||||
free(data);
|
||||
PrintAndLogEx(NORMAL, "\nWrote %d bytes to card from file %s", numofbytes, filename);
|
||||
PrintAndLogEx(SUCCESS, "\nWrote %d bytes to card from file %s", numofbytes, filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1077,12 +1109,11 @@ int CmdLegicELoad(const char *Cmd) {
|
||||
}
|
||||
|
||||
// set up buffer
|
||||
uint8_t *data = malloc(numofbytes);
|
||||
uint8_t *data = calloc(numofbytes, sizeof(uint8_t));
|
||||
if (!data) {
|
||||
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
|
||||
return 3;
|
||||
}
|
||||
memset(data, 0, numofbytes);
|
||||
|
||||
// set up file
|
||||
len = param_getstr(Cmd, nameParamNo, filename, FILE_PATH_SIZE);
|
||||
@@ -1094,7 +1125,7 @@ int CmdLegicELoad(const char *Cmd) {
|
||||
// open file
|
||||
f = fopen(filename,"rb");
|
||||
if (!f) {
|
||||
PrintAndLogEx(NORMAL, "File %s not found or locked", filename);
|
||||
PrintAndLogEx(WARNING, "File %s not found or locked", filename);
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
@@ -1102,7 +1133,7 @@ int CmdLegicELoad(const char *Cmd) {
|
||||
// load file
|
||||
size_t bytes_read = fread(data, 1, numofbytes, f);
|
||||
if ( bytes_read == 0){
|
||||
PrintAndLogEx(NORMAL, "File reading error");
|
||||
PrintAndLogEx(WARNING, "File reading error");
|
||||
free(data);
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
@@ -1115,7 +1146,7 @@ int CmdLegicELoad(const char *Cmd) {
|
||||
legic_seteml(data, 0, numofbytes);
|
||||
|
||||
free(data);
|
||||
PrintAndLogEx(NORMAL, "\nLoaded %d bytes from file: %s to emulator memory", numofbytes, filename);
|
||||
PrintAndLogEx(SUCCESS, "\nLoaded %d bytes from file: %s to emulator memory", numofbytes, filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1146,15 +1177,14 @@ int CmdLegicESave(const char *Cmd) {
|
||||
fileNlen = FILE_PATH_SIZE - 5;
|
||||
|
||||
// set up buffer
|
||||
uint8_t *data = malloc(numofbytes);
|
||||
uint8_t *data = calloc(numofbytes, sizeof(uint8_t));
|
||||
if (!data) {
|
||||
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
|
||||
return 3;
|
||||
}
|
||||
memset(data, 0, numofbytes);
|
||||
|
||||
// download emulator memory
|
||||
PrintAndLogEx(NORMAL, "Reading emulator memory...");
|
||||
PrintAndLogEx(SUCCESS, "Reading emulator memory...");
|
||||
if (!GetFromDevice( BIG_BUF_EML, data, numofbytes, 0, NULL, 2500, false)) {
|
||||
PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
|
||||
free(data);
|
||||
@@ -1185,16 +1215,15 @@ int CmdLegicWipe(const char *Cmd){
|
||||
}
|
||||
|
||||
// set up buffer
|
||||
uint8_t *data = malloc(card.cardsize);
|
||||
uint8_t *data = calloc(card.cardsize, sizeof(uint8_t));
|
||||
if (!data) {
|
||||
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
|
||||
return 2;
|
||||
}
|
||||
memset(data, 0, card.cardsize);
|
||||
|
||||
legic_print_type(card.cardsize, 0);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Erasing");
|
||||
PrintAndLogEx(SUCCESS, "Erasing");
|
||||
|
||||
// transfer to device
|
||||
size_t len = 0;
|
||||
@@ -1210,11 +1239,18 @@ int CmdLegicWipe(const char *Cmd){
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
free(data);
|
||||
return 3;
|
||||
}
|
||||
uint8_t timeout = 0;
|
||||
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
++timeout;
|
||||
printf("."); fflush(stdout);
|
||||
if (timeout > 7) {
|
||||
PrintAndLogEx(WARNING, "\ncommand execution time out");
|
||||
free(data);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "\n");
|
||||
|
||||
uint8_t isOK = resp.arg[0] & 0xFF;
|
||||
if ( !isOK ) {
|
||||
PrintAndLogEx(WARNING, "Failed writing tag [msg = %u]", resp.arg[1] & 0xFF);
|
||||
@@ -1222,7 +1258,7 @@ int CmdLegicWipe(const char *Cmd){
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "ok\n");
|
||||
PrintAndLogEx(SUCCESS, "ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1236,7 +1272,7 @@ static command_t CommandTable[] = {
|
||||
{"reader", CmdLegicReader, 1, "LEGIC Prime Reader UID and tag info"},
|
||||
{"info", CmdLegicInfo, 0, "Display deobfuscated and decoded LEGIC Prime tag data"},
|
||||
{"dump", CmdLegicDump, 0, "Dump LEGIC Prime tag to binary file"},
|
||||
{"restore", CmdLegicRestore, 0, "Restore a dump onto a LEGIC Prime tag"},
|
||||
{"restore", CmdLegicRestore, 0, "Restore a dump file onto a LEGIC Prime tag"},
|
||||
{"rdmem", CmdLegicRdmem, 0, "Read bytes from a LEGIC Prime tag"},
|
||||
{"sim", CmdLegicRfSim, 0, "Start tag simulator"},
|
||||
{"write", CmdLegicRfWrite, 0, "Write data to a LEGIC Prime tag"},
|
||||
|
||||
+44
-2
@@ -159,6 +159,7 @@ int applyIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) {
|
||||
MifareAuthState = masNone;
|
||||
break;
|
||||
case ISO14443A_CMD_RATS: snprintf(exp,size,"RATS"); break;
|
||||
case ISO14443A_CMD_OPTS: snprintf(exp,size,"OPTIONAL TIMESLOT"); break;
|
||||
case MIFARE_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break;
|
||||
case MIFARE_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break;
|
||||
case MIFARE_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break;
|
||||
@@ -356,7 +357,7 @@ void annotateIso7816(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){
|
||||
case ISO7816_EXTERNAL_AUTHENTICATION :snprintf(exp, size, "EXTERNAL AUTH");break;
|
||||
case ISO7816_GET_CHALLENGE :snprintf(exp, size, "GET CHALLENGE");break;
|
||||
case ISO7816_MANAGE_CHANNEL :snprintf(exp, size, "MANAGE CHANNEL");break;
|
||||
case ISO7816_GETSTATUS :snprintf(exp, size, "GET RESPONSE");break;
|
||||
case ISO7816_GET_RESPONSE :snprintf(exp, size, "GET RESPONSE");break;
|
||||
default :snprintf(exp,size,"?"); break;
|
||||
}
|
||||
}
|
||||
@@ -535,7 +536,48 @@ void annotateLegic(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){
|
||||
}
|
||||
|
||||
void annotateFelica(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){
|
||||
|
||||
switch(cmd[0]){
|
||||
case FELICA_POLL_REQ: snprintf(exp,size ,"POLLING");break;
|
||||
case FELICA_POLL_ACK: snprintf(exp,size ,"POLL ACK");break;
|
||||
case FELICA_REQSRV_REQ: snprintf(exp,size ,"REQUEST SERVICE");break;
|
||||
case FELICA_REQSRV_ACK: snprintf(exp,size ,"REQ SERV ACK");break;
|
||||
case FELICA_REQRESP_REQ: snprintf(exp,size ,"REQUEST RESPONSE");break;
|
||||
case FELICA_REQRESP_ACK: snprintf(exp,size ,"REQ RESP ACK");break;
|
||||
case FELICA_RDBLK_REQ: snprintf(exp,size ,"READ BLK");break;
|
||||
case FELICA_RDBLK_ACK: snprintf(exp,size ,"READ BLK ACK");break;
|
||||
case FELICA_WRTBLK_REQ: snprintf(exp,size ,"WRITE BLK");break;
|
||||
case FELICA_WRTBLK_ACK: snprintf(exp,size ,"WRITE BLK ACK");break;
|
||||
case FELICA_SRCHSYSCODE_REQ: snprintf(exp,size ,"SEARCH SERVICE CODE");break;
|
||||
case FELICA_SRCHSYSCODE_ACK: snprintf(exp,size ,"SSC ACK");break;
|
||||
case FELICA_REQSYSCODE_REQ: snprintf(exp,size ,"REQUEST SYSTEM CODE");break;
|
||||
case FELICA_REQSYSCODE_ACK: snprintf(exp,size ,"RSC ACK");break;
|
||||
case FELICA_AUTH1_REQ: snprintf(exp,size ,"AUTH 1");break;
|
||||
case FELICA_AUTH1_ACK: snprintf(exp,size ,"AUTH 1 ACK");break;
|
||||
case FELICA_AUTH2_REQ: snprintf(exp,size ,"AUTH 2");break;
|
||||
case FELICA_AUTH2_ACK: snprintf(exp,size ,"AUTH 2 ACK");break;
|
||||
case FELICA_RDSEC_REQ: snprintf(exp,size ,"READ");break;
|
||||
case FELICA_RDSEC_ACK: snprintf(exp,size ,"READ ACK");break;
|
||||
case FELICA_WRTSEC_REQ: snprintf(exp,size ,"WRITE");break;
|
||||
case FELICA_WRTSEC_ACK: snprintf(exp,size ,"WRITE ACK");break;
|
||||
case FELICA_REQSRV2_REQ: snprintf(exp,size ,"REQUEST SERVICE v2");break;
|
||||
case FELICA_REQSRV2_ACK: snprintf(exp,size ,"REQ SERV v2 ACK");break;
|
||||
case FELICA_GETSTATUS_REQ: snprintf(exp,size ,"GET STATUS");break;
|
||||
case FELICA_GETSTATUS_ACK: snprintf(exp,size ,"GET STATUS ACK");break;
|
||||
case FELICA_OSVER_REQ: snprintf(exp,size ,"REQUEST SPECIFIC VERSION");break;
|
||||
case FELICA_OSVER_ACK: snprintf(exp,size ,"RSV ACK");break;
|
||||
case FELICA_RESET_MODE_REQ: snprintf(exp,size ,"RESET MODE");break;
|
||||
case FELICA_RESET_MODE_ACK: snprintf(exp,size ,"RESET MODE ACK");break;
|
||||
case FELICA_AUTH1V2_REQ: snprintf(exp,size ,"AUTH 1 v2");break;
|
||||
case FELICA_AUTH1V2_ACK: snprintf(exp,size ,"AUTH 1 v2 ACK");break;
|
||||
case FELICA_AUTH2V2_REQ: snprintf(exp,size ,"AUTH 2 v2");break;
|
||||
case FELICA_AUTH2V2_ACK: snprintf(exp,size ,"AUTH 2 v2 ACK");break;
|
||||
case FELICA_RDSECV2_REQ: snprintf(exp,size ,"READ v2");break;
|
||||
case FELICA_RDSECV2_ACK: snprintf(exp,size ,"READ v2 ACK");break;
|
||||
case FELICA_WRTSECV2_REQ: snprintf(exp,size ,"WRITE v2");break;
|
||||
case FELICA_WRTSECV2_ACK: snprintf(exp,size ,"WRITE v2 ACK");break;
|
||||
case FELICA_UPDATE_RNDID_REQ: snprintf(exp,size ,"UPDATE RANDOM ID");break;
|
||||
case FELICA_UPDATE_RNDID_ACK: snprintf(exp,size ,"URI ACK");break;
|
||||
default : snprintf(exp,size ,"?");break;
|
||||
}
|
||||
}
|
||||
@@ -644,7 +686,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
|
||||
PrintAndLogEx(NORMAL, " | | * |%49s %012"PRIx64" prng %s | |",
|
||||
"key",
|
||||
mfLastKey,
|
||||
validate_prng_nonce(AuthData.nt) ? "WEAK": "HARD");
|
||||
validate_prng_nonce(AuthData.nt) ? _GREEN_(WEAK): _YELLOW_(HARD));
|
||||
|
||||
AuthData.first_auth = false;
|
||||
|
||||
|
||||
+2
-2
@@ -31,8 +31,8 @@
|
||||
#include "emv/cmdemv.h" // EMV
|
||||
#include "protocols.h"
|
||||
#include "crapto1/crapto1.h"
|
||||
#include "mifarehost.h"
|
||||
#include "mifaredefault.h"
|
||||
#include "mifare/mifarehost.h"
|
||||
#include "mifare/mifaredefault.h"
|
||||
#include "parity.h" // oddparity
|
||||
#include "iso15693tools.h" // ISO15693 crc
|
||||
|
||||
|
||||
+388
-238
File diff suppressed because it is too large
Load Diff
+9
-8
@@ -23,18 +23,19 @@
|
||||
#include "cmdparser.h"
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
#include "mifare.h" // nonces_t struct
|
||||
#include "mfkey.h" // mfkey32_moebious
|
||||
#include "mifare.h" // nonces_t struct
|
||||
#include "mifare/mfkey.h" // mfkey32_moebious
|
||||
#include "cmdhfmfhard.h"
|
||||
#include "mifarehost.h" // icesector_t, sector_t
|
||||
#include "util_posix.h" // msclock
|
||||
#include "mifaredefault.h" // mifare default key array
|
||||
#include "cmdhf14a.h" // dropfield
|
||||
#include "cliparser/cliparser.h" // argtable
|
||||
#include "mifare/mifarehost.h" // icesector_t, sector_t
|
||||
#include "util_posix.h" // msclock
|
||||
#include "mifare/mifaredefault.h" // mifare default key array
|
||||
#include "cmdhf14a.h" // dropfield
|
||||
#include "cliparser/cliparser.h" // argtable
|
||||
#include "hardnested/hardnested_bf_core.h" // SetSIMDInstr
|
||||
|
||||
extern int CmdHFMF(const char *Cmd);
|
||||
|
||||
extern int CmdHF14AMfList(const char *Cmd);
|
||||
extern int CmdHF14AMfDbg(const char* cmd);
|
||||
extern int CmdHF14AMfRdBl(const char* cmd);
|
||||
extern int CmdHF14AMfURdBl(const char* cmd);
|
||||
@@ -45,7 +46,7 @@ extern int CmdHF14AMfRestore(const char* cmd);
|
||||
extern int CmdHF14AMfWrBl(const char* cmd);
|
||||
extern int CmdHF14AMfUWrBl(const char* cmd);
|
||||
extern int CmdHF14AMfChk(const char* cmd);
|
||||
extern int CmdHF14ADarkside(const char* cmd);
|
||||
extern int CmdHF14AMfDarkside(const char* cmd);
|
||||
extern int CmdHF14AMfNested(const char* cmd);
|
||||
extern int CmdHF14AMfNestedHard(const char *Cmd);
|
||||
//extern int CmdHF14AMfSniff(const char* cmd);
|
||||
|
||||
+42
-51
@@ -209,7 +209,7 @@ static int compare_count_bitflip_bitarrays(const void *b1, const void *b2)
|
||||
|
||||
static voidpf inflate_malloc(voidpf opaque, uInt items, uInt size)
|
||||
{
|
||||
return malloc(items*size);
|
||||
return calloc(items*size, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
|
||||
@@ -266,14 +266,20 @@ static void init_bitflip_bitarrays(void)
|
||||
continue;
|
||||
} else {
|
||||
fseek(statesfile, 0, SEEK_END);
|
||||
uint32_t filesize = (uint32_t)ftell(statesfile);
|
||||
int fsize = ftell(statesfile);
|
||||
if ( fsize == -1 ){
|
||||
PrintAndLogEx(WARNING, "File read error with %s. Aborting...\n", state_file_name);
|
||||
fclose(statesfile);
|
||||
exit(5);
|
||||
}
|
||||
uint32_t filesize = (uint32_t)fsize;
|
||||
rewind(statesfile);
|
||||
uint8_t input_buffer[filesize];
|
||||
size_t bytesread = fread(input_buffer, 1, filesize, statesfile);
|
||||
if (bytesread != filesize) {
|
||||
PrintAndLogEx(WARNING, "File read error with %s. Aborting...\n", state_file_name);
|
||||
fclose(statesfile);
|
||||
inflateEnd(&compressed_stream);
|
||||
//inflateEnd(&compressed_stream);
|
||||
exit(5);
|
||||
}
|
||||
fclose(statesfile);
|
||||
@@ -1038,8 +1044,11 @@ static bool shrink_key_space(float *brute_forces)
|
||||
}
|
||||
*brute_forces = MIN(brute_forces1, brute_forces2);
|
||||
float reduction_rate = update_reduction_rate(*brute_forces, false);
|
||||
return ((hardnested_stage & CHECK_2ND_BYTES)
|
||||
&& reduction_rate >= 0.0 && reduction_rate < brute_force_per_second * sample_period / 1000.0);
|
||||
|
||||
//iceman 2018
|
||||
return ((hardnested_stage & CHECK_2ND_BYTES) &&
|
||||
reduction_rate >= 0.0 &&
|
||||
( reduction_rate < brute_force_per_second * (float)sample_period / 1000.0 || *brute_forces < 0x1F00000000));
|
||||
}
|
||||
|
||||
|
||||
@@ -1663,9 +1672,9 @@ static inline bool bitflips_match(uint8_t byte, uint32_t state, odd_even_t odd_e
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1705,11 +1714,13 @@ static bool all_bitflips_match(uint8_t byte, uint32_t state, odd_even_t odd_even
|
||||
#ifdef DEBUG_KEY_ELIMINATION
|
||||
if (known_target_key != -1 && state == test_state[odd_even]) {
|
||||
PrintAndLogEx(NORMAL, "all_bitflips_match() 1st Byte: %s test state (0x%06x): Eliminated. Bytes = %02x, %02x, Common Bits = %d\n",
|
||||
odd_even==ODD_STATE?"odd":"even",
|
||||
odd_even == ODD_STATE ? "odd" : "even",
|
||||
test_state[odd_even],
|
||||
byte, byte2, num_common);
|
||||
byte,
|
||||
byte2,
|
||||
num_common);
|
||||
if (failstr[0] == '\0') {
|
||||
sprintf(failstr, "Other 1st Byte %s, all_bitflips_match(), no match", odd_even?"odd":"even");
|
||||
sprintf(failstr, "Other 1st Byte %s, all_bitflips_match(), no match", odd_even ? "odd" : "even");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1761,12 +1772,10 @@ static void add_matching_states(statelist_t *candidates, uint8_t part_sum_a0, ui
|
||||
uint32_t *bitarray_a8 = part_sum_a8_bitarrays[odd_even][part_sum_a8/2];
|
||||
uint32_t *bitarray_bitflips = nonces[best_first_bytes[0]].states_bitarray[odd_even];
|
||||
|
||||
// for (uint32_t i = 0; i < (1<<19); i++) {
|
||||
// candidates_bitarray[i] = bitarray_a0[i] & bitarray_a8[i] & bitarray_bitflips[i];
|
||||
// }
|
||||
bitarray_AND4(candidates_bitarray, bitarray_a0, bitarray_a8, bitarray_bitflips);
|
||||
|
||||
bitarray_to_list(best_first_bytes[0], candidates_bitarray, candidates->states[odd_even], &(candidates->len[odd_even]), odd_even);
|
||||
|
||||
if (candidates->len[odd_even] == 0) {
|
||||
free(candidates->states[odd_even]);
|
||||
candidates->states[odd_even] = NULL;
|
||||
@@ -1775,17 +1784,14 @@ static void add_matching_states(statelist_t *candidates, uint8_t part_sum_a0, ui
|
||||
}
|
||||
free_bitarray(candidates_bitarray);
|
||||
|
||||
|
||||
pthread_mutex_lock(&statelist_cache_mutex);
|
||||
sl_cache[part_sum_a0/2][part_sum_a8/2][odd_even].sl = candidates->states[odd_even];
|
||||
sl_cache[part_sum_a0/2][part_sum_a8/2][odd_even].len = candidates->len[odd_even];
|
||||
sl_cache[part_sum_a0/2][part_sum_a8/2][odd_even].cache_status = COMPLETED;
|
||||
pthread_mutex_unlock(&statelist_cache_mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static statelist_t *add_more_candidates(void)
|
||||
{
|
||||
statelist_t *new_candidates = candidates;
|
||||
@@ -1879,7 +1885,6 @@ static bool TestIfKeyExists(uint64_t key)
|
||||
|
||||
static work_status_t book_of_work[NUM_PART_SUMS][NUM_PART_SUMS][NUM_PART_SUMS][NUM_PART_SUMS];
|
||||
|
||||
|
||||
static void init_book_of_work(void)
|
||||
{
|
||||
for (uint8_t p = 0; p < NUM_PART_SUMS; p++) {
|
||||
@@ -2043,19 +2048,6 @@ __attribute__((force_align_arg_pointer))
|
||||
|
||||
static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx)
|
||||
{
|
||||
// PrintAndLogEx(NORMAL, "Generating crypto1 state candidates... \n");
|
||||
|
||||
// estimate maximum candidate states
|
||||
// maximum_states = 0;
|
||||
// for (uint16_t sum_odd = 0; sum_odd <= 16; sum_odd += 2) {
|
||||
// for (uint16_t sum_even = 0; sum_even <= 16; sum_even += 2) {
|
||||
// if (sum_odd*(16-sum_even) + (16-sum_odd)*sum_even == sum_a0) {
|
||||
// maximum_states += (uint64_t)count_states(part_sum_a0_bitarrays[EVEN_STATE][sum_even/2])
|
||||
// * count_states(part_sum_a0_bitarrays[ODD_STATE][sum_odd/2]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// PrintAndLogEx(NORMAL, "Number of possible keys with Sum(a0) = %d: %" PRIu64 " (2^%1.1f)\n", sum_a0, maximum_states, log(maximum_states)/log(2.0));
|
||||
|
||||
init_statelist_cache();
|
||||
init_book_of_work();
|
||||
@@ -2102,12 +2094,11 @@ static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx)
|
||||
|
||||
static void free_candidates_memory(statelist_t *sl)
|
||||
{
|
||||
if (sl == NULL) {
|
||||
if (sl == NULL)
|
||||
return;
|
||||
} else {
|
||||
free_candidates_memory(sl->next);
|
||||
free(sl);
|
||||
}
|
||||
|
||||
free_candidates_memory(sl->next);
|
||||
free(sl);
|
||||
}
|
||||
|
||||
|
||||
@@ -2128,7 +2119,6 @@ static void pre_XOR_nonces(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool brute_force(uint64_t *found_key)
|
||||
{
|
||||
@@ -2138,7 +2128,6 @@ static bool brute_force(uint64_t *found_key)
|
||||
return brute_force_bs(NULL, candidates, cuid, num_acquired_nonces, maximum_states, nonces, best_first_bytes, found_key);
|
||||
}
|
||||
|
||||
|
||||
static uint16_t SumProperty(struct Crypto1State *s)
|
||||
{
|
||||
uint16_t sum_odd = PartialSumProperty(s->odd, ODD_STATE);
|
||||
@@ -2214,11 +2203,11 @@ static void set_test_state(uint8_t byte)
|
||||
|
||||
int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *trgkey, bool nonce_file_read, bool nonce_file_write, bool slow, int tests, uint64_t *foundkey, char *filename)
|
||||
{
|
||||
char progress_text[80];
|
||||
|
||||
char progress_text[80];
|
||||
char instr_set[12] = {0};
|
||||
|
||||
get_SIMD_instruction_set(instr_set);
|
||||
PrintAndLog("Using %s SIMD core.", instr_set);
|
||||
PrintAndLogEx(SUCCESS,"Using %s SIMD core.", instr_set);
|
||||
|
||||
srand((unsigned) time(NULL));
|
||||
brute_force_per_second = brute_force_benchmark();
|
||||
@@ -2232,6 +2221,7 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
|
||||
PrintAndLogEx(WARNING, "Could not create/open file hardnested_stats.txt");
|
||||
return 3;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < tests; i++) {
|
||||
start_time = msclock();
|
||||
print_progress_header();
|
||||
@@ -2273,6 +2263,7 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
|
||||
float expected_brute_force1 = (float)num_odd * num_even / 2.0;
|
||||
float expected_brute_force2 = nonces[best_first_bytes[0]].expected_num_brute_force;
|
||||
fprintf(fstats, "%1.1f;%1.1f;", log(expected_brute_force1)/log(2.0), log(expected_brute_force2)/log(2.0));
|
||||
|
||||
if (expected_brute_force1 < expected_brute_force2) {
|
||||
hardnested_print_progress(num_acquired_nonces, "(Ignoring Sum(a8) properties)", expected_brute_force1, 0);
|
||||
set_test_state(best_first_byte_smallest_bitarray);
|
||||
@@ -2282,12 +2273,11 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
|
||||
for (statelist_t *sl = candidates; sl != NULL; sl = sl->next) {
|
||||
maximum_states += (uint64_t)sl->len[ODD_STATE] * sl->len[EVEN_STATE];
|
||||
}
|
||||
//PrintAndLogEx(NORMAL, "Number of remaining possible keys: %" PRIu64 " (2^%1.1f)\n", maximum_states, log(maximum_states)/log(2.0));
|
||||
// fPrintAndLogEx(NORMAL, "fstats, "%" PRIu64 ";", maximum_states);
|
||||
|
||||
best_first_bytes[0] = best_first_byte_smallest_bitarray;
|
||||
pre_XOR_nonces();
|
||||
prepare_bf_test_nonces(nonces, best_first_bytes[0]);
|
||||
//hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force1, 0);
|
||||
|
||||
key_found = brute_force(foundkey);
|
||||
free(candidates->states[ODD_STATE]);
|
||||
free(candidates->states[EVEN_STATE]);
|
||||
@@ -2304,10 +2294,8 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
|
||||
sprintf(progress_text, "(Estimated Sum(a8) is WRONG! Correct Sum(a8) = %" PRIu16 ")", real_sum_a8);
|
||||
hardnested_print_progress(num_acquired_nonces, progress_text, expected_brute_force, 0);
|
||||
}
|
||||
// PrintAndLogEx(NORMAL, "Estimated remaining states: %" PRIu64 " (2^%1.1f)\n", nonces[best_first_bytes[0]].sum_a8_guess[j].num_states, log(nonces[best_first_bytes[0]].sum_a8_guess[j].num_states)/log(2.0));
|
||||
generate_candidates(first_byte_Sum, nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx);
|
||||
// PrintAndLogEx(NORMAL, "Time for generating key candidates list: %1.0f sec (%1.1f sec CPU)\n", difftime(time(NULL), start_time), (float)(msclock() - start_clock)/1000.0);
|
||||
//hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force, 0);
|
||||
|
||||
key_found = brute_force(foundkey);
|
||||
free_statelist_cache();
|
||||
free_candidates_memory(candidates);
|
||||
@@ -2390,40 +2378,43 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
|
||||
uint32_t num_even = nonces[best_first_byte_smallest_bitarray].num_states_bitarray[EVEN_STATE];
|
||||
float expected_brute_force1 = (float)num_odd * num_even / 2.0;
|
||||
float expected_brute_force2 = nonces[best_first_bytes[0]].expected_num_brute_force;
|
||||
|
||||
if (expected_brute_force1 < expected_brute_force2) {
|
||||
hardnested_print_progress(num_acquired_nonces, "(Ignoring Sum(a8) properties)", expected_brute_force1, 0);
|
||||
set_test_state(best_first_byte_smallest_bitarray);
|
||||
add_bitflip_candidates(best_first_byte_smallest_bitarray);
|
||||
Tests2();
|
||||
maximum_states = 0;
|
||||
|
||||
for (statelist_t *sl = candidates; sl != NULL; sl = sl->next) {
|
||||
maximum_states += (uint64_t)sl->len[ODD_STATE] * sl->len[EVEN_STATE];
|
||||
}
|
||||
// PrintAndLogEx(NORMAL, "Number of remaining possible keys: %" PRIu64 " (2^%1.1f)\n", maximum_states, log(maximum_states)/log(2.0));
|
||||
|
||||
best_first_bytes[0] = best_first_byte_smallest_bitarray;
|
||||
pre_XOR_nonces();
|
||||
prepare_bf_test_nonces(nonces, best_first_bytes[0]);
|
||||
//hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force1, 0);
|
||||
|
||||
key_found = brute_force(foundkey);
|
||||
free(candidates->states[ODD_STATE]);
|
||||
free(candidates->states[EVEN_STATE]);
|
||||
free_candidates_memory(candidates);
|
||||
candidates = NULL;
|
||||
} else {
|
||||
|
||||
pre_XOR_nonces();
|
||||
prepare_bf_test_nonces(nonces, best_first_bytes[0]);
|
||||
|
||||
for (uint8_t j = 0; j < NUM_SUMS && !key_found; j++) {
|
||||
float expected_brute_force = nonces[best_first_bytes[0]].expected_num_brute_force;
|
||||
sprintf(progress_text, "(%d. guess: Sum(a8) = %" PRIu16 ")", j+1, sums[nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx]);
|
||||
hardnested_print_progress(num_acquired_nonces, progress_text, expected_brute_force, 0);
|
||||
|
||||
if (trgkey != NULL && sums[nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx] != real_sum_a8) {
|
||||
sprintf(progress_text, "(Estimated Sum(a8) is WRONG! Correct Sum(a8) = %" PRIu16 ")", real_sum_a8);
|
||||
hardnested_print_progress(num_acquired_nonces, progress_text, expected_brute_force, 0);
|
||||
}
|
||||
// PrintAndLogEx(NORMAL, "Estimated remaining states: %" PRIu64 " (2^%1.1f)\n", nonces[best_first_bytes[0]].sum_a8_guess[j].num_states, log(nonces[best_first_bytes[0]].sum_a8_guess[j].num_states)/log(2.0));
|
||||
|
||||
generate_candidates(first_byte_Sum, nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx);
|
||||
// PrintAndLogEx(NORMAL, "Time for generating key candidates list: %1.0f sec (%1.1f sec CPU)\n", difftime(time(NULL), start_time), (float)(msclock() - start_clock)/1000.0);
|
||||
//hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force, 0);
|
||||
key_found = brute_force(foundkey);
|
||||
free_statelist_cache();
|
||||
free_candidates_memory(candidates);
|
||||
|
||||
+109
-108
@@ -22,109 +22,15 @@
|
||||
#include "ui.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "mifare.h"
|
||||
#include "mifare4.h"
|
||||
#include "mifare/mifare4.h"
|
||||
#include "mifare/mad.h"
|
||||
#include "cliparser/cliparser.h"
|
||||
#include "crypto/libpcrypto.h"
|
||||
|
||||
static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
typedef struct {
|
||||
uint8_t Code;
|
||||
const char *Description;
|
||||
} PlusErrorsElm;
|
||||
|
||||
static const PlusErrorsElm PlusErrors[] = {
|
||||
{0xFF, ""},
|
||||
{0x00, "Transfer cannot be granted within the current authentication."},
|
||||
{0x06, "Access Conditions not fulfilled. Block does not exist, block is not a value block."},
|
||||
{0x07, "Too many read or write commands in the session or in the transaction."},
|
||||
{0x08, "Invalid MAC in command or response"},
|
||||
{0x09, "Block Number is not valid"},
|
||||
{0x0a, "Invalid block number, not existing block number"},
|
||||
{0x0b, "The current command code not available at the current card state."},
|
||||
{0x0c, "Length error"},
|
||||
{0x0f, "General Manipulation Error. Failure in the operation of the PICC (cannot write to the data block), etc."},
|
||||
{0x90, "OK"},
|
||||
};
|
||||
int PlusErrorsLen = sizeof(PlusErrors) / sizeof(PlusErrorsElm);
|
||||
|
||||
const char * GetErrorDescription(uint8_t errorCode) {
|
||||
for(int i = 0; i < PlusErrorsLen; i++)
|
||||
if (errorCode == PlusErrors[i].Code)
|
||||
return PlusErrors[i].Description;
|
||||
|
||||
return PlusErrors[0].Description;
|
||||
}
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static bool VerboseMode = false;
|
||||
void SetVerboseMode(bool verbose) {
|
||||
VerboseMode = verbose;
|
||||
}
|
||||
|
||||
int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
if(VerboseMode)
|
||||
PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen));
|
||||
|
||||
int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
|
||||
if(VerboseMode)
|
||||
PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00};
|
||||
memmove(&rcmd[3], key, 16);
|
||||
|
||||
return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
}
|
||||
|
||||
int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
uint8_t rcmd[1] = {0xaa};
|
||||
|
||||
return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
}
|
||||
|
||||
int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
||||
uint8_t rcmd[4 + 8] = {(plain?(0x37):(0x33)), blockNum, 0x00, blockCount};
|
||||
if (!plain && session)
|
||||
CalculateMAC(session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode);
|
||||
|
||||
int res = intExchangeRAW14aPlus(rcmd, plain?4:sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
if(res)
|
||||
return res;
|
||||
|
||||
if (session)
|
||||
session->R_Ctr++;
|
||||
|
||||
if(session && mac && *dataoutlen > 11)
|
||||
CalculateMAC(session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
||||
uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00};
|
||||
memmove(&rcmd[3], data, 16);
|
||||
if (session)
|
||||
CalculateMAC(session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode);
|
||||
|
||||
int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
if(res)
|
||||
return res;
|
||||
|
||||
if (session)
|
||||
session->W_Ctr++;
|
||||
|
||||
if(session && mac && *dataoutlen > 3)
|
||||
CalculateMAC(session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdHFMFPInfo(const char *cmd) {
|
||||
|
||||
if (cmd && strlen(cmd) > 0)
|
||||
@@ -229,7 +135,7 @@ int CmdHFMFPWritePerso(const char *cmd) {
|
||||
CLIGetHexWithReturn(3, key, &keyLen);
|
||||
CLIParserFree();
|
||||
|
||||
SetVerboseMode(verbose);
|
||||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keyLen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
@@ -260,7 +166,7 @@ int CmdHFMFPWritePerso(const char *cmd) {
|
||||
}
|
||||
|
||||
if (data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Command error: %02x %s", data[0], GetErrorDescription(data[0]));
|
||||
PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
|
||||
return 1;
|
||||
}
|
||||
PrintAndLogEx(INFO, "Write OK.");
|
||||
@@ -304,7 +210,7 @@ int CmdHFMFPInitPerso(const char *cmd) {
|
||||
if (!keyLen)
|
||||
memmove(key, DefaultKey, 16);
|
||||
|
||||
SetVerboseMode(verbose2);
|
||||
mfpSetVerboseMode(verbose2);
|
||||
for (uint16_t sn = 0x4000; sn < 0x4050; sn++) {
|
||||
keyNum[0] = sn >> 8;
|
||||
keyNum[1] = sn & 0xff;
|
||||
@@ -319,7 +225,7 @@ int CmdHFMFPInitPerso(const char *cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
SetVerboseMode(verbose);
|
||||
mfpSetVerboseMode(verbose);
|
||||
for (int i = 0; i < sizeof(CardAddresses) / 2; i++) {
|
||||
keyNum[0] = CardAddresses[i] >> 8;
|
||||
keyNum[1] = CardAddresses[i] & 0xff;
|
||||
@@ -360,7 +266,7 @@ int CmdHFMFPCommitPerso(const char *cmd) {
|
||||
bool verbose = arg_get_lit(1);
|
||||
CLIParserFree();
|
||||
|
||||
SetVerboseMode(verbose);
|
||||
mfpSetVerboseMode(verbose);
|
||||
|
||||
uint8_t data[250] = {0};
|
||||
int datalen = 0;
|
||||
@@ -377,7 +283,7 @@ int CmdHFMFPCommitPerso(const char *cmd) {
|
||||
}
|
||||
|
||||
if (data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Command error: %02x %s", data[0], GetErrorDescription(data[0]));
|
||||
PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
|
||||
return 1;
|
||||
}
|
||||
PrintAndLogEx(INFO, "Switch level OK.");
|
||||
@@ -453,7 +359,7 @@ int CmdHFMFPRdbl(const char *cmd) {
|
||||
CLIGetHexWithReturn(6, key, &keylen);
|
||||
CLIParserFree();
|
||||
|
||||
SetVerboseMode(verbose);
|
||||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keylen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
@@ -504,7 +410,7 @@ int CmdHFMFPRdbl(const char *cmd) {
|
||||
}
|
||||
|
||||
if (datalen && data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Card read error: %02x %s", data[0], GetErrorDescription(data[0]));
|
||||
PrintAndLogEx(ERR, "Card read error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
|
||||
return 6;
|
||||
}
|
||||
|
||||
@@ -563,7 +469,7 @@ int CmdHFMFPRdsc(const char *cmd) {
|
||||
CLIGetHexWithReturn(5, key, &keylen);
|
||||
CLIParserFree();
|
||||
|
||||
SetVerboseMode(verbose);
|
||||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keylen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
@@ -605,7 +511,7 @@ int CmdHFMFPRdsc(const char *cmd) {
|
||||
}
|
||||
|
||||
if (datalen && data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Card read error: %02x %s", data[0], GetErrorDescription(data[0]));
|
||||
PrintAndLogEx(ERR, "Card read error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
|
||||
DropField();
|
||||
return 6;
|
||||
}
|
||||
@@ -661,7 +567,7 @@ int CmdHFMFPWrbl(const char *cmd) {
|
||||
CLIGetHexWithReturn(5, key, &keylen);
|
||||
CLIParserFree();
|
||||
|
||||
SetVerboseMode(verbose);
|
||||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keylen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
@@ -714,7 +620,7 @@ int CmdHFMFPWrbl(const char *cmd) {
|
||||
}
|
||||
|
||||
if (datalen && data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Card write error: %02x %s", data[0], GetErrorDescription(data[0]));
|
||||
PrintAndLogEx(ERR, "Card write error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
|
||||
DropField();
|
||||
return 6;
|
||||
}
|
||||
@@ -733,6 +639,100 @@ int CmdHFMFPWrbl(const char *cmd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdHFMFPMAD(const char *cmd) {
|
||||
|
||||
CLIParserInit("hf mfp mad",
|
||||
"Checks and prints Mifare Application Directory (MAD)",
|
||||
"Usage:\n\thf mfp mad -> shows MAD if exists\n"
|
||||
"\thf mfp mad -a 03e1 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data if exists\n");
|
||||
|
||||
void* argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("vV", "verbose", "show technical data"),
|
||||
arg_str0("aA", "aid", "print all sectors with aid", NULL),
|
||||
arg_str0("kK", "key", "key for printing sectors", NULL),
|
||||
arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(cmd, argtable, true);
|
||||
|
||||
bool verbose = arg_get_lit(1);
|
||||
uint8_t aid[2] = {0};
|
||||
int aidlen;
|
||||
CLIGetHexWithReturn(2, aid, &aidlen);
|
||||
uint8_t key[16] = {0};
|
||||
int keylen;
|
||||
CLIGetHexWithReturn(3, key, &keylen);
|
||||
bool keyB = arg_get_lit(4);
|
||||
|
||||
CLIParserFree();
|
||||
|
||||
if (aidlen != 2 && keylen > 0) {
|
||||
PrintAndLogEx(WARNING, "do not need a key without aid.");
|
||||
}
|
||||
|
||||
uint8_t sector0[16 * 4] = {0};
|
||||
uint8_t sector10[16 * 4] = {0};
|
||||
|
||||
if (mfpReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector0, verbose)) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
for(int i = 0; i < 4; i ++)
|
||||
PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16));
|
||||
}
|
||||
|
||||
bool haveMAD2 = false;
|
||||
MAD1DecodeAndPrint(sector0, verbose, &haveMAD2);
|
||||
|
||||
if (haveMAD2) {
|
||||
if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
MAD2DecodeAndPrint(sector10, verbose);
|
||||
}
|
||||
|
||||
if (aidlen == 2) {
|
||||
uint16_t aaid = (aid[0] << 8) + aid[1];
|
||||
PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid);
|
||||
|
||||
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
|
||||
size_t madlen = 0;
|
||||
if (MADDecode(sector0, sector10, mad, &madlen)) {
|
||||
PrintAndLogEx(ERR, "can't decode mad.");
|
||||
return 10;
|
||||
}
|
||||
|
||||
uint8_t akey[16] = {0};
|
||||
memcpy(akey, g_mifarep_ndef_key, 16);
|
||||
if (keylen == 16) {
|
||||
memcpy(akey, key, 16);
|
||||
}
|
||||
|
||||
for (int i = 0; i < madlen; i++) {
|
||||
if (aaid == mad[i]) {
|
||||
uint8_t vsector[16 * 4] = {0};
|
||||
if (mfpReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector, false)) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(ERR, "read sector %d error.", i + 1);
|
||||
return 2;
|
||||
}
|
||||
|
||||
for(int j = 0; j < (verbose ? 4 : 3); j ++)
|
||||
PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] =
|
||||
{
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
@@ -744,6 +744,7 @@ static command_t CommandTable[] =
|
||||
{"rdbl", CmdHFMFPRdbl, 0, "Read blocks"},
|
||||
{"rdsc", CmdHFMFPRdsc, 0, "Read sectors"},
|
||||
{"wrbl", CmdHFMFPWrbl, 0, "Write blocks"},
|
||||
{"mad", CmdHFMFPMAD, 0, "Checks and prints MAD"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
#ifndef CMDHFMFP_H__
|
||||
#define CMDHFMFP_H__
|
||||
|
||||
#include "mifaredefault.h"
|
||||
#include "mifare/mifaredefault.h"
|
||||
|
||||
extern int CmdHFMFP(const char *Cmd);
|
||||
|
||||
|
||||
+50
-46
@@ -980,11 +980,11 @@ int CmdHF14AMfUInfo(const char *Cmd){
|
||||
if ( hasAuthKey ) return 1;
|
||||
|
||||
// also try to diversify default keys.. look into CmdHF14AMfuGenDiverseKeys
|
||||
PrintAndLogEx(NORMAL, "Trying some default 3des keys");
|
||||
PrintAndLogEx(INFO, "Trying some default 3des keys");
|
||||
for (uint8_t i = 0; i < KEYS_3DES_COUNT; ++i ) {
|
||||
key = default_3des_keys[i];
|
||||
if (ulc_authentication(key, true)) {
|
||||
PrintAndLogEx(NORMAL, "Found default 3des key: ");
|
||||
PrintAndLogEx(SUCCESS, "Found default 3des key: ");
|
||||
uint8_t keySwap[16];
|
||||
memcpy(keySwap, SwapEndian64(key,16,8), 16);
|
||||
ulc_print_3deskey(keySwap);
|
||||
@@ -1079,7 +1079,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
|
||||
num_to_bytes( ul_ev1_pwdgenA(card.uid), 4, key);
|
||||
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
||||
if (len > -1) {
|
||||
PrintAndLogEx(NORMAL, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]);
|
||||
PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1089,7 +1089,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
|
||||
num_to_bytes( ul_ev1_pwdgenB(card.uid), 4, key);
|
||||
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
||||
if (len > -1) {
|
||||
PrintAndLogEx(NORMAL, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]);
|
||||
PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1099,7 +1099,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
|
||||
num_to_bytes( ul_ev1_pwdgenC(card.uid), 4, key);
|
||||
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
||||
if (len > -1) {
|
||||
PrintAndLogEx(NORMAL, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]);
|
||||
PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1109,7 +1109,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
|
||||
num_to_bytes( ul_ev1_pwdgenD(card.uid), 4, key);
|
||||
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
||||
if (len > -1) {
|
||||
PrintAndLogEx(NORMAL, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]);
|
||||
PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1119,13 +1119,13 @@ int CmdHF14AMfUInfo(const char *Cmd){
|
||||
key = default_pwd_pack[i];
|
||||
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
||||
if (len > -1) {
|
||||
PrintAndLogEx(NORMAL, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]);
|
||||
PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]);
|
||||
break;
|
||||
} else {
|
||||
if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1;
|
||||
}
|
||||
}
|
||||
if (len < 1) PrintAndLogEx(NORMAL, "password not known");
|
||||
if (len < 1) PrintAndLogEx(WARNING, "password not known");
|
||||
}
|
||||
}
|
||||
out:
|
||||
@@ -1250,7 +1250,7 @@ int CmdHF14AMfUWrBl(const char *Cmd){
|
||||
UsbCommand resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
uint8_t isOK = resp.arg[0] & 0xff;
|
||||
PrintAndLogEx(NORMAL, "isOk:%02x", isOK);
|
||||
PrintAndLogEx(SUCCESS, "isOk:%02x", isOK);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||
}
|
||||
@@ -1365,7 +1365,7 @@ int CmdHF14AMfURdBl(const char *Cmd){
|
||||
PrintAndLogEx(WARNING, "Failed reading block: (%02x)", isOK);
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "Command execute time-out");
|
||||
PrintAndLogEx(WARNING, "Command execute time-out");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1743,7 +1743,7 @@ int CmdHF14AMfUDump(const char *Cmd){
|
||||
}
|
||||
}
|
||||
ul_print_type(tagtype, 0);
|
||||
PrintAndLogEx(NORMAL, "Reading tag memory...");
|
||||
PrintAndLogEx(SUCCESS, "Reading tag memory...");
|
||||
UsbCommand c = {CMD_MIFAREU_READCARD, {startPage, pages}};
|
||||
if ( hasAuthKey ) {
|
||||
if (tagtype & UL_C)
|
||||
@@ -1912,12 +1912,10 @@ int CmdHF14AMfURestore(const char *Cmd){
|
||||
memset(authkey, 0x00, sizeof(authkey));
|
||||
|
||||
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch(param_getchar(Cmd, cmdp)) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
return usage_hf_mfu_restore();
|
||||
case 'k':
|
||||
case 'K':
|
||||
keylen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
|
||||
if (keylen == 32 || keylen == 8) { //ul-c or ev1/ntag key length
|
||||
errors = param_gethex(tempStr, 0, authkey, keylen);
|
||||
@@ -1930,12 +1928,10 @@ int CmdHF14AMfURestore(const char *Cmd){
|
||||
hasKey = true;
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
swapEndian = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'f':
|
||||
case 'F':
|
||||
filelen = param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE);
|
||||
|
||||
if (filelen > FILE_PATH_SIZE-5)
|
||||
@@ -1947,17 +1943,14 @@ int CmdHF14AMfURestore(const char *Cmd){
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 's':
|
||||
case 'S':
|
||||
cmdp++;
|
||||
write_special = true;
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
cmdp++;
|
||||
write_extra = true;
|
||||
break;
|
||||
case 'r':
|
||||
case 'R':
|
||||
cmdp++;
|
||||
read_key = true;
|
||||
break;
|
||||
@@ -1972,7 +1965,7 @@ int CmdHF14AMfURestore(const char *Cmd){
|
||||
if (errors || cmdp == 0) return usage_hf_mfu_restore();
|
||||
|
||||
if ((f = fopen(filename,"rb")) == NULL) {
|
||||
PrintAndLogEx(WARNING, "Could not find file %s", filename);
|
||||
PrintAndLogEx(WARNING, "Could not find file " _YELLOW_(%s), filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1989,6 +1982,7 @@ int CmdHF14AMfURestore(const char *Cmd){
|
||||
uint8_t *dump = calloc(fsize, sizeof(uint8_t));
|
||||
if ( !dump ) {
|
||||
PrintAndLogEx(WARNING, "Failed to allocate memory");
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1997,10 +1991,11 @@ int CmdHF14AMfURestore(const char *Cmd){
|
||||
fclose(f);
|
||||
if ( bytes_read < 48 ) {
|
||||
PrintAndLogEx(WARNING, "Error, dump file is too small");
|
||||
free(dump);
|
||||
return 1;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Restoring %s to card", filename);
|
||||
PrintAndLogEx(INFO, "Restoring " _YELLOW_(%s)" to card", filename);
|
||||
|
||||
mfu_dump_t *mem = (mfu_dump_t*)dump;
|
||||
uint8_t pages = (bytes_read-48)/4;
|
||||
@@ -2084,7 +2079,7 @@ int CmdHF14AMfURestore(const char *Cmd){
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Restoring data blocks.");
|
||||
PrintAndLogEx(INFO, "Restoring data blocks.");
|
||||
// write all other data
|
||||
// Skip block 0,1,2,3 (only magic tags can write to them)
|
||||
// Skip last 5 blocks usually is configuration
|
||||
@@ -2103,7 +2098,7 @@ int CmdHF14AMfURestore(const char *Cmd){
|
||||
// write special data last
|
||||
if (write_special) {
|
||||
|
||||
PrintAndLogEx(NORMAL, "Restoring configuration blocks.\n");
|
||||
PrintAndLogEx(INFO, "Restoring configuration blocks.\n");
|
||||
|
||||
PrintAndLogEx(NORMAL, "authentication with keytype[%x] %s\n", (uint8_t)(c.arg[1] & 0xff), sprint_hex(p_authkey,4));
|
||||
|
||||
@@ -2128,16 +2123,16 @@ int CmdHF14AMfURestore(const char *Cmd){
|
||||
// Load emulator with dump file
|
||||
//
|
||||
int CmdHF14AMfUeLoad(const char *Cmd){
|
||||
char c = param_getchar(Cmd, 0);
|
||||
if ( c == 'h' || c == 'H' || c == 0x00) return usage_hf_mfu_eload();
|
||||
char c = tolower(param_getchar(Cmd, 0));
|
||||
if ( c == 'h' || c == 0x00) return usage_hf_mfu_eload();
|
||||
return CmdHF14AMfELoad(Cmd);
|
||||
}
|
||||
//
|
||||
// Simulate tag
|
||||
//
|
||||
int CmdHF14AMfUSim(const char *Cmd){
|
||||
char c = param_getchar(Cmd, 0);
|
||||
if ( c == 'h' || c == 'H' || c == 0x00) return usage_hf_mfu_sim();
|
||||
char c = tolower(param_getchar(Cmd, 0));
|
||||
if ( c == 'h' || c == 0x00) return usage_hf_mfu_sim();
|
||||
return CmdHF14ASim(Cmd);
|
||||
}
|
||||
|
||||
@@ -2153,16 +2148,16 @@ int CmdHF14AMfucAuth(const char *Cmd){
|
||||
uint8_t keyNo = 3;
|
||||
bool errors = false;
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
|
||||
//Change key to user defined one
|
||||
if (cmdp == 'k' || cmdp == 'K'){
|
||||
if (cmdp == 'k'){
|
||||
keyNo = param_get8(Cmd, 1);
|
||||
if(keyNo >= KEYS_3DES_COUNT)
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (cmdp == 'h' || cmdp == 'H') errors = true;
|
||||
if (cmdp == 'h') errors = true;
|
||||
|
||||
if (errors) return usage_hf_mfu_ucauth();
|
||||
|
||||
@@ -2278,9 +2273,9 @@ int CmdTestDES(const char * cmd)
|
||||
int CmdHF14AMfucSetPwd(const char *Cmd){
|
||||
|
||||
uint8_t pwd[16] = {0x00};
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_hf_mfu_ucsetpwd();
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_ucsetpwd();
|
||||
|
||||
if (param_gethex(Cmd, 0, pwd, 32)) {
|
||||
PrintAndLogEx(WARNING, "Password must include 32 HEX symbols");
|
||||
@@ -2295,7 +2290,7 @@ int CmdHF14AMfucSetPwd(const char *Cmd){
|
||||
UsbCommand resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK,&resp,1500) ) {
|
||||
if ( (resp.arg[0] & 0xff) == 1) {
|
||||
PrintAndLogEx(NORMAL, "Ultralight-C new password: %s", sprint_hex(pwd,16));
|
||||
PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd,16));
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Failed writing at block %d", resp.arg[1] & 0xff);
|
||||
return 1;
|
||||
@@ -2315,9 +2310,9 @@ int CmdHF14AMfucSetUid(const char *Cmd){
|
||||
UsbCommand c = {CMD_MIFAREU_READBL};
|
||||
UsbCommand resp;
|
||||
uint8_t uid[7] = {0x00};
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_hf_mfu_ucsetuid();
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_ucsetuid();
|
||||
|
||||
if (param_gethex(Cmd, 0, uid, 14)) {
|
||||
PrintAndLogEx(WARNING, "UID must include 14 HEX symbols");
|
||||
@@ -2386,7 +2381,7 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_gendiverse();
|
||||
|
||||
if ( cmdp == 'r' ) {
|
||||
// read uid from tag
|
||||
// read uid from tag
|
||||
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0}};
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
@@ -2395,8 +2390,13 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
|
||||
iso14a_card_select_t card;
|
||||
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
|
||||
|
||||
uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
|
||||
if(select_status == 0) {
|
||||
uint64_t select_status = resp.arg[0];
|
||||
// 0: couldn't read,
|
||||
// 1: OK, with ATS
|
||||
// 2: OK, no ATS
|
||||
// 3: proprietary Anticollision
|
||||
|
||||
if ( select_status == 0 ) {
|
||||
PrintAndLogEx(WARNING, "iso14443a card select failed");
|
||||
return 1;
|
||||
}
|
||||
@@ -2451,12 +2451,12 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
|
||||
PrintAndLogEx(NORMAL, "Diversified key: %s", sprint_hex(divkey+1, 6));
|
||||
|
||||
for (int i=0; i < sizeof(mifarekeyA); ++i){
|
||||
dkeyA[i] = (mifarekeyA[i] << 1) & 0xff;
|
||||
dkeyA[6] |= ((mifarekeyA[i] >> 7) & 1) << (i+1);
|
||||
dkeyA[i] = (mifarekeyA[i] << 1) & 0xff;
|
||||
dkeyA[6] |= ((mifarekeyA[i] >> 7) & 1) << (i+1);
|
||||
}
|
||||
|
||||
for (int i=0; i < sizeof(mifarekeyB); ++i){
|
||||
dkeyB[1] |= ((mifarekeyB[i] >> 7) & 1) << (i+1);
|
||||
dkeyB[1] |= ((mifarekeyB[i] >> 7) & 1) << (i+1);
|
||||
dkeyB[2+i] = (mifarekeyB[i] << 1) & 0xff;
|
||||
}
|
||||
|
||||
@@ -2493,6 +2493,7 @@ int CmdHF14AMfuPwdGen(const char *Cmd){
|
||||
uint8_t uid[7] = {0x00};
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_pwdgen();
|
||||
|
||||
if (cmdp == 't') return ul_ev1_pwdgen_selftest();
|
||||
|
||||
if ( cmdp == 'r') {
|
||||
@@ -2505,8 +2506,12 @@ int CmdHF14AMfuPwdGen(const char *Cmd){
|
||||
iso14a_card_select_t card;
|
||||
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
|
||||
|
||||
uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
|
||||
if(select_status == 0) {
|
||||
uint64_t select_status = resp.arg[0];
|
||||
// 0: couldn't read
|
||||
// 1: OK with ATS
|
||||
// 2: OK, no ATS
|
||||
// 3: proprietary Anticollision
|
||||
if ( select_status == 0 ) {
|
||||
PrintAndLogEx(WARNING, "iso14443a card select failed");
|
||||
return 1;
|
||||
}
|
||||
@@ -2519,6 +2524,7 @@ int CmdHF14AMfuPwdGen(const char *Cmd){
|
||||
else {
|
||||
if (param_gethex(Cmd, 0, uid, 14)) return usage_hf_mfu_pwdgen();
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "---------------------------------");
|
||||
PrintAndLogEx(NORMAL, " Using UID : %s", sprint_hex(uid, 7));
|
||||
PrintAndLogEx(NORMAL, "---------------------------------");
|
||||
@@ -2536,8 +2542,7 @@ int CmdHF14AMfuPwdGen(const char *Cmd){
|
||||
//------------------------------------
|
||||
// Menu Stuff
|
||||
//------------------------------------
|
||||
static command_t CommandTable[] =
|
||||
{
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
{"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"},
|
||||
{"info", CmdHF14AMfUInfo, 0, "Tag information"},
|
||||
@@ -2557,7 +2562,6 @@ static command_t CommandTable[] =
|
||||
|
||||
int CmdHFMFUltra(const char *Cmd){
|
||||
clearCommandBuffer();
|
||||
//WaitForResponseTimeout(CMD_ACK,NULL,100);
|
||||
CmdsParse(CommandTable, Cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+3
-3
@@ -194,7 +194,7 @@ static int topaz_print_CC(uint8_t *data) {
|
||||
PrintAndLogEx(NORMAL, " %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f);
|
||||
uint16_t memsize = (data[2] + 1) * 8;
|
||||
topaz_tag.size = memsize;
|
||||
topaz_tag.dynamic_memory = malloc(memsize - TOPAZ_STATIC_MEMORY);
|
||||
topaz_tag.dynamic_memory = calloc(memsize - TOPAZ_STATIC_MEMORY, sizeof(uint8_t));
|
||||
PrintAndLogEx(NORMAL, " %02x: Physical Memory Size of this tag: %d bytes", data[2], memsize);
|
||||
PrintAndLogEx(NORMAL, " %02x: %s / %s", data[3],
|
||||
(data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security",
|
||||
@@ -278,12 +278,12 @@ static void topaz_print_control_TLVs(uint8_t *memory) {
|
||||
dynamic_lock_area_t *old = topaz_tag.dynamic_lock_areas;
|
||||
dynamic_lock_area_t *new = topaz_tag.dynamic_lock_areas;
|
||||
if (old == NULL) {
|
||||
new = topaz_tag.dynamic_lock_areas = (dynamic_lock_area_t *)malloc(sizeof(dynamic_lock_area_t));
|
||||
new = topaz_tag.dynamic_lock_areas = (dynamic_lock_area_t *) calloc(sizeof(dynamic_lock_area_t) , sizeof(uint8_t));
|
||||
} else {
|
||||
while(old->next != NULL) {
|
||||
old = old->next;
|
||||
}
|
||||
new = old->next = (dynamic_lock_area_t *)malloc(sizeof(dynamic_lock_area_t));
|
||||
new = old->next = (dynamic_lock_area_t *) calloc(sizeof(dynamic_lock_area_t), sizeof(uint8_t));
|
||||
}
|
||||
new->next = NULL;
|
||||
if (area_start <= next_lockable_byte) {
|
||||
|
||||
+4
-4
@@ -74,7 +74,7 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) {
|
||||
if ( mem_avail > 0 )
|
||||
mem_left = (mem_avail * 1024) - mem_used;
|
||||
|
||||
PrintAndLogEx(NORMAL, " --= Nonvolatile Program Memory Size: %uK bytes, Used: %u bytes (%2.0f\%) Free: %u bytes (%2.0f\%)",
|
||||
PrintAndLogEx(NORMAL, " --= Nonvolatile Program Memory Size: %uK bytes, Used: %u bytes (%2.0f%%) Free: %u bytes (%2.0f%%)",
|
||||
mem_avail,
|
||||
mem_used,
|
||||
mem_avail == 0 ? 0.0f : (float)mem_used/(mem_avail*1024)*100,
|
||||
@@ -257,9 +257,9 @@ int CmdVersion(const char *Cmd) {
|
||||
SendCommand(&c);
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
|
||||
#ifdef __WIN32
|
||||
PrintAndLogEx(NORMAL, "\nProxmark3 RFID instrument\n");
|
||||
PrintAndLogEx(NORMAL, "\n [ Proxmark3 RFID instrument ]\n");
|
||||
#else
|
||||
PrintAndLogEx(NORMAL, "\n\e[34mProxmark3 RFID instrument\e[0m\n");
|
||||
PrintAndLogEx(NORMAL, "\n\e[34m [ Proxmark3 RFID instrument ]\e[0m\n");
|
||||
#endif
|
||||
char s[50] = {0};
|
||||
#if defined(WITH_FLASH) || defined(WITH_SMARTCARD) || defined(WITH_FPC)
|
||||
@@ -275,7 +275,7 @@ int CmdVersion(const char *Cmd) {
|
||||
strncat(s, "fpc; ", sizeof(s) - strlen(s) - 1);
|
||||
#endif
|
||||
PrintAndLogEx(NORMAL, "\n [ CLIENT ]");
|
||||
PrintAndLogEx(NORMAL, " client: iceman %s \n", s);
|
||||
PrintAndLogEx(NORMAL, " client: iceman %s \n", s);
|
||||
|
||||
PrintAndLogEx(NORMAL, (char*)resp.d.asBytes);
|
||||
lookupChipID(resp.arg[0], resp.arg[1]);
|
||||
|
||||
+22
-11
@@ -186,15 +186,21 @@ int CmdLFCommandRead(const char *Cmd) {
|
||||
}
|
||||
|
||||
int CmdFlexdemod(const char *Cmd) {
|
||||
#define LONG_WAIT 100
|
||||
|
||||
if ( GraphTraceLen < 0 )
|
||||
return 0;
|
||||
|
||||
#ifndef LONG_WAIT
|
||||
#define LONG_WAIT 100
|
||||
#endif
|
||||
int i, j, start, bit, sum, phase = 0;
|
||||
|
||||
uint8_t data[MAX_GRAPH_TRACE_LEN] = {0};
|
||||
size_t size = getFromGraphBuf(data);
|
||||
if (size == 0)
|
||||
return 0;
|
||||
int data[GraphTraceLen];
|
||||
memcpy(data, GraphBuffer, GraphTraceLen);
|
||||
|
||||
for (i = 0; i < size; ++i)
|
||||
size_t size = GraphTraceLen;
|
||||
|
||||
for (i = 0; i < GraphTraceLen; ++i)
|
||||
data[i] = (data[i] < 0) ? -1 : 1;
|
||||
|
||||
for (start = 0; start < size - LONG_WAIT; start++) {
|
||||
@@ -819,14 +825,16 @@ int CheckChipType(bool getDeviceData) {
|
||||
//check for em4x05/em4x69 chips first
|
||||
uint32_t word = 0;
|
||||
if (EM4x05IsBlock0(&word)) {
|
||||
PrintAndLogEx(NORMAL, "\nValid EM4x05/EM4x69 Chip Found\nTry lf em 4x05... commands\n");
|
||||
PrintAndLogEx(SUCCESS, "\nValid EM4x05/EM4x69 Chip Found");
|
||||
PrintAndLogEx(SUCCESS, "Try " _YELLOW_(`lf em 4x05`) " commands");
|
||||
save_restoreGB(GRAPH_RESTORE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//check for t55xx chip...
|
||||
if (tryDetectP1(true)) {
|
||||
PrintAndLogEx(NORMAL, "\nValid T55xx Chip Found\nTry `lf t55xx` commands\n");
|
||||
PrintAndLogEx(SUCCESS, "\nValid T55xx Chip Found");
|
||||
PrintAndLogEx(SUCCESS, "Try " _YELLOW_(`lf t55xx`)" commands");
|
||||
save_restoreGB(GRAPH_RESTORE);
|
||||
return 1;
|
||||
}
|
||||
@@ -856,9 +864,10 @@ int CmdLFfind(const char *Cmd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "NOTE: some demods output possible binary\n if it finds something that looks like a tag");
|
||||
PrintAndLogEx(NORMAL, "False Positives ARE possible\n");
|
||||
PrintAndLogEx(NORMAL, "\nChecking for known tags:\n");
|
||||
PrintAndLogEx(INFO, "NOTE: some demods output possible binary");
|
||||
PrintAndLogEx(INFO, "if it finds something that looks like a tag");
|
||||
PrintAndLogEx(INFO, "False Positives " _YELLOW_(ARE) "possible\n");
|
||||
PrintAndLogEx(INFO, "\nChecking for known tags:\n");
|
||||
|
||||
// only run these tests if device is online
|
||||
if (isOnline) {
|
||||
@@ -891,6 +900,7 @@ int CmdLFfind(const char *Cmd) {
|
||||
if (CmdLFNedapDemod("")) { PrintAndLogEx(SUCCESS, "\nValid NEDAP ID Found!"); goto out;}
|
||||
if (CmdNexWatchDemod("")) { PrintAndLogEx(SUCCESS, "\nValid NexWatch ID Found!"); goto out;}
|
||||
if (CmdNoralsyDemod("")) { PrintAndLogEx(SUCCESS, "\nValid Noralsy ID Found!"); goto out;}
|
||||
if (CmdKeriDemod("")) { PrintAndLogEx(SUCCESS, "\nValid KERI ID Found!"); goto out;}
|
||||
if (CmdPacDemod("")) { PrintAndLogEx(SUCCESS, "\nValid PAC/Stanley ID Found!"); goto out;}
|
||||
if (CmdParadoxDemod("")) { PrintAndLogEx(SUCCESS, "\nValid Paradox ID Found!"); goto out;}
|
||||
if (CmdPrescoDemod("")) { PrintAndLogEx(SUCCESS, "\nValid Presco ID Found!"); goto out;}
|
||||
@@ -957,6 +967,7 @@ static command_t CommandTable[] = {
|
||||
{"indala", CmdLFINDALA, 1, "{ Indala RFIDs... }"},
|
||||
{"io", CmdLFIO, 1, "{ ioProx RFIDs... }"},
|
||||
{"jablotron", CmdLFJablotron, 1, "{ Jablotron RFIDs... }"},
|
||||
{"keri", CmdLFKeri, 1, "{ KERI RFIDs... }"},
|
||||
{"nedap", CmdLFNedap, 1, "{ Nedap RFIDs... }"},
|
||||
{"nexwatch", CmdLFNEXWATCH, 1, "{ NexWatch RFIDs... }"},
|
||||
{"noralsy", CmdLFNoralsy, 1, "{ Noralsy RFIDs... }"},
|
||||
|
||||
+5
-4
@@ -42,13 +42,14 @@
|
||||
#include "cmdlfnoralsy.h" // for NORALSY meny
|
||||
#include "cmdlffdx.h" // for FDX-B meny
|
||||
#include "cmdlfcotag.h" // for COTAG meny
|
||||
#include "cmdlfindala.h" // for indala menu
|
||||
#include "cmdlfguard.h"// for gproxii menu
|
||||
#include "cmdlffdx.h" // for fdx-b menu
|
||||
#include "cmdlfparadox.h"// for paradox menu
|
||||
#include "cmdlfindala.h" // for indala menu
|
||||
#include "cmdlfguard.h" // for gproxii menu
|
||||
#include "cmdlffdx.h" // for fdx-b menu
|
||||
#include "cmdlfparadox.h" // for paradox menu
|
||||
#include "cmdlfnexwatch.h" //for nexwatch menu
|
||||
#include "cmdlfsecurakey.h" //for securakey menu
|
||||
#include "cmdlfpac.h" // for pac menu
|
||||
#include "cmdlfkeri.h" // for keri menu
|
||||
|
||||
#define T55XX_WRITE_TIMEOUT 1500
|
||||
|
||||
|
||||
+29
-35
@@ -101,7 +101,7 @@ static bool sendPing(void){
|
||||
static bool sendTry(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint32_t delay, uint8_t *bits, size_t bs_len, bool verbose){
|
||||
|
||||
if ( verbose )
|
||||
PrintAndLogEx(NORMAL, "Trying FC: %u; CN: %u", fc, cn);
|
||||
PrintAndLogEx(INFO, "Trying FC: %u; CN: %u", fc, cn);
|
||||
|
||||
if ( !getAWIDBits(fmtlen, fc, cn, bits)) {
|
||||
PrintAndLogEx(WARNING, "Error with tag bitstream generation.");
|
||||
@@ -171,7 +171,7 @@ int getAWIDBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *bits) {
|
||||
|
||||
if (bitLen != 88) return 0;
|
||||
|
||||
PrintAndLogEx(NORMAL, "awid raw bits:\n %s \n", sprint_bin(bits, bitLen));
|
||||
PrintAndLogEx(SUCCESS, "awid raw bits:\n %s \n", sprint_bin(bits, bitLen));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -181,27 +181,27 @@ static void verify_values(uint8_t *fmtlen, uint32_t *fc, uint32_t *cn){
|
||||
case 50:
|
||||
if ((*fc & 0xFFFF) != *fc) {
|
||||
*fc &= 0xFFFF;
|
||||
PrintAndLogEx(NORMAL, "Facility-Code Truncated to 16-bits (AWID50): %u", *fc);
|
||||
PrintAndLogEx(INFO, "Facility-Code Truncated to 16-bits (AWID50): %u", *fc);
|
||||
}
|
||||
break;
|
||||
case 37:
|
||||
if ((*fc & 0x1FFF) != *fc) {
|
||||
*fc &= 0x1FFF;
|
||||
PrintAndLogEx(NORMAL, "Facility-Code Truncated to 13-bits (AWID37): %u", *fc);
|
||||
PrintAndLogEx(INFO, "Facility-Code Truncated to 13-bits (AWID37): %u", *fc);
|
||||
}
|
||||
if ((*cn & 0x3FFFF) != *cn) {
|
||||
*cn &= 0x3FFFF;
|
||||
PrintAndLogEx(NORMAL, "Card Number Truncated to 18-bits (AWID37): %u", *cn);
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 18-bits (AWID37): %u", *cn);
|
||||
}
|
||||
break;
|
||||
case 34:
|
||||
if ((*fc & 0xFF) != *fc) {
|
||||
*fc &= 0xFF;
|
||||
PrintAndLogEx(NORMAL, "Facility-Code Truncated to 8-bits (AWID34): %u", *fc);
|
||||
PrintAndLogEx(INFO, "Facility-Code Truncated to 8-bits (AWID34): %u", *fc);
|
||||
}
|
||||
if ((*cn & 0xFFFFFF) != *cn) {
|
||||
*cn &= 0xFFFFFF;
|
||||
PrintAndLogEx(NORMAL, "Card Number Truncated to 24-bits (AWID34): %u", *cn);
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 24-bits (AWID34): %u", *cn);
|
||||
}
|
||||
break;
|
||||
case 26:
|
||||
@@ -209,11 +209,11 @@ static void verify_values(uint8_t *fmtlen, uint32_t *fc, uint32_t *cn){
|
||||
*fmtlen = 26;
|
||||
if ((*fc & 0xFF) != *fc) {
|
||||
*fc &= 0xFF;
|
||||
PrintAndLogEx(NORMAL, "Facility-Code Truncated to 8-bits (AWID26): %u", *fc);
|
||||
PrintAndLogEx(INFO, "Facility-Code Truncated to 8-bits (AWID26): %u", *fc);
|
||||
}
|
||||
if ((*cn & 0xFFFF) != *cn) {
|
||||
*cn &= 0xFFFF;
|
||||
PrintAndLogEx(NORMAL, "Card Number Truncated to 16-bits (AWID26): %u", *cn);
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (AWID26): %u", *cn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -290,7 +290,7 @@ int CmdAWIDDemod(const char *Cmd) {
|
||||
uint32_t rawHi2 = bytebits_to_byte(bits + idx, 32);
|
||||
|
||||
size = removeParity(bits, idx+8, 4, 1, 88);
|
||||
if (size != 66){
|
||||
if (size != 66) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - AWID at parity check-tag size does not match AWID format");
|
||||
return 0;
|
||||
}
|
||||
@@ -323,21 +323,21 @@ int CmdAWIDDemod(const char *Cmd) {
|
||||
fc = bytebits_to_byte(bits + 9, 8);
|
||||
cardnum = bytebits_to_byte(bits + 17, 16);
|
||||
code1 = bytebits_to_byte(bits + 8,fmtLen);
|
||||
PrintAndLogEx(NORMAL, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, rawHi2, rawHi, rawLo);
|
||||
PrintAndLogEx(SUCCESS, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, rawHi2, rawHi, rawLo);
|
||||
break;
|
||||
case 34:
|
||||
fc = bytebits_to_byte(bits + 9, 8);
|
||||
cardnum = bytebits_to_byte(bits + 17, 24);
|
||||
code1 = bytebits_to_byte(bits + 8, (fmtLen-32) );
|
||||
code2 = bytebits_to_byte(bits + 8 + (fmtLen-32), 32);
|
||||
PrintAndLogEx(NORMAL, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo);
|
||||
PrintAndLogEx(SUCCESS, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo);
|
||||
break;
|
||||
case 37:
|
||||
fc = bytebits_to_byte(bits + 9, 13);
|
||||
cardnum = bytebits_to_byte(bits + 22, 18);
|
||||
code1 = bytebits_to_byte(bits + 8, (fmtLen-32) );
|
||||
code2 = bytebits_to_byte(bits + 8 + (fmtLen-32), 32);
|
||||
PrintAndLogEx(NORMAL, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo);
|
||||
PrintAndLogEx(SUCCESS, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo);
|
||||
break;
|
||||
// case 40:
|
||||
// break;
|
||||
@@ -346,18 +346,18 @@ int CmdAWIDDemod(const char *Cmd) {
|
||||
cardnum = bytebits_to_byte(bits + 25, 32);
|
||||
code1 = bytebits_to_byte(bits + 8, (fmtLen-32) );
|
||||
code2 = bytebits_to_byte(bits + 8 + (fmtLen-32), 32);
|
||||
PrintAndLogEx(NORMAL, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo);
|
||||
PrintAndLogEx(SUCCESS, "AWID Found - BitLength: %d, FC: %d, Card: %u - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo);
|
||||
break;
|
||||
default:
|
||||
if (fmtLen > 32 ) {
|
||||
cardnum = bytebits_to_byte(bits + 8 + (fmtLen-17), 16);
|
||||
code1 = bytebits_to_byte(bits + 8, fmtLen-32);
|
||||
code2 = bytebits_to_byte(bits + 8 + (fmtLen-32), 32);
|
||||
PrintAndLogEx(NORMAL, "AWID Found - BitLength: %d -unknown BitLength- (%u) - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo);
|
||||
PrintAndLogEx(SUCCESS, "AWID Found - BitLength: %d -unknown BitLength- (%u) - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo);
|
||||
} else {
|
||||
cardnum = bytebits_to_byte(bits + 8 + (fmtLen-17), 16);
|
||||
code1 = bytebits_to_byte(bits + 8, fmtLen);
|
||||
PrintAndLogEx(NORMAL, "AWID Found - BitLength: %d -unknown BitLength- (%u) - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo);
|
||||
PrintAndLogEx(SUCCESS, "AWID Found - BitLength: %d -unknown BitLength- (%u) - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -386,8 +386,8 @@ int CmdAWIDSim(const char *Cmd) {
|
||||
|
||||
verify_values(&fmtlen, &fc, &cn);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Emulating AWID %u -- FC: %u; CN: %u\n", fmtlen, fc, cn);
|
||||
PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or run another command");
|
||||
PrintAndLogEx(SUCCESS, "Simulating AWID %u -- FC: %u; CN: %u\n", fmtlen, fc, cn);
|
||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command");
|
||||
|
||||
if (!getAWIDBits(fmtlen, fc, cn, bits)) {
|
||||
PrintAndLogEx(WARNING, "Error with tag bitstream generation.");
|
||||
@@ -417,8 +417,8 @@ int CmdAWIDClone(const char *Cmd) {
|
||||
uint8_t *bs=bits;
|
||||
memset(bs,0,sizeof(bits));
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_awid_clone();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_awid_clone();
|
||||
|
||||
fmtlen = param_get8(Cmd, 0);
|
||||
fc = param_get32ex(Cmd, 1, 0, 10);
|
||||
@@ -426,7 +426,7 @@ int CmdAWIDClone(const char *Cmd) {
|
||||
|
||||
if ( !fc || !cn) return usage_lf_awid_clone();
|
||||
|
||||
if (param_getchar(Cmd, 3) == 'Q' || param_getchar(Cmd, 3) == 'q')
|
||||
if (tolower(param_getchar(Cmd, 3)) == 'q')
|
||||
//t5555 (Q5) BITRATE = (RF-2)/2 (iceman)
|
||||
blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 3<<T5555_MAXBLOCK_SHIFT;
|
||||
|
||||
@@ -441,7 +441,7 @@ int CmdAWIDClone(const char *Cmd) {
|
||||
blocks[2] = bytebits_to_byte(bs + 32, 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);
|
||||
|
||||
UsbCommand resp;
|
||||
@@ -470,38 +470,32 @@ int CmdAWIDBrute(const char *Cmd) {
|
||||
memset(bits, 0x00, size);
|
||||
uint8_t cmdp = 0;
|
||||
|
||||
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch(param_getchar(Cmd, cmdp)) {
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch ( tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
return usage_lf_awid_brute();
|
||||
case 'f':
|
||||
case 'F':
|
||||
fc = param_get32ex(Cmd ,cmdp+1, 0, 10);
|
||||
if ( !fc )
|
||||
errors = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
// delay between attemps, defaults to 1000ms.
|
||||
delay = param_get32ex(Cmd, cmdp+1, 1000, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'c':
|
||||
case 'C':
|
||||
cn = param_get32ex(Cmd, cmdp+1, 0, 10);
|
||||
// truncate cardnumber.
|
||||
cn &= 0xFFFF;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'a':
|
||||
case 'A':
|
||||
fmtlen = param_get8(Cmd, cmdp+1);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'v':
|
||||
case 'V':
|
||||
verbose = true;
|
||||
cmdp++;
|
||||
break;
|
||||
@@ -511,7 +505,7 @@ int CmdAWIDBrute(const char *Cmd) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( fc == 0 )errors = true;
|
||||
if ( fc == 0 ) errors = true;
|
||||
if ( errors ) return usage_lf_awid_brute();
|
||||
|
||||
// limit fc according to selected format
|
||||
@@ -519,19 +513,19 @@ int CmdAWIDBrute(const char *Cmd) {
|
||||
case 50:
|
||||
if ((fc & 0xFFFF) != fc) {
|
||||
fc &= 0xFFFF;
|
||||
PrintAndLogEx(NORMAL, "Facility-code truncated to 16-bits (AWID50): %u", fc);
|
||||
PrintAndLogEx(INFO, "Facility-code truncated to 16-bits (AWID50): %u", fc);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ((fc & 0xFF) != fc) {
|
||||
fc &= 0xFF;
|
||||
PrintAndLogEx(NORMAL, "Facility-code truncated to 8-bits (AWID26): %u", fc);
|
||||
PrintAndLogEx(INFO, "Facility-code truncated to 8-bits (AWID26): %u", fc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Bruteforceing AWID %d Reader", fmtlen);
|
||||
PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or press key");
|
||||
PrintAndLogEx(SUCCESS, "Bruteforceing AWID %d Reader", fmtlen);
|
||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or press key");
|
||||
|
||||
uint16_t up = cn;
|
||||
uint16_t down = cn;
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ int CmdCOTAGDemod(const char *Cmd) {
|
||||
0 1001 1100 1100 0001 1000 0101 0000 0000 100001010000000001111011100000011010000010000000000000000000000000000000000000000000000000000000100111001100000110000101000
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+22
-21
@@ -364,9 +364,7 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo ) {
|
||||
int ans = Em410xDecode(bits, &size, &idx, hi, lo);
|
||||
if ( ans < 0){
|
||||
|
||||
if (ans == -1)
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x not only 0|1 in decoded bitstream");
|
||||
else if (ans == -2)
|
||||
if (ans == -2)
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x not enough samples after demod");
|
||||
else if (ans == -4)
|
||||
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.
|
||||
int CmdEM410xRead(const char *Cmd) {
|
||||
lf_read(true, 8192);
|
||||
CmdEM410xDemod(Cmd);
|
||||
return 0;
|
||||
return CmdEM410xDemod(Cmd);
|
||||
}
|
||||
|
||||
// this read loops on device side.
|
||||
@@ -446,14 +443,14 @@ int CmdEM410xSim(const char *Cmd) {
|
||||
uint8_t clock = 64;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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(NORMAL, "Press pm3-button to abort simulation");
|
||||
PrintAndLogEx(SUCCESS, "Starting simulating UID %02X%02X%02X%02X%02X clock: %d", uid[0],uid[1],uid[2],uid[3],uid[4],clock);
|
||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation");
|
||||
|
||||
ConstructEM410xEmulGraph(Cmd, clock);
|
||||
|
||||
@@ -474,14 +471,14 @@ int CmdEM410xBrute(const char *Cmd) {
|
||||
/* default pause time: 1 second */
|
||||
uint32_t delay = 1000;
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (cmdp == 'h' || cmdp == 'H') return usage_lf_em410x_brute();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_lf_em410x_brute();
|
||||
|
||||
cmdp = param_getchar(Cmd, 1);
|
||||
if (cmdp == 'd' || cmdp == 'D') {
|
||||
cmdp = tolower(param_getchar(Cmd, 1));
|
||||
if (cmdp == 'd') {
|
||||
delay = param_get32ex(Cmd, 2, 1000, 10);
|
||||
param_getdec(Cmd, 4, &clock);
|
||||
} else if (cmdp == 'c' || cmdp == 'C') {
|
||||
} else if (cmdp == 'c') {
|
||||
param_getdec(Cmd, 2, &clock);
|
||||
delay = param_get32ex(Cmd, 4, 1000, 10);
|
||||
}
|
||||
@@ -498,7 +495,10 @@ int CmdEM410xBrute(const char *Cmd) {
|
||||
}
|
||||
|
||||
uidBlock = calloc(stUidBlock, 5);
|
||||
if (uidBlock == NULL) return 1;
|
||||
if (uidBlock == NULL) {
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while( fgets(buf, sizeof(buf), f) ) {
|
||||
if (strlen(buf) < 10 || buf[9] == '\n') continue;
|
||||
@@ -508,7 +508,7 @@ int CmdEM410xBrute(const char *Cmd) {
|
||||
if( buf[0]=='#' ) continue;
|
||||
|
||||
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);
|
||||
fclose(f);
|
||||
return 1;
|
||||
@@ -535,11 +535,12 @@ int CmdEM410xBrute(const char *Cmd) {
|
||||
fclose(f);
|
||||
|
||||
if (uidcnt == 0) {
|
||||
PrintAndLogEx(NORMAL, "No UIDs found in file");
|
||||
PrintAndLogEx(FAILED, "No UIDs found in file");
|
||||
free(uidBlock);
|
||||
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
|
||||
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.
|
||||
CmdEM410xWatch(Cmd);
|
||||
PrintAndLogEx(NORMAL, "# Replaying captured ID: %010" PRIx64 , g_em410xid);
|
||||
PrintAndLogEx(SUCCESS, "# Replaying captured ID: %010" PRIx64 , g_em410xid);
|
||||
CmdLFaskSim("");
|
||||
return 0;
|
||||
}
|
||||
@@ -645,17 +646,17 @@ int CmdEM410xWrite(const char *Cmd) {
|
||||
}
|
||||
|
||||
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
|
||||
// provide for backwards-compatibility for older firmware, and to avoid
|
||||
// having to add another argument to CMD_EM410X_WRITE_TAG, we just store
|
||||
// the clock rate in bits 8-15 of the card value
|
||||
card = (card & 0xFF) | ((clock << 8) & 0xFF00);
|
||||
} 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);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Error! Bad card type selected.\n");
|
||||
PrintAndLogEx(FAILED, "Error! Bad card type selected.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+39
-41
@@ -82,11 +82,11 @@ int detectFDXB(uint8_t *dest, size_t *size) {
|
||||
static void verify_values(uint32_t countryid, uint64_t animalid){
|
||||
if ((animalid & 0x3FFFFFFFFF) != animalid) {
|
||||
animalid &= 0x3FFFFFFFFF;
|
||||
PrintAndLogEx(NORMAL, "Animal ID Truncated to 38bits: %"PRIx64, animalid);
|
||||
PrintAndLogEx(INFO, "Animal ID Truncated to 38bits: %"PRIx64, animalid);
|
||||
}
|
||||
if ( (countryid & 0x3ff) != countryid ) {
|
||||
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 invert = 1;
|
||||
int clk = 32;
|
||||
int errCnt = 0;
|
||||
int offset = 0, maxErr = 0;
|
||||
uint8_t BitStream[MAX_DEMOD_BUF_LEN];
|
||||
size_t size = getFromGraphBuf(BitStream);
|
||||
int clk = 32;
|
||||
int invert = 1, errCnt = 0, offset = 0, maxErr = 0;
|
||||
uint8_t bs[MAX_DEMOD_BUF_LEN];
|
||||
size_t size = getFromGraphBuf(bs);
|
||||
|
||||
errCnt = askdemod(BitStream, &size, &clk, &invert, maxErr, 0, 0);
|
||||
errCnt = askdemod(bs, &size, &clk, &invert, maxErr, 0, 0);
|
||||
if ( errCnt < 0 || errCnt > maxErr ) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB no data or error found %d, clock: %d", errCnt, clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errCnt = BiphaseRawDecode(BitStream, &size, &offset, 1);
|
||||
errCnt = BiphaseRawDecode(bs, &size, &offset, 1);
|
||||
if (errCnt < 0 || errCnt > maxErr ) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB BiphaseRawDecode: %d", errCnt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int preambleIndex = detectFDXB(BitStream, &size);
|
||||
int preambleIndex = detectFDXB(bs, &size);
|
||||
if (preambleIndex < 0){
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB preamble not found :: %d",preambleIndex);
|
||||
return 0;
|
||||
@@ -188,44 +186,44 @@ int CmdFDXBdemodBI(const char *Cmd){
|
||||
return 0;
|
||||
}
|
||||
|
||||
setDemodBuf(BitStream, 128, preambleIndex);
|
||||
setDemodBuf(bs, 128, preambleIndex);
|
||||
|
||||
// remove marker bits (1's every 9th digit after preamble) (pType = 2)
|
||||
size = removeParity(BitStream, preambleIndex + 11, 9, 2, 117);
|
||||
size = removeParity(bs, preambleIndex + 11, 9, 2, 117);
|
||||
if ( size != 104 ) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - FDXB error removeParity:: %d", size);
|
||||
return 0;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "\nFDX-B / ISO 11784/5 Animal Tag ID Found:");
|
||||
PrintAndLogEx(SUCCESS, "\nFDX-B / ISO 11784/5 Animal Tag ID Found:");
|
||||
|
||||
//got a good demod
|
||||
uint64_t NationalCode = ((uint64_t)(bytebits_to_byteLSBF(BitStream+32,6)) << 32) | bytebits_to_byteLSBF(BitStream,32);
|
||||
uint32_t countryCode = bytebits_to_byteLSBF(BitStream+38,10);
|
||||
uint8_t dataBlockBit = BitStream[48];
|
||||
uint32_t reservedCode = bytebits_to_byteLSBF(BitStream+49,14);
|
||||
uint8_t animalBit = BitStream[63];
|
||||
uint32_t crc16 = bytebits_to_byteLSBF(BitStream+64,16);
|
||||
uint32_t extended = bytebits_to_byteLSBF(BitStream+80,24);
|
||||
uint64_t NationalCode = ((uint64_t)(bytebits_to_byteLSBF(bs+32, 6)) << 32) | bytebits_to_byteLSBF(bs, 32);
|
||||
uint32_t countryCode = bytebits_to_byteLSBF(bs+38, 10);
|
||||
uint8_t dataBlockBit = bs[48];
|
||||
uint32_t reservedCode = bytebits_to_byteLSBF(bs+49, 14);
|
||||
uint8_t animalBit = bs[63];
|
||||
uint32_t crc16 = bytebits_to_byteLSBF(bs+64, 16);
|
||||
uint32_t extended = bytebits_to_byteLSBF(bs+80, 24);
|
||||
|
||||
uint64_t rawid = ((uint64_t)bytebits_to_byte(BitStream,32)<<32) | bytebits_to_byte(BitStream+32,32);
|
||||
uint64_t rawid = ((uint64_t)bytebits_to_byte(bs, 32) << 32) | bytebits_to_byte(bs+32, 32);
|
||||
uint8_t raw[8];
|
||||
num_to_bytes(rawid, 8, raw);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Raw ID Hex: %s", sprint_hex(raw,8));
|
||||
PrintAndLogEx(SUCCESS, "Raw ID Hex: %s", sprint_hex(raw,8));
|
||||
|
||||
uint16_t calcCrc = crc16_kermit(raw, 8);
|
||||
PrintAndLogEx(NORMAL, "Animal ID: %04u-%012" PRIu64, countryCode, NationalCode);
|
||||
PrintAndLogEx(NORMAL, "National Code: %012" PRIu64, NationalCode);
|
||||
PrintAndLogEx(NORMAL, "CountryCode: %04u", countryCode);
|
||||
PrintAndLogEx(SUCCESS, "Animal ID: %04u-%012" PRIu64, countryCode, NationalCode);
|
||||
PrintAndLogEx(SUCCESS, "National Code: %012" PRIu64, NationalCode);
|
||||
PrintAndLogEx(SUCCESS, "CountryCode: %04u", countryCode);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Reserved/RFU: %u", reservedCode);
|
||||
PrintAndLogEx(NORMAL, "Animal Tag: %s", animalBit ? "True" : "False");
|
||||
PrintAndLogEx(NORMAL, "Has extended data: %s [0x%X]", dataBlockBit ? "True" : "False", extended);
|
||||
PrintAndLogEx(NORMAL, "CRC: 0x%04X - [%04X] - %s", crc16, calcCrc, (calcCrc == crc16) ? "Passed" : "Failed");
|
||||
PrintAndLogEx(SUCCESS, "Reserved/RFU: %u", reservedCode);
|
||||
PrintAndLogEx(SUCCESS, "Animal Tag: %s", animalBit ? _YELLOW_(True) : "False");
|
||||
PrintAndLogEx(SUCCESS, "Has extended data: %s [0x%X]", dataBlockBit ? _YELLOW_(True) : "False", extended);
|
||||
PrintAndLogEx(SUCCESS, "CRC: 0x%04X - [%04X] - %s", crc16, calcCrc, (calcCrc == crc16) ? _GREEN_(Passed) : "Failed");
|
||||
|
||||
if (g_debugMode) {
|
||||
PrintAndLogEx(DEBUG, "Start marker %d; Size %d", preambleIndex, size);
|
||||
char *bin = sprint_bin_break(BitStream,size,16);
|
||||
char *bin = sprint_bin_break(bs, size, 16);
|
||||
PrintAndLogEx(DEBUG, "DEBUG BinStream:\n%s",bin);
|
||||
}
|
||||
return 1;
|
||||
@@ -282,14 +280,14 @@ int CmdFdxDemod(const char *Cmd) {
|
||||
|
||||
uint16_t calcCrc = crc16_kermit(raw, 8);
|
||||
|
||||
PrintAndLogEx(NORMAL, "\nFDX-B / ISO 11784/5 Animal Tag ID Found: Raw : %s", sprint_hex(raw, 8));
|
||||
PrintAndLogEx(NORMAL, "Animal ID %04u-%012" PRIu64, countryCode, NationalCode);
|
||||
PrintAndLogEx(NORMAL, "National Code %012" PRIu64 " (0x%" PRIx64 ")", NationalCode, NationalCode);
|
||||
PrintAndLogEx(NORMAL, "Country Code %04u", countryCode);
|
||||
PrintAndLogEx(NORMAL, "Reserved/RFU %u (0x04%X)", reservedCode, reservedCode);
|
||||
PrintAndLogEx(NORMAL, "Animal Tag %s", animalBit ? "True" : "False");
|
||||
PrintAndLogEx(NORMAL, "Has extended data %s [0x%X]", dataBlockBit ? "True" : "False", extended);
|
||||
PrintAndLogEx(NORMAL, "CRC-16 0x%04X - 0x%04X [%s]", crc16, calcCrc, (calcCrc == crc16) ? "Ok" : "Failed");
|
||||
PrintAndLogEx(SUCCESS, "\nFDX-B / ISO 11784/5 Animal Tag ID Found: Raw : %s", sprint_hex(raw, 8));
|
||||
PrintAndLogEx(SUCCESS, "Animal ID %04u-%012" PRIu64, countryCode, NationalCode);
|
||||
PrintAndLogEx(SUCCESS, "National Code %012" PRIu64 " (0x%" PRIx64 ")", NationalCode, NationalCode);
|
||||
PrintAndLogEx(SUCCESS, "Country Code %04u", countryCode);
|
||||
PrintAndLogEx(SUCCESS, "Reserved/RFU %u (0x04%X)", reservedCode, reservedCode);
|
||||
PrintAndLogEx(SUCCESS, "Animal Tag %s", animalBit ? _YELLOW_(True) : "False");
|
||||
PrintAndLogEx(SUCCESS, "Has extended data %s [0x%X]", dataBlockBit ? _YELLOW_(True) : "False", extended);
|
||||
PrintAndLogEx(SUCCESS, "CRC-16 0x%04X - 0x%04X [%s]", crc16, calcCrc, (calcCrc == crc16) ? _GREEN_(Ok) : "Failed");
|
||||
|
||||
if (g_debugMode) {
|
||||
PrintAndLogEx(DEBUG, "Start marker %d; Size %d", preambleIndex, size);
|
||||
@@ -341,7 +339,7 @@ int CmdFdxClone(const char *Cmd) {
|
||||
blocks[3] = bytebits_to_byte(bs + 64, 32);
|
||||
blocks[4] = bytebits_to_byte(bs + 96, 32);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Preparing to clone FDX-B to T55x7 with animal ID: %04u-%"PRIu64, countryid, animalid);
|
||||
PrintAndLogEx(INFO, "Preparing to clone FDX-B to T55x7 with animal ID: %04u-%"PRIu64, countryid, animalid);
|
||||
print_blocks(blocks, 5);
|
||||
|
||||
UsbCommand resp;
|
||||
@@ -379,7 +377,7 @@ int CmdFdxSim(const char *Cmd) {
|
||||
arg1 = clk << 8 | encoding;
|
||||
arg2 = invert << 8 | separator;
|
||||
|
||||
PrintAndLogEx(NORMAL, "Simulating FDX-B animal ID: %04u-%"PRIu64, countryid, animalid);
|
||||
PrintAndLogEx(SUCCESS, "Simulating FDX-B animal ID: %04u-%"PRIu64, countryid, animalid);
|
||||
|
||||
UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
|
||||
|
||||
|
||||
+10
-10
@@ -107,21 +107,21 @@ int GetGuardBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits) {
|
||||
for (i = 0; i < 4; ++i)
|
||||
rawbytes[i+4] = bytebits_to_byte( pre + (i*8), 8);
|
||||
|
||||
if (g_debugMode) PrintAndLogEx(NORMAL, " WIE | %s\n", sprint_hex(rawbytes, sizeof(rawbytes)));
|
||||
PrintAndLogEx(DEBUG, " WIE | %s\n", sprint_hex(rawbytes, sizeof(rawbytes)));
|
||||
|
||||
|
||||
// XOR (only works on wiegand stuff)
|
||||
for (i = 1; i < 12; ++i)
|
||||
rawbytes[i] ^= xorKey ;
|
||||
|
||||
if (g_debugMode) PrintAndLogEx(NORMAL, " XOR | %s \n", sprint_hex(rawbytes, sizeof(rawbytes)));
|
||||
PrintAndLogEx(DEBUG, " XOR | %s \n", sprint_hex(rawbytes, sizeof(rawbytes)));
|
||||
|
||||
// convert rawbytes to bits in pre
|
||||
for (i = 0; i < 12; ++i)
|
||||
num_to_bytebitsLSBF( rawbytes[i], 8, pre + (i*8));
|
||||
|
||||
if (g_debugMode) PrintAndLogEx(NORMAL, "\n Raw | %s \n", sprint_hex(rawbytes, sizeof(rawbytes)));
|
||||
if (g_debugMode) PrintAndLogEx(NORMAL, " Raw | %s\n", sprint_bin(pre, 64) );
|
||||
PrintAndLogEx(DEBUG, "\n Raw | %s \n", sprint_hex(rawbytes, sizeof(rawbytes)));
|
||||
PrintAndLogEx(DEBUG, " Raw | %s\n", sprint_bin(pre, 64) );
|
||||
|
||||
// add spacer bit 0 every 4 bits, starting with index 0,
|
||||
// 12 bytes, 24 nibbles. 24+1 extra bites. 3bytes. ie 9bytes | 1byte xorkey, 8bytes rawdata (64bits, should be enough for a 40bit wiegand)
|
||||
@@ -135,7 +135,7 @@ int GetGuardBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits) {
|
||||
guardBits[4] = 1;
|
||||
guardBits[5] = 0;
|
||||
|
||||
if (g_debugMode) PrintAndLogEx(NORMAL, " FIN | %s\n", sprint_bin(guardBits, 96) );
|
||||
PrintAndLogEx(DEBUG, " FIN | %s\n", sprint_bin(guardBits, 96) );
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ int CmdGuardDemod(const char *Cmd) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII preamble not found");
|
||||
else if (preambleIndex == -3)
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII size not correct: %d", size);
|
||||
else if (preambleIndex == -3)
|
||||
else if (preambleIndex == -5)
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII wrong spacerbits");
|
||||
else
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII ans: %d", preambleIndex);
|
||||
@@ -246,9 +246,9 @@ int CmdGuardDemod(const char *Cmd) {
|
||||
break;
|
||||
}
|
||||
if ( !unknown)
|
||||
PrintAndLogEx(NORMAL, "G-Prox-II Found: Format Len: %ubit - FC: %u - Card: %u, Raw: %08x%08x%08x", fmtLen, FC, Card, raw1, raw2, raw3);
|
||||
PrintAndLogEx(SUCCESS, "G-Prox-II Found: Format Len: %ubit - FC: %u - Card: %u, Raw: %08x%08x%08x", fmtLen, FC, Card, raw1, raw2, raw3);
|
||||
else
|
||||
PrintAndLogEx(NORMAL, "Unknown G-Prox-II Fmt Found: Format Len: %u, Raw: %08x%08x%08x", fmtLen, raw1, raw2, raw3);
|
||||
PrintAndLogEx(SUCCESS, "Unknown G-Prox-II Fmt Found: Format Len: %u, Raw: %08x%08x%08x", fmtLen, raw1, raw2, raw3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -290,7 +290,7 @@ int CmdGuardClone(const char *Cmd) {
|
||||
blocks[2] = bytebits_to_byte(bs + 32, 32);
|
||||
blocks[3] = bytebits_to_byte(bs + 64, 32);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Preparing to clone Guardall to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Guardall to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber);
|
||||
print_blocks(blocks, 4);
|
||||
|
||||
UsbCommand resp;
|
||||
@@ -333,7 +333,7 @@ int CmdGuardSim(const char *Cmd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Simulating Guardall - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber );
|
||||
PrintAndLogEx(SUCCESS, "Simulating Guardall - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber );
|
||||
|
||||
uint64_t arg1, arg2;
|
||||
arg1 = (clock << 8) | encoding;
|
||||
|
||||
+14
-20
@@ -106,7 +106,7 @@ static bool sendTry(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint32_t delay, ui
|
||||
|
||||
// this should be optional.
|
||||
if ( verbose )
|
||||
PrintAndLogEx(NORMAL, "Trying FC: %u; CN: %u", fc, cn);
|
||||
PrintAndLogEx(INFO, "Trying FC: %u; CN: %u", fc, cn);
|
||||
|
||||
calcWiegand( fmtlen, fc, cn, bits);
|
||||
|
||||
@@ -164,7 +164,7 @@ int CmdHIDDemod(const char *Cmd) {
|
||||
}
|
||||
|
||||
if (hi2 != 0){ //extra large HID tags
|
||||
PrintAndLogEx(NORMAL, "HID Prox TAG ID: %x%08x%08x (%u)", hi2, hi, lo, (lo>>1) & 0xFFFF);
|
||||
PrintAndLogEx(SUCCESS, "HID Prox TAG ID: %x%08x%08x (%u)", hi2, hi, lo, (lo>>1) & 0xFFFF);
|
||||
} else { //standard HID tags <38 bits
|
||||
uint8_t fmtLen = 0;
|
||||
uint32_t cc = 0;
|
||||
@@ -209,9 +209,9 @@ int CmdHIDDemod(const char *Cmd) {
|
||||
}
|
||||
}
|
||||
if(fmtLen==32 && (lo & 0x40000000)){//if 32 bit and Kastle bit set
|
||||
PrintAndLogEx(NORMAL, "HID Prox TAG (Kastle format) ID: %08x (%u) - Format Len: 32bit - CC: %u - FC: %u - Card: %u", lo, (lo >> 1) & 0xFFFF, cc, fc, cardnum);
|
||||
PrintAndLogEx(SUCCESS, "HID Prox TAG (Kastle format) ID: %08x (%u) - Format Len: 32bit - CC: %u - FC: %u - Card: %u", lo, (lo >> 1) & 0xFFFF, cc, fc, cardnum);
|
||||
}else{
|
||||
PrintAndLogEx(NORMAL, "HID Prox TAG ID: %x%08x (%u) - Format Len: %ubit - FC: %u - Card: %u", hi, lo, (lo >> 1) & 0xFFFF, fmtLen, fc, cardnum);
|
||||
PrintAndLogEx(SUCCESS, "HID Prox TAG ID: %x%08x (%u) - Format Len: %ubit - FC: %u - Card: %u", hi, lo, (lo >> 1) & 0xFFFF, fmtLen, fc, cardnum);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,16 +244,16 @@ int CmdHIDSim(const char *Cmd) {
|
||||
uint32_t hi = 0, lo = 0;
|
||||
uint32_t n = 0, i = 0;
|
||||
|
||||
uint8_t ctmp = param_getchar(Cmd, 0);
|
||||
if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_hid_sim();
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if ( strlen(Cmd) == 0 || ctmp == 'h' ) return usage_lf_hid_sim();
|
||||
|
||||
while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
|
||||
hi = (hi << 4) | (lo >> 28);
|
||||
lo = (lo << 4) | (n & 0xf);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Emulating tag with ID %x%08x", hi, lo);
|
||||
PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation");
|
||||
PrintAndLogEx(SUCCESS, "Simulating HID tag with ID %x%08x", hi, lo);
|
||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation");
|
||||
|
||||
UsbCommand c = {CMD_HID_SIM_TAG, {hi, lo, 0}};
|
||||
clearCommandBuffer();
|
||||
@@ -277,7 +277,7 @@ int CmdHIDClone(const char *Cmd) {
|
||||
lo = (lo << 4) | (n & 0xf);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Cloning tag with long ID %x%08x%08x", hi2, hi, lo);
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag with long ID %x%08x%08x", hi2, hi, lo);
|
||||
|
||||
c.d.asBytes[0] = 1;
|
||||
} else {
|
||||
@@ -285,7 +285,7 @@ int CmdHIDClone(const char *Cmd) {
|
||||
hi = (hi << 4) | (lo >> 28);
|
||||
lo = (lo << 4) | (n & 0xf);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "Cloning tag with ID %x%08x", hi, lo);
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag with ID %x%08x", hi, lo);
|
||||
hi2 = 0;
|
||||
c.d.asBytes[0] = 0;
|
||||
}
|
||||
@@ -492,33 +492,28 @@ int CmdHIDBrute(const char *Cmd){
|
||||
memset(bits, 0, sizeof(bits));
|
||||
uint8_t cmdp = 0;
|
||||
|
||||
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch(param_getchar(Cmd, cmdp)) {
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
return usage_lf_hid_brute();
|
||||
case 'f':
|
||||
case 'F':
|
||||
fc = param_get32ex(Cmd ,cmdp+1, 0, 10);
|
||||
if ( !fc )
|
||||
errors = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
// delay between attemps, defaults to 1000ms.
|
||||
delay = param_get32ex(Cmd, cmdp+1, 1000, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'c':
|
||||
case 'C':
|
||||
cn = param_get32ex(Cmd, cmdp+1, 0, 10);
|
||||
// truncate cardnumber.
|
||||
cn &= 0xFFFF;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'a':
|
||||
case 'A':
|
||||
fmtlen = param_get8(Cmd, cmdp+1);
|
||||
cmdp += 2;
|
||||
bool is_ftm_ok = false;
|
||||
@@ -532,7 +527,6 @@ int CmdHIDBrute(const char *Cmd){
|
||||
errors = !is_ftm_ok;
|
||||
break;
|
||||
case 'v':
|
||||
case 'V':
|
||||
verbose = true;
|
||||
cmdp++;
|
||||
break;
|
||||
@@ -545,8 +539,8 @@ int CmdHIDBrute(const char *Cmd){
|
||||
if ( fc == 0 ) errors = true;
|
||||
if ( errors ) return usage_lf_hid_brute();
|
||||
|
||||
PrintAndLogEx(NORMAL, "Brute-forcing HID reader");
|
||||
PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or run another command");
|
||||
PrintAndLogEx(INFO, "Brute-forcing HID reader");
|
||||
PrintAndLogEx(INFO, "Press pm3-button to abort simulation or run another command");
|
||||
|
||||
uint16_t up = cn;
|
||||
uint16_t down = cn;
|
||||
|
||||
+19
-17
@@ -136,7 +136,7 @@ int CmdIndalaDemod(const char *Cmd) {
|
||||
idx = indala224decode(DemodBuffer, &size, &invert);
|
||||
if (idx < 0 || size != 224) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - Indala wrong size, expected [64|224] got: %d (startindex %i)", size, idx);
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,8 +231,8 @@ int CmdIndalaDemodAlt(const char *Cmd) {
|
||||
}
|
||||
|
||||
if (rawbit > 0){
|
||||
PrintAndLogEx(NORMAL, "Recovered %d raw bits, expected: %d", rawbit, GraphTraceLen/32);
|
||||
PrintAndLogEx(NORMAL, "worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);
|
||||
PrintAndLogEx(INFO, "Recovered %d raw bits, expected: %d", rawbit, GraphTraceLen/32);
|
||||
PrintAndLogEx(INFO, "worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -262,7 +262,7 @@ int CmdIndalaDemodAlt(const char *Cmd) {
|
||||
}
|
||||
|
||||
if (start == rawbit - uidlen + 1) {
|
||||
PrintAndLogEx(NORMAL, "nothing to wait for");
|
||||
PrintAndLogEx(FAILED, "nothing to wait for");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ int CmdIndalaDemodAlt(const char *Cmd) {
|
||||
showbits[bit] = '.' + bits[bit];
|
||||
}
|
||||
showbits[bit+1]='\0';
|
||||
PrintAndLogEx(NORMAL, "Partial UID=%s", showbits);
|
||||
PrintAndLogEx(SUCCESS, "Partial UID | %s", showbits);
|
||||
return 0;
|
||||
} else {
|
||||
for (bit = 0; bit < uidlen; bit++) {
|
||||
@@ -313,7 +313,7 @@ int CmdIndalaDemodAlt(const char *Cmd) {
|
||||
uid2 = (uid2<<1) | 1;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "UID=%s (%x%08x)", showbits, uid1, uid2);
|
||||
PrintAndLogEx(SUCCESS, "UID | %s (%x%08x)", showbits, uid1, uid2);
|
||||
}
|
||||
else {
|
||||
uid3 = uid4 = uid5 = uid6 = uid7 = 0;
|
||||
@@ -331,7 +331,7 @@ int CmdIndalaDemodAlt(const char *Cmd) {
|
||||
else
|
||||
uid7 = (uid7<<1) | 1;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "UID=%s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7);
|
||||
PrintAndLogEx(SUCCESS, "UID | %s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7);
|
||||
}
|
||||
|
||||
// Checking UID against next occurrences
|
||||
@@ -350,7 +350,7 @@ int CmdIndalaDemodAlt(const char *Cmd) {
|
||||
times += 1;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Occurrences: %d (expected %d)", times, (rawbit - start) / uidlen);
|
||||
PrintAndLogEx(DEBUG, "Occurrences: %d (expected %d)", times, (rawbit - start) / uidlen);
|
||||
|
||||
// Remodulating for tag cloning
|
||||
// HACK: 2015-01-04 this will have an impact on our new way of seening lf commands (demod)
|
||||
@@ -377,8 +377,8 @@ int CmdIndalaDemodAlt(const char *Cmd) {
|
||||
|
||||
int CmdIndalaSim(const char *Cmd) {
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_indala_sim();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_indala_sim();
|
||||
|
||||
uint8_t bits[224];
|
||||
size_t size = sizeof(bits);
|
||||
@@ -392,9 +392,9 @@ int CmdIndalaSim(const char *Cmd) {
|
||||
return usage_lf_indala_sim();
|
||||
|
||||
// convert to binarray
|
||||
uint8_t counter = 224;
|
||||
for (uint8_t i=0; i< len; i++) {
|
||||
for(uint8_t j=0; j<8; j++) {
|
||||
uint8_t counter = 223;
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
for(uint8_t j = 0; j < 8; j++) {
|
||||
bits[counter--] = hexuid[i] & 1;
|
||||
hexuid[i] >>= 1;
|
||||
}
|
||||
@@ -409,8 +409,8 @@ int CmdIndalaSim(const char *Cmd) {
|
||||
// It has to send either 64bits (8bytes) or 224bits (28bytes). Zero padding needed if not.
|
||||
// lf simpsk 1 c 32 r 2 d 0102030405060708
|
||||
|
||||
// PrintAndLogEx(NORMAL, "Emulating Indala UID: %u \n", cn);
|
||||
// PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or run another command");
|
||||
PrintAndLogEx(SUCCESS, "Simulating Indala UID: %s", sprint_hex(hexuid, len));
|
||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command");
|
||||
|
||||
UsbCommand c = {CMD_PSK_SIM_TAG, {arg1, arg2, size}};
|
||||
memcpy(c.d.asBytes, bits, size);
|
||||
@@ -427,6 +427,7 @@ int CmdIndalaClone(const char *Cmd) {
|
||||
uint32_t n = 0, i = 0;
|
||||
|
||||
if (strchr(Cmd,'l') != 0) {
|
||||
|
||||
while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
|
||||
uid1 = (uid1 << 4) | (uid2 >> 28);
|
||||
uid2 = (uid2 << 4) | (uid3 >> 28);
|
||||
@@ -436,7 +437,8 @@ int CmdIndalaClone(const char *Cmd) {
|
||||
uid6 = (uid6 << 4) | (uid7 >> 28);
|
||||
uid7 = (uid7 << 4) | (n & 0xf);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "Cloning 224bit tag with UID %x%08x%08x%08x%08x%08x%08x", uid1, uid2, uid3, uid4, uid5, uid6, uid7);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Indala 224bit tag with UID %x%08x%08x%08x%08x%08x%08x", uid1, uid2, uid3, uid4, uid5, uid6, uid7);
|
||||
c.cmd = CMD_INDALA_CLONE_TAG_L;
|
||||
c.d.asDwords[0] = uid1;
|
||||
c.d.asDwords[1] = uid2;
|
||||
@@ -450,7 +452,7 @@ int CmdIndalaClone(const char *Cmd) {
|
||||
uid1 = (uid1 << 4) | (uid2 >> 28);
|
||||
uid2 = (uid2 << 4) | (n & 0xf);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "Cloning 64bit tag with UID %x%08x", uid1, uid2);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Indala 64bit tag with UID %x%08x", uid1, uid2);
|
||||
c.cmd = CMD_INDALA_CLONE_TAG;
|
||||
c.arg[0] = uid1;
|
||||
c.arg[1] = uid2;
|
||||
|
||||
+24
-26
@@ -86,15 +86,15 @@ int CmdIOProxDemod(const char *Cmd) {
|
||||
uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0};
|
||||
size_t size = getFromGraphBuf(bits);
|
||||
if (size < 65) {
|
||||
if (g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox not enough samples in GraphBuffer");
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox not enough samples in GraphBuffer");
|
||||
return 0;
|
||||
}
|
||||
//get binary from fsk wave
|
||||
int waveIdx = 0;
|
||||
idx = detectIOProx(bits, &size, &waveIdx);
|
||||
if (idx < 0){
|
||||
if (g_debugMode){
|
||||
if (idx == -1){
|
||||
if (idx < 0) {
|
||||
if (g_debugMode) {
|
||||
if (idx == -1) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox not enough samples");
|
||||
} else if (idx == -2) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox just noise detected");
|
||||
@@ -115,10 +115,10 @@ int CmdIOProxDemod(const char *Cmd) {
|
||||
setDemodBuf(bits, size, idx);
|
||||
setClockGrid(64, waveIdx + (idx*64));
|
||||
|
||||
if (idx==0){
|
||||
if (g_debugMode){
|
||||
if (idx == 0) {
|
||||
if (g_debugMode) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox data not found - FSK Bits: %d", size);
|
||||
if (size > 92) PrintAndLogEx(NORMAL, "%s", sprint_bin_break(bits, 92, 16));
|
||||
if (size > 92) PrintAndLogEx(DEBUG, "%s", sprint_bin_break(bits, 92, 16));
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -132,15 +132,13 @@ int CmdIOProxDemod(const char *Cmd) {
|
||||
//
|
||||
//XSF(version)facility:codeone+codetwo (raw)
|
||||
|
||||
if (g_debugMode) {
|
||||
PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d", bits[idx], bits[idx+1], bits[idx+2], bits[idx+3], bits[idx+4], bits[idx+5], bits[idx+6], bits[idx+7], bits[idx+8]);
|
||||
PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d", bits[idx+9], bits[idx+10], bits[idx+11],bits[idx+12],bits[idx+13],bits[idx+14],bits[idx+15],bits[idx+16],bits[idx+17]);
|
||||
PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d facility", bits[idx+18], bits[idx+19], bits[idx+20],bits[idx+21],bits[idx+22],bits[idx+23],bits[idx+24],bits[idx+25],bits[idx+26]);
|
||||
PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d version", bits[idx+27], bits[idx+28], bits[idx+29],bits[idx+30],bits[idx+31],bits[idx+32],bits[idx+33],bits[idx+34],bits[idx+35]);
|
||||
PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d code1", bits[idx+36], bits[idx+37], bits[idx+38],bits[idx+39],bits[idx+40],bits[idx+41],bits[idx+42],bits[idx+43],bits[idx+44]);
|
||||
PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d code2", bits[idx+45], bits[idx+46], bits[idx+47],bits[idx+48],bits[idx+49],bits[idx+50],bits[idx+51],bits[idx+52],bits[idx+53]);
|
||||
PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d%d checksum", bits[idx+54],bits[idx+55],bits[idx+56],bits[idx+57],bits[idx+58],bits[idx+59],bits[idx+60],bits[idx+61],bits[idx+62],bits[idx+63]);
|
||||
}
|
||||
PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d", bits[idx], bits[idx+1], bits[idx+2], bits[idx+3], bits[idx+4], bits[idx+5], bits[idx+6], bits[idx+7], bits[idx+8]);
|
||||
PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d", bits[idx+9], bits[idx+10], bits[idx+11],bits[idx+12],bits[idx+13],bits[idx+14],bits[idx+15],bits[idx+16],bits[idx+17]);
|
||||
PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d facility", bits[idx+18], bits[idx+19], bits[idx+20],bits[idx+21],bits[idx+22],bits[idx+23],bits[idx+24],bits[idx+25],bits[idx+26]);
|
||||
PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d version", bits[idx+27], bits[idx+28], bits[idx+29],bits[idx+30],bits[idx+31],bits[idx+32],bits[idx+33],bits[idx+34],bits[idx+35]);
|
||||
PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d code1", bits[idx+36], bits[idx+37], bits[idx+38],bits[idx+39],bits[idx+40],bits[idx+41],bits[idx+42],bits[idx+43],bits[idx+44]);
|
||||
PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d code2", bits[idx+45], bits[idx+46], bits[idx+47],bits[idx+48],bits[idx+49],bits[idx+50],bits[idx+51],bits[idx+52],bits[idx+53]);
|
||||
PrintAndLogEx(DEBUG, "%d%d%d%d%d%d%d%d %d%d checksum", bits[idx+54],bits[idx+55],bits[idx+56],bits[idx+57],bits[idx+58],bits[idx+59],bits[idx+60],bits[idx+61],bits[idx+62],bits[idx+63]);
|
||||
|
||||
uint32_t code = bytebits_to_byte(bits+idx,32);
|
||||
uint32_t code2 = bytebits_to_byte(bits+idx+32,32);
|
||||
@@ -163,13 +161,13 @@ int CmdIOProxDemod(const char *Cmd) {
|
||||
snprintf(crcStr, 3, "ok");
|
||||
retval = 1;
|
||||
} else {
|
||||
if (g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox crc failed");
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox crc failed");
|
||||
|
||||
snprintf(crcStr, sizeof(crcStr), "failed 0x%02X != 0x%02X", crc, calccrc);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "IO Prox XSF(%02d)%02x:%05d (%08x%08x) [crc %s]", version, facilitycode, number, code, code2, crcStr);
|
||||
PrintAndLogEx(SUCCESS, "IO Prox XSF(%02d)%02x:%05d (%08x%08x) [crc %s]", version, facilitycode, number, code, code2, crcStr);
|
||||
|
||||
if (g_debugMode){
|
||||
PrintAndLogEx(DEBUG, "DEBUG: IO prox idx: %d, Len: %d, Printing demod buffer:", idx, size);
|
||||
@@ -241,7 +239,7 @@ int getIOProxBits(uint8_t version, uint8_t fc, uint16_t cn, uint8_t *bits) {
|
||||
|
||||
memcpy(bits, pre, sizeof(pre));
|
||||
|
||||
PrintAndLogEx(NORMAL, "IO raw bits:\n %s \n", sprint_bin(bits, 64));
|
||||
PrintAndLogEx(SUCCESS, "IO raw bits:\n %s \n", sprint_bin(bits, 64));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -252,8 +250,8 @@ int CmdIOProxSim(const char *Cmd) {
|
||||
size_t size = sizeof(bits);
|
||||
memset(bits, 0x00, size);
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_io_sim();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_io_sim();
|
||||
|
||||
version = param_get8(Cmd, 0);
|
||||
fc = param_get8(Cmd, 1);
|
||||
@@ -263,7 +261,7 @@ int CmdIOProxSim(const char *Cmd) {
|
||||
|
||||
if ((cn & 0xFFFF) != cn) {
|
||||
cn &= 0xFFFF;
|
||||
PrintAndLogEx(NORMAL, "Card Number Truncated to 16-bits (IOProx): %u", cn);
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (IOProx): %u", cn);
|
||||
}
|
||||
|
||||
// clock 64, FSK2a fcHIGH 10 | fcLOW 8
|
||||
@@ -272,8 +270,8 @@ int CmdIOProxSim(const char *Cmd) {
|
||||
arg1 = high << 8 | low;
|
||||
arg2 = invert << 8 | clk;
|
||||
|
||||
PrintAndLogEx(NORMAL, "Emulating IOProx Version: %u FC: %u; CN: %u\n", version, fc, cn);
|
||||
PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation or run another command");
|
||||
PrintAndLogEx(SUCCESS, "Simulating IOProx version: %u FC: %u; CN: %u\n", version, fc, cn);
|
||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command");
|
||||
|
||||
if ( !getIOProxBits(version, fc, cn, bits)) {
|
||||
PrintAndLogEx(WARNING, "Error with tag bitstream generation.");
|
||||
@@ -309,7 +307,7 @@ int CmdIOProxClone(const char *Cmd) {
|
||||
|
||||
if ((cn & 0xFFFF) != cn) {
|
||||
cn &= 0xFFFF;
|
||||
PrintAndLogEx(NORMAL, "Card Number Truncated to 16-bits (IOProx): %u", cn);
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (IOProx): %u", cn);
|
||||
}
|
||||
|
||||
if ( !getIOProxBits(version, fc, cn, bits)) {
|
||||
@@ -323,7 +321,7 @@ int CmdIOProxClone(const char *Cmd) {
|
||||
blocks[1] = bytebits_to_byte(bits, 32);
|
||||
blocks[2] = bytebits_to_byte(bits + 32, 32);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Preparing to clone IOProx to T55x7 with Version: %u FC: %u, CN: %u", version, fc, cn);
|
||||
PrintAndLogEx(INFO, "Preparing to clone IOProx to T55x7 with Version: %u FC: %u, CN: %u", version, fc, cn);
|
||||
print_blocks(blocks, 3);
|
||||
|
||||
//UsbCommand c = {CMD_T55XX_WRITE_BLOCK, {0,0,0}};
|
||||
|
||||
+12
-12
@@ -130,14 +130,14 @@ int CmdJablotronDemod(const char *Cmd) {
|
||||
PrintAndLogEx(SUCCESS, "Jablotron Tag Found: Card ID: %"PRIx64" :: Raw: %08X%08X", id, raw1, raw2);
|
||||
|
||||
uint8_t chksum = raw2 & 0xFF;
|
||||
PrintAndLogEx(NORMAL, "Checksum: %02X [%s]",
|
||||
PrintAndLogEx(INFO, "Checksum: %02X [%s]",
|
||||
chksum,
|
||||
(chksum == jablontron_chksum(DemodBuffer)) ? "OK":"FAIL"
|
||||
(chksum == jablontron_chksum(DemodBuffer)) ? _GREEN_(OK) : _RED_(FAIL)
|
||||
);
|
||||
|
||||
id = DEC2BCD(id);
|
||||
// Printed format: 1410-nn-nnnn-nnnn
|
||||
PrintAndLogEx(NORMAL, "Printed: 1410-%02X-%04X-%04X",
|
||||
PrintAndLogEx(SUCCESS, "Printed: 1410-%02X-%04X-%04X",
|
||||
(uint8_t)(id >> 32) & 0xFF,
|
||||
(uint16_t)(id >> 16) & 0xFFFF,
|
||||
(uint16_t)id & 0xFFFF
|
||||
@@ -158,8 +158,8 @@ int CmdJablotronClone(const char *Cmd) {
|
||||
uint8_t bits[64];
|
||||
memset(bits, 0, sizeof(bits));
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_jablotron_clone();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_jablotron_clone();
|
||||
|
||||
fullcode = param_get64ex(Cmd, 0, 0, 16);
|
||||
|
||||
@@ -170,7 +170,7 @@ int CmdJablotronClone(const char *Cmd) {
|
||||
// clearing the topbit needed for the preambl detection.
|
||||
if ((fullcode & 0x7FFFFFFFFF) != fullcode) {
|
||||
fullcode &= 0x7FFFFFFFFF;
|
||||
PrintAndLogEx(NORMAL, "Card Number Truncated to 39bits: %"PRIx64, fullcode);
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 39bits: %"PRIx64, fullcode);
|
||||
}
|
||||
|
||||
if ( !getJablotronBits(fullcode, bits)) {
|
||||
@@ -181,13 +181,13 @@ int CmdJablotronClone(const char *Cmd) {
|
||||
blocks[1] = bytebits_to_byte(bits, 32);
|
||||
blocks[2] = bytebits_to_byte(bits + 32, 32);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Preparing to clone Jablotron to T55x7 with FullCode: %"PRIx64, fullcode);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Jablotron to T55x7 with FullCode: %"PRIx64, fullcode);
|
||||
print_blocks(blocks, 3);
|
||||
|
||||
UsbCommand resp;
|
||||
UsbCommand c = {CMD_T55XX_WRITE_BLOCK, {0,0,0}};
|
||||
|
||||
for (uint8_t i=0; i<4; i++) {
|
||||
for (uint8_t i=0; i<3; i++) {
|
||||
c.arg[0] = blocks[i];
|
||||
c.arg[1] = i;
|
||||
clearCommandBuffer();
|
||||
@@ -203,15 +203,15 @@ int CmdJablotronClone(const char *Cmd) {
|
||||
int CmdJablotronSim(const char *Cmd) {
|
||||
uint64_t fullcode = 0;
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_jablotron_sim();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_jablotron_sim();
|
||||
|
||||
fullcode = param_get64ex(Cmd, 0, 0, 16);
|
||||
|
||||
// clearing the topbit needed for the preambl detection.
|
||||
if ((fullcode & 0x7FFFFFFFFF) != fullcode) {
|
||||
fullcode &= 0x7FFFFFFFFF;
|
||||
PrintAndLogEx(NORMAL, "Card Number Truncated to 39bits: %"PRIx64, fullcode);
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 39bits: %"PRIx64, fullcode);
|
||||
}
|
||||
|
||||
uint8_t clk = 64, encoding = 2, separator = 0, invert = 1;
|
||||
@@ -220,7 +220,7 @@ int CmdJablotronSim(const char *Cmd) {
|
||||
arg1 = clk << 8 | encoding;
|
||||
arg2 = invert << 8 | separator;
|
||||
|
||||
PrintAndLogEx(NORMAL, "Simulating Jablotron - FullCode: %"PRIx64, fullcode);
|
||||
PrintAndLogEx(SUCCESS, "Simulating Jablotron - FullCode: %"PRIx64, fullcode);
|
||||
|
||||
UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
|
||||
getJablotronBits(fullcode, c.d.asBytes);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
+10
-10
@@ -194,15 +194,15 @@ int CmdLFNedapDemod(const char *Cmd) {
|
||||
chksum2 = bytebits_to_byte(DemodBuffer+110, 8);
|
||||
chksum2 |= bytebits_to_byte(DemodBuffer+119, 8) << 8;
|
||||
|
||||
PrintAndLogEx(NORMAL, "NEDAP ID Found - Raw: %08x%08x%08x%08x", raw[3], raw[2], raw[1], raw[0]);
|
||||
PrintAndLogEx(NORMAL, " - UID: %06X", uid);
|
||||
PrintAndLogEx(NORMAL, " - i: %04X", two);
|
||||
PrintAndLogEx(NORMAL, " - Checksum2 %04X", chksum2);
|
||||
PrintAndLogEx(SUCCESS, "NEDAP ID Found - Raw: %08x%08x%08x%08x", raw[3], raw[2], raw[1], raw[0]);
|
||||
PrintAndLogEx(SUCCESS, " - UID: %06X", uid);
|
||||
PrintAndLogEx(SUCCESS, " - i: %04X", two);
|
||||
PrintAndLogEx(SUCCESS, " - Checksum2 %04X", chksum2);
|
||||
|
||||
if (g_debugMode){
|
||||
PrintAndLogEx(DEBUG, "DEBUG: idx: %d, Len: %d, Printing Demod Buffer:", idx, 128);
|
||||
printDemodBuff();
|
||||
PrintAndLogEx(NORMAL, "BIN:\n%s", sprint_bin_break( DemodBuffer, 128, 64) );
|
||||
PrintAndLogEx(DEBUG, "BIN:\n%s", sprint_bin_break( DemodBuffer, 128, 64) );
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -268,7 +268,7 @@ int CmdLFNedapClone(const char *Cmd) {
|
||||
blocks[3] = bytebits_to_byte(bits + 64, 32);
|
||||
blocks[4] = bytebits_to_byte(bits + 96, 32);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Preparing to clone NEDAP to T55x7 with card number: %u", cardnumber);
|
||||
PrintAndLogEx(INFO, "Preparing to clone NEDAP to T55x7 with card number: %u", cardnumber);
|
||||
print_blocks(blocks, 5);
|
||||
|
||||
UsbCommand resp;
|
||||
@@ -314,8 +314,8 @@ int CmdLFNedapSim(const char *Cmd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "bin %s", sprint_bin_break(bs, 128, 32));
|
||||
PrintAndLogEx(NORMAL, "Simulating Nedap - CardNumber: %u", cardnumber );
|
||||
PrintAndLogEx(SUCCESS, "bin %s", sprint_bin_break(bs, 128, 32));
|
||||
PrintAndLogEx(SUCCESS, "Simulating Nedap - CardNumber: %u", cardnumber );
|
||||
|
||||
UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
|
||||
memcpy(c.d.asBytes, bs, size);
|
||||
@@ -332,7 +332,7 @@ int CmdLFNedapChk(const char *Cmd){
|
||||
|
||||
len = ( len == 0 ) ? 5 : len>>1;
|
||||
|
||||
PrintAndLogEx(NORMAL, "Input: [%d] %s", len, sprint_hex(data, len));
|
||||
PrintAndLogEx(SUCCESS, "Input: [%d] %s", len, sprint_hex(data, len));
|
||||
|
||||
//uint8_t last = GetParity(data, EVEN, 62);
|
||||
//PrintAndLogEx(NORMAL, "TEST PARITY:: %d | %d ", DemodBuffer[62], last);
|
||||
@@ -367,7 +367,7 @@ int CmdLFNedapChk(const char *Cmd){
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Nedap checksum: 0x%X", ((ch << 8) | cl) );
|
||||
PrintAndLogEx(SUCCESS, "Nedap checksum: 0x%X", ((ch << 8) | cl) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,14 +34,13 @@ int detectNexWatch(uint8_t *dest, size_t *size, bool *invert) {
|
||||
int CmdNexWatchDemod(const char *Cmd) {
|
||||
|
||||
if (!PSKDemod("", false)) {
|
||||
if (g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch can't demod signal");
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch can't demod signal");
|
||||
return 0;
|
||||
}
|
||||
bool invert = false;
|
||||
size_t size = DemodBufferLen;
|
||||
int idx = detectNexWatch(DemodBuffer, &size, &invert);
|
||||
if (idx <= 0){
|
||||
if (g_debugMode){
|
||||
if (idx <= 0) {
|
||||
if (idx == -1)
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch not enough samples");
|
||||
// else if (idx == -2)
|
||||
@@ -54,7 +53,7 @@ int CmdNexWatchDemod(const char *Cmd) {
|
||||
// PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch size not correct: %d", size);
|
||||
else
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch error %d",idx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -101,6 +100,7 @@ static command_t CommandTable[] = {
|
||||
};
|
||||
|
||||
int CmdLFNEXWATCH(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
CmdsParse(CommandTable, Cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -161,10 +161,10 @@ int CmdNoralsyDemod(const char *Cmd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Noralsy Tag Found: Card ID %u, Year: %u Raw: %08X%08X%08X", cardid, year, raw1 ,raw2, raw3);
|
||||
PrintAndLogEx(SUCCESS, "Noralsy Tag Found: Card ID %u, Year: %u Raw: %08X%08X%08X", cardid, year, raw1 ,raw2, raw3);
|
||||
if (raw1 != 0xBB0214FF) {
|
||||
PrintAndLogEx(NORMAL, "Unknown bits set in first block! Expected 0xBB0214FF, Found: 0x%08X", raw1);
|
||||
PrintAndLogEx(NORMAL, "Please post this output in forum to further research on this format");
|
||||
PrintAndLogEx(WARNING, "Unknown bits set in first block! Expected 0xBB0214FF, Found: 0x%08X", raw1);
|
||||
PrintAndLogEx(WARNING, "Please post this output in forum to further research on this format");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -202,7 +202,7 @@ int CmdNoralsyClone(const char *Cmd) {
|
||||
blocks[2] = bytebits_to_byte(bits + 32, 32);
|
||||
blocks[3] = bytebits_to_byte(bits + 64, 32);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Preparing to clone Noralsy to T55x7 with CardId: %u", id);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Noralsy to T55x7 with CardId: %u", id);
|
||||
print_blocks(blocks, 4);
|
||||
|
||||
UsbCommand resp;
|
||||
@@ -247,7 +247,7 @@ int CmdNoralsySim(const char *Cmd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Simulating Noralsy - CardId: %u", id);
|
||||
PrintAndLogEx(SUCCESS, "Simulating Noralsy - CardId: %u", id);
|
||||
|
||||
UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
|
||||
memcpy(c.d.asBytes, bs, size);
|
||||
|
||||
+12
-15
@@ -12,11 +12,11 @@ static int CmdHelp(const char *Cmd);
|
||||
|
||||
int usage_lf_presco_clone(void){
|
||||
PrintAndLogEx(NORMAL, "clone a Presco tag to a T55x7 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf presco clone [h] d <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, " h : this help");
|
||||
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, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
@@ -29,11 +29,11 @@ int usage_lf_presco_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf presco sim [h] d <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, " h : this help");
|
||||
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, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf presco sim d 123456789");
|
||||
@@ -62,24 +62,22 @@ int GetWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode
|
||||
int stringlen = 0;
|
||||
memset(id, 0x00, sizeof(id));
|
||||
|
||||
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch(param_getchar(Cmd, cmdp)) {
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return -1;
|
||||
case 'H':
|
||||
case 'c':
|
||||
hex = true;
|
||||
//get hex
|
||||
*fullcode = param_get32ex(Cmd, cmdp+1, 0, 16);
|
||||
cmdp+=2;
|
||||
break;
|
||||
case 'D':
|
||||
case 'd':
|
||||
//param get string int param_getstr(const char *line, int paramnum, char * str)
|
||||
stringlen = param_getstr(Cmd, cmdp+1, id, sizeof(id));
|
||||
if (stringlen < 2) return -1;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'Q':
|
||||
case 'q':
|
||||
*Q5 = true;
|
||||
cmdp++;
|
||||
@@ -136,7 +134,6 @@ int CmdPrescoDemod(const char *Cmd) {
|
||||
size_t size = DemodBufferLen;
|
||||
int ans = detectPresco(DemodBuffer, &size);
|
||||
if (ans < 0) {
|
||||
|
||||
if (ans == -1)
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - Presco: too few bits found");
|
||||
else if (ans == -2)
|
||||
@@ -163,7 +160,7 @@ int CmdPrescoDemod(const char *Cmd) {
|
||||
char cmd[12] = {0};
|
||||
sprintf(cmd, "H %08X", cardid);
|
||||
GetWiegandFromPresco(cmd, &sitecode, &usercode, &fullcode, &Q5);
|
||||
PrintAndLogEx(NORMAL, "SiteCode %u, UserCode %u, FullCode, %08X", sitecode, usercode, fullcode);
|
||||
PrintAndLogEx(SUCCESS, "SiteCode %u, UserCode %u, FullCode, %08X", sitecode, usercode, fullcode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -190,12 +187,12 @@ int CmdPrescoClone(const char *Cmd) {
|
||||
|
||||
if ((sitecode & 0xFF) != sitecode) {
|
||||
sitecode &= 0xFF;
|
||||
PrintAndLogEx(NORMAL, "Facility-Code Truncated to 8-bits (Presco): %u", sitecode);
|
||||
PrintAndLogEx(INFO, "Facility-Code Truncated to 8-bits (Presco): %u", sitecode);
|
||||
}
|
||||
|
||||
if ((usercode & 0xFFFF) != usercode) {
|
||||
usercode &= 0xFFFF;
|
||||
PrintAndLogEx(NORMAL, "Card Number Truncated to 16-bits (Presco): %u", usercode);
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (Presco): %u", usercode);
|
||||
}
|
||||
|
||||
blocks[1] = 0x10D00000; //preamble
|
||||
@@ -203,7 +200,7 @@ int CmdPrescoClone(const char *Cmd) {
|
||||
blocks[3] = 0x00000000;
|
||||
blocks[4] = fullcode;
|
||||
|
||||
PrintAndLogEx(NORMAL, "Preparing to clone Presco to T55x7 with SiteCode: %u, UserCode: %u, FullCode: %08x", sitecode, usercode, fullcode);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Presco to T55x7 with SiteCode: %u, UserCode: %u, FullCode: %08x", sitecode, usercode, fullcode);
|
||||
print_blocks(blocks, 5);
|
||||
|
||||
UsbCommand resp;
|
||||
@@ -236,7 +233,7 @@ int CmdPrescoSim(const char *Cmd) {
|
||||
arg1 = clk << 8 | encoding;
|
||||
arg2 = invert << 8 | separator;
|
||||
|
||||
PrintAndLogEx(NORMAL, "Simulating Presco - SiteCode: %u, UserCode: %u, FullCode: %08X",sitecode, usercode, fullcode);
|
||||
PrintAndLogEx(SUCCESS, "Simulating Presco - SiteCode: %u, UserCode: %u, FullCode: %08X",sitecode, usercode, fullcode);
|
||||
|
||||
UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
|
||||
GetPrescoBits(fullcode, c.d.asBytes);
|
||||
|
||||
@@ -285,7 +285,7 @@ int CmdPyramidClone(const char *Cmd) {
|
||||
blocks[3] = bytebits_to_byte(bs + 64, 32);
|
||||
blocks[4] = bytebits_to_byte(bs + 96, 32);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Preparing to clone Farpointe/Pyramid to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber);
|
||||
print_blocks(blocks, 5);
|
||||
|
||||
UsbCommand resp;
|
||||
@@ -331,7 +331,7 @@ int CmdPyramidSim(const char *Cmd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Simulating Farpointe/Pyramid - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber );
|
||||
PrintAndLogEx(SUCCESS, "Simulating Farpointe/Pyramid - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber );
|
||||
|
||||
UsbCommand c = {CMD_FSK_SIM_TAG, {arg1, arg2, size}};
|
||||
memcpy(c.d.asBytes, bs, size);
|
||||
|
||||
@@ -97,12 +97,12 @@ int CmdSecurakeyDemod(const char *Cmd) {
|
||||
// test parities - evenparity32 looks to add an even parity returns 0 if already even...
|
||||
bool parity = !evenparity32(lWiegand) && !oddparity32(rWiegand);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Securakey Tag Found--BitLen: %u, Card ID: %u, FC: 0x%X, Raw: %08X%08X%08X", bitLen, cardid, fc, raw1 ,raw2, raw3);
|
||||
PrintAndLogEx(SUCCESS, "Securakey Tag Found--BitLen: %u, Card ID: %u, FC: 0x%X, Raw: %08X%08X%08X", bitLen, cardid, fc, raw1 ,raw2, raw3);
|
||||
if (bitLen <= 32)
|
||||
PrintAndLogEx(NORMAL, "Wiegand: %08X, Parity: %s", (lWiegand<<(bitLen/2)) | rWiegand, parity ? "Passed" : "Failed");
|
||||
PrintAndLogEx(NORMAL, "\nHow the FC translates to printed FC is unknown");
|
||||
PrintAndLogEx(NORMAL, "How the checksum is calculated is unknown");
|
||||
PrintAndLogEx(NORMAL, "Help the community identify this format further\n by sharing your tag on the pm3 forum or with forum members");
|
||||
PrintAndLogEx(SUCCESS, "Wiegand: %08X, Parity: %s", (lWiegand<<(bitLen/2)) | rWiegand, parity ? "Passed" : "Failed");
|
||||
PrintAndLogEx(INFO, "\nHow the FC translates to printed FC is unknown");
|
||||
PrintAndLogEx(INFO, "How the checksum is calculated is unknown");
|
||||
PrintAndLogEx(INFO, "Help the community identify this format further\n by sharing your tag on the pm3 forum or with forum members");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+167
-103
@@ -141,21 +141,33 @@ int usage_t55xx_wakup(){
|
||||
PrintAndLogEx(NORMAL, " lf t55xx wakeup p 11223344 - send wakeup password");
|
||||
return 0;
|
||||
}
|
||||
int usage_t55xx_bruteforce(){
|
||||
PrintAndLogEx(NORMAL, "This command uses A) bruteforce to scan a number range");
|
||||
PrintAndLogEx(NORMAL, " B) a dictionary attack");
|
||||
int usage_t55xx_chk(){
|
||||
PrintAndLogEx(NORMAL, "This command uses a dictionary attack");
|
||||
PrintAndLogEx(NORMAL, "press 'enter' to cancel the command");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf t55xx bruteforce [h] <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, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
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, " i <*.dic> - loads a default keys dictionary file <*.dic>");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf t55xx bruteforce aaaaaaaa bbbbbbbb");
|
||||
PrintAndLogEx(NORMAL, " lf t55xx bruteforce i default_pwd.dic");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return 0;
|
||||
}
|
||||
@@ -224,10 +236,9 @@ int CmdT55xxSetConfig(const char *Cmd) {
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
tmp = param_getchar(Cmd, cmdp);
|
||||
tmp = tolower(param_getchar(Cmd, cmdp));
|
||||
switch(tmp) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
return usage_t55xx_config();
|
||||
case 'b':
|
||||
errors |= param_getdec(Cmd, cmdp+1, &bitRate);
|
||||
@@ -292,12 +303,10 @@ int CmdT55xxSetConfig(const char *Cmd) {
|
||||
config.offset = offset;
|
||||
cmdp+=2;
|
||||
break;
|
||||
case 'Q':
|
||||
case 'q':
|
||||
config.Q5 = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'S':
|
||||
case 's':
|
||||
config.ST = true;
|
||||
cmdp++;
|
||||
@@ -343,8 +352,8 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32
|
||||
if (!AquireData(page1, block, usepwd, password) ) return 0;
|
||||
if (!DecodeT55xxBlock()) return 0;
|
||||
|
||||
char blk[10]={0};
|
||||
sprintf(blk,"%02d", block);
|
||||
char blk[10] = {0};
|
||||
sprintf(blk, "%02d", block);
|
||||
printT55xxBlock(blk);
|
||||
return 1;
|
||||
}
|
||||
@@ -358,22 +367,18 @@ int CmdT55xxReadBlock(const char *Cmd) {
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch(param_getchar(Cmd, cmdp)) {
|
||||
switch ( tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
return usage_t55xx_read();
|
||||
case 'b':
|
||||
case 'B':
|
||||
errors |= param_getdec(Cmd, cmdp+1, &block);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'o':
|
||||
case 'O':
|
||||
override = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
password = param_get32ex(Cmd, cmdp+1, 0, 16);
|
||||
usepwd = true;
|
||||
cmdp += 2;
|
||||
@@ -686,7 +691,7 @@ bool tryDetectModulation(){
|
||||
|
||||
bool retval = false;
|
||||
if ( hits > 1) {
|
||||
PrintAndLogEx(NORMAL, "Found [%d] possible matches for modulation.",hits);
|
||||
PrintAndLogEx(SUCCESS, "Found [%d] possible matches for modulation.", hits);
|
||||
for(int i=0; i<hits; ++i){
|
||||
retval = testKnownConfigBlock(tests[i].block0);
|
||||
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, "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, "Inverted : %s", (b.inverted) ? "Yes" : "No" );
|
||||
PrintAndLogEx(NORMAL, "Inverted : %s", (b.inverted) ? _GREEN_(Yes) : "No" );
|
||||
PrintAndLogEx(NORMAL, "Offset : %d", b.offset);
|
||||
PrintAndLogEx(NORMAL, "Seq. Term. : %s", (b.ST) ? "Yes" : "No" );
|
||||
PrintAndLogEx(NORMAL, "Seq. Term. : %s", (b.ST) ? _GREEN_(Yes) : "No" );
|
||||
PrintAndLogEx(NORMAL, "Block0 : 0x%08X", b.block0);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return 0;
|
||||
@@ -949,13 +954,11 @@ int CmdT55xxWakeUp(const char *Cmd) {
|
||||
uint32_t password = 0;
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch(param_getchar(Cmd, cmdp)) {
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
return usage_t55xx_wakup();
|
||||
case 'p':
|
||||
case 'P':
|
||||
password = param_get32ex(Cmd, cmdp+1, 0, 16);
|
||||
cmdp += 2;
|
||||
errors = false;
|
||||
@@ -971,7 +974,7 @@ int CmdT55xxWakeUp(const char *Cmd) {
|
||||
UsbCommand c = {CMD_T55XX_WAKEUP, {password, 0, 0}};
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
PrintAndLogEx(NORMAL, "Wake up command sent. Try read now");
|
||||
PrintAndLogEx(SUCCESS, "Wake up command sent. Try read now");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -985,30 +988,25 @@ int CmdT55xxWriteBlock(const char *Cmd) {
|
||||
bool testMode = false;
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch(param_getchar(Cmd, cmdp)) {
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
return usage_t55xx_write();
|
||||
case 'b':
|
||||
case 'B':
|
||||
errors |= param_getdec(Cmd, cmdp+1, &block);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
data = param_get32ex(Cmd, cmdp+1, 0, 16);
|
||||
gotdata = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
password = param_get32ex(Cmd, cmdp+1, 0, 16);
|
||||
usepwd = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
testMode = true;
|
||||
cmdp++;
|
||||
break;
|
||||
@@ -1025,7 +1023,7 @@ int CmdT55xxWriteBlock(const char *Cmd) {
|
||||
if (errors || !gotdata) return usage_t55xx_write();
|
||||
|
||||
if (block > 7) {
|
||||
PrintAndLogEx(NORMAL, "Block number must be between 0 and 7");
|
||||
PrintAndLogEx(WARNING, "Block number must be between 0 and 7");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1037,7 +1035,7 @@ int CmdT55xxWriteBlock(const char *Cmd) {
|
||||
char pwdStr[16] = {0};
|
||||
snprintf(pwdStr, sizeof(pwdStr), "pwd: 0x%08X", password);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Writing page %d block: %02d data: 0x%08X %s", page1, block, data, (usepwd) ? pwdStr : "" );
|
||||
PrintAndLogEx(INFO, "Writing page %d block: %02d data: 0x%08X %s", page1, block, data, (usepwd) ? pwdStr : "" );
|
||||
|
||||
//Password mode
|
||||
if (usepwd) {
|
||||
@@ -1054,12 +1052,13 @@ int CmdT55xxWriteBlock(const char *Cmd) {
|
||||
}
|
||||
|
||||
int CmdT55xxReadTrace(const char *Cmd) {
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
bool pwdmode = false;
|
||||
uint32_t password = 0;
|
||||
if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') return usage_t55xx_trace();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) > 1 || cmdp == 'h') return usage_t55xx_trace();
|
||||
|
||||
if (strlen(Cmd)==0) {
|
||||
bool pwdmode = false;
|
||||
uint32_t password = 0;
|
||||
|
||||
if (strlen(Cmd) == 0) {
|
||||
// sanity check.
|
||||
if (!SanityOfflineCheck(false)) return 1;
|
||||
|
||||
@@ -1086,7 +1085,7 @@ int CmdT55xxReadTrace(const char *Cmd) {
|
||||
uint32_t hdr = PackBits(si, 9, DemodBuffer); si += 9;
|
||||
|
||||
if (hdr != 0x1FF) {
|
||||
PrintAndLogEx(NORMAL, "Invalid Q5 Trace data header (expected 0x1FF, found %X)", hdr);
|
||||
PrintAndLogEx(FAILED, "Invalid Q5 Trace data header (expected 0x1FF, found %X)", hdr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1125,7 +1124,7 @@ int CmdT55xxReadTrace(const char *Cmd) {
|
||||
|
||||
data.acl = PackBits(si, 8, DemodBuffer); si += 8;
|
||||
if ( data.acl != 0xE0 ) {
|
||||
PrintAndLogEx(NORMAL, "The modulation is most likely wrong since the ACL is not 0xE0. ");
|
||||
PrintAndLogEx(FAILED, "The modulation is most likely wrong since the ACL is not 0xE0. ");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1222,11 +1221,11 @@ int CmdT55xxInfo(const char *Cmd){
|
||||
*/
|
||||
bool pwdmode = false;
|
||||
uint32_t password = 0;
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
|
||||
if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') return usage_t55xx_info();
|
||||
if (strlen(Cmd) > 1 || cmdp == 'h') return usage_t55xx_info();
|
||||
|
||||
if (strlen(Cmd)==0){
|
||||
if (strlen(Cmd) == 0) {
|
||||
// sanity check.
|
||||
if (!SanityOfflineCheck(false)) return 1;
|
||||
|
||||
@@ -1259,24 +1258,26 @@ int CmdT55xxInfo(const char *Cmd){
|
||||
uint32_t inv = PackBits(si, 1, DemodBuffer); si += 1;
|
||||
uint32_t por = PackBits(si, 1, DemodBuffer); si += 1;
|
||||
|
||||
if (config.Q5) PrintAndLogEx(NORMAL, "*** Warning *** Config Info read off a Q5 will not display as expected");
|
||||
if (config.Q5)
|
||||
PrintAndLogEx(NORMAL, _RED_(*** Warning ***) " Config Info read off a Q5 will not display as expected");
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "-- T55x7 Configuration & Tag Information --------------------");
|
||||
PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
|
||||
PrintAndLogEx(NORMAL, " Safer key : %s", GetSaferStr(safer));
|
||||
PrintAndLogEx(NORMAL, " reserved : %d", resv);
|
||||
PrintAndLogEx(NORMAL, " Data bit rate : %s", GetBitRateStr(dbr, extend));
|
||||
PrintAndLogEx(NORMAL, " eXtended mode : %s", (extend) ? "Yes - Warning":"No");
|
||||
PrintAndLogEx(NORMAL, " eXtended mode : %s", (extend) ? _YELLOW_(Yes - Warning) : "No");
|
||||
PrintAndLogEx(NORMAL, " Modulation : %s", GetModulationStr(datamod));
|
||||
PrintAndLogEx(NORMAL, " PSK clock frequency : %d", pskcf);
|
||||
PrintAndLogEx(NORMAL, " AOR - Answer on Request : %s", (aor) ? "Yes":"No");
|
||||
PrintAndLogEx(NORMAL, " OTP - One Time Pad : %s", (otp) ? "Yes - Warning":"No" );
|
||||
PrintAndLogEx(NORMAL, " AOR - Answer on Request : %s", (aor) ? _GREEN_(Yes) : "No");
|
||||
PrintAndLogEx(NORMAL, " OTP - One Time Pad : %s", (otp) ? _YELLOW_(Yes - Warning) : "No" );
|
||||
PrintAndLogEx(NORMAL, " Max block : %d", maxblk);
|
||||
PrintAndLogEx(NORMAL, " Password mode : %s", (pwd) ? "Yes":"No");
|
||||
PrintAndLogEx(NORMAL, " Sequence Start Terminator : %s", (sst) ? "Yes":"No");
|
||||
PrintAndLogEx(NORMAL, " Fast Write : %s", (fw) ? "Yes":"No");
|
||||
PrintAndLogEx(NORMAL, " Inverse data : %s", (inv) ? "Yes":"No");
|
||||
PrintAndLogEx(NORMAL, " POR-Delay : %s", (por) ? "Yes":"No");
|
||||
PrintAndLogEx(NORMAL, " Password mode : %s", (pwd) ? _GREEN_(Yes) : "No");
|
||||
PrintAndLogEx(NORMAL, " Sequence Start Terminator : %s", (sst) ? _GREEN_(Yes) : "No");
|
||||
PrintAndLogEx(NORMAL, " Fast Write : %s", (fw) ? _GREEN_(Yes) : "No");
|
||||
PrintAndLogEx(NORMAL, " Inverse data : %s", (inv) ? _GREEN_(Yes) : "No");
|
||||
PrintAndLogEx(NORMAL, " POR-Delay : %s", (por) ? _GREEN_(Yes) : "No");
|
||||
PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
|
||||
PrintAndLogEx(NORMAL, " Raw Data - Page 0");
|
||||
PrintAndLogEx(NORMAL, " Block 0 : 0x%08X %s", block0, sprint_bin(DemodBuffer + config.offset, 32) );
|
||||
@@ -1288,8 +1289,8 @@ int CmdT55xxDump(const char *Cmd){
|
||||
|
||||
uint32_t password = 0;
|
||||
bool override = false;
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if ( cmdp == 'h' || cmdp == 'H') return usage_t55xx_dump();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if ( cmdp == 'h') return usage_t55xx_dump();
|
||||
|
||||
bool usepwd = ( strlen(Cmd) > 0);
|
||||
if ( usepwd ){
|
||||
@@ -1474,7 +1475,7 @@ int CmdT55xxWipe(const char *Cmd) {
|
||||
|
||||
// Try with the default password to reset block 0
|
||||
// With a pwd should work even if pwd bit not set
|
||||
PrintAndLogEx(NORMAL, "\nBeginning Wipe of a T55xx tag (assuming the tag is not password protected)\n");
|
||||
PrintAndLogEx(INFO, "\nBeginning Wipe of a T55xx tag (assuming the tag is not password protected)\n");
|
||||
|
||||
if ( Q5 )
|
||||
snprintf(ptrData,sizeof(writeData),"b 0 d 6001F004 p 0");
|
||||
@@ -1489,7 +1490,7 @@ int CmdT55xxWipe(const char *Cmd) {
|
||||
|
||||
if (!CmdT55xxWriteBlock(ptrData)) PrintAndLogEx(WARNING, "Error writing blk %d", blk);
|
||||
|
||||
memset(writeData,0x00, sizeof(writeData));
|
||||
memset(writeData, 0x00, sizeof(writeData));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1503,23 +1504,68 @@ bool IsCancelled(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int CmdT55xxBruteForce(const char *Cmd) {
|
||||
|
||||
int CmdT55xxChkPwds(const char *Cmd) {
|
||||
// load a default pwd file.
|
||||
char line[9];
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
int keycnt = 0;
|
||||
uint8_t stKeyBlock = 20;
|
||||
uint8_t *keyBlock = NULL, *p = NULL;
|
||||
uint32_t start_password = 0x00000000; //start password
|
||||
uint32_t end_password = 0xFFFFFFFF; //end password
|
||||
bool found = false;
|
||||
uint8_t timeout = 0;
|
||||
|
||||
memset(line, 0, sizeof(line));
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_t55xx_bruteforce();
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_t55xx_chk();
|
||||
|
||||
/*
|
||||
if ( T55xxReadBlock(7, 0, 0, 0, 0) ) {
|
||||
|
||||
// now try to validate it..
|
||||
PrintAndLogEx(WARNING, "\n Block 7 was readable");
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
if ( cmdp == 'm' ) {
|
||||
UsbCommand c = {CMD_T55XX_CHKPWDS, {0,0,0} };
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
UsbCommand resp;
|
||||
|
||||
while ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) {
|
||||
timeout++;
|
||||
printf("."); fflush(stdout);
|
||||
if (timeout > 180) {
|
||||
PrintAndLogEx(WARNING, "\nno response from Proxmark. Aborting...");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if ( resp.arg[0] ) {
|
||||
PrintAndLogEx(SUCCESS, "\nFound a candidate [ %08X ]. Trying to validate", resp.arg[1]);
|
||||
|
||||
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, resp.arg[1])) {
|
||||
PrintAndLogEx(INFO, "Aquireing data from device failed. Quitting");
|
||||
return 2;
|
||||
}
|
||||
|
||||
found = tryDetectModulation();
|
||||
if (found) {
|
||||
PrintAndLogEx(SUCCESS, "Found valid password: [ %08X ]", resp.arg[1]);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Password NOT found.");
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Password NOT found.");
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
keyBlock = calloc(stKeyBlock, 4);
|
||||
if (keyBlock == NULL) return 1;
|
||||
|
||||
@@ -1531,7 +1577,7 @@ int CmdT55xxBruteForce(const char *Cmd) {
|
||||
|
||||
FILE * f = fopen( filename , "r");
|
||||
if ( !f ) {
|
||||
PrintAndLogEx(NORMAL, "File: %s: not found or locked.", filename);
|
||||
PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename);
|
||||
free(keyBlock);
|
||||
return 1;
|
||||
}
|
||||
@@ -1546,7 +1592,7 @@ int CmdT55xxBruteForce(const char *Cmd) {
|
||||
if( line[0]=='#' ) continue;
|
||||
|
||||
if (!isxdigit(line[0])) {
|
||||
PrintAndLogEx(NORMAL, "File content error. '%s' must include 8 HEX symbols", line);
|
||||
PrintAndLogEx(WARNING, "File content error. '%s' must include 8 HEX symbols", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1569,19 +1615,20 @@ int CmdT55xxBruteForce(const char *Cmd) {
|
||||
|
||||
num_to_bytes( strtoll(line, NULL, 16), 4, keyBlock + 4*keycnt);
|
||||
|
||||
PrintAndLogEx(NORMAL, "chk custom pwd[%2d] %08X", keycnt, bytes_to_num(keyBlock + 4 * keycnt, 4) );
|
||||
// PrintAndLogEx(NORMAL, "chk custom pwd[%2d] %08X", keycnt, bytes_to_num(keyBlock + 4 * keycnt, 4) );
|
||||
keycnt++;
|
||||
memset(line, 0, sizeof(line));
|
||||
}
|
||||
}
|
||||
|
||||
if (f)
|
||||
fclose(f);
|
||||
|
||||
if (keycnt == 0) {
|
||||
PrintAndLogEx(NORMAL, "No keys found in file");
|
||||
PrintAndLogEx(WARNING, "No keys found in file");
|
||||
free(keyBlock);
|
||||
return 1;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "Loaded %d keys", keycnt);
|
||||
PrintAndLogEx(SUCCESS, "Loaded %d keys", keycnt);
|
||||
|
||||
// loop
|
||||
uint64_t testpwd = 0x00;
|
||||
@@ -1600,74 +1647,92 @@ int CmdT55xxBruteForce(const char *Cmd) {
|
||||
|
||||
testpwd = bytes_to_num(keyBlock + 4*c, 4);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Testing %08X", testpwd);
|
||||
PrintAndLogEx(INFO, "Testing %08X", testpwd);
|
||||
|
||||
if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd)) {
|
||||
PrintAndLogEx(NORMAL, "Aquireing data from device failed. Quitting");
|
||||
PrintAndLogEx(INFO, "Aquireing data from device failed. Quitting");
|
||||
free(keyBlock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
found = tryDetectModulation();
|
||||
if ( found ) {
|
||||
PrintAndLogEx(NORMAL, "Found valid password: [%08X]", testpwd);
|
||||
//free(keyBlock);
|
||||
//return 0;
|
||||
}
|
||||
if ( found )
|
||||
break;
|
||||
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "Password NOT found.");
|
||||
free(keyBlock);
|
||||
return 0;
|
||||
if ( found )
|
||||
PrintAndLogEx(SUCCESS, "Found valid password: [ %08X ]", testpwd);
|
||||
else
|
||||
PrintAndLogEx(WARNING, "Password NOT found.");
|
||||
}
|
||||
|
||||
free(keyBlock);
|
||||
|
||||
out:
|
||||
t1 = msclock() - t1;
|
||||
PrintAndLogEx(SUCCESS, "\nTime in bruteforce: %.0f seconds\n", (float)t1/1000.0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdT55xxBruteForce(const char *Cmd) {
|
||||
|
||||
uint32_t start_password = 0x00000000; //start password
|
||||
uint32_t end_password = 0xFFFFFFFF; //end password
|
||||
uint32_t curr = 0;
|
||||
bool found = false;
|
||||
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_t55xx_bruteforce();
|
||||
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
// Try to read Block 7, first :)
|
||||
|
||||
// incremental pwd range search
|
||||
start_password = param_get32ex(Cmd, 0, 0, 16);
|
||||
end_password = param_get32ex(Cmd, 1, 0, 16);
|
||||
|
||||
curr = start_password;
|
||||
|
||||
if ( start_password >= end_password ) {
|
||||
free(keyBlock);
|
||||
return usage_t55xx_bruteforce();
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Search password range [%08X -> %08X]", start_password, end_password);
|
||||
|
||||
uint32_t i = start_password;
|
||||
PrintAndLogEx(INFO, "Search password range [%08X -> %08X]", start_password, end_password);
|
||||
|
||||
while ((!found) && (i <= end_password)){
|
||||
while ( !found || (curr <= end_password)){
|
||||
|
||||
printf("."); fflush(stdout);
|
||||
|
||||
if (IsCancelled()) {
|
||||
free(keyBlock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i)) {
|
||||
PrintAndLogEx(NORMAL, "Aquireing data from device failed. Quitting");
|
||||
free(keyBlock);
|
||||
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, curr)) {
|
||||
PrintAndLogEx(WARNING, "Aquireing data from device failed. Quitting");
|
||||
return 0;
|
||||
}
|
||||
|
||||
found = tryDetectModulation();
|
||||
|
||||
if (found) break;
|
||||
i++;
|
||||
|
||||
++curr;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
if (found)
|
||||
PrintAndLogEx(NORMAL, "Found valid password: [%08x]", i);
|
||||
PrintAndLogEx(SUCCESS, "Found valid password: [ %08X ]", curr);
|
||||
else
|
||||
PrintAndLogEx(NORMAL, "Password NOT found. Last tried: [%08x]", --i);
|
||||
PrintAndLogEx(WARNING, "Password NOT found. Last tried: [ %08X ]", --curr);
|
||||
|
||||
free(keyBlock);
|
||||
t1 = msclock() - t1;
|
||||
PrintAndLogEx(SUCCESS, "\nTime in bruteforce: %.0f seconds\n", (float)t1/1000.0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tryOnePassword(uint32_t password) {
|
||||
PrintAndLogEx(NORMAL, "Trying password %08x", password);
|
||||
PrintAndLogEx(INFO, "Trying password %08x", password);
|
||||
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, password)) {
|
||||
PrintAndLogEx(NORMAL, "Acquire data from device failed. Quitting");
|
||||
return -1;
|
||||
@@ -1686,8 +1751,8 @@ int CmdT55xxRecoverPW(const char *Cmd) {
|
||||
uint32_t prev_password = 0xffffffff;
|
||||
uint32_t mask = 0x0;
|
||||
int found = 0;
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (cmdp == 'h' || cmdp == 'H') return usage_t55xx_recoverpw();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h' ) return usage_t55xx_recoverpw();
|
||||
|
||||
orig_password = param_get32ex(Cmd, 0, 0x51243648, 16); //password used by handheld cloners
|
||||
|
||||
@@ -1746,9 +1811,9 @@ int CmdT55xxRecoverPW(const char *Cmd) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
if (found == 1)
|
||||
PrintAndLogEx(NORMAL, "Found valid password: [%08x]", curr_password);
|
||||
PrintAndLogEx(SUCCESS, "Found valid password: [%08x]", curr_password);
|
||||
else
|
||||
PrintAndLogEx(NORMAL, "Password NOT found.");
|
||||
PrintAndLogEx(WARNING, "Password NOT found.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1870,13 +1935,11 @@ int CmdT55xxDetectPage1(const char *Cmd){
|
||||
uint32_t password = 0;
|
||||
uint8_t cmdp = 0;
|
||||
|
||||
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch(param_getchar(Cmd, cmdp)) {
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
return usage_t55xx_detectP1();
|
||||
case 'p':
|
||||
case 'P':
|
||||
password = param_get32ex(Cmd, cmdp+1, 0, 16);
|
||||
usepwd = true;
|
||||
cmdp += 2;
|
||||
@@ -1899,7 +1962,7 @@ int CmdT55xxDetectPage1(const char *Cmd){
|
||||
return false;
|
||||
}
|
||||
bool success = tryDetectP1(false);
|
||||
if (success) PrintAndLogEx(NORMAL, "T55xx chip found!");
|
||||
if (success) PrintAndLogEx(SUCCESS, "T55xx chip found!");
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -1959,6 +2022,7 @@ static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
{"bruteforce", CmdT55xxBruteForce,0, "<start password> <end password> [i <*.dic>] Simple bruteforce attack to find password"},
|
||||
{"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"},
|
||||
{"chk", CmdT55xxChkPwds, 1, "Check passwords"},
|
||||
{"detect", CmdT55xxDetect, 1, "[1] Try detecting the tag modulation from reading the configuration block."},
|
||||
{"deviceconfig", CmdT55xxSetDeviceConfig, 1, "Set/Get T55XX device configuration (startgap, writegap, write0, write1, readgap"},
|
||||
{"p1detect", CmdT55xxDetectPage1,1, "[1] Try detecting if this is a t55xx tag by reading page 1"},
|
||||
|
||||
@@ -133,6 +133,7 @@ t55xx_conf_block_t Get_t55xx_Config(void);
|
||||
void Set_t55xx_Config(t55xx_conf_block_t conf);
|
||||
|
||||
extern int CmdLFT55XX(const char *Cmd);
|
||||
extern int CmdT55xxChk(const char *Cmd);
|
||||
extern int CmdT55xxBruteForce(const char *Cmd);
|
||||
extern int CmdT55xxSetConfig(const char *Cmd);
|
||||
extern int CmdT55xxReadBlock(const char *Cmd);
|
||||
|
||||
@@ -118,7 +118,7 @@ int CmdVikingClone(const char *Cmd) {
|
||||
|
||||
rawID = getVikingBits(id);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Cloning - ID: %08X, Raw: %08X%08X",id,(uint32_t)(rawID >> 32),(uint32_t) (rawID & 0xFFFFFFFF));
|
||||
PrintAndLogEx(INFO, "Preparing to clone Viking tag - ID: %08X, Raw: %08X%08X",id,(uint32_t)(rawID >> 32),(uint32_t) (rawID & 0xFFFFFFFF));
|
||||
|
||||
UsbCommand c = {CMD_VIKING_CLONE_TAG, {rawID >> 32, rawID & 0xFFFFFFFF, Q5}};
|
||||
clearCommandBuffer();
|
||||
@@ -149,7 +149,7 @@ int CmdVikingSim(const char *Cmd) {
|
||||
arg1 = clk << 8 | encoding;
|
||||
arg2 = invert << 8 | separator;
|
||||
|
||||
PrintAndLogEx(NORMAL, "Simulating Viking - ID: %08X, Raw: %08X%08X",id,(uint32_t)(rawID >> 32),(uint32_t) (rawID & 0xFFFFFFFF));
|
||||
PrintAndLogEx(SUCCESS, "Simulating Viking - ID: %08X, Raw: %08X%08X",id,(uint32_t)(rawID >> 32),(uint32_t) (rawID & 0xFFFFFFFF));
|
||||
|
||||
UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
|
||||
num_to_bytebits(rawID, size, c.d.asBytes);
|
||||
|
||||
@@ -165,8 +165,8 @@ int CmdVisa2kClone(const char *Cmd) {
|
||||
uint64_t id = 0;
|
||||
uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_64 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, BL0CK1, 0};
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_visa2k_clone();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_visa2k_clone();
|
||||
|
||||
id = param_get32ex(Cmd, 0, 0, 10);
|
||||
|
||||
@@ -210,7 +210,7 @@ int CmdVisa2kSim(const char *Cmd) {
|
||||
arg1 = clk << 8 | encoding;
|
||||
arg2 = invert << 8 | separator;
|
||||
|
||||
PrintAndLogEx(NORMAL, "Simulating Visa2000 - CardId: %u", id);
|
||||
PrintAndLogEx(SUCCESS, "Simulating Visa2000 - CardId: %u", id);
|
||||
|
||||
UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
|
||||
|
||||
|
||||
+3
-3
@@ -24,14 +24,14 @@ static command_t CommandTable[] = {
|
||||
{"lf", CmdLF, 1, "{ Low Frequency commands... }"},
|
||||
{"emv", CmdEMV, 1, "{ EMV iso14443 and iso7816... }"},
|
||||
{"rem", CmdRem, 1, "{ Add text to row in log file }"},
|
||||
{"reveng", CmdRev, 1, "{ Crc calculations from the software reveng 1.53... }"},
|
||||
{"reveng", CmdRev, 1, "{ Crc calculations from the RevEng software... }"},
|
||||
{"script", CmdScript, 1, "{ Scripting commands }"},
|
||||
{"trace", CmdTrace, 1, "{ Trace manipulation... }"},
|
||||
#ifdef WITH_FLASH
|
||||
{"mem", CmdFlashMem, 1, "{ RDV40, Flash Memory manipulation... }"},
|
||||
{"mem", CmdFlashMem, 1, "{ Flash Memory manipulation... }"},
|
||||
#endif
|
||||
#ifdef WITH_SMARTCARD
|
||||
{"sc", CmdSmartcard, 1, "{ RDV40, Smart card ISO7816 commands... }"},
|
||||
{"sc", CmdSmartcard, 1, "{ Smart card ISO7816 commands... }"},
|
||||
#endif
|
||||
{"quit", CmdQuit, 1, ""},
|
||||
{"exit", CmdQuit, 1, "Exit program"},
|
||||
|
||||
+397
-123
@@ -8,6 +8,7 @@
|
||||
// Proxmark3 RDV40 Smartcard module commands
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdsmartcard.h"
|
||||
#include "../emv/emvjson.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
@@ -15,14 +16,18 @@ int usage_sm_raw(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: sc raw [h|r|c] d <0A 0B 0C ... hex>");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " r : do not read response");
|
||||
PrintAndLogEx(NORMAL, " a : active smartcard without select");
|
||||
PrintAndLogEx(NORMAL, " s : active smartcard with select");
|
||||
PrintAndLogEx(NORMAL, " a : active smartcard without select (reset sc module)");
|
||||
PrintAndLogEx(NORMAL, " s : active smartcard with select (get ATR)");
|
||||
PrintAndLogEx(NORMAL, " t : executes TLV decoder if it possible");
|
||||
PrintAndLogEx(NORMAL, " 0 : use protocol T=0");
|
||||
PrintAndLogEx(NORMAL, " d <bytes> : bytes to send");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " sc raw d 00a404000e315041592e5359532e444446303100 - `1PAY.SYS.DDF01` PPSE directory");
|
||||
PrintAndLogEx(NORMAL, " sc raw d 00a404000e325041592e5359532e444446303100 - `2PAY.SYS.DDF01` PPSE directory");
|
||||
PrintAndLogEx(NORMAL, " sc raw s 0 d 00a404000e315041592e5359532e4444463031 - `1PAY.SYS.DDF01` PPSE directory with get ATR");
|
||||
PrintAndLogEx(NORMAL, " sc raw 0 d 00a404000e325041592e5359532e4444463031 - `2PAY.SYS.DDF01` PPSE directory");
|
||||
PrintAndLogEx(NORMAL, " sc raw 0 t d 00a4040007a0000000041010 - Mastercard");
|
||||
PrintAndLogEx(NORMAL, " sc raw 0 t d 00a4040007a0000000031010 - Visa");
|
||||
|
||||
return 0;
|
||||
}
|
||||
int usage_sm_reader(void) {
|
||||
@@ -63,15 +68,48 @@ int usage_sm_setclock(void) {
|
||||
return 0;
|
||||
}
|
||||
int usage_sm_brute(void) {
|
||||
PrintAndLogEx(NORMAL, "Tries to bruteforce SFI, ");
|
||||
PrintAndLogEx(NORMAL, "Tries to bruteforce SFI, using a known list of AID's ");
|
||||
PrintAndLogEx(NORMAL, "Usage: sc brute [h]");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " t : executes TLV decoder if it possible");
|
||||
// PrintAndLogEx(NORMAL, " 0 : use protocol T=0");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " sc brute");
|
||||
PrintAndLogEx(NORMAL, " sc brute t");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smart_loadjson(const char *preferredName, const char *suffix, json_t **root) {
|
||||
|
||||
json_error_t error;
|
||||
|
||||
if ( preferredName == NULL ) return 1;
|
||||
if ( suffix == NULL ) return 1;
|
||||
|
||||
int retval = 0;
|
||||
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
|
||||
char * fileName = calloc(size, sizeof(char));
|
||||
sprintf(fileName, "%s.%s", preferredName, suffix);
|
||||
|
||||
*root = json_load_file(fileName, 0, &error);
|
||||
if (!*root) {
|
||||
PrintAndLogEx(ERR, "json (%s) error on line %d: %s", fileName, error.line, error.text);
|
||||
retval = 2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!json_is_array(*root)) {
|
||||
PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", fileName);
|
||||
retval = 3;
|
||||
goto out;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Loaded file (%s) OK.", fileName);
|
||||
out:
|
||||
free(fileName);
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint8_t GetATRTA1(uint8_t *atr, size_t atrlen) {
|
||||
if (atrlen > 2) {
|
||||
uint8_t T0 = atr[1];
|
||||
@@ -79,7 +117,7 @@ uint8_t GetATRTA1(uint8_t *atr, size_t atrlen) {
|
||||
return atr[2];
|
||||
}
|
||||
|
||||
return 0x11; // default value is ‘0x11’, corresponding to fmax=5 MHz, Fi=372, Di=1.
|
||||
return 0x11; // default value is ‘0x11’, corresponding to fmax=5 MHz, Fi=372, Di=1.
|
||||
}
|
||||
|
||||
int DiArray[] = {
|
||||
@@ -141,75 +179,60 @@ float FArray[] = {
|
||||
|
||||
int GetATRDi(uint8_t *atr, size_t atrlen) {
|
||||
uint8_t TA1 = GetATRTA1(atr, atrlen);
|
||||
|
||||
return DiArray[TA1 & 0x0f]; // The 4 low-order bits of TA1 (4th MSbit to 1st LSbit) encode Di
|
||||
return DiArray[TA1 & 0x0F]; // The 4 low-order bits of TA1 (4th MSbit to 1st LSbit) encode Di
|
||||
}
|
||||
|
||||
int GetATRFi(uint8_t *atr, size_t atrlen) {
|
||||
uint8_t TA1 = GetATRTA1(atr, atrlen);
|
||||
|
||||
return FiArray[TA1 >> 4]; // The 4 high-order bits of TA1 (8th MSbit to 5th LSbit) encode fmax and Fi
|
||||
}
|
||||
|
||||
float GetATRF(uint8_t *atr, size_t atrlen) {
|
||||
uint8_t TA1 = GetATRTA1(atr, atrlen);
|
||||
|
||||
return FArray[TA1 >> 4]; // The 4 high-order bits of TA1 (8th MSbit to 5th LSbit) encode fmax and Fi
|
||||
}
|
||||
|
||||
static int PrintATR(uint8_t *atr, size_t atrlen) {
|
||||
uint8_t vxor = 0;
|
||||
for (int i = 1; i < atrlen; i++)
|
||||
vxor ^= atr[i];
|
||||
|
||||
if (vxor)
|
||||
PrintAndLogEx(WARNING, "Check summ error. Must be 0 but: 0x%02x", vxor);
|
||||
else
|
||||
PrintAndLogEx(INFO, "Check summ OK.");
|
||||
|
||||
if (atr[0] != 0x3b)
|
||||
PrintAndLogEx(WARNING, "Not a direct convention: 0x%02x", atr[0]);
|
||||
|
||||
uint8_t T0 = atr[1];
|
||||
uint8_t K = T0 & 0x0F;
|
||||
uint8_t TD1 = 0;
|
||||
|
||||
uint8_t T1len = 0;
|
||||
uint8_t TD1len = 0;
|
||||
uint8_t TDilen = 0;
|
||||
uint8_t TD1 = 0, T1len = 0, TD1len = 0, TDilen = 0;
|
||||
|
||||
if (T0 & 0x10) {
|
||||
PrintAndLog("TA1 (Maximum clock frequency, proposed bit duration): 0x%02x", atr[2 + T1len]);
|
||||
PrintAndLog("\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]);
|
||||
T1len++;
|
||||
}
|
||||
|
||||
if (T0 & 0x20) {
|
||||
PrintAndLog("TB1 (Deprecated: VPP requirements): 0x%02x", atr[2 + T1len]);
|
||||
PrintAndLog("\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]);
|
||||
T1len++;
|
||||
}
|
||||
|
||||
if (T0 & 0x40) {
|
||||
PrintAndLog("TC1 (Extra delay between bytes required by card): 0x%02x", atr[2 + T1len]);
|
||||
PrintAndLog("\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]);
|
||||
T1len++;
|
||||
}
|
||||
|
||||
if (T0 & 0x80) {
|
||||
TD1 = atr[2 + T1len];
|
||||
PrintAndLog("TD1 (First offered transmission protocol, presence of TA2..TD2): 0x%02x. Protocol T=%d", TD1, TD1 & 0x0f);
|
||||
PrintAndLog("\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f);
|
||||
T1len++;
|
||||
|
||||
if (TD1 & 0x10) {
|
||||
PrintAndLog("TA2 (Specific protocol and parameters to be used after the ATR): 0x%02x", atr[2 + T1len + TD1len]);
|
||||
PrintAndLog("\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
TD1len++;
|
||||
}
|
||||
if (TD1 & 0x20) {
|
||||
PrintAndLog("TB2 (Deprecated: VPP precise voltage requirement): 0x%02x", atr[2 + T1len + TD1len]);
|
||||
PrintAndLog("\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
TD1len++;
|
||||
}
|
||||
if (TD1 & 0x40) {
|
||||
PrintAndLog("TC2 (Maximum waiting time for protocol T=0): 0x%02x", atr[2 + T1len + TD1len]);
|
||||
PrintAndLog("\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
TD1len++;
|
||||
}
|
||||
if (TD1 & 0x80) {
|
||||
uint8_t TDi = atr[2 + T1len + TD1len];
|
||||
PrintAndLog("TD2 (A supported protocol or more global parameters, presence of TA3..TD3): 0x%02x. Protocol T=%d", TDi, TDi & 0x0f);
|
||||
PrintAndLog("\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f);
|
||||
TD1len++;
|
||||
|
||||
bool nextCycle = true;
|
||||
@@ -217,20 +240,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
|
||||
while (nextCycle) {
|
||||
nextCycle = false;
|
||||
if (TDi & 0x10) {
|
||||
PrintAndLog("TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
PrintAndLog("\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
TDilen++;
|
||||
}
|
||||
if (TDi & 0x20) {
|
||||
PrintAndLog("TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
PrintAndLog("\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
TDilen++;
|
||||
}
|
||||
if (TDi & 0x40) {
|
||||
PrintAndLog("TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
PrintAndLog("\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
TDilen++;
|
||||
}
|
||||
if (TDi & 0x80) {
|
||||
TDi = atr[2 + T1len + TD1len + TDilen];
|
||||
PrintAndLog("TD%d: 0x%02x. Protocol T=%d", vi, TDi, TDi & 0x0f);
|
||||
PrintAndLog("\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f);
|
||||
TDilen++;
|
||||
|
||||
nextCycle = true;
|
||||
@@ -239,27 +262,40 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t vxor = 0;
|
||||
for (int i = 1; i < atrlen; i++)
|
||||
vxor ^= atr[i];
|
||||
|
||||
if (vxor)
|
||||
PrintAndLogEx(WARNING, "Check summ error. Must be 0 got 0x%02X", vxor);
|
||||
else
|
||||
PrintAndLogEx(INFO, "Check summ OK.");
|
||||
|
||||
if (atr[0] != 0x3b)
|
||||
PrintAndLogEx(WARNING, "Not a direct convention [ 0x%02x ]", atr[0]);
|
||||
|
||||
|
||||
uint8_t calen = 2 + T1len + TD1len + TDilen + K;
|
||||
|
||||
if (atrlen != calen && atrlen != calen + 1) // may be CRC
|
||||
PrintAndLogEx(ERR, "ATR length error. len: %d, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K);
|
||||
else
|
||||
PrintAndLogEx(INFO, "ATR length OK.");
|
||||
|
||||
PrintAndLog("Historical bytes len: 0x%02x", K);
|
||||
if (K > 0)
|
||||
PrintAndLog("The format of historical bytes: %02x", atr[2 + T1len + TD1len + TDilen]);
|
||||
PrintAndLogEx(INFO, "\nHistorical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]);
|
||||
|
||||
if (K > 1) {
|
||||
PrintAndLog("Historical bytes:");
|
||||
PrintAndLogEx(INFO, "\tHistorical bytes");
|
||||
dump_buffer(&atr[2 + T1len + TD1len + TDilen], K, NULL, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool smart_select(bool silent, smart_card_atr_t *atr) {
|
||||
if (atr)
|
||||
memset(atr, 0, sizeof(smart_card_atr_t));
|
||||
|
||||
static bool smart_select(bool silent) {
|
||||
UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}};
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
@@ -275,40 +311,43 @@ static bool smart_select(bool silent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!silent) {
|
||||
smart_card_atr_t card;
|
||||
memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t));
|
||||
|
||||
smart_card_atr_t card;
|
||||
memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t));
|
||||
|
||||
if (atr)
|
||||
memcpy(atr, &card, sizeof(smart_card_atr_t));
|
||||
|
||||
if (!silent)
|
||||
PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int smart_wait(uint8_t *data) {
|
||||
static int smart_wait(uint8_t *data, bool silent) {
|
||||
UsbCommand resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
PrintAndLogEx(WARNING, "smart card response failed");
|
||||
if (!silent) PrintAndLogEx(WARNING, "smart card response timeout");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t len = resp.arg[0];
|
||||
if ( !len ) {
|
||||
PrintAndLogEx(WARNING, "smart card response failed");
|
||||
if (!silent) PrintAndLogEx(WARNING, "smart card response failed");
|
||||
return -2;
|
||||
}
|
||||
memcpy(data, resp.d.asBytes, len);
|
||||
PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 32));
|
||||
|
||||
if (len >= 2) {
|
||||
PrintAndLogEx(SUCCESS, "%02X%02X | %s", data[len - 2], data[len - 1], GetAPDUCodeDescription(data[len - 2], data[len - 1]));
|
||||
if (!silent) PrintAndLogEx(SUCCESS, "%02X%02X | %s", data[len - 2], data[len - 1], GetAPDUCodeDescription(data[len - 2], data[len - 1]));
|
||||
} else {
|
||||
if (!silent) PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 8));
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int smart_response(uint8_t *data) {
|
||||
static int smart_responseEx(uint8_t *data, bool silent) {
|
||||
|
||||
int datalen = smart_wait(data);
|
||||
int datalen = smart_wait(data, silent);
|
||||
bool needGetData = false;
|
||||
|
||||
if (datalen < 2 ) {
|
||||
@@ -321,14 +360,14 @@ static int smart_response(uint8_t *data) {
|
||||
|
||||
if (needGetData) {
|
||||
int len = data[datalen - 1];
|
||||
PrintAndLogEx(INFO, "Requesting response. len=0x%x", len);
|
||||
uint8_t getstatus[] = {0x00, ISO7816_GETSTATUS, 0x00, 0x00, len};
|
||||
if (!silent) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len);
|
||||
uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len};
|
||||
UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}};
|
||||
memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) );
|
||||
clearCommandBuffer();
|
||||
SendCommand(&cStatus);
|
||||
|
||||
datalen = smart_wait(data);
|
||||
datalen = smart_wait(data, silent);
|
||||
|
||||
if (datalen < 2 ) {
|
||||
goto out;
|
||||
@@ -338,8 +377,10 @@ static int smart_response(uint8_t *data) {
|
||||
if (datalen != len + 2) {
|
||||
// data with ACK
|
||||
if (datalen == len + 2 + 1) { // 2 - response, 1 - ACK
|
||||
if (data[0] != ISO7816_GETSTATUS) {
|
||||
PrintAndLogEx(ERR, "GetResponse ACK error. len=0x%x data[0]=%02x", len, data[0]);
|
||||
if (data[0] != ISO7816_GET_RESPONSE) {
|
||||
if (!silent) {
|
||||
PrintAndLogEx(ERR, "GetResponse ACK error. len 0x%x | data[0] %02X", len, data[0]);
|
||||
}
|
||||
datalen = 0;
|
||||
goto out;
|
||||
}
|
||||
@@ -348,7 +389,9 @@ static int smart_response(uint8_t *data) {
|
||||
memmove(data, &data[1], datalen);
|
||||
} else {
|
||||
// wrong length
|
||||
PrintAndLogEx(WARNING, "GetResponse wrong length. Must be: 0x%02x but: 0x%02x", len, datalen - 3);
|
||||
if (!silent) {
|
||||
PrintAndLogEx(WARNING, "GetResponse wrong length. Must be 0x%02X got 0x%02X", len, datalen - 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -357,11 +400,16 @@ out:
|
||||
return datalen;
|
||||
}
|
||||
|
||||
static int smart_response(uint8_t *data) {
|
||||
return smart_responseEx(data, false);
|
||||
}
|
||||
|
||||
int CmdSmartRaw(const char *Cmd) {
|
||||
|
||||
int hexlen = 0;
|
||||
bool active = false;
|
||||
bool active_select = false;
|
||||
bool useT0 = false;
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false, reply = true, decodeTLV = false, breakloop = false;
|
||||
uint8_t data[USB_CMD_DATA_SIZE] = {0x00};
|
||||
@@ -385,6 +433,10 @@ int CmdSmartRaw(const char *Cmd) {
|
||||
decodeTLV = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case '0':
|
||||
useT0 = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'd': {
|
||||
switch (param_gethex_to_eol(Cmd, cmdp+1, data, sizeof(data), &hexlen)) {
|
||||
case 1:
|
||||
@@ -425,7 +477,10 @@ int CmdSmartRaw(const char *Cmd) {
|
||||
}
|
||||
|
||||
if (hexlen > 0) {
|
||||
c.arg[0] |= SC_RAW;
|
||||
if (useT0)
|
||||
c.arg[0] |= SC_RAW_T0;
|
||||
else
|
||||
c.arg[0] |= SC_RAW;
|
||||
}
|
||||
|
||||
memcpy(c.d.asBytes, data, hexlen );
|
||||
@@ -457,7 +512,7 @@ int CmdSmartRaw(const char *Cmd) {
|
||||
}
|
||||
|
||||
if (decodeTLV && len > 4)
|
||||
TLVPrintFromBuffer(buf+1, len-3);
|
||||
TLVPrintFromBuffer(buf, len-2);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
@@ -468,8 +523,9 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
|
||||
*dataoutlen = 0;
|
||||
|
||||
if (activateCard)
|
||||
smart_select(false);
|
||||
printf("* APDU SC\n");
|
||||
smart_select(false, NULL);
|
||||
|
||||
PrintAndLogEx(DEBUG, "APDU SC");
|
||||
|
||||
UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, datainlen, 0}};
|
||||
if (activateCard) {
|
||||
@@ -479,10 +535,10 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
int len = smart_response(dataout);
|
||||
int len = smart_responseEx(dataout, true);
|
||||
|
||||
if ( len < 0 ) {
|
||||
return 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// retry
|
||||
@@ -496,15 +552,13 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c2);
|
||||
|
||||
len = smart_response(dataout);
|
||||
len = smart_responseEx(dataout, true);
|
||||
}
|
||||
|
||||
*dataoutlen = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int CmdSmartUpgrade(const char *Cmd) {
|
||||
|
||||
PrintAndLogEx(WARNING, "WARNING - Smartcard socket firmware upgrade.");
|
||||
@@ -541,7 +595,7 @@ int CmdSmartUpgrade(const char *Cmd) {
|
||||
// load file
|
||||
f = fopen(filename, "rb");
|
||||
if ( !f ){
|
||||
PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename);
|
||||
PrintAndLogEx(FAILED, "File: " _YELLOW_(%s) ": not found or locked.", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -652,33 +706,37 @@ int CmdSmartInfo(const char *Cmd){
|
||||
memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t));
|
||||
|
||||
// print header
|
||||
PrintAndLogEx(INFO, "\n--- Smartcard Information ---------");
|
||||
PrintAndLogEx(INFO, "--- Smartcard Information ---------");
|
||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||
PrintAndLogEx(INFO, "ISO76183 ATR : %s", sprint_hex(card.atr, card.atr_len));
|
||||
PrintAndLogEx(INFO, "look up ATR");
|
||||
PrintAndLogEx(INFO, "http://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) );
|
||||
PrintAndLogEx(INFO, "ISO7618-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
|
||||
PrintAndLogEx(INFO, "\nhttp://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) );
|
||||
|
||||
// print ATR
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "* ATR:");
|
||||
PrintAndLogEx(INFO, "ATR");
|
||||
PrintATR(card.atr, card.atr_len);
|
||||
|
||||
// print D/F (brom byte TA1 or defaults)
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "* D/F (TA1):");
|
||||
PrintAndLogEx(INFO, "D/F (TA1)");
|
||||
int Di = GetATRDi(card.atr, card.atr_len);
|
||||
int Fi = GetATRFi(card.atr, card.atr_len);
|
||||
float F = GetATRF(card.atr, card.atr_len);
|
||||
if (GetATRTA1(card.atr, card.atr_len) == 0x11)
|
||||
PrintAndLogEx(INFO, "Using default values...");
|
||||
|
||||
PrintAndLogEx(NORMAL, "Di=%d", Di);
|
||||
PrintAndLogEx(NORMAL, "Fi=%d", Fi);
|
||||
PrintAndLogEx(NORMAL, "F=%.1f MHz", F);
|
||||
PrintAndLogEx(NORMAL, "Cycles/ETU=%d", Fi/Di);
|
||||
PrintAndLogEx(NORMAL, "%.1f bits/sec at 4MHz", (float)4000000 / (Fi/Di));
|
||||
PrintAndLogEx(NORMAL, "%.1f bits/sec at Fmax=%.1fMHz", (F * 1000000) / (Fi/Di), F);
|
||||
|
||||
PrintAndLogEx(NORMAL, "\t- Di %d", Di);
|
||||
PrintAndLogEx(NORMAL, "\t- Fi %d", Fi);
|
||||
PrintAndLogEx(NORMAL, "\t- F %.1f MHz", F);
|
||||
|
||||
if (Di && Fi) {
|
||||
PrintAndLogEx(NORMAL, "\t- Cycles/ETU %d", Fi/Di);
|
||||
PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at 4MHz", (float)4000000 / (Fi/Di));
|
||||
PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at Fmax (%.1fMHz)", (F * 1000000) / (Fi/Di), F);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "\t- Di or Fi is RFU.");
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -784,63 +842,279 @@ int CmdSmartList(const char *Cmd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdSmartBruteforceSFI(const char *Cmd) {
|
||||
static void smart_brute_prim(){
|
||||
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_sm_brute();
|
||||
uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t));
|
||||
if ( !buf )
|
||||
return;
|
||||
|
||||
uint8_t data[5] = {0x00, 0xB2, 0x00, 0x00, 0x00};
|
||||
int len = 0;
|
||||
uint8_t get_card_data[] = {
|
||||
0x80, 0xCA, 0x9F, 0x13, 0x00,
|
||||
0x80, 0xCA, 0x9F, 0x17, 0x00,
|
||||
0x80, 0xCA, 0x9F, 0x36, 0x00,
|
||||
0x80, 0xCA, 0x9F, 0x4f, 0x00
|
||||
};
|
||||
|
||||
UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, 5, 0}};
|
||||
|
||||
PrintAndLogEx(INFO, "Reading primitives");
|
||||
|
||||
PrintAndLogEx(INFO, "Selecting card");
|
||||
if ( !smart_select(false) ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Selecting PPSE aid");
|
||||
CmdSmartRaw("d 00a404000e325041592e5359532e444446303100");
|
||||
CmdSmartRaw("d 00a4040007a000000004101000");
|
||||
|
||||
PrintAndLogEx(INFO, "starting");
|
||||
|
||||
UsbCommand c = {CMD_SMART_RAW, {SC_RAW, sizeof(data), 0}};
|
||||
uint8_t* buf = malloc(USB_CMD_DATA_SIZE);
|
||||
if ( !buf )
|
||||
return 1;
|
||||
for (int i = 0; i < sizeof(get_card_data); i += 5) {
|
||||
|
||||
for (uint8_t i=1; i < 4; i++) {
|
||||
for (int p1=1; p1 < 5; p1++) {
|
||||
|
||||
data[2] = p1;
|
||||
data[3] = (i << 3) + 4;
|
||||
memcpy(c.d.asBytes, get_card_data+i, 5 );
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
len = smart_responseEx(buf, true);
|
||||
|
||||
memcpy(c.d.asBytes, data, sizeof(data) );
|
||||
if ( len > 2 ) {
|
||||
|
||||
//if ( decodeTLV ) {
|
||||
//if (!TLVPrintFromBuffer(buf, len-2)) {
|
||||
PrintAndLogEx(SUCCESS, "\tHEX %d |: %s", len, sprint_hex(buf, len));
|
||||
//}
|
||||
//}
|
||||
}
|
||||
len = 0;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static int smart_brute_sfi(bool decodeTLV){
|
||||
|
||||
uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t));
|
||||
if ( !buf )
|
||||
return 1;
|
||||
|
||||
int len = 0;
|
||||
// READ RECORD
|
||||
uint8_t READ_RECORD[] = {0x00, 0xB2, 0x00, 0x00, 0x00};
|
||||
UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, sizeof(READ_RECORD), 0}};
|
||||
|
||||
PrintAndLogEx(INFO, "Start SFI brute forcing");
|
||||
|
||||
for (uint8_t sfi=1; sfi <= 31; sfi++) {
|
||||
|
||||
printf("."); fflush(stdout);
|
||||
|
||||
for (uint16_t rec=1; rec <= 255; rec++) {
|
||||
|
||||
if (ukbhit()) {
|
||||
int gc = getchar(); (void)gc;
|
||||
PrintAndLogEx(NORMAL, "\naborted via keyboard!\n");
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
READ_RECORD[2] = rec;
|
||||
READ_RECORD[3] = (sfi << 3) | 4;
|
||||
|
||||
memcpy(c.d.asBytes, READ_RECORD, sizeof(READ_RECORD) );
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
smart_response(buf);
|
||||
len = smart_responseEx(buf, true);
|
||||
|
||||
// if 0x6C
|
||||
if ( buf[0] == 0x6C ) {
|
||||
data[4] = buf[1];
|
||||
READ_RECORD[4] = buf[1];
|
||||
|
||||
memcpy(c.d.asBytes, data, sizeof(data) );
|
||||
memcpy(c.d.asBytes, READ_RECORD, sizeof(READ_RECORD) );
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
uint8_t len = smart_response(buf);
|
||||
len = smart_responseEx(buf, true);
|
||||
|
||||
// TLV decoder
|
||||
if (len > 4)
|
||||
TLVPrintFromBuffer(buf+1, len-3);
|
||||
|
||||
data[4] = 0;
|
||||
READ_RECORD[4] = 0;
|
||||
}
|
||||
|
||||
if ( len > 4 ) {
|
||||
|
||||
PrintAndLogEx(SUCCESS, "\n\t file %02d, record %02d found", sfi, rec);
|
||||
|
||||
uint8_t modifier = (buf[0] == 0xC0) ? 1 : 0;
|
||||
|
||||
if ( decodeTLV ) {
|
||||
if (!TLVPrintFromBuffer(buf + modifier, len-2-modifier)) {
|
||||
PrintAndLogEx(SUCCESS, "\tHEX: %s", sprint_hex(buf, len));
|
||||
}
|
||||
}
|
||||
}
|
||||
memset(buf, 0x00, USB_CMD_DATA_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smart_brute_options(bool decodeTLV) {
|
||||
|
||||
uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t));
|
||||
if ( !buf )
|
||||
return;
|
||||
|
||||
uint8_t GET_PROCESSING_OPTIONS[] = {0x80, 0xA8, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00};
|
||||
|
||||
// Get processing options command
|
||||
UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, sizeof(GET_PROCESSING_OPTIONS), 0}};
|
||||
memcpy(c.d.asBytes, GET_PROCESSING_OPTIONS, sizeof(GET_PROCESSING_OPTIONS) );
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
int len = smart_responseEx(buf, true);
|
||||
if ( len > 4 ) {
|
||||
PrintAndLogEx(SUCCESS, "Got processing options");
|
||||
if ( decodeTLV ) {
|
||||
TLVPrintFromBuffer(buf, len-2);
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(FAILED, "Getting processing options failed");
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
int CmdSmartBruteforceSFI(const char *Cmd) {
|
||||
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false, decodeTLV = false; //, useT0 = false;
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h': return usage_sm_brute();
|
||||
case 't':
|
||||
decodeTLV = true;
|
||||
cmdp++;
|
||||
break;
|
||||
/*
|
||||
case '0':
|
||||
useT0 = true;
|
||||
cmdp++;
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Validations
|
||||
if (errors) return usage_sm_brute();
|
||||
|
||||
const char *SELECT = "00a40400%02x%s";
|
||||
|
||||
// uint8_t GENERATE_AC[] = {0x80, 0xAE};
|
||||
// uint8_t GET_CHALLENGE[] = {0x00, 0x84, 0x00};
|
||||
// uint8_t GET_DATA[] = {0x80, 0xCA, 0x00, 0x00, 0x00};
|
||||
// uint8_t SELECT[] = {0x00, 0xA4, 0x04, 0x00};
|
||||
// uint8_t UNBLOCK_PIN[] = {0x84, 0x24, 0x00, 0x00, 0x00};
|
||||
// uint8_t VERIFY[] = {0x00, 0x20, 0x00, 0x80};
|
||||
|
||||
// Select AID command
|
||||
UsbCommand cAid = {CMD_SMART_RAW, {SC_RAW_T0, 0, 0}};
|
||||
|
||||
PrintAndLogEx(INFO, "Importing AID list");
|
||||
json_t *root = NULL;
|
||||
smart_loadjson("aidlist", "json", &root);
|
||||
|
||||
uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t));
|
||||
if ( !buf )
|
||||
return 1;
|
||||
|
||||
PrintAndLogEx(INFO, "Selecting card");
|
||||
if ( !smart_select(false, NULL) ) {
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* caid = NULL;
|
||||
|
||||
for (int i = 0; i < json_array_size(root); i++) {
|
||||
|
||||
printf("+"); fflush(stdout);
|
||||
|
||||
if (caid)
|
||||
free(caid);
|
||||
|
||||
json_t *data, *jaid;
|
||||
|
||||
data = json_array_get(root, i);
|
||||
if (!json_is_object(data)) {
|
||||
PrintAndLogEx(ERR, "data %d is not an object\n", i + 1);
|
||||
json_decref(root);
|
||||
return 1;
|
||||
}
|
||||
|
||||
jaid = json_object_get(data, "AID");
|
||||
if (!json_is_string(jaid)) {
|
||||
PrintAndLogEx(ERR, "AID data [%d] is not a string", i + 1);
|
||||
json_decref(root);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* aid = json_string_value(jaid);
|
||||
if ( !aid )
|
||||
continue;
|
||||
|
||||
size_t aidlen = strlen(aid);
|
||||
caid = calloc( 8+2+aidlen+1, sizeof(uint8_t));
|
||||
snprintf(caid, 8+2+aidlen+1, SELECT, aidlen >> 1, aid);
|
||||
|
||||
int hexlen = 0;
|
||||
int res = param_gethex_to_eol(caid, 0, cAid.d.asBytes, sizeof(cAid.d.asBytes), &hexlen);
|
||||
if ( res )
|
||||
continue;
|
||||
|
||||
cAid.arg[1] = hexlen;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommand(&cAid);
|
||||
|
||||
int len = smart_responseEx(buf, true);
|
||||
if ( len < 3 )
|
||||
continue;
|
||||
|
||||
json_t *jvendor, *jname;
|
||||
jvendor = json_object_get(data, "Vendor");
|
||||
if (!json_is_string(jvendor)) {
|
||||
PrintAndLogEx(ERR, "Vendor data [%d] is not a string", i + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* vendor = json_string_value(jvendor);
|
||||
if ( !vendor )
|
||||
continue;
|
||||
|
||||
jname = json_object_get(data, "Name");
|
||||
if (!json_is_string(jname)) {
|
||||
PrintAndLogEx(ERR, "Name data [%d] is not a string", i + 1);
|
||||
continue;
|
||||
}
|
||||
const char* name = json_string_value(jname);
|
||||
if ( !name )
|
||||
continue;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "\nAID %s | %s | %s", aid, vendor, name);
|
||||
|
||||
smart_brute_options(decodeTLV);
|
||||
|
||||
smart_brute_prim();
|
||||
|
||||
smart_brute_sfi(decodeTLV);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "\nSFI brute force done\n");
|
||||
}
|
||||
|
||||
if (caid)
|
||||
free(caid);
|
||||
|
||||
free(buf);
|
||||
json_decref(root);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "\nSearch completed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
{"list", CmdSmartList, 0, "List ISO 7816 history"},
|
||||
|
||||
@@ -33,6 +33,7 @@ extern int CmdSmartUpgrade(const char* cmd);
|
||||
extern int CmdSmartInfo(const char* cmd);
|
||||
extern int CmdSmartReader(const char *Cmd);
|
||||
|
||||
extern bool smart_select(bool silent, smart_card_atr_t *atr);
|
||||
extern int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||
|
||||
extern int usage_sm_raw(void);
|
||||
|
||||
+8
-8
@@ -14,7 +14,6 @@ static int CmdHelp(const char *Cmd);
|
||||
// trace pointer
|
||||
static uint8_t *trace;
|
||||
long traceLen = 0;
|
||||
bool preRDV40 = true;
|
||||
|
||||
int usage_trace_list(){
|
||||
PrintAndLogEx(NORMAL, "List protocol data in trace buffer.");
|
||||
@@ -166,7 +165,8 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
|
||||
crcStatus = iso14443B_CRC_check(frame, data_len);
|
||||
break;
|
||||
case PROTO_MIFARE:
|
||||
crcStatus = mifare_CRC_check(isResponse, frame, data_len);
|
||||
crcStatus = mifare_CRC_check(isResponse, frame, data_len);
|
||||
break;
|
||||
case ISO_14443A:
|
||||
case MFDES:
|
||||
crcStatus = iso14443A_CRC_check(isResponse, frame, data_len);
|
||||
@@ -289,6 +289,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
|
||||
|
||||
void printFelica(uint16_t traceLen, uint8_t *trace) {
|
||||
|
||||
PrintAndLogEx(NORMAL, "ISO18092 / FeliCa - Timings are not as accurate");
|
||||
PrintAndLogEx(NORMAL, " Gap | Src | Data | CRC | Annotation |");
|
||||
PrintAndLogEx(NORMAL, "--------|-----|---------------------------------|----------|-------------------|");
|
||||
uint16_t tracepos = 0;
|
||||
@@ -297,8 +298,9 @@ void printFelica(uint16_t traceLen, uint8_t *trace) {
|
||||
|
||||
if (tracepos + 3 >= traceLen) break;
|
||||
|
||||
uint16_t gap = (uint16_t)trace[tracepos+1] + ((uint16_t)trace[tracepos] >> 8);
|
||||
uint16_t crc_ok = trace[tracepos+2];
|
||||
|
||||
uint16_t gap = *((uint16_t *)(trace + tracepos));
|
||||
uint8_t crc_ok = trace[tracepos+2];
|
||||
tracepos += 3;
|
||||
|
||||
if (tracepos + 3 >= traceLen) break;
|
||||
@@ -511,8 +513,8 @@ int CmdTraceList(const char *Cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Recorded Activity (TraceLen = %d bytes)", traceLen);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "Recorded Activity (TraceLen = %d bytes)", traceLen);
|
||||
PrintAndLogEx(INFO, "");
|
||||
if (protocol == FELICA) {
|
||||
printFelica(traceLen, trace);
|
||||
} else {
|
||||
@@ -526,8 +528,6 @@ int CmdTraceList(const char *Cmd) {
|
||||
" Tag Mode: Timings are in sub carrier periods (1/212 kHz == 4.7us)");
|
||||
if ( protocol == ISO_15693 )
|
||||
PrintAndLogEx(NORMAL, "ISO15693 - Timings are not as accurate");
|
||||
if ( protocol == FELICA )
|
||||
PrintAndLogEx(NORMAL, "ISO18092 / FeliCa - Timings are not as accurate");
|
||||
if ( protocol == ISO_7816_4 )
|
||||
PrintAndLogEx(NORMAL, "ISO7816-4 / Smartcard - Timings N/A yet");
|
||||
|
||||
|
||||
+19
-30
@@ -154,42 +154,31 @@ static void UsbCommandReceived(UsbCommand* c) {
|
||||
char s[USB_CMD_DATA_SIZE+1];
|
||||
memset(s, 0x00, sizeof(s));
|
||||
size_t len = MIN(c->arg[0], USB_CMD_DATA_SIZE);
|
||||
memcpy(s, c->d.asBytes, len);
|
||||
|
||||
|
||||
//#define FLAG_RAWPRINT 0x0111
|
||||
//#define FLAG_NOOPT 0x0000
|
||||
//#define FLAG_NOLOG 0x0001
|
||||
//#define FLAG_NONEWLINE 0x0010
|
||||
//#define FLAG_NOPROMPT 0x0100
|
||||
memcpy(s, c->d.asBytes, len);
|
||||
uint64_t flag = c->arg[1];
|
||||
if (flag > 0) { // FLAG_RAWPRINT) {
|
||||
switch (flag) {
|
||||
case FLAG_RAWPRINT:
|
||||
printf("%s", s);
|
||||
return;
|
||||
case FLAG_NONEWLINE:
|
||||
printf("%s\r", s);
|
||||
return;
|
||||
case FLAG_NOLOG:
|
||||
printf("%s\r\n", s);
|
||||
return;
|
||||
}
|
||||
fflush(stdout);
|
||||
return;
|
||||
}
|
||||
|
||||
// print debug line on same row. escape seq \r
|
||||
if ( c->arg[1] == CMD_MEASURE_ANTENNA_TUNING_HF) {
|
||||
PrintAndLogEx(NORMAL, "\r#db# %s", s);
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "#db# %s", s);
|
||||
|
||||
switch (flag) {
|
||||
case FLAG_RAWPRINT:
|
||||
printf("%s", s);
|
||||
break;
|
||||
case FLAG_NONEWLINE:
|
||||
printf("\r%s", s);
|
||||
break;
|
||||
case FLAG_NOLOG:
|
||||
printf("%s\r\n", s);
|
||||
break;
|
||||
//case FLAG_NOPROMPT:
|
||||
// break;
|
||||
case FLAG_NOOPT:
|
||||
default:
|
||||
PrintAndLogEx(NORMAL, "#db# %s", s);
|
||||
break;
|
||||
}
|
||||
fflush(stdout);
|
||||
break;
|
||||
}
|
||||
case CMD_DEBUG_PRINT_INTEGERS: {
|
||||
PrintAndLogEx(NORMAL, "#db# %08x, %08x, %08x", c->arg[0], c->arg[1], c->arg[2]);
|
||||
PrintAndLogEx(NORMAL, "#db# %" PRIx64 ", %" PRIx64 ", %" PRIx64 "", c->arg[0], c->arg[1], c->arg[2]);
|
||||
break;
|
||||
}
|
||||
// iceman: hw status - down the path on device, runs printusbspeed which starts sending a lot of
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
#include "util.h"
|
||||
#include "proxmark3.h"
|
||||
|
||||
#define PRINT_INDENT(level) {for (int i = 0; i < (level); i++) fprintf(f, " ");}
|
||||
#ifndef PRINT_INDENT
|
||||
# define PRINT_INDENT(level) {for (int i = 0; i < (level); i++) fprintf(f, " ");}
|
||||
#endif
|
||||
|
||||
enum asn1_tag_t {
|
||||
ASN1_TAG_GENERIC,
|
||||
@@ -235,10 +237,13 @@ static char *asn1_oid_description(const char *oid, bool with_group_desc) {
|
||||
static char res[300];
|
||||
memset(res, 0x00, sizeof(res));
|
||||
|
||||
strcpy(fname, get_my_executable_directory());
|
||||
size_t len = strlen(get_my_executable_directory());
|
||||
if ( len > 300 ) len = 299;
|
||||
|
||||
strncpy(fname, get_my_executable_directory(), len);
|
||||
strcat(fname, "crypto/oids.json");
|
||||
if (access(fname, F_OK) < 0) {
|
||||
strcpy(fname, get_my_executable_directory());
|
||||
strncpy(fname, get_my_executable_directory(), len);
|
||||
strcat(fname, "oids.json");
|
||||
if (access(fname, F_OK) < 0) {
|
||||
goto error; // file not found
|
||||
|
||||
@@ -8,3 +8,4 @@ AEA684A6DAB23278 -- AA1
|
||||
5b7c62c491c11b39 -- from loclass demo file.
|
||||
F0E1D2C3B4A59687 -- Kd from PicoPass 2k documentation
|
||||
5CBCF1DA45D5FB4F -- PicoPass Default Exchange Key
|
||||
31ad7ebd2f282168 -- From HID multiclassSE reader
|
||||
|
||||
+48
-1
@@ -98,6 +98,7 @@ fc00018778f7,--VästtrafikenKeyA, RKFÖstgötaTrafikenKeyA
|
||||
314B49474956,--VIGIK1KeyA
|
||||
564c505f4d41,--VIGIK1KeyB
|
||||
ba5b895da162,--VIGIK1KeyB
|
||||
4143414F5250,
|
||||
#
|
||||
# Data from: http://irq5.io/2013/04/13/decoding-bcard-conference-badges/
|
||||
f4a9ef2afc6d,--BCARD KeyB
|
||||
@@ -708,4 +709,50 @@ E56AC127DD45,
|
||||
EA0FD73CB149,
|
||||
FC0001877BF7,
|
||||
FD8705E721B0,
|
||||
00ada2cd516d,
|
||||
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,
|
||||
|
||||
@@ -96,6 +96,7 @@ FABADA11, //china?
|
||||
69696969,
|
||||
12121212,
|
||||
12344321,
|
||||
1234ABCD,
|
||||
11112222,
|
||||
13131313,
|
||||
10041004,
|
||||
@@ -104,8 +105,8 @@ FABADA11, //china?
|
||||
abcd1234,
|
||||
20002000,
|
||||
19721972,
|
||||
aa55aa55, //amiboo
|
||||
55aa55aa, //rev amiboo
|
||||
aa55aa55, // amiboo
|
||||
55aa55aa, // rev amiboo
|
||||
4f271149, // seeds ul-ev1
|
||||
07d7bb0b, // seeds ul-ev1
|
||||
9636ef8f, // seeds ul-ev1
|
||||
@@ -113,4 +114,4 @@ b5f44686, // seeds ul-ev1
|
||||
9E3779B9, // TEA
|
||||
C6EF3720, // TEA
|
||||
7854794A, // xbox tea constant :)
|
||||
F1EA5EED, //burtle
|
||||
F1EA5EED, // burtle
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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,
|
||||
+537
-74
@@ -38,6 +38,20 @@ void ParamLoadDefaults(struct tlvdb *tlvRoot) {
|
||||
TLV_ADD(0x9F6A, "\x01\x02\x03\x04");
|
||||
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
|
||||
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
||||
//95:(Terminal Verification Results) len:5
|
||||
// all OK TVR
|
||||
TLV_ADD(0x95, "\x00\x00\x00\x00\x00");
|
||||
}
|
||||
|
||||
void PrintChannel(EMVCommandChannel channel) {
|
||||
switch(channel) {
|
||||
case ECC_CONTACTLESS:
|
||||
PrintAndLogEx(INFO, "Channel: CONTACTLESS");
|
||||
break;
|
||||
case ECC_CONTACT:
|
||||
PrintAndLogEx(INFO, "Channel: CONTACT");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int CmdEMVSelect(const char *cmd) {
|
||||
@@ -67,6 +81,7 @@ int CmdEMVSelect(const char *cmd) {
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
if (arg_get_lit(5))
|
||||
channel = ECC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIGetHexWithReturn(6, data, &datalen);
|
||||
CLIParserFree();
|
||||
|
||||
@@ -114,6 +129,7 @@ int CmdEMVSearch(const char *cmd) {
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
if (arg_get_lit(5))
|
||||
channel = ECC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIParserFree();
|
||||
|
||||
SetAPDULogging(APDULogging);
|
||||
@@ -170,6 +186,7 @@ int CmdEMVPPSE(const char *cmd) {
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
if (arg_get_lit(7))
|
||||
channel = ECC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIParserFree();
|
||||
|
||||
SetAPDULogging(APDULogging);
|
||||
@@ -224,6 +241,7 @@ int CmdEMVGPO(const char *cmd) {
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
if (arg_get_lit(6))
|
||||
channel = ECC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIGetHexWithReturn(7, data, &datalen);
|
||||
CLIParserFree();
|
||||
|
||||
@@ -235,6 +253,7 @@ int CmdEMVGPO(const char *cmd) {
|
||||
|
||||
// calc PDOL
|
||||
struct tlv *pdol_data_tlv = NULL;
|
||||
struct tlvdb *tmp_ext = NULL;
|
||||
struct tlv data_tlv = {
|
||||
.tag = 0x83,
|
||||
.len = datalen,
|
||||
@@ -248,9 +267,11 @@ int CmdEMVGPO(const char *cmd) {
|
||||
ParamLoadFromJson(tlvRoot);
|
||||
};
|
||||
|
||||
pdol_data_tlv = dol_process((const struct tlv *)tlvdb_external(0x9f38, datalen, data), tlvRoot, 0x83);
|
||||
tmp_ext = tlvdb_external(0x9f38, datalen, data);
|
||||
pdol_data_tlv = dol_process((const struct tlv *)tmp_ext, tlvRoot, 0x83);
|
||||
if (!pdol_data_tlv){
|
||||
PrintAndLogEx(ERR, "Can't create PDOL TLV.");
|
||||
tlvdb_free(tmp_ext);
|
||||
tlvdb_free(tlvRoot);
|
||||
return 4;
|
||||
}
|
||||
@@ -265,6 +286,7 @@ int CmdEMVGPO(const char *cmd) {
|
||||
unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len);
|
||||
if (!pdol_data_tlv_data) {
|
||||
PrintAndLogEx(ERR, "Can't create PDOL data.");
|
||||
tlvdb_free(tmp_ext);
|
||||
tlvdb_free(tlvRoot);
|
||||
return 4;
|
||||
}
|
||||
@@ -278,6 +300,8 @@ int CmdEMVGPO(const char *cmd) {
|
||||
|
||||
if (pdol_data_tlv != &data_tlv)
|
||||
free(pdol_data_tlv);
|
||||
|
||||
tlvdb_free(tmp_ext);
|
||||
tlvdb_free(tlvRoot);
|
||||
|
||||
if (sw)
|
||||
@@ -306,7 +330,7 @@ int CmdEMVReadRecord(const char *cmd) {
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results of selected applets"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
arg_strx1(NULL, NULL, "<SFI 1byte HEX><SFIrec 1byte HEX>", NULL),
|
||||
arg_strx1(NULL, NULL, "<SFI 1byte HEX><SFIrecord 1byte HEX>", NULL),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(cmd, argtable, true);
|
||||
@@ -317,6 +341,7 @@ int CmdEMVReadRecord(const char *cmd) {
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
if (arg_get_lit(4))
|
||||
channel = ECC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIGetHexWithReturn(5, data, &datalen);
|
||||
CLIParserFree();
|
||||
|
||||
@@ -399,6 +424,7 @@ int CmdEMVAC(const char *cmd) {
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
if (arg_get_lit(8))
|
||||
channel = ECC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIGetHexWithReturn(9, data, &datalen);
|
||||
CLIParserFree();
|
||||
|
||||
@@ -410,6 +436,7 @@ int CmdEMVAC(const char *cmd) {
|
||||
|
||||
// calc CDOL
|
||||
struct tlv *cdol_data_tlv = NULL;
|
||||
struct tlvdb *tmp_ext = NULL;
|
||||
struct tlv data_tlv = {
|
||||
.tag = 0x01,
|
||||
.len = datalen,
|
||||
@@ -424,9 +451,11 @@ int CmdEMVAC(const char *cmd) {
|
||||
ParamLoadFromJson(tlvRoot);
|
||||
};
|
||||
|
||||
cdol_data_tlv = dol_process((const struct tlv *)tlvdb_external(0x8c, datalen, data), tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
tmp_ext = tlvdb_external(0x8c, datalen, data);
|
||||
cdol_data_tlv = dol_process((const struct tlv *)tmp_ext, tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!cdol_data_tlv){
|
||||
PrintAndLogEx(ERR, "Can't create CDOL TLV.");
|
||||
tlvdb_free(tmp_ext);
|
||||
tlvdb_free(tlvRoot);
|
||||
return 4;
|
||||
}
|
||||
@@ -447,6 +476,8 @@ int CmdEMVAC(const char *cmd) {
|
||||
|
||||
if (cdol_data_tlv != &data_tlv)
|
||||
free(cdol_data_tlv);
|
||||
|
||||
tlvdb_free(tmp_ext);
|
||||
tlvdb_free(tlvRoot);
|
||||
|
||||
if (sw)
|
||||
@@ -481,6 +512,7 @@ int CmdEMVGenerateChallenge(const char *cmd) {
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
if (arg_get_lit(3))
|
||||
channel = ECC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIParserFree();
|
||||
|
||||
SetAPDULogging(APDULogging);
|
||||
@@ -510,8 +542,11 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
|
||||
int datalen = 0;
|
||||
|
||||
CLIParserInit("emv intauth",
|
||||
"Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\nNeeds a EMV applet to be selected and GPO to be executed.",
|
||||
"Usage:\n\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n"
|
||||
"Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\n"
|
||||
"Needs a EMV applet to be selected and GPO to be executed.",
|
||||
|
||||
"Usage:\n"
|
||||
"\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n"
|
||||
"\temv intauth -t 01020304 -> execute Internal Authenticate with 4-byte DDOL data, show result in TLV\n"
|
||||
"\temv intauth -pmt 9F 37 04 -> load params from file, make DDOL data from DDOL, Internal Authenticate with DDOL, show result in TLV");
|
||||
|
||||
@@ -536,6 +571,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
if (arg_get_lit(6))
|
||||
channel = ECC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIGetHexWithReturn(7, data, &datalen);
|
||||
CLIParserFree();
|
||||
|
||||
@@ -547,6 +583,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
|
||||
|
||||
// calc DDOL
|
||||
struct tlv *ddol_data_tlv = NULL;
|
||||
struct tlvdb *tmp_ext = NULL;
|
||||
struct tlv data_tlv = {
|
||||
.tag = 0x01,
|
||||
.len = datalen,
|
||||
@@ -561,9 +598,11 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
|
||||
ParamLoadFromJson(tlvRoot);
|
||||
};
|
||||
|
||||
ddol_data_tlv = dol_process((const struct tlv *)tlvdb_external(0x9f49, datalen, data), tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
tmp_ext = tlvdb_external(0x9f49, datalen, data);
|
||||
ddol_data_tlv = dol_process((const struct tlv *)tmp_ext, tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!ddol_data_tlv){
|
||||
PrintAndLogEx(ERR, "Can't create DDOL TLV.");
|
||||
tlvdb_free(tmp_ext);
|
||||
tlvdb_free(tlvRoot);
|
||||
return 4;
|
||||
}
|
||||
@@ -584,6 +623,8 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
|
||||
|
||||
if (ddol_data_tlv != &data_tlv)
|
||||
free(ddol_data_tlv);
|
||||
|
||||
tlvdb_free(tmp_ext);
|
||||
tlvdb_free(tlvRoot);
|
||||
|
||||
if (sw)
|
||||
@@ -598,7 +639,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;}
|
||||
#define dreturn(n) {free(pdol_data_tlv); tlvdb_free(tlvSelect); tlvdb_free(tlvRoot); DropFieldEx( channel ); return n;}
|
||||
|
||||
void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum TransactionType TrType, bool GenACGPO) {
|
||||
|
||||
@@ -663,6 +704,50 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessACResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV) {
|
||||
if (buf[0] == 0x80) {
|
||||
if (decodeTLV){
|
||||
PrintAndLog("GPO response format1:");
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
}
|
||||
|
||||
uint8_t elmlen = len - 2; // wo 0x80XX
|
||||
|
||||
if (len < 4 + 2 || (elmlen - 2) % 4 || elmlen != buf[1]) {
|
||||
PrintAndLogEx(ERR, "GPO response format1 parsing error. length=%d", len);
|
||||
} else {
|
||||
struct tlvdb *tlvElm = NULL;
|
||||
if (decodeTLV)
|
||||
PrintAndLog("\n------------ Format1 decoded ------------");
|
||||
|
||||
// CID (Cryptogram Information Data)
|
||||
tlvdb_change_or_add_node_ex(tlvRoot, 0x9f27, 1, &buf[2], &tlvElm);
|
||||
if (decodeTLV)
|
||||
TLVPrintFromTLV(tlvElm);
|
||||
|
||||
// ATC (Application Transaction Counter)
|
||||
tlvdb_change_or_add_node_ex(tlvRoot, 0x9f36, 2, &buf[3], &tlvElm);
|
||||
if (decodeTLV)
|
||||
TLVPrintFromTLV(tlvElm);
|
||||
|
||||
// AC (Application Cryptogram)
|
||||
tlvdb_change_or_add_node_ex(tlvRoot, 0x9f26, MIN(8, elmlen - 3), &buf[5], &tlvElm);
|
||||
if (decodeTLV)
|
||||
TLVPrintFromTLV(tlvElm);
|
||||
|
||||
// IAD (Issuer Application Data) - optional
|
||||
if (len > 11 + 2) {
|
||||
tlvdb_change_or_add_node_ex(tlvRoot, 0x9f10, elmlen - 11, &buf[13], &tlvElm);
|
||||
if (decodeTLV)
|
||||
TLVPrintFromTLV(tlvElm);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (decodeTLV)
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
int CmdEMVExec(const char *cmd) {
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 0;
|
||||
@@ -680,7 +765,8 @@ int CmdEMVExec(const char *cmd) {
|
||||
|
||||
CLIParserInit("emv exec",
|
||||
"Executes EMV contactless transaction",
|
||||
"Usage:\n\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n"
|
||||
"Usage:\n"
|
||||
"\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n"
|
||||
"\temv exec -satc -> select card, execute CDA transaction, show APDU and TLV\n");
|
||||
|
||||
void* argtable[] = {
|
||||
@@ -708,9 +794,9 @@ int CmdEMVExec(const char *cmd) {
|
||||
|
||||
enum TransactionType TrType = TT_MSD;
|
||||
if (arg_get_lit(7))
|
||||
TrType = TT_QVSDCMCHIP;
|
||||
TrType = TT_QVSDCMCHIP;
|
||||
if (arg_get_lit(8))
|
||||
TrType = TT_CDA;
|
||||
TrType = TT_CDA;
|
||||
if (arg_get_lit(9))
|
||||
TrType = TT_VSDC;
|
||||
|
||||
@@ -718,8 +804,18 @@ int CmdEMVExec(const char *cmd) {
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
if (arg_get_lit(11))
|
||||
channel = ECC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
|
||||
CLIParserFree();
|
||||
|
||||
#ifndef WITH_SMARTCARD
|
||||
// not compiled with smartcard functionality, we need to exit
|
||||
if ( channel == ECC_CONTACT ) {
|
||||
PrintAndLogEx(WARNING, "PM3 Client is not compiled with support for SMARTCARD. Exiting.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
SetAPDULogging(showAPDU);
|
||||
|
||||
// init applets list tree
|
||||
@@ -732,7 +828,7 @@ int CmdEMVExec(const char *cmd) {
|
||||
// PPSE
|
||||
PrintAndLogEx(NORMAL, "\n* PPSE.");
|
||||
SetAPDULogging(showAPDU);
|
||||
res = EMVSearchPSE(channel, activateField, true, decodeTLV, tlvSelect);
|
||||
res = EMVSearchPSE(channel, activateField, true, psenum, decodeTLV, tlvSelect);
|
||||
|
||||
// check PPSE and select application id
|
||||
if (!res) {
|
||||
@@ -845,7 +941,7 @@ int CmdEMVExec(const char *cmd) {
|
||||
uint8_t SFIend = AFL->value[i * 4 + 2];
|
||||
uint8_t SFIoffline = AFL->value[i * 4 + 3];
|
||||
|
||||
PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline);
|
||||
PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline count:%02x", SFI, SFIstart, SFIend, SFIoffline);
|
||||
if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) {
|
||||
PrintAndLogEx(NORMAL, "SFI ERROR! Skipped...");
|
||||
continue;
|
||||
@@ -867,7 +963,7 @@ int CmdEMVExec(const char *cmd) {
|
||||
|
||||
// Build Input list for Offline Data Authentication
|
||||
// EMV 4.3 book3 10.3, page 96
|
||||
if (SFIoffline) {
|
||||
if (SFIoffline > 0) {
|
||||
if (SFI < 11) {
|
||||
const unsigned char *abuf = buf;
|
||||
size_t elmlen = len;
|
||||
@@ -882,6 +978,8 @@ int CmdEMVExec(const char *cmd) {
|
||||
memcpy(&ODAiList[ODAiListLen], buf, len);
|
||||
ODAiListLen += len;
|
||||
}
|
||||
|
||||
SFIoffline--;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -921,7 +1019,7 @@ int CmdEMVExec(const char *cmd) {
|
||||
// transaction check
|
||||
|
||||
// qVSDC
|
||||
if (TrType == TT_QVSDCMCHIP|| TrType == TT_CDA){
|
||||
if (TrType == TT_QVSDCMCHIP || TrType == TT_CDA){
|
||||
// 9F26: Application Cryptogram
|
||||
const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL);
|
||||
if (AC) {
|
||||
@@ -938,7 +1036,7 @@ int CmdEMVExec(const char *cmd) {
|
||||
// print AC data
|
||||
PrintAndLogEx(NORMAL, "ATC: %s", sprint_hex(ATC->value, ATC->len));
|
||||
PrintAndLogEx(NORMAL, "AC: %s", sprint_hex(AC->value, AC->len));
|
||||
if (IAD){
|
||||
if (IAD) {
|
||||
PrintAndLogEx(NORMAL, "IAD: %s", sprint_hex(IAD->value, IAD->len));
|
||||
|
||||
if (IAD->len >= IAD->value[0] + 1) {
|
||||
@@ -978,17 +1076,18 @@ int CmdEMVExec(const char *cmd) {
|
||||
// ICC Dynamic Number
|
||||
struct tlvdb * ICCDynN = tlvdb_fixed(0x9f4c, len, buf);
|
||||
tlvdb_add(tlvRoot, ICCDynN);
|
||||
if (decodeTLV){
|
||||
if (decodeTLV) {
|
||||
PrintAndLogEx(NORMAL, "\n* * ICC Dynamic Number:");
|
||||
TLVPrintFromTLV(ICCDynN);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "* * Calc CDOL1");
|
||||
struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!cdol_data_tlv){
|
||||
if (!cdol_data_tlv) {
|
||||
PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV.");
|
||||
dreturn(6);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
|
||||
|
||||
PrintAndLogEx(NORMAL, "* * AC1");
|
||||
@@ -1010,6 +1109,7 @@ int CmdEMVExec(const char *cmd) {
|
||||
if (res) {
|
||||
PrintAndLogEx(NORMAL, "CDA error (%d)", res);
|
||||
}
|
||||
|
||||
free(ac_tlv);
|
||||
free(cdol_data_tlv);
|
||||
|
||||
@@ -1073,7 +1173,7 @@ int CmdEMVExec(const char *cmd) {
|
||||
PrintAndLogEx(NORMAL, "Use default UDOL.");
|
||||
|
||||
struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!udol_data_tlv){
|
||||
if (!udol_data_tlv) {
|
||||
PrintAndLogEx(WARNING, "Error: can't create UDOL TLV.");
|
||||
dreturn(8);
|
||||
}
|
||||
@@ -1101,7 +1201,140 @@ int CmdEMVExec(const char *cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
DropField();
|
||||
// VSDC
|
||||
if (GetCardPSVendor(AID, AIDlen) == CV_VISA && (TrType == TT_VSDC || TrType == TT_CDA)){
|
||||
PrintAndLogEx(NORMAL, "\n--> VSDC transaction.");
|
||||
|
||||
PrintAndLogEx(NORMAL, "* * Calc CDOL1");
|
||||
struct tlv *cdol1_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!cdol1_data_tlv) {
|
||||
PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV.");
|
||||
dreturn(6);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol1_data_tlv->len, sprint_hex(cdol1_data_tlv->value, cdol1_data_tlv->len));
|
||||
|
||||
PrintAndLogEx(NORMAL, "* * AC1");
|
||||
// EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
|
||||
res = EMVAC(channel, true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol1_data_tlv->value, cdol1_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(NORMAL, "AC1 error(%d): %4x. Exit...", res, sw);
|
||||
free(cdol1_data_tlv);
|
||||
dreturn(7);
|
||||
}
|
||||
|
||||
// process Format1 (0x80) and print Format2 (0x77)
|
||||
ProcessACResponseFormat1(tlvRoot, buf, len, decodeTLV);
|
||||
|
||||
uint8_t CID = 0;
|
||||
tlvdb_get_uint8(tlvRoot, 0x9f27, &CID);
|
||||
|
||||
// AC1 print result
|
||||
PrintAndLog("");
|
||||
if ((CID & EMVAC_AC_MASK) == EMVAC_AAC) PrintAndLogEx(INFO, "AC1 result: AAC (Transaction declined)");
|
||||
if ((CID & EMVAC_AC_MASK) == EMVAC_TC) PrintAndLogEx(INFO, "AC1 result: TC (Transaction approved)");
|
||||
if ((CID & EMVAC_AC_MASK) == EMVAC_ARQC) PrintAndLogEx(INFO, "AC1 result: ARQC (Online authorisation requested)");
|
||||
if ((CID & EMVAC_AC_MASK) == EMVAC_AC_MASK) PrintAndLogEx(INFO, "AC1 result: RFU");
|
||||
|
||||
// decode Issuer Application Data (IAD)
|
||||
uint8_t CryptoVersion = 0;
|
||||
const struct tlv *IAD = tlvdb_get(tlvRoot, 0x9f10, NULL);
|
||||
if (IAD && (IAD->len > 1)) {
|
||||
PrintAndLogEx(NORMAL, "\n* * Issuer Application Data (IAD):");
|
||||
uint8_t VDDlen = IAD->value[0]; // Visa discretionary data length
|
||||
uint8_t IDDlen = 0; // Issuer discretionary data length
|
||||
PrintAndLogEx(NORMAL, "IAD length: %d", IAD->len);
|
||||
PrintAndLogEx(NORMAL, "VDDlen: %d", VDDlen);
|
||||
if (VDDlen < IAD->len - 1)
|
||||
IDDlen = IAD->value[VDDlen + 1];
|
||||
PrintAndLogEx(NORMAL, "IDDlen: %d", IDDlen);
|
||||
|
||||
uint8_t DerivKeyIndex = IAD->value[1];
|
||||
CryptoVersion = IAD->value[2];
|
||||
|
||||
PrintAndLogEx(NORMAL, "CryptoVersion: %d", CryptoVersion);
|
||||
PrintAndLogEx(NORMAL, "DerivKeyIndex: %d", DerivKeyIndex);
|
||||
|
||||
// Card Verification Results (CVR) decode
|
||||
if ((VDDlen - 2) > 0) {
|
||||
uint8_t CVRlen = IAD->value[3];
|
||||
if (CVRlen == (VDDlen - 2 - 1)) {
|
||||
PrintAndLogEx(NORMAL, "CVR length: %d", CVRlen);
|
||||
PrintAndLogEx(NORMAL, "CVR: %s", sprint_hex(&IAD->value[4], CVRlen));
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "Wrong CVR length! CVR: %s", sprint_hex(&IAD->value[3], VDDlen - 2));
|
||||
}
|
||||
}
|
||||
if (IDDlen)
|
||||
PrintAndLogEx(NORMAL, "IDD: %s", sprint_hex(&IAD->value[VDDlen + 1], IDDlen));
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "Issuer Application Data (IAD) not found.");
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "\n* * Processing online request");
|
||||
|
||||
// authorization response code from acquirer
|
||||
const char HostResponse[] = "00"; // 0x3030
|
||||
size_t HostResponseLen = sizeof(HostResponse) - 1;
|
||||
PrintAndLogEx(NORMAL, "Host Response: `%s`", HostResponse);
|
||||
tlvdb_change_or_add_node(tlvRoot, 0x8a, HostResponseLen, (const unsigned char *)HostResponse);
|
||||
|
||||
if (CryptoVersion == 10) {
|
||||
PrintAndLogEx(NORMAL, "\n* * Generate ARPC");
|
||||
|
||||
// Application Cryptogram (AC)
|
||||
const struct tlv *AC = tlvdb_get(tlvRoot, 0x9f26, NULL);
|
||||
if (AC && (AC->len > 0)) {
|
||||
PrintAndLogEx(NORMAL, "AC: %s", sprint_hex(AC->value, AC->len));
|
||||
|
||||
size_t rawARPClen = AC->len;
|
||||
uint8_t rawARPC[rawARPClen];
|
||||
memcpy(rawARPC, AC->value, AC->len);
|
||||
for (int i = 0; (i < HostResponseLen) && (i < rawARPClen); i++)
|
||||
rawARPC[i] ^= HostResponse[i];
|
||||
PrintAndLogEx(NORMAL, "raw ARPC: %s", sprint_hex(rawARPC, rawARPClen));
|
||||
|
||||
// here must be calculation of ARPC, but we dont know a bank keys.
|
||||
PrintAndLogEx(NORMAL, "ARPC: n/a");
|
||||
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "Application Cryptogram (AC) not found.");
|
||||
}
|
||||
|
||||
// here must be external authenticate, but we dont know ARPC
|
||||
|
||||
}
|
||||
|
||||
|
||||
// needs to send AC2 command (res == ARQC)
|
||||
if ((CID & EMVAC_AC_MASK) == EMVAC_ARQC) {
|
||||
PrintAndLogEx(NORMAL, "\n* * Calc CDOL2");
|
||||
struct tlv *cdol2_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8d, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!cdol2_data_tlv) {
|
||||
PrintAndLogEx(WARNING, "Error: can't create CDOL2 TLV.");
|
||||
dreturn(6);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "CDOL2 data[%d]: %s", cdol2_data_tlv->len, sprint_hex(cdol2_data_tlv->value, cdol2_data_tlv->len));
|
||||
|
||||
//PrintAndLogEx(NORMAL, "* * AC2");
|
||||
|
||||
|
||||
// here must be AC2, but we dont make external authenticate (
|
||||
|
||||
/* // AC2
|
||||
PRINT_INDENT(level);
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_AAC2) fprintf(f, "\tAC2: AAC (Transaction declined)\n");
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_TC2) fprintf(f, "\tAC2: TC (Transaction approved)\n");
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_ARQC2) fprintf(f, "\tAC2: not requested (ARQC)\n");
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_AC2_MASK) fprintf(f, "\tAC2: RFU\n");
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DropFieldEx( channel );
|
||||
|
||||
// Destroy TLV's
|
||||
free(pdol_data_tlv);
|
||||
@@ -1164,19 +1397,23 @@ int CmdEMVScan(const char *cmd) {
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
if (arg_get_lit(11))
|
||||
channel = ECC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
|
||||
uint8_t relfname[250] ={0};
|
||||
char *crelfname = (char *)relfname;
|
||||
int relfnamelen = 0;
|
||||
CLIGetStrWithReturn(12, relfname, &relfnamelen);
|
||||
CLIParserFree();
|
||||
|
||||
SetAPDULogging(showAPDU);
|
||||
|
||||
// TODO
|
||||
if (channel == ECC_CONTACT) {
|
||||
PrintAndLogEx(ERR, "Do not use contact interface. Exit.");
|
||||
return 1;
|
||||
#ifndef WITH_SMARTCARD
|
||||
// not compiled with smartcard functionality, we need to exit
|
||||
if ( channel == ECC_CONTACT ) {
|
||||
PrintAndLogEx(WARNING, "PM3 Client is not compiled with support for SMARTCARD. Exiting.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
SetAPDULogging(showAPDU);
|
||||
|
||||
// current path + file name
|
||||
if (!strstr(crelfname, ".json"))
|
||||
@@ -1201,23 +1438,37 @@ int CmdEMVScan(const char *cmd) {
|
||||
}
|
||||
|
||||
// drop field at start
|
||||
DropField();
|
||||
|
||||
// iso 14443 select
|
||||
PrintAndLogEx(NORMAL, "--> GET UID, ATS.");
|
||||
|
||||
iso14a_card_select_t card;
|
||||
if (Hf14443_4aGetCardData(&card)) {
|
||||
return 2;
|
||||
}
|
||||
DropFieldEx( channel );
|
||||
|
||||
JsonSaveStr(root, "$.File.Created", "proxmark3 `emv scan`");
|
||||
|
||||
JsonSaveStr(root, "$.Card.Communication", "iso14443-4a");
|
||||
JsonSaveBufAsHex(root, "$.Card.UID", (uint8_t *)&card.uid, card.uidlen);
|
||||
JsonSaveHex(root, "$.Card.ATQA", card.atqa[0] + (card.atqa[1] << 2), 2);
|
||||
JsonSaveHex(root, "$.Card.SAK", card.sak, 0);
|
||||
JsonSaveBufAsHex(root, "$.Card.ATS", (uint8_t *)card.ats, card.ats_len);
|
||||
if (channel == ECC_CONTACTLESS) {
|
||||
// iso 14443 select
|
||||
PrintAndLogEx(NORMAL, "--> GET UID, ATS.");
|
||||
|
||||
iso14a_card_select_t card;
|
||||
if (Hf14443_4aGetCardData(&card)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
JsonSaveStr(root, "$.Card.Contactless.Communication", "iso14443-4a");
|
||||
JsonSaveBufAsHex(root, "$.Card.Contactless.UID", (uint8_t *)&card.uid, card.uidlen);
|
||||
JsonSaveHex(root, "$.Card.Contactless.ATQA", card.atqa[0] + (card.atqa[1] << 2), 2);
|
||||
JsonSaveHex(root, "$.Card.Contactless.SAK", card.sak, 0);
|
||||
JsonSaveBufAsHex(root, "$.Card.Contactless.ATS", (uint8_t *)card.ats, card.ats_len);
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "--> GET ATR.");
|
||||
|
||||
smart_card_atr_t card;
|
||||
smart_select(true, &card);
|
||||
if (!card.atr_len) {
|
||||
PrintAndLogEx(ERR, "Can't get ATR from a smart card.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
JsonSaveStr(root, "$.Card.Contact.Communication", "iso7816");
|
||||
JsonSaveBufAsHex(root, "$.Card.Contact.ATR", (uint8_t *)card.atr, card.atr_len);
|
||||
}
|
||||
|
||||
// init applets list tree
|
||||
const char *al = "Applets list";
|
||||
@@ -1242,7 +1493,7 @@ int CmdEMVScan(const char *cmd) {
|
||||
tlvdb_free(fci);
|
||||
}
|
||||
|
||||
res = EMVSearchPSE(channel, false, true, decodeTLV, tlvSelect);
|
||||
res = EMVSearchPSE(channel, false, true, psenum, decodeTLV, tlvSelect);
|
||||
|
||||
// check PPSE and select application id
|
||||
if (!res) {
|
||||
@@ -1254,7 +1505,7 @@ int CmdEMVScan(const char *cmd) {
|
||||
if (EMVSearch(channel, false, true, decodeTLV, tlvSelect)) {
|
||||
PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit...");
|
||||
tlvdb_free(tlvSelect);
|
||||
DropField();
|
||||
DropFieldEx( channel );
|
||||
return 3;
|
||||
}
|
||||
|
||||
@@ -1270,7 +1521,7 @@ int CmdEMVScan(const char *cmd) {
|
||||
|
||||
if (!AIDlen) {
|
||||
PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit...");
|
||||
DropField();
|
||||
DropFieldEx( channel );
|
||||
return 4;
|
||||
}
|
||||
|
||||
@@ -1289,7 +1540,7 @@ int CmdEMVScan(const char *cmd) {
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res);
|
||||
tlvdb_free(tlvRoot);
|
||||
DropField();
|
||||
DropFieldEx( channel );
|
||||
return 5;
|
||||
}
|
||||
|
||||
@@ -1317,7 +1568,7 @@ int CmdEMVScan(const char *cmd) {
|
||||
if (!pdol_data_tlv){
|
||||
PrintAndLogEx(ERR, "Can't create PDOL TLV.");
|
||||
tlvdb_free(tlvRoot);
|
||||
DropField();
|
||||
DropFieldEx( channel );
|
||||
return 6;
|
||||
}
|
||||
|
||||
@@ -1326,7 +1577,7 @@ int CmdEMVScan(const char *cmd) {
|
||||
if (!pdol_data_tlv_data) {
|
||||
PrintAndLogEx(ERR, "Can't create PDOL data.");
|
||||
tlvdb_free(tlvRoot);
|
||||
DropField();
|
||||
DropFieldEx( channel );
|
||||
return 6;
|
||||
}
|
||||
PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
|
||||
@@ -1340,7 +1591,7 @@ int CmdEMVScan(const char *cmd) {
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw);
|
||||
tlvdb_free(tlvRoot);
|
||||
DropField();
|
||||
DropFieldEx( channel );
|
||||
return 7;
|
||||
}
|
||||
ProcessGPOResponseFormat1(tlvRoot, buf, len, decodeTLV);
|
||||
@@ -1382,7 +1633,7 @@ int CmdEMVScan(const char *cmd) {
|
||||
uint8_t SFIend = AFL->value[i * 4 + 2];
|
||||
uint8_t SFIoffline = AFL->value[i * 4 + 3];
|
||||
|
||||
PrintAndLog("--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline);
|
||||
PrintAndLogEx(INFO, "--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline);
|
||||
if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) {
|
||||
PrintAndLogEx(ERR, "SFI ERROR! Skipped...");
|
||||
continue;
|
||||
@@ -1432,8 +1683,7 @@ int CmdEMVScan(const char *cmd) {
|
||||
// free tlv object
|
||||
tlvdb_free(tlvRoot);
|
||||
|
||||
// DropField
|
||||
DropField();
|
||||
DropFieldEx( channel );
|
||||
|
||||
res = json_dump_file(root, fname, JSON_INDENT(2));
|
||||
if (res) {
|
||||
@@ -1448,25 +1698,6 @@ int CmdEMVScan(const char *cmd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usage_emv_getrnd(void){
|
||||
PrintAndLogEx(NORMAL, "retrieve the UN number from a terminal");
|
||||
PrintAndLogEx(NORMAL, "Usage: emv getrnd [h]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " emv getrnd");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//retrieve the UN number from a terminal
|
||||
int CmdEMVGetrng(const char *Cmd) {
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if ( cmdp == 'h' || cmdp == 'H') return usage_emv_getrnd();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdEMVList(const char *Cmd) {
|
||||
return CmdTraceList("7816");
|
||||
}
|
||||
@@ -1475,6 +1706,237 @@ int CmdEMVTest(const char *cmd) {
|
||||
return ExecuteCryptoTests(true);
|
||||
}
|
||||
|
||||
int CmdEMVRoca(const char *cmd) {
|
||||
uint8_t AID[APDU_AID_LEN] = {0};
|
||||
size_t AIDlen = 0;
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 0;
|
||||
uint16_t sw = 0;
|
||||
int res;
|
||||
|
||||
CLIParserInit("emv roca",
|
||||
"Tries to extract public keys and run the ROCA test against them.\n",
|
||||
"Usage:\n"
|
||||
"\temv roca -w -> select --CONTACT-- card and run test\n"
|
||||
"\temv roca -> select --CONTACTLESS-- card and run test\n"
|
||||
);
|
||||
|
||||
void* argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("tT", "selftest", "self test"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(cmd, argtable, true);
|
||||
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
if (arg_get_lit(1))
|
||||
return roca_self_test();
|
||||
|
||||
if (arg_get_lit(2))
|
||||
channel = ECC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIParserFree();
|
||||
|
||||
#ifndef WITH_SMARTCARD
|
||||
// not compiled with smartcard functionality, we need to exit
|
||||
if ( channel == ECC_CONTACT ) {
|
||||
PrintAndLogEx(WARNING, "PM3 Client is not compiled with support for SMARTCARD. Exiting.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// select card
|
||||
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
|
||||
|
||||
SetAPDULogging(false);
|
||||
|
||||
// init applets list tree
|
||||
const char *al = "Applets list";
|
||||
struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al);
|
||||
|
||||
// EMV PPSE
|
||||
PrintAndLogEx(NORMAL, "--> PPSE.");
|
||||
res = EMVSearchPSE(channel, false, true, psenum, false, tlvSelect);
|
||||
|
||||
// check PPSE and select application id
|
||||
if (!res) {
|
||||
TLVPrintAIDlistFromSelectTLV(tlvSelect);
|
||||
} else {
|
||||
// EMV SEARCH with AID list
|
||||
PrintAndLogEx(NORMAL, "--> AID search.");
|
||||
if (EMVSearch(channel, false, true, false, tlvSelect)) {
|
||||
PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit...");
|
||||
tlvdb_free(tlvSelect);
|
||||
DropFieldEx( channel );
|
||||
return 3;
|
||||
}
|
||||
|
||||
// check search and select application id
|
||||
TLVPrintAIDlistFromSelectTLV(tlvSelect);
|
||||
}
|
||||
|
||||
// EMV SELECT application
|
||||
SetAPDULogging(false);
|
||||
EMVSelectApplication(tlvSelect, AID, &AIDlen);
|
||||
|
||||
tlvdb_free(tlvSelect);
|
||||
|
||||
if (!AIDlen) {
|
||||
PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit...");
|
||||
DropFieldEx( channel );
|
||||
return 4;
|
||||
}
|
||||
|
||||
// Init TLV tree
|
||||
const char *alr = "Root terminal TLV tree";
|
||||
struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr);
|
||||
|
||||
// EMV SELECT applet
|
||||
PrintAndLogEx(NORMAL, "\n-->Selecting AID:%s.", sprint_hex_inrow(AID, AIDlen));
|
||||
res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res);
|
||||
tlvdb_free(tlvRoot);
|
||||
DropFieldEx( channel );
|
||||
return 5;
|
||||
}
|
||||
|
||||
PrintAndLog("\n* Init transaction parameters.");
|
||||
InitTransactionParameters(tlvRoot, true, TT_QVSDCMCHIP, false);
|
||||
|
||||
PrintAndLogEx(NORMAL, "-->Calc PDOL.");
|
||||
struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
|
||||
if (!pdol_data_tlv){
|
||||
PrintAndLogEx(ERR, "Can't create PDOL TLV.");
|
||||
tlvdb_free(tlvRoot);
|
||||
DropFieldEx( channel );
|
||||
return 6;
|
||||
}
|
||||
|
||||
size_t pdol_data_tlv_data_len;
|
||||
unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len);
|
||||
if (!pdol_data_tlv_data) {
|
||||
PrintAndLogEx(ERR, "Can't create PDOL data.");
|
||||
tlvdb_free(tlvRoot);
|
||||
DropFieldEx( channel );
|
||||
free(pdol_data_tlv);
|
||||
return 6;
|
||||
}
|
||||
PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
|
||||
|
||||
PrintAndLogEx(INFO, "-->GPO.");
|
||||
res = EMVGPO(channel, true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
|
||||
free(pdol_data_tlv_data);
|
||||
free(pdol_data_tlv);
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw);
|
||||
tlvdb_free(tlvRoot);
|
||||
DropFieldEx( channel );
|
||||
return 7;
|
||||
}
|
||||
ProcessGPOResponseFormat1(tlvRoot, buf, len, false);
|
||||
|
||||
PrintAndLogEx(INFO, "-->Read records from AFL.");
|
||||
const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL);
|
||||
|
||||
while(AFL && AFL->len) {
|
||||
if (AFL->len % 4) {
|
||||
PrintAndLogEx(ERR, "Wrong AFL length: %d", AFL->len);
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < AFL->len / 4; i++) {
|
||||
uint8_t SFI = AFL->value[i * 4 + 0] >> 3;
|
||||
uint8_t SFIstart = AFL->value[i * 4 + 1];
|
||||
uint8_t SFIend = AFL->value[i * 4 + 2];
|
||||
uint8_t SFIoffline = AFL->value[i * 4 + 3];
|
||||
|
||||
PrintAndLogEx(INFO, "--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline);
|
||||
if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) {
|
||||
PrintAndLogEx(ERR, "SFI ERROR! Skipped...");
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int n = SFIstart; n <= SFIend; n++) {
|
||||
PrintAndLogEx(INFO, "---->SFI[%02x] %d", SFI, n);
|
||||
|
||||
res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "SFI[%02x]. APDU error %4x", SFI, sw);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// getting certificates
|
||||
if (tlvdb_get(tlvRoot, 0x90, NULL)) {
|
||||
PrintAndLogEx(INFO, "-->Recovering certificates.");
|
||||
PKISetStrictExecution(false);
|
||||
|
||||
struct emv_pk *pk = get_ca_pk(tlvRoot);
|
||||
if (!pk) {
|
||||
PrintAndLogEx(ERR, "ERROR: Key not found. Exit.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlvRoot);
|
||||
if (!issuer_pk) {
|
||||
emv_pk_free(pk);
|
||||
PrintAndLogEx(WARNING, "WARNING: Issuer certificate not found. Exit.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %s IDX %02hhx CSN %s",
|
||||
sprint_hex(issuer_pk->rid, 5),
|
||||
issuer_pk->index,
|
||||
sprint_hex(issuer_pk->serial, 3)
|
||||
);
|
||||
|
||||
|
||||
struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlvRoot, NULL);
|
||||
if (!icc_pk) {
|
||||
emv_pk_free(pk);
|
||||
emv_pk_free(issuer_pk);
|
||||
PrintAndLogEx(WARNING, "WARNING: ICC certificate not found. Exit.");
|
||||
goto out;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %s IDX %02hhx CSN %s\n",
|
||||
sprint_hex(icc_pk->rid, 5),
|
||||
icc_pk->index,
|
||||
sprint_hex(icc_pk->serial, 3)
|
||||
);
|
||||
|
||||
PrintAndLogEx(INFO, "ICC pk modulus: %s", sprint_hex_inrow(icc_pk->modulus, icc_pk->mlen));
|
||||
|
||||
// icc_pk->exp, icc_pk->elen
|
||||
// icc_pk->modulus, icc_pk->mlen
|
||||
if (icc_pk->elen > 0 && icc_pk->mlen > 0) {
|
||||
if (emv_rocacheck(icc_pk->modulus, icc_pk->mlen, true)) {
|
||||
PrintAndLogEx(INFO, "ICC pk is a subject to ROCA vulnerability, insecure..");
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "ICC pk is OK(");
|
||||
}
|
||||
}
|
||||
|
||||
PKISetStrictExecution(true);
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
// free tlv object
|
||||
tlvdb_free(tlvRoot);
|
||||
|
||||
DropFieldEx( channel );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
{"exec", CmdEMVExec, 0, "Executes EMV contactless transaction."},
|
||||
@@ -1489,13 +1951,14 @@ static command_t CommandTable[] = {
|
||||
{"scan", CmdEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."},
|
||||
{"test", CmdEMVTest, 0, "Crypto logic test."},
|
||||
/*
|
||||
{"getrng", CmdEMVGetrng, 0, "get random number from terminal"},
|
||||
{"eload", CmdEmvELoad, 0, "load EMV tag into device"},
|
||||
{"dump", CmdEmvDump, 0, "dump EMV tag values"},
|
||||
{"sim", CmdEmvSim, 0, "simulate EMV tag"},
|
||||
{"clone", CmdEmvClone, 0, "clone an EMV tag"},
|
||||
{"getrng", CmdEMVGetrng, 0, "get random number from terminal"},
|
||||
{"eload", CmdEmvELoad, 0, "load EMV tag into device"},
|
||||
{"dump", CmdEmvDump, 0, "dump EMV tag values"},
|
||||
{"sim", CmdEmvSim, 0, "simulate EMV tag"},
|
||||
{"clone", CmdEmvClone, 0, "clone an EMV tag"},
|
||||
*/
|
||||
{"list", CmdEMVList, 0, "[Deprecated] List ISO7816 history"},
|
||||
{"list", CmdEMVList, 0, "[Deprecated] List ISO7816 history"},
|
||||
{"roca", CmdEMVRoca, 0, "Extract public keys and run ROCA test"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "cmdmain.h"
|
||||
#include "emvcore.h"
|
||||
#include "apduinfo.h"
|
||||
#include "emv_roca.h"
|
||||
|
||||
int CmdEMV(const char *Cmd);
|
||||
|
||||
@@ -34,5 +35,6 @@ extern int CmdEMVPPSE(const char *cmd);
|
||||
extern int CmdEMVExec(const char *cmd);
|
||||
extern int CmdEMVGetrng(const char *Cmd);
|
||||
extern int CmdEMVList(const char *Cmd);
|
||||
extern int CmdEMVRoca(const char *Cmd);
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user