Merge branch 'master' into patch-1

Signed-off-by: Esteban Martinena Guerrero <orensbruli@gmail.com>
This commit is contained in:
Esteban Martinena Guerrero 2023-04-07 11:20:30 +02:00 committed by GitHub
commit 1683fc53ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
339 changed files with 26675 additions and 5927 deletions

View file

@ -18,26 +18,11 @@ assignees: doegox, iceman1001
- [ ] `tools/build_all_firmwares.sh` check that the script contains all standalone modes then compile all standalone modes (linux only)
- [ ] `experimental_lib` compilation & tests
- [ ] `experimental_client_with_swig` compilation & tests
- [ ] Check Android `CMakeLists.txt` list of source file
- [ ] GitHub Actions - green across the board ( MacOS, Ubuntu, Windows)
# OS compilation and tests
```bash
#!/usr/bin/env bash
make clean && make -j PLATFORM=PM3GENERIC PLATFORM_EXTRAS= && tools/pm3_tests.sh --long || exit 1
make clean && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS= || exit 1
make clean && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON || exit 1
make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && sudo make install PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && ( cd /tmp; proxmark3 -c 'data load -f lf_EM4x05.pm3;lf search -1'|grep 'Valid FDX-B ID found' ) && sudo make uninstall || exit 1
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3GENERIC PLATFORM_EXTRAS= && cp -a ../*scripts ../*libs . && ../../tools/pm3_tests.sh --clientbin $(pwd)/proxmark3 client ) || exit 1
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS= ) || exit 1
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON ) || exit 1
# Hitag2crack, optionally with --long and --opencl ...
make hitag2crack/clean && make hitag2crack && tools/pm3_tests.sh hitag2crack || exit 1
```
Run `tools/release_tests.sh` on:
- [ ] RPI Zero
- [ ] Jetson Nano
@ -47,9 +32,9 @@ make hitag2crack/clean && make hitag2crack && tools/pm3_tests.sh hitag2crack ||
- [ ] Kali
- [ ] Debian Stable
- [ ] Debian Testing
- [ ] Ubuntu21
- [ ] Ubuntu 22
- [ ] ParrotOS
- [ ] Fedora
- [ ] Fedora 37
- [ ] OpenSuse Leap
- [ ] OpenSuse Tumbleweed
- [ ] OSX (MacPorts)

View file

@ -41,7 +41,7 @@ jobs:
run: sudo apt-get update
- name: Install dependencies
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed libssl-dev
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev
- name: Install Python dependencies
run: |
@ -51,7 +51,7 @@ jobs:
if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL

View file

@ -19,7 +19,7 @@ jobs:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set Git http.postBuffer to something high
run: git config --global http.postBuffer 524288000
@ -36,6 +36,7 @@ jobs:
- name: Install dependencies
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
continue-on-error: true
- name: Install Python dependencies
run: |
@ -60,7 +61,7 @@ jobs:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set Git http.postBuffer to something high
run: git config --global http.postBuffer 524288000
@ -77,6 +78,7 @@ jobs:
- name: Install dependencies
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
continue-on-error: true
- name: Install Python dependencies
run: |
@ -102,7 +104,7 @@ jobs:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set Git http.postBuffer to something high
run: git config --global http.postBuffer 524288000
@ -119,6 +121,7 @@ jobs:
- name: Install dependencies
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
continue-on-error: true
- name: Install Python dependencies
run: |

View file

@ -20,13 +20,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Update apt repos
run: sudo apt-get update
- name: Install dependencies
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed libssl-dev
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev
- name: Install Python dependencies
run: |
@ -52,13 +52,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Update apt repos
run: sudo apt-get update
- name: Install dependencies
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed libssl-dev
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev
- name: Install Python dependencies
run: |
@ -85,13 +85,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Update apt repos
run: sudo apt-get update
- name: Install dependencies
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed libssl-dev
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev
- name: Install Python dependencies
run: |

View file

@ -48,7 +48,7 @@ jobs:
working-directory: C:\ProxSpace
run: ./runme64.bat -c "exit"
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: make clean
run: make clean
@ -98,9 +98,9 @@ jobs:
steps:
- name: WSL setup
uses: Vampire/setup-wsl@v1
uses: Vampire/setup-wsl@v2
with:
distribution: Ubuntu-20.04
distribution: Ubuntu-22.04
update: "true"
additional-packages: git
ca-certificates
@ -134,7 +134,7 @@ jobs:
git config --global core.autocrlf false
git config --global core.eol lf
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: make clean
run: make clean

View file

@ -3,7 +3,137 @@ 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]
- Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty)
- Added iClass credit key to default iClass key table and reorganized key order (@GuruSteve)
- Changed `hf mf value` - ability to use transfer on different block (@AloneLiberty)
- Change `hf mf dump --ns` - dump command now supports `no save` of MFC card memory (@iceman1001)
- Added `hf mf gdmsetcfg` - Supprt Gen4 GDM write configuration block (@iceman1001)
- Added `hf mf gdmcfg` - Support Gen4 GDM read configuration block (@iceman1001)
- Changed magic note to include a section about GDM tags (@iceman1001)
- Added `hf mf gdmsetblk` - Support Gen4 GDM write block (@iceman1001)
- Changed `hf 14a info` - detect Gen GDM magic tags (@iceman1001)
- Changed CLI max string argument length limit from 512 to 4096 (@iceman1001)
- Fixed `data asn1` - now handles bad input better (@iceman1001)
- Added new public key for signature MIFARE Plus Troika (@iceman100)
- Fixed the client build on Android (@wh201906)
- Added TCP connection support on Windows (@wh201906)
- Added `data num` - easy convert between dec/hex/bin (@iceman1001)
- Fixed `hf mfdes info` - now handles incorrect tag answers better (@didiera)
- Fixed `hf mfdes` generic help text is now correct (@didiera)
- Fixed `pm3` script to correctly identify WSL enabled distros (@henrygab)
- Changed device enumeration with "unique USB serial numbers when built with `FLASH` -- **_UPDATES BOOTROM ALSO_**" (@henrygab)
- Changed the readline package to v8.2 in the CMAKE files for the client (@iceman1001)
- Fixed `pm3` script for passing arguments (@doegox)
- Fixed python paths to include current directory (@jmichelp)
- Fixed infinite loops in spindelayus (@lnv42)
- Changed ICECLASS standalone to support a read/sim mode (@natesales)
- Changed `hf iclass encode` - added verbose flag (@natesales)
- Changed `hf waveshare` - now identify 1.54 nfc epaper correct (@ah01)
- Fixed `Makefile` regression that broke `make install` (@henrygab)
- Fixed `lf em 4x70 brute` - now works as expected (@adite)
- Fixed the lf sampling when bits_per_sample is less than 8 (@wh201906)
- Added `lf em 4x70 brute` command (@adite)
- Added documentation for usage of Proxmark3 under WSL2 (@henrygab)
- Fixed device permissions via updated `udev` rules (@henrygab)
- Added `--back` option to `clear` command to clear the scrollback buffer (@wh201906)
- Changed `hf iclass decrypt` - mark credentials as decrypted in the dump (@natesales)
- Changed `hf iclass view` - show credentials on a decrypted dump (@natesales)
- Changed `hf mfu info` - NTAG213TT tamper info (mjaksn)
- Added commands for configuring NTAG213TT tamper featue (@mjaksn)
- Added Mifare Classic EV1 signature write support to gen4 magic tag lua script (@augustozanellato)
- Added XOR key extraction and flag to Guardall G-Prox II (@GuruSteve)
- Changed verbiage on `hf iclass info` KeyAccess area to be congruent with AA1 and AA2 areas (@GuruSteve)
- Added `hf legic info` command for other sources (@0xdeb)
- Added `hf legic einfo` - views emulator menory (@0xdeb)
- Changed `hf legic view` - now also print the decoded info of the dump file (@0xdeb)
## [Nitride.4.16191][2023-01-29]
- Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox)
- Fixed some coverity fixes (@iceman1001)
- Fixed `make accessrights` on Fedora (@mooey5775)
- Fixed `hf mfu info` - can now identify the 50 pF version of NTAG 210u(micro) (@mjacksn)
- Added `hf 15` sub-commands for controlling EAS, AFI, privacy mode, and the setting of passwords on SLIX tags (@mjacksn)
- Added new magic gen4 cards command in docs (@McEloff)
- Added `hf tesla info` - intital information command to read TESLA cards (@iceman1001)
- Changed `hf emrtd info` - looking for lower case .bin extensions (@iceman1001)
- Changed `hf emrtd dump` - looking for lower case .bin extensions (@iceman1001)
- Changed `lf paradox clone` - it now accepts FC/CN (@mwalker33)
- Added standalone mode for simulatin Nedap ID (@anon)
- Changed `hf mfu info` - now also does a simple OTP fingerprinting (@iceman1001)
- Changed `hf mf wrbl` - now checks for strict readonly ACL's in the data to write (@iceman1001)
- Changed `hf mf view` - verbose printing if strict readonly ACL's exists in dump file (@iceman1001)
- Add command `piv authsign` to get a buffer signed by the selected key (@jmichelp)
- Add command `piv scan` which tries to read all known containers on PIV (@jmichelp)
- Add support for PIV commands, over wired and contactless interfaces (@jmichelp)
- Add `--shallow` option to `hf iclass` reader commands to do shallow (ASK) reader modulation instead of OOK (@nvx)
- Improved NXP SLI/SLIX series tag identification (@nvx)
- Fixed buffer overflow in "lf em 4x05 sniff" (@HeinrichsH)
- Fixed potential NULL array printing (@jmichelp)
- Added PIV aid to resource file (@jmichelp)
- Fixed failing compilation on Proxspace environment due to how python is initialized (@jmichelp)
- Fixed length check in sim module communications (@jmichelp)
- Changed timings in i2c.c when communicating with sim module (@iceman1001)
- Moved to non-deprecated API to initialize Python interpreter (@jmichelp)
- Changed `sc upgrade` updated firmware v4.13 (RDV40) - frame buffer is now 384 bytes (@sentiprox)
- Fixed contact interface / smartcard APDU chaining logic and allow 256 bytes ADPU payload. Need SIM firmware 4.13 to work (@jmichelp)
- Fixed `lf hitag dump` - Should now work as described in the command help (@natmchugh)
- Fixed SPI flash overflow when loading dictionnaries into flash. Breaking change: added 1 more sector for Mifare - dictionnaries should be loaded again (@jmichelp)
- Added `hf mf gload, gsave, ggetblk, gsetblk` for Gen4 GTU in mifare classic mode (@DidierA)
- Fixed `trace list -r` (relative times) not working unless `-u` (microseconds) was specified, and made `--frame` respect `-u` and `-r` options (@nvx)
- Added detection of magic Gen4 GTU (@DidierA)
- Added luascript `hf_i2c_plus_2k_utils` - Script for dumping/modifying user memory of sectors 0 and 1 (@flamebarke)
- Added `hf mfu esave` - saves emulator memory to mfu dump file (@DidierA)
- Added luascript `hf_mfu_ntag` - Script for configuring NTAG216 configuration pages (@flamebarke)
- Changed `hf mf hardnested` - a detection for static encrypted nonces (@iceman1001)
- Added requirements.txt file to tools folder. Minimum to run pm3_tests.sh (@iceman1001)
- Changed `hf mf hardnested` - now can detect and use MFC EV1 signature sector key (@iceman1001)
- Changed `hf mf autopwn` - now can detect and use MFC EV1 signature sector key (@iceman1001)
- Fixed `pm3` shell script now automatically detects WSL2 with USBIPD serial ports (@iceman1001)
- Fixed `trace list -c` - annotation of CRC bytes now is colored or squared if no ansi colors is supported (@iceman1001)
- Fixed `trace list -t mf` - now also finds UID if anticollision is partial captured, to be used for mfkey (@iceman1001)
## [Radium.4.15864][2022-10-29]
- Changed `lf indala sim` - now accepts fc / cn (@iceman1001)
- Added `lf indala brute`- brute forcing of 64b Indala ID (@iceman1001)
- Added `hf 14a ndefwrite` - write raw NDEF records to TYPE4A tags (@iceman1001)
- Changed ndef output to be more dense. Honors verbose now (@iceman1001)
- Fixed `hf mf ndefwrite` - now skips not ndef formatted sectors (@iceman1001)
- Fixed `hf mf ndefread` - now skips not ndef formatted sectors correctly (@iceman1001)
- Fixed `lf hitag` - keep inside the arrays for key/password/nrar (@iceman1001)
- Added `hf mf ndefwrite` - write raw NDEF records to MIFARE Classic tag (@iceman1001)
- Changed `hf mf cwipe` - swapped the block0 data to genuine manufacture ones (@iceman1001)
- Added `hf mf ndefformat` - format a MIFARE Classic tag as NFC tag with Data Exchange Format (NDEF) (@iceman1001)
- Changed `hf 14b dump, view` to get correct chip type in case of SRT512 and friends (@DidierA)
- Added `hf 15 eview` and `hf 15 esave` - Retrieve emulator image for ISO15693 simulation (@markus-oehme-pg40)
- Changed `hf 15 sim` - now supports reader writes (@markus-oehme-pg40)
- Added `hf 15 eload` - specify memory image for ISO15693 simulation (@markus-oehme-pg40)
- Added `hf 15 sim --blocksize` - configure block size for simulation (@markus-oehme-pg40)
- Fixed buffer overflow in mfu ndef decode (@mwalker)
- Changed spiffs write/append to send in 8192 chunks to ensure its eraised (@mwalker)
- Fixed spiffs dump to ensure to fails correctly if no big_buff was allocated (@mwalker)
- Change Client Makefile to respect global flags (@blshkv)
- Change Makefile, honors global CC values (@blshkv)
- Fixed bad memory handling in MifareSim device side (@iceman1001)
- Added json topaz file format (@iceman1001)
- Added `hf topaz rdbl, wrbl, view` commands (@iceman1001)
- Added more details to the annotations of `hf mfdes list` output (@nvx)
- Changed `hf iclass view` and related to suppress consecutive blocks with repeated contents with a `-z` flag, or `prefs set output --dense` (@nvx)
- Changed `hf iclass list` to display matched keys on the CHECK command rather than the card response, and made it check for elite keys too (@nvx)
- Fixed `hf iclass info` and `hf iclass view` key access info looking at the wrong card config bit (@nvx)
- Added `hf gallagher decode` command and fix Gallagher diversification for card master key (@nvx)
- Changed `hf texkom reader` - now supports mmbit-002 (kibi-002, kb5004xk1) russian tag (@merlokk)
- Added `hf sniff --smode` skip/group adc data to consume less memory. Now it can sniff very long signals (@merlokk)
- Added `hf fudan` skeleton commands (@iceman1001)
- Added `--reboot-to-bootloader` arg to pm3
- Changed `hf 14b raw` - now supports selecting Fuji/Xerox tag (@horror)
- Added `hf xerox dump` - dump a Fuji/Xerox tag (@horror)
- Added `hf xerox info` - read Fuji/Xerox tag (@horror)
- Fixed `hf 14a reader --ecp` to work consistently (@kormax)
- Change `trace list -t 14a` to annotate ECP frames of all valid V1 and V2 formats (@kormax)
- Added 122 new keys from Flipper Zero community to `mfc_default_keys.dic` (@UberGuidoZ)
- Added showing password for the read command in the `lf t55xx sniff` command (@merlokk)
- Added reading texcom tk13 and tk17 tags with `hf texkom read` command (@merlokk @iceman1001)
- Added simulating texcom tk13 and tk17 tags with `hf texkom sim` command (@merlokk)
- Changed `hf mf staticnested` - significant speedups by using two encrypted nonces (@xianglin1998)
- Change use of `sprintf` in code to `snprintf` to fix compilation on macOS (@Doridian)
- Change `hf mf mad` - it now takes a dump file for offline MAD decoding (@iceman1001)
@ -64,6 +194,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Changed - AID limitations when using Gallagher key diversification (@DarkMatterMatt)
- Added new standalone mode `lf_em4100rsww` (@zabszk)
- Fixed `hf 15 slixdisable` wrong pass id (@r1ddl3rz)
- Added `script run hf_mf_hid_sim.lua` (@micsen)
## [Frostbit.4.14831][2022-01-11]
- Changed Wiegand format lookup - now case-insensitive (@iceman1001)
@ -1281,7 +1412,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Mifare simulation, `hf mf sim` (was broken a long time) (@pwpiwi)
- Major improvements in LF area and data operations. (@marshmellow42, @iceman1001)
- Issues regarding LF simulation (@pwpiwi)
- Issue interpreting NXP "get sys info" command return value for icode tags. (@mjacksn)
### Added
- iClass functionality: full simulation of iclass tags, so tags can be simulated with data (not only CSN). Not yet support for write/update, but readers do not seem to enforce update. (@holiman).
- iClass decryption. Proxmark can now decrypt data on an iclass tag, but requires you to have the HID decryption key locally on your computer, as this is not bundled with the sourcecode.
- `hf 15 info` can detect NTAG 5 tags
- `hf 15 info` include an EAS status check on more of the icode tags which support EAS (SLI, SLIX, SLIX-L, and SLIX-S)

View file

@ -34,7 +34,7 @@ all clean install uninstall check: %: client/% bootrom/% armsrc/% recovery/% mfk
#all clean install uninstall check: %: hitag2crack/%
INSTALLTOOLS=pm3_eml2lower.sh pm3_eml2upper.sh pm3_mfdread.py pm3_mfd2eml.py pm3_eml2mfd.py pm3_amii_bin2eml.pl pm3_reblay-emulating.py pm3_reblay-reading.py
INSTALLSIMFW=sim011.bin sim011.sha512.txt
INSTALLSIMFW=sim011.bin sim011.sha512.txt sim013.bin sim013.sha512.txt
INSTALLSCRIPTS=pm3 pm3-flash pm3-flash-all pm3-flash-bootrom pm3-flash-fullimage
INSTALLSHARES=tools/jtag_openocd traces
INSTALLDOCS=doc/*.md doc/md
@ -65,7 +65,13 @@ ifneq (,$(INSTALLSIMFW))
endif
ifeq ($(platform),Linux)
$(Q)$(INSTALLSUDO) $(MKDIR) $(DESTDIR)$(UDEV_PREFIX)
$(Q)$(INSTALLSUDO) $(CP) driver/77-pm3-usb-device-blacklist.rules $(DESTDIR)$(UDEV_PREFIX)/77-pm3-usb-device-blacklist.rules
# If user is running ArchLinux, use group 'uucp'
# Else, use group 'dialout'
ifneq ($(wildcard /etc/arch-release),)
$(Q)$(INSTALLSUDO) $(CP) driver/77-pm3-usb-device-blacklist-uucp.rules $(DESTDIR)$(UDEV_PREFIX)/77-pm3-usb-device-blacklist.rules
else
$(Q)$(INSTALLSUDO) $(CP) driver/77-pm3-usb-device-blacklist-dialout.rules $(DESTDIR)$(UDEV_PREFIX)/77-pm3-usb-device-blacklist.rules
endif
endif
uninstall: common/uninstall
@ -75,25 +81,32 @@ common/uninstall:
ifneq (,$(INSTALLSCRIPTS))
$(Q)$(INSTALLSUDO) $(RM) $(foreach script,$(INSTALLSCRIPTS),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLBINRELPATH)$(PATHSEP)$(notdir $(script)))
endif
ifneq (,$(INSTALLSHARES))
$(Q)$(INSTALLSUDO) $(RMDIR) $(foreach share,$(INSTALLSHARES),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)$(PATHSEP)$(notdir $(share)))
endif
ifneq (,$(INSTALLDOCS))
$(Q)$(INSTALLSUDO) $(RMDIR) $(foreach doc,$(INSTALLDOCS),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH)$(PATHSEP)$(notdir $(doc)))
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH)
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH)
endif
ifneq (,$(INSTALLTOOLS))
$(Q)$(INSTALLSUDO) $(RM) $(foreach tool,$(INSTALLTOOLS),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)$(PATHSEP)$(notdir $(tool)))
endif
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)
ifneq (,$(INSTALLSIMFW))
$(Q)$(INSTALLSUDO) $(RM) $(foreach fw,$(INSTALLSIMFW),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(notdir $(fw)))
endif
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)
ifeq ($(platform),Linux)
$(Q)$(INSTALLSUDO) $(RM) $(DESTDIR)$(UDEV_PREFIX)/77-pm3-usb-device-blacklist.rules
endif
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)
# tests
mfkey/check: FORCE
@ -248,28 +261,39 @@ ifeq ($(PLATFORM_CHANGED),true)
$(Q)$(MAKE) --no-print-directory -C recovery clean
$(Q)$(MAKE) --no-print-directory -C client clean
$(Q)$(MAKE) --no-print-directory -C tools/fpga_compress clean
$(Q)echo CACHED_PLATFORM=$(PLATFORM) > .Makefile.options.cache
$(Q)echo CACHED_PLATFORM_EXTRAS=$(PLATFORM_EXTRAS) >> .Makefile.options.cache
$(Q)echo CACHED_PLATFORM_DEFS=$(PLATFORM_DEFS) >> .Makefile.options.cache
$(Q)$(ECHO) CACHED_PLATFORM=$(PLATFORM) > .Makefile.options.cache
$(Q)$(ECHO) CACHED_PLATFORM_EXTRAS=$(PLATFORM_EXTRAS) >> .Makefile.options.cache
$(Q)$(ECHO) CACHED_PLATFORM_DEFS=$(PLATFORM_DEFS) >> .Makefile.options.cache
endif
# configure system to ignore PM3 device as a modem (ModemManager blacklist, effective *only* if ModemManager is not using _strict_ policy)
# Read doc/md/ModemManager-Must-Be-Discarded.md for more info
udev:
sudo cp -rf driver/77-pm3-usb-device-blacklist.rules $(DESTDIR)$(UDEV_PREFIX)/77-pm3-usb-device-blacklist.rules
sudo udevadm control --reload-rules
ifneq ($(wildcard /etc/arch-release),)
# If user is running ArchLinux, use group 'uucp'
$(SUDO) cp -rf driver/77-pm3-usb-device-blacklist-uucp.rules $(DESTDIR)$(UDEV_PREFIX)/77-pm3-usb-device-blacklist.rules
else
# Else, use group 'dialout'
$(SUDO) cp -rf driver/77-pm3-usb-device-blacklist-dialout.rules $(DESTDIR)$(UDEV_PREFIX)/77-pm3-usb-device-blacklist.rules
endif
$(SUDO) udevadm control --reload-rules
$(SUDO) udevadm trigger --action=change
# configure system to add user to the dialout group
# configure system to add user to the dialout group and if bluetooth group exists, add user to it
# you need to logout, relogin to get this access right correct.
# Finally, you might need to run the proxmark3 client under SUDO on some systems
accessrights:
ifneq ($(wildcard /etc/arch-release),)
#If user is running ArchLinux, use specific command and group
$(Q)sudo usermod -aG uucp $(USER)
$(Q)getent group bluetooth >/dev/null && sudo usermod -aG bluetooth $(USER) || true
$(Q)$(SUDO) $(USERMOD) uucp $(USER)
$(Q)$(GETENT_BL) >/dev/null && $(SUDO) $(USERMOD) bluetooth $(USER) || true
else ifneq ($(wildcard /etc/fedora-release),)
# If the user is running Fedora, use `usermod` with the dialout group
$(Q)$(SUDO) $(USERMOD) dialout $(USER)
$(Q)$(GETENT_BL) >/dev/null && $(SUDO) $(USERMOD) bluetooth $(USER) || true
else
$(Q)sudo adduser $(USER) dialout
$(Q)getent group bluetooth >/dev/null && sudo adduser $(USER) bluetooth || true
$(Q)$(SUDO) $(ADDUSER) $(USER) dialout
$(Q)$(GETENT_BL) >/dev/null && $(SUDO) $(ADDUSER) $(USER) bluetooth || true
endif
# easy printing of MAKE VARIABLES

View file

@ -29,18 +29,17 @@ GZIP = gzip
MKDIR = mkdir -p
RM = rm -f
RMDIR = rm -rf
# rmdir only if dir is empty, tolerate failure
RMDIR_SOFT = -rmdir
# rmdir only if dir is empty, you must add "-" when using it to tolerate failure
RMDIR_SOFT = rmdir
MV = mv
TOUCH = touch
FALSE = false
TAR = tar
TARFLAGS ?= -v --ignore-failed-read -r
TARFLAGS += -C .. -f
CROSS ?= arm-none-eabi-
CC = gcc
CXX = g++
LD = g++
CROSS ?= arm-none-eabi-
CC ?= gcc
CXX ?= g++
SH = sh
BASH = bash
PERL = perl
@ -48,6 +47,14 @@ SWIG = swig
CC_VERSION = $(shell $(CC) -dumpversion 2>/dev/null|sed 's/\..*//')
CC_VERSION := $(or $(strip $(CC_VERSION)),0)
ECHO = echo
SUDO = sudo
USERMOD = usermod -aG
ADDUSER = adduser
GETENT_BL = getent group bluetooth
PATHSEP=/
PREFIX ?= /usr/local
UDEV_PREFIX ?= /etc/udev/rules.d
@ -78,9 +85,13 @@ else
endif
ifeq ($(USE_BREW),1)
BREW_PREFIX = $(shell brew --prefix 2>/dev/null)
ifeq ($(strip $(BREW_PREFIX)),)
USE_BREW = 0
ifneq ($(strip $(HOMEBREW_PREFIX)),)
BREW_PREFIX = $(HOMEBREW_PREFIX)
else
BREW_PREFIX = $(shell brew --prefix 2>/dev/null)
ifeq ($(strip $(BREW_PREFIX)),)
USE_BREW = 0
endif
endif
endif

View file

@ -86,8 +86,8 @@ $(BINDIR)/$(LIB_A): $(MYOBJS) $(MYCXXOBJS)
$(Q)$(RANLIB) $@
$(BINDIR)/% : $(OBJDIR)/%.o $(MYOBJS) $(MYCXXOBJS) $(MYLIBS)
$(info [=] LD $(notdir $@))
$(Q)$(LD) $(LDFLAGS) $(MYOBJS) $(MYCXXOBJS) $< -o $@ $(MYLIBS) $(MYLDLIBS)
$(info [=] CXX $(notdir $@))
$(Q)$(CXX) $(LDFLAGS) $(MYOBJS) $(MYCXXOBJS) $< -o $@ $(MYLIBS) $(MYLDLIBS)
%.o: %.c
$(OBJDIR)/%.o : %.c $(OBJDIR)/%.d | $(OBJDIR)

View file

@ -5,8 +5,23 @@ PLATFORM=PM3RDV4
#PLATFORM=PM3GENERIC
# If you want more than one PLATFORM_EXTRAS option, separate them by spaces:
#PLATFORM_EXTRAS=BTADDON
#PLATFORM_EXTRAS=FLASH
#PLATFORM_EXTRAS=BTADDON FLASH
#STANDALONE=LF_SAMYRUN
# Uncomment the lines below in order to make a 256KB image
# and comment out the lines above
#PLATFORM=PM3GENERIC
#PLATFORM_SIZE=256
#STANDALONE=
#SKIP_HITAG=1
#SKIP_FELICA=1
#SKIP_HFPLOT=1
#SKIP_NFCBARCODE=1
#SKIP_ZX8211=1
#SKIP_LF=1
# To accelerate repetitive compilations:
# Install package "ccache" -> Debian/Ubuntu: /usr/lib/ccache, Fedora/CentOS/RHEL: /usr/lib64/ccache
# And uncomment the following line

View file

@ -83,7 +83,7 @@ We define generic Proxmark3 platforms as following devices.
- **Note**: unknown pin assignments.
- ⚠ Ryscorp Proxmark3 Pro
- **Note**: device has different fpga and unknown pin assignments.
- **Note**: Company have dissappared, leaving their customers in the dark.
- **Note**: Company have disappeared, leaving their customers in the dark.
- ⚠ iCopy-X
- **Note**: experimental support, currently incompatible with iCopy-X GUI as Proxmark client commands are now using cliparser.
- **Note**: see also [icopyx-community repos](https://github.com/iCopy-X-Community/) for upstream sources, reversed hw etc.
@ -93,24 +93,30 @@ We define generic Proxmark3 platforms as following devices.
- ⚠ VX
- **Note**: unknown device hw
- ⚠ Proxmark3 X
- **Note**: unknown device hw.
- **Note**: unknown device hw
- ⚠ Proxmark3 Ultimate
- **Note**: unknown device hw
- ⚠ Proxmark3 SE
- **Note**: unknown device hw
When it comes to these new unknown models we are depending on the community to report in if this repo works and what they did to make it work.
**256kb flash memory size of generic Proxmark3 platforms**
**256KB flash memory size of generic Proxmark3 platforms**
> ⚠ **Note**:
> You need to keep a eye on how large your ARM chip built-in flash memory is.
> With 512kb you are fine but if its 256kb you need to compile this repo with even less functionality.
> With 512KB you are fine but if its 256KB you need to compile this repo with even less functionality.
> When running the `./pm3-flash-all` you can see which size your device have if you have the bootloader from this repo installed.
> Otherwise you will find the size reported in the start message when running the Proxmark3 client `./pm3`.
>
> [OBS! Read the 256kb flash memory advisory](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md#256kb-versions)
> [OBS! Read the 256KB flash memory advisory](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md#256KB-versions)
# What has changed?
Proxmark3 RDV4 hardware modifications:
* added flash memory 256kb
* added flash memory 256KB
* added smart card module
* added FPC connector for peripherals such as Bluetooth+battery addon
* improved antennas
@ -200,7 +206,7 @@ The official PM3-GUI from Gaucho will not work. Not to mention is quite old and
## Official channels
Where do you find the community?
- [RFID Hacking community discord server](https://discord.gg/iceman)
- [RFID Hacking community discord server](https://t.ly/d4_C)
- [Proxmark3 IRC channel](https://web.libera.chat/?channels=#proxmark3)
- [Proxmark3 sub reddit](https://www.reddit.com/r/proxmark3/)
- [Proxmark3 forum](http://www.proxmark.org/forum/index.php)

15
SECURITY.md Normal file
View file

@ -0,0 +1,15 @@
# Security Policy
This is an open source project driven by volunteering devs contributing their time for free.
This is a bleeding edge repository.
The maintainers actively is working out of this repository and will be periodically re-structuring the code to make it easier to comprehend, navigate, build, test, and contribute to, so DO expect significant changes to code layout on a regular basis.
## Reporting a Vulnerability
if you find a vulnerability feel free to make a pull request with your fix and we will deal with it.
👉 Remember!
If you intend to contribute to the code, please read the coding style notes first. We usually merge your contributions fast since we do like the idea of getting a functionality in the Proxmark3 and weed out the bugs afterwards.

View file

@ -35,6 +35,7 @@ APP_CFLAGS = $(PLATFORM_DEFS) \
-ffunction-sections -fdata-sections
SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c
SRC_HF = hfops.c
SRC_ISO15693 = iso15693.c iso15693tools.c
SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c
#UNUSED: mifaresniff.c
@ -132,6 +133,7 @@ THUMBSRC = start.c \
$(SRC_EM4x50) \
$(SRC_EM4x70) \
$(SRC_SPIFFS) \
$(SRC_HF) \
$(SRC_ISO14443a) \
$(SRC_ISO14443b) \
$(SRC_CRAPTO1) \
@ -150,7 +152,8 @@ THUMBSRC = start.c \
BigBuf.c \
ticks.c \
clocks.c \
hfsnoop.c
hfsnoop.c \
generator.c
# These are to be compiled in ARM mode
@ -182,7 +185,7 @@ showinfo:
.DELETE_ON_ERROR:
# version_pm3.c should be remade on every time fullimage.stage1.elf should be remade
version_pm3.c: default_version_pm3.c $(OBJDIR)/fpga_version_info.o $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ)
version_pm3.c: default_version_pm3.c $(OBJDIR)/fpga_version_info.o $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ) .FORCE
$(info [-] GEN $@)
$(Q)$(SH) ../tools/mkversion.sh > $@ || $(CP) $< $@
@ -254,7 +257,7 @@ uninstall:
$(info [@] Uninstalling fullimage from $(DESTDIR)$(PREFIX)...)
$(Q)$(INSTALLSUDO) $(RM) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(INSTALLFWTAG)
.PHONY: all clean help install uninstall
.PHONY: all clean help install uninstall .FORCE
help:
@echo Multi-OS Makefile, you are running on $(DETECTED_OS)
@echo Possible targets:

View file

@ -50,12 +50,18 @@ define KNOWN_STANDALONE_DEFINITIONS
| LF_ICEHID | LF HID collector to flashmem |
| (RDV4 only) | |
+----------------------------------------------------------+
| LF_NEDAP_SIM | LF Nedap ID simple simulator |
| | |
+----------------------------------------------------------+
| LF_NEXID | LF Nexwatch collector to flashmem |
| (RDV4 only) | |
+----------------------------------------------------------+
| LF_PROXBRUTE | HID ProxII bruteforce |
| | - Brad Antoniewicz |
+----------------------------------------------------------+
| LF_PROX2BRUTE | HID ProxII bruteforce v2 |
| | |
+----------------------------------------------------------+
| LF_SAMYRUN | HID26 read/clone/sim |
| (default) | - Samy Kamkar |
+----------------------------------------------------------+
@ -118,11 +124,14 @@ define KNOWN_STANDALONE_DEFINITIONS
+----------------------------------------------------------+
endef
STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN LF_THAREXDE LF_NEXID
STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_TCPRST HF_TMUDFORD HF_YOUNG HF_REBLAY DANKARMULTI
STANDALONE_MODES := LF_SKELETON
STANDALONE_MODES += LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE
STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_YOUNG
STANDALONE_MODES += DANKARMULTI
STANDALONE_MODES_REQ_BT := HF_REBLAY
STANDALONE_MODES_REQ_SMARTCARD :=
STANDALONE_MODES_REQ_FLASH := LF_HIDFCBRUTE LF_ICEHID LF_NEXID LF_THAREXDE HF_BOG HF_COLIN HF_ICECLASS HF_MFCSIM HF_LEGICSIM
STANDALONE_MODES_REQ_FLASH := LF_HIDFCBRUTE LF_ICEHID LF_NEXID LF_THAREXDE HF_BOG HF_COLIN HF_ICECLASS HF_LEGICSIM HF_MFCSIM
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),)
STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE)
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),)

View file

@ -21,13 +21,21 @@ SRC_STANDALONE = placeholder.c
ifneq (,$(findstring WITH_STANDALONE_LF_SKELETON,$(APP_CFLAGS)))
SRC_STANDALONE = lf_skeleton.c
endif
# WITH_STANDALONE_LF_SAMYRUN
ifneq (,$(findstring WITH_STANDALONE_LF_SAMYRUN,$(APP_CFLAGS)))
SRC_STANDALONE = lf_samyrun.c
# WITH_STANDALONE_LF_EM4100EMUL
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100EMUL,$(APP_CFLAGS)))
SRC_STANDALONE = lf_em4100emul.c
endif
# WITH_STANDALONE_LF_PROXBRUTE
ifneq (,$(findstring WITH_STANDALONE_LF_PROXBRUTE,$(APP_CFLAGS)))
SRC_STANDALONE = lf_proxbrute.c
# WITH_STANDALONE_LF_EM4100RSWB
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RSWB,$(APP_CFLAGS)))
SRC_STANDALONE = lf_em4100rswb.c
endif
# WITH_STANDALONE_LF_EM4100RSWW
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RSWW,$(APP_CFLAGS)))
SRC_STANDALONE = lf_em4100rsww.c
endif
# WITH_STANDALONE_LF_EM4100RWC
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RWC,$(APP_CFLAGS)))
SRC_STANDALONE = lf_em4100rwc.c
endif
# WITH_STANDALONE_LF_HIDBRUTE
ifneq (,$(findstring WITH_STANDALONE_LF_HIDBRUTE,$(APP_CFLAGS)))
@ -37,21 +45,33 @@ endif
ifneq (,$(findstring WITH_STANDALONE_LF_HIDFCBRUTE,$(APP_CFLAGS)))
SRC_STANDALONE = lf_hidfcbrute.c
endif
# WITH_STANDALONE_HF_YOUNG
ifneq (,$(findstring WITH_STANDALONE_HF_YOUNG,$(APP_CFLAGS)))
SRC_STANDALONE = hf_young.c
# WITH_STANDALONE_LF_ICEHID
ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS)))
SRC_STANDALONE = lf_icehid.c
endif
# WITH_STANDALONE_HF_MATTYRUN
ifneq (,$(findstring WITH_STANDALONE_HF_MATTYRUN,$(APP_CFLAGS)))
SRC_STANDALONE = hf_mattyrun.c
# WITH_STANDALONE_LF_NEDAP_SIM
ifneq (,$(findstring WITH_STANDALONE_LF_NEDAP_SIM,$(APP_CFLAGS)))
SRC_STANDALONE = lf_nedap_sim.c
endif
# WITH_STANDALONE_HF_COLIN
ifneq (,$(findstring WITH_STANDALONE_HF_COLIN,$(APP_CFLAGS)))
SRC_STANDALONE = vtsend.c hf_colin.c frozen.c nprintf.c
# WITH_STANDALONE_LF_NEXID
ifneq (,$(findstring WITH_STANDALONE_LF_NEXID,$(APP_CFLAGS)))
SRC_STANDALONE = lf_nexid.c
endif
# WITH_STANDALONE_HF_BOG
ifneq (,$(findstring WITH_STANDALONE_HF_BOG,$(APP_CFLAGS)))
SRC_STANDALONE = hf_bog.c
# WITH_STANDALONE_LF_SAMYRUN
ifneq (,$(findstring WITH_STANDALONE_LF_SAMYRUN,$(APP_CFLAGS)))
SRC_STANDALONE = lf_samyrun.c
endif
# WITH_STANDALONE_LF_PROXBRUTE
ifneq (,$(findstring WITH_STANDALONE_LF_PROXBRUTE,$(APP_CFLAGS)))
SRC_STANDALONE = lf_proxbrute.c
endif
# WITH_STANDALONE_LF_PROX2BRUTE
ifneq (,$(findstring WITH_STANDALONE_LF_PROX2BRUTE,$(APP_CFLAGS)))
SRC_STANDALONE = lf_prox2brute.c
endif
# WITH_STANDALONE_LF_THAREXDE
ifneq (,$(findstring WITH_STANDALONE_LF_THAREXDE,$(APP_CFLAGS)))
SRC_STANDALONE = lf_tharexde.c
endif
# WITH_STANDALONE_HF_14ASNIFF
ifneq (,$(findstring WITH_STANDALONE_HF_14ASNIFF,$(APP_CFLAGS)))
@ -69,33 +89,21 @@ endif
ifneq (,$(findstring WITH_STANDALONE_HF_AVEFUL,$(APP_CFLAGS)))
SRC_STANDALONE = hf_aveful.c
endif
# WITH_STANDALONE_HF_TCPRST
ifneq (,$(findstring WITH_STANDALONE_HF_TCPRST,$(APP_CFLAGS)))
SRC_STANDALONE = hf_tcprst.c
# WITH_STANDALONE_HF_BOG
ifneq (,$(findstring WITH_STANDALONE_HF_BOG,$(APP_CFLAGS)))
SRC_STANDALONE = hf_bog.c
endif
# WITH_STANDALONE_LF_ICEHID
ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS)))
SRC_STANDALONE = lf_icehid.c
# WITH_STANDALONE_HF_COLIN
ifneq (,$(findstring WITH_STANDALONE_HF_COLIN,$(APP_CFLAGS)))
SRC_STANDALONE = vtsend.c hf_colin.c frozen.c nprintf.c
endif
# WITH_STANDALONE_LF_NEXID
ifneq (,$(findstring WITH_STANDALONE_LF_NEXID,$(APP_CFLAGS)))
SRC_STANDALONE = lf_nexid.c
# WITH_STANDALONE_HF_CRAFTBYTE
ifneq (,$(findstring WITH_STANDALONE_HF_CRAFTBYTE,$(APP_CFLAGS)))
SRC_STANDALONE = hf_craftbyte.c
endif
# WITH_STANDALONE_LF_EM4100EMUL
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100EMUL,$(APP_CFLAGS)))
SRC_STANDALONE = lf_em4100emul.c
endif
# WITH_STANDALONE_LF_EM4100RSWB
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RSWB,$(APP_CFLAGS)))
SRC_STANDALONE = lf_em4100rswb.c
endif
# WITH_STANDALONE_LF_EM4100RSWW
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RSWW,$(APP_CFLAGS)))
SRC_STANDALONE = lf_em4100rsww.c
endif
# WITH_STANDALONE_LF_EM4100RWC
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RWC,$(APP_CFLAGS)))
SRC_STANDALONE = lf_em4100rwc.c
# WITH_STANDALONE_HF_ICECLASS
ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS)))
SRC_STANDALONE = hf_iceclass.c
endif
# WITH_STANDALONE_HF_LEGIC
ifneq (,$(findstring WITH_STANDALONE_HF_LEGIC,$(APP_CFLAGS)))
@ -105,33 +113,33 @@ endif
ifneq (,$(findstring WITH_STANDALONE_HF_LEGICSIM,$(APP_CFLAGS)))
SRC_STANDALONE = hf_legicsim.c
endif
# WITH_STANDALONE_HF_MATTYRUN
ifneq (,$(findstring WITH_STANDALONE_HF_MATTYRUN,$(APP_CFLAGS)))
SRC_STANDALONE = hf_mattyrun.c
endif
# WITH_STANDALONE_HF_MFCSIM
ifneq (,$(findstring WITH_STANDALONE_HF_MFCSIM,$(APP_CFLAGS)))
SRC_STANDALONE = hf_mfcsim.c
endif
# WITH_STANDALONE_HF_MSDSAL
ifneq (,$(findstring WITH_STANDALONE_HF_MSDSAL,$(APP_CFLAGS)))
SRC_STANDALONE = hf_msdsal.c
endif
# WITH_STANDALONE_HF_ICECLASS
ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS)))
SRC_STANDALONE = hf_iceclass.c
# WITH_STANDALONE_HF_REBLAY
ifneq (,$(findstring WITH_STANDALONE_HF_REBLAY,$(APP_CFLAGS)))
SRC_STANDALONE = hf_reblay.c
endif
# WITH_STANDALONE_LF_THAREXDE
ifneq (,$(findstring WITH_STANDALONE_LF_THAREXDE,$(APP_CFLAGS)))
SRC_STANDALONE = lf_tharexde.c
endif
# WITH_STANDALONE_HF_CRAFTBYTE
ifneq (,$(findstring WITH_STANDALONE_HF_CRAFTBYTE,$(APP_CFLAGS)))
SRC_STANDALONE = hf_craftbyte.c
# WITH_STANDALONE_HF_TCPRST
ifneq (,$(findstring WITH_STANDALONE_HF_TCPRST,$(APP_CFLAGS)))
SRC_STANDALONE = hf_tcprst.c
endif
# WITH_STANDALONE_HF_TMUDFORD
ifneq (,$(findstring WITH_STANDALONE_HF_TMUDFORD,$(APP_CFLAGS)))
SRC_STANDALONE = hf_tmudford.c
endif
# WITH_STANDALONE_HF_REBLAY
ifneq (,$(findstring WITH_STANDALONE_HF_REBLAY,$(APP_CFLAGS)))
SRC_STANDALONE = hf_reblay.c
endif
# WITH_STANDALONE_HF_MFCSIM
ifneq (,$(findstring WITH_STANDALONE_HF_MFCSIM,$(APP_CFLAGS)))
SRC_STANDALONE = hf_mfcsim.c
# WITH_STANDALONE_HF_YOUNG
ifneq (,$(findstring WITH_STANDALONE_HF_YOUNG,$(APP_CFLAGS)))
SRC_STANDALONE = hf_young.c
endif
ifneq (,$(findstring WITH_STANDALONE_DANKARMULTI,$(APP_CFLAGS)))

View file

@ -43,9 +43,10 @@
#define ICE_STATE_ATTACK 2
#define ICE_STATE_READER 3
#define ICE_STATE_CONFIGCARD 4
#define ICE_STATE_DUMP_SIM 5
#define ICE_STATE_DUMP_SIM 5
#define ICE_STATE_READ_SIM 6
#define HF_ICLASS_NUM_MODES 6
#define HF_ICLASS_NUM_MODES 7
// ====================================================
// Select which standalone function to be active.
@ -56,6 +57,7 @@
//#define ICE_USE ICE_STATE_READER
//#define ICE_USE ICE_STATE_CONFIGCARD
//#define ICE_USE ICE_STATE_DUMP_SIM
//#define ICE_USE ICE_STATE_READ_SIM
// ====================================================
@ -322,6 +324,7 @@ static int reader_dump_mode(void) {
.use_credit_key = false,
.do_auth = true,
.send_reply = false,
.shallow_mod = false,
};
memcpy(auth.key, legacy_aa1_key, sizeof(auth.key));
@ -333,7 +336,7 @@ static int reader_dump_mode(void) {
// select tag.
uint32_t eof_time = 0;
bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time);
bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time, false);
if (res == false) {
switch_off();
continue;
@ -382,7 +385,7 @@ static int reader_dump_mode(void) {
// main read loop
for (uint16_t i = start_block; i <= app1_limit; i++) {
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) {
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time, false)) {
dumped++;
}
}
@ -394,7 +397,7 @@ static int reader_dump_mode(void) {
auth.use_credit_key = true;
memcpy(auth.key, aa2_key, sizeof(auth.key));
res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time);
res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time, false);
if (res) {
// sanity check of CSN.
@ -408,7 +411,7 @@ static int reader_dump_mode(void) {
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
for (uint16_t i = app1_limit + 1; i <= app2_limit; i++) {
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) {
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time, false)) {
dumped++;
}
}
@ -458,6 +461,7 @@ static int dump_sim_mode(void) {
.use_credit_key = false,
.do_auth = true,
.send_reply = false,
.shallow_mod = false,
};
memcpy(auth.key, legacy_aa1_key, sizeof(auth.key));
@ -469,7 +473,7 @@ static int dump_sim_mode(void) {
// select tag.
uint32_t eof_time = 0;
bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time);
bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time, false);
if (res == false) {
switch_off();
continue;
@ -518,7 +522,7 @@ static int dump_sim_mode(void) {
// main read loop
for (uint16_t i = start_block; i <= app1_limit; i++) {
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) {
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time, false)) {
dumped++;
}
}
@ -530,7 +534,7 @@ static int dump_sim_mode(void) {
auth.use_credit_key = true;
memcpy(auth.key, aa2_key, sizeof(auth.key));
res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time);
res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time, false);
if (res) {
// sanity check of CSN.
@ -544,7 +548,7 @@ static int dump_sim_mode(void) {
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
for (uint16_t i = app1_limit + 1; i <= app2_limit; i++) {
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) {
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time, false)) {
dumped++;
}
}
@ -718,6 +722,16 @@ void RunMod(void) {
mode = ICE_STATE_NONE;
break;
}
case ICE_STATE_READ_SIM: {
DbpString("-=[ enter " _CYAN_("`read & sim`") " mode, read cards, then sim after button press ]=-");
DbpString("Entering reader dump mode");
reader_dump_mode();
SpinDelay(1200); // debounce button press
DbpString("Entering fullsim mode");
fullsim_mode();
DbpString("Exiting fullsim mode");
LEDsoff();
}
}
}

View file

@ -111,7 +111,7 @@ void RunMod(void) {
//Indicate which card will be simulated
LED(i, 0);
//Try to load dump form flash
//Try to load dump from flash
sprintf(cur_dump_file, HF_LEGICSIM_DUMPFILE_SIM, i);
Dbprintf(_YELLOW_("[Slot: %d] Try to load dump file: %s"), i, cur_dump_file);
if (!fill_eml_from_file(cur_dump_file)) {

View file

@ -56,10 +56,11 @@ static char cur_dump_file[22] = {0};
static bool fill_eml_from_file(char *dumpfile) {
// check file exist
if (!exists_in_spiffs(dumpfile)) {
if (exists_in_spiffs(dumpfile) == false) {
Dbprintf(_RED_("Dump file %s not found!"), dumpfile);
return false;
}
//check dumpfile size
uint32_t size = size_in_spiffs(dumpfile);
if (size != DUMP_SIZE) {
@ -67,9 +68,12 @@ static bool fill_eml_from_file(char *dumpfile) {
BigBuf_free();
return false;
}
//read and load dump file
if (g_dbglevel >= DBG_INFO)
if (g_dbglevel >= DBG_INFO) {
Dbprintf(_YELLOW_("Found dump file %s. Uploading to emulator memory..."), dumpfile);
}
emlClearMem();
uint8_t *emCARD = BigBuf_get_EM_addr();
rdv40_spiffs_read_as_filetype(dumpfile, emCARD, size, RDV40_SPIFFS_SAFETY_SAFE);
@ -77,7 +81,7 @@ static bool fill_eml_from_file(char *dumpfile) {
}
static bool write_file_from_eml(char *dumpfile) {
if (!exists_in_spiffs(dumpfile)) {
if (exists_in_spiffs(dumpfile) == false) {
Dbprintf(_RED_("Dump file %s not found!"), dumpfile);
return false;
}
@ -99,14 +103,18 @@ void RunMod(void) {
bool flag_has_dumpfile = false;
for (int i = 1;; i++) {
//Exit! usbcommand break
if (data_available()) break;
//Infinite loop
// infinite loop
if (i > 15) {
if (!flag_has_dumpfile)
break; //still no dump file found
i = 1; //next loop
// still no dump file found
if (flag_has_dumpfile == false) {
break;
}
// next loop
i = 1;
}
//Indicate which card will be simulated
@ -115,7 +123,7 @@ void RunMod(void) {
//Try to load dump form flash
sprintf(cur_dump_file, HF_MFCSIM_DUMPFILE_SIM, i);
Dbprintf(_YELLOW_("[Slot: %d] Try to load dump file: %s"), i, cur_dump_file);
if (!fill_eml_from_file(cur_dump_file)) {
if (fill_eml_from_file(cur_dump_file) == false) {
Dbprintf(_YELLOW_("[Slot: %d] Dump load Failed, Next one!"), i);
LEDsoff();
continue;
@ -145,8 +153,10 @@ void RunMod(void) {
}
Dbprintf(_YELLOW_("[Slot: %d] Write Success! Change to next one!"), i);
}
if (!flag_has_dumpfile)
if (flag_has_dumpfile == false) {
Dbprintf("No dump file found!");
}
Dbprintf("Breaked! Exit standalone mode!");
SpinErr(15, 200, 3);
return;

View file

@ -386,28 +386,28 @@ void RunMod(void) {
// received a HALT
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) {
DbpString(_YELLOW_("+") "Received a HALT");
// DbpString(_YELLOW_("+") "Received a HALT");
p_response = NULL;
// received a WAKEUP
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) {
DbpString(_YELLOW_("+") "WAKEUP Received");
// DbpString(_YELLOW_("+") "WAKEUP Received");
prevCmd = 0;
p_response = &responses[RESP_INDEX_ATQA];
// received request for UID (cascade 1)
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) {
DbpString(_YELLOW_("+") "Request for UID C1");
// DbpString(_YELLOW_("+") "Request for UID C1");
p_response = &responses[RESP_INDEX_UIDC1];
// received a SELECT (cascade 1)
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) {
DbpString(_YELLOW_("+") "Request for SELECT S1");
// DbpString(_YELLOW_("+") "Request for SELECT S1");
p_response = &responses[RESP_INDEX_SAKC1];
// received a RATS request
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) {
DbpString(_YELLOW_("+") "Request for RATS");
// DbpString(_YELLOW_("+") "Request for RATS");
prevCmd = 0;
p_response = &responses[RESP_INDEX_RATS];

View file

@ -314,24 +314,24 @@ void RunMod() {
}
}
if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST
DbpString(_YELLOW_("+") "REQUEST Received");
// DbpString(_YELLOW_("+") "REQUEST Received");
p_response = &responses[RESP_INDEX_ATQA];
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { // Received a HALT
DbpString(_YELLOW_("+") "Received a HALT");
// DbpString(_YELLOW_("+") "Received a HALT");
p_response = NULL;
resp = 0;
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP
DbpString(_YELLOW_("+") "WAKEUP Received");
// DbpString(_YELLOW_("+") "WAKEUP Received");
p_response = &responses[RESP_INDEX_ATQA];
resp = 0;
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1)
DbpString(_YELLOW_("+") "Request for UID C1");
// DbpString(_YELLOW_("+") "Request for UID C1");
p_response = &responses[RESP_INDEX_UIDC1];
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1)
DbpString(_YELLOW_("+") "Request for SELECT S1");
// DbpString(_YELLOW_("+") "Request for SELECT S1");
p_response = &responses[RESP_INDEX_SAKC1];
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
DbpString(_YELLOW_("+") "Request for RATS");
// DbpString(_YELLOW_("+") "Request for RATS");
p_response = &responses[RESP_INDEX_RATS];
resp = 1;
} else if (receivedCmd[0] == 0xf2 && len == 4) { // ACKed - Time extension

View file

@ -75,7 +75,8 @@ void RunMod(void) {
} else if (state == STATE_EMUL) {
Iso15693InitTag();
Dbprintf("Starting simulation, press pm3-button to stop and go back to search state.");
SimTagIso15693(card.uid);
// default block size is 4
SimTagIso15693(card.uid, 4);
state = STATE_READ;
}

View file

@ -11,7 +11,7 @@
// then from shell:
// hexdump lf.bin -e '5/1 "%02X" /0 "\n"'
//
// To recall only LAST stored ID from flash use lf-last instead of lf file.
// To recall only LAST stored ID from flash use lf-last instead of lf file.
//
//-----------------------------------------------------------------------------
// Modes of operation:

View file

@ -0,0 +1,207 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// This simple mode encode, then emulate a Nedap identificator until button pressed
// lots of code from client side, cmdlfnedap, util, etc.
//-----------------------------------------------------------------------------
#include "standalone.h" // standalone definitions
#include "proxmark3_arm.h"
#include "appmain.h"
#include "fpgaloader.h"
#include "lfops.h"
#include "util.h"
#include "dbprint.h"
#include "string.h"
#include "BigBuf.h"
#include "crc16.h"
#define MODULE_LONG_NAME "LF Nedap simple simulator"
typedef struct _NEDAP_TAG {
uint8_t subType;
uint16_t customerCode;
uint32_t id;
uint8_t bIsLong;
} NEDAP_TAG, *PNEDAP_TAG;
const NEDAP_TAG Tag = {.subType = 0x5, .customerCode = 0x123, .id = 42424, .bIsLong = 1};
static int NedapPrepareBigBuffer(const NEDAP_TAG *pTag);
static void biphaseSimBitInverted(uint8_t c, int *n, uint8_t *phase);
static void NedapGen(uint8_t subType, uint16_t customerCode, uint32_t id, bool isLong, uint8_t *data);
static uint8_t isEven_64_63(const uint8_t *data);
static inline uint32_t bitcount32(uint32_t a);
static void bytes_to_bytebits(const void *src, const size_t srclen, void *dest);
void ModInfo(void) {
DbpString(" " MODULE_LONG_NAME);
}
void RunMod(void) {
int n;
StandAloneMode();
Dbprintf("[=] " MODULE_LONG_NAME " -- started");
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
Dbprintf("[=] NEDAP (%s) - ID: " _GREEN_("%05u") " subtype: " _GREEN_("%1u") " customer code: " _GREEN_("%u / 0x%03X"), Tag.bIsLong ? "128b" : "64b", Tag.id, Tag.subType, Tag.customerCode, Tag.customerCode);
n = NedapPrepareBigBuffer(&Tag);
do {
WDT_HIT();
if (data_available())
break;
SimulateTagLowFrequency(n, 0, true);
} while (BUTTON_HELD(1000) == BUTTON_NO_CLICK);
Dbprintf("[=] " MODULE_LONG_NAME " -- exiting");
LEDsoff();
}
static int NedapPrepareBigBuffer(const NEDAP_TAG *pTag) {
int ret = 0;
uint8_t data[16], bitStream[sizeof(data) * 8], phase = 0;
uint16_t i, size = pTag->bIsLong ? sizeof(data) : (sizeof(data) / 2);
NedapGen(pTag->subType, pTag->customerCode, pTag->id, pTag->bIsLong, data);
bytes_to_bytebits(data, size, bitStream);
size <<= 3;
for (i = 0; i < size; i++) {
biphaseSimBitInverted(!bitStream[i], &ret, &phase);
}
if (phase == 1) { //run a second set inverted to keep phase in check
for (i = 0; i < size; i++) {
biphaseSimBitInverted(!bitStream[i], &ret, &phase);
}
}
return ret;
}
static void biphaseSimBitInverted(uint8_t c, int *n, uint8_t *phase) {
uint8_t *dest = BigBuf_get_addr();
if (c) {
memset(dest + (*n), c ^ 1 ^ *phase, 32);
memset(dest + (*n) + 32, c ^ *phase, 32);
} else {
memset(dest + (*n), c ^ *phase, 64);
*phase ^= 1;
}
*n += 64;
}
#define FIXED_71 0x71
#define FIXED_40 0x40
#define UNKNOWN_A 0x00
#define UNKNOWN_B 0x00
static const uint8_t translateTable[10] = {8, 2, 1, 12, 4, 5, 10, 13, 0, 9};
static void NedapGen(uint8_t subType, uint16_t customerCode, uint32_t id, bool isLong, uint8_t *data) { // 8 or 16
uint8_t buffer[7];
uint8_t r1 = (uint8_t)(id / 10000);
uint8_t r2 = (uint8_t)((id % 10000) / 1000);
uint8_t r3 = (uint8_t)((id % 1000) / 100);
uint8_t r4 = (uint8_t)((id % 100) / 10);
uint8_t r5 = (uint8_t)(id % 10);
// first part
uint8_t idxC1 = r1;
uint8_t idxC2 = (idxC1 + 1 + r2) % 10;
uint8_t idxC3 = (idxC2 + 1 + r3) % 10;
uint8_t idxC4 = (idxC3 + 1 + r4) % 10;
uint8_t idxC5 = (idxC4 + 1 + r5) % 10;
buffer[0] = 0xc0 | (subType & 0x0F);
buffer[1] = (customerCode & 0x0FF0) >> 4;
buffer[2] = ((customerCode & 0x000F) << 4) | translateTable[idxC1];
buffer[3] = (translateTable[idxC2] << 4) | translateTable[idxC3];
buffer[4] = (translateTable[idxC4] << 4) | translateTable[idxC5];
// checksum
init_table(CRC_XMODEM);
uint16_t checksum = crc16_xmodem(buffer, 5);
buffer[6] = ((checksum & 0x000F) << 4) | (buffer[4] & 0x0F);
buffer[5] = (checksum & 0x00F0) | ((buffer[4] & 0xF0) >> 4);
buffer[4] = ((checksum & 0x0F00) >> 4) | (buffer[3] & 0x0F);
buffer[3] = ((checksum & 0xF000) >> 8) | ((buffer[3] & 0xF0) >> 4);
// carry calc
uint8_t carry = 0;
for (uint8_t i = 0; i < sizeof(buffer); i++) {
uint8_t tmp = buffer[sizeof(buffer) - 1 - i];
data[7 - i] = ((tmp & 0x7F) << 1) | carry;
carry = (tmp & 0x80) >> 7;
}
data[0] = 0xFE | carry;
data[7] |= isEven_64_63(data);
// second part
if (isLong) {
uint8_t id0 = r1;
uint8_t id1 = (r2 << 4) | r3;
uint8_t id2 = (r4 << 4) | r5;
data[8] = (id2 >> 1);
data[9] = ((id2 & 0x01) << 7) | (id1 >> 2);
data[10] = ((id1 & 0x03) << 6) | (id0 >> 3);
data[11] = ((id0 & 0x07) << 5) | (FIXED_71 >> 4);
data[12] = ((FIXED_71 & 0x0F) << 4) | (FIXED_40 >> 5);
data[13] = ((FIXED_40 & 0x1F) << 3) | (UNKNOWN_A >> 6);
data[14] = ((UNKNOWN_A & 0x3F) << 2) | (UNKNOWN_B >> 7);
data[15] = ((UNKNOWN_B & 0x7F) << 1);
data[15] |= isEven_64_63(data + 8);
}
}
static uint8_t isEven_64_63(const uint8_t *data) { // 8
uint32_t tmp[2];
memcpy(tmp, data, 8);
return (bitcount32(tmp[0]) + (bitcount32(tmp[1] & 0xfeffffff))) & 1;
}
static void bytes_to_bytebits(const void *src, const size_t srclen, void *dest) {
uint8_t *s = (uint8_t *)src, *d = (uint8_t *)dest;
size_t i = srclen * 8, j = srclen;
while (j--) {
uint8_t b = s[j];
d[--i] = (b >> 0) & 1;
d[--i] = (b >> 1) & 1;
d[--i] = (b >> 2) & 1;
d[--i] = (b >> 3) & 1;
d[--i] = (b >> 4) & 1;
d[--i] = (b >> 5) & 1;
d[--i] = (b >> 6) & 1;
d[--i] = (b >> 7) & 1;
}
}
static inline uint32_t bitcount32(uint32_t a) {
#if defined __GNUC__
return __builtin_popcountl(a);
#else
a = a - ((a >> 1) & 0x55555555);
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
return (((a + (a >> 4)) & 0x0f0f0f0f) * 0x01010101) >> 24;
#endif
}

View file

@ -0,0 +1,108 @@
//-----------------------------------------------------------------------------
// Copyright (C) Yann Gascuel 2023
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// LF HID ProxII Brutforce v2 by lnv42 - based on Proxbrute by Brad antoniewicz
//
// Following code is a trivial brute forcer for when you know the facility
// code and want to find valid(s) card number(s). It will try all card
// fnumbers rom CARDNUM_START to CARDNUM_END one by one (max. ~65k tries).
// This brute force will be a lot faster than Proxbrute that will try all
// possibles values for LF low, even those with bad checksum (~4g tries).
// LEDs will help you know which card number(s) worked.
//
//-----------------------------------------------------------------------------
#include "standalone.h" // standalone definitions
#include "proxmark3_arm.h"
#include "appmain.h"
#include "fpgaloader.h"
#include "util.h"
#include "dbprint.h"
#include "lfops.h"
#include "parity.h"
#define CARDNUM_START 0
#define CARDNUM_END 0xFFFF
#define FACILITY_CODE 2
void ModInfo(void) {
DbpString(" LF HID ProxII bruteforce v2");
}
// samy's sniff and repeat routine for LF
void RunMod(void) {
StandAloneMode();
Dbprintf(">> LF HID proxII bruteforce v2 a.k.a Prox2Brute Started <<");
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
const uint32_t high = 0x20; // LF high value is always 0x20 here
uint32_t low = 0;
uint32_t fac = FACILITY_CODE, cardnum = 0;
LED_D_ON();
while (BUTTON_HELD(200) != BUTTON_HOLD) { // Waiting for a 200ms button press
WDT_HIT();
// exit from SamyRun, send a usbcommand.
if (data_available()) { // early exit
DbpString("[=] You can take the shell back :) ...");
LEDsoff();
return;
}
}
LED_C_ON();
WAIT_BUTTON_RELEASED(); // We are now ready to start brutforcing card numbers
LEDsoff();
Dbprintf("[=] Starting HID ProxII Bruteforce from card %08x to %08x",
CARDNUM_START, MIN(CARDNUM_END, 0xFFFF));
for (cardnum = CARDNUM_START ; cardnum <= MIN(CARDNUM_END, 0xFFFF) ; cardnum++) {
WDT_HIT();
// exit from SamyRun, send a usbcommand.
if (data_available()) break;
// short button press may be used for fast-forward
if (BUTTON_HELD(1000) == BUTTON_HOLD) break; // long button press (>=1sec) exit
// calculate the new LF low value including Card number, Facility code and checksum
low = (cardnum << 1) | (fac << 17);
low |= oddparity32((low >> 1) & 0xFFF);
low |= evenparity32((low >> 13) & 0xFFF) << 25;
Dbprintf("[=] trying Facility = %08x, Card = %08x, raw = %08x%08x",
fac, cardnum, high, low);
// Start simulating an HID TAG, with high/low values, no led control and 20000 cycles timeout
CmdHIDsimTAGEx(0, high, low, 0, false, 20000);
// switch leds to be able to know (aproximatly) which card number worked (64 tries loop)
LED_A_INV(); // switch led A every try
if ((cardnum - CARDNUM_START) % 8 == 7) // switch led B every 8 tries
LED_B_INV();
if ((cardnum - CARDNUM_START) % 16 == 15) // switch led C every 16 tries
LED_C_INV();
if ((cardnum - CARDNUM_START) % 32 == 31) // switch led D every 32 tries
LED_D_INV();
}
SpinErr((LED_A | LED_B | LED_C | LED_D), 250, 5); // Xmax tree
Dbprintf("[=] Ending HID ProxII Bruteforce from card %08x to %08x",
CARDNUM_START, cardnum - 1);
DbpString("[=] You can take the shell back :) ...");
LEDsoff(); // This is the end
}

View file

@ -100,6 +100,8 @@ STANDALONE_MODES_REQ_FLASH :=
STANDALONE_MODES_REQ_BT :=
```
Please respect alphabetic order!
## Update MAKEFILE.INC
^[Top](#top)
@ -117,6 +119,8 @@ ifneq (,$(findstring WITH_STANDALONE_LF_FOO,$(APP_CFLAGS)))
endif
```
Please respect alphabetic order!
## Adding identification string of your mode
^[Top](#top)
@ -174,9 +178,11 @@ Once you're ready to share your mode, please
* add a line in CHANGELOG.md
* add your mode in the modes table in `doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md`
* add your mode in `tools/build_all_firmwares.sh`
* add your mode in `tools/build_all_firmwares.sh` such that it reflects `armsrc/Standalone/Makefile.hal` list of firmwares to build.
and submit your PR.
Please respect alphabetic order of standalone modes everywhere!
Then submit your PR.
Once approved, add also your mode in https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode

View file

@ -33,6 +33,7 @@
#include "legicrf.h"
#include "BigBuf.h"
#include "iclass_cmd.h"
#include "hfops.h"
#include "iso14443a.h"
#include "iso14443b.h"
#include "iso15693.h"
@ -344,7 +345,7 @@ static void print_debug_level(void) {
char dbglvlstr[20] = {0};
switch (g_dbglevel) {
case DBG_NONE:
sprintf(dbglvlstr, "none");
sprintf(dbglvlstr, "off");
break;
case DBG_ERROR:
sprintf(dbglvlstr, "error");
@ -452,6 +453,12 @@ static void SendCapabilities(void) {
capabilities.baudrate = g_usart_baudrate;
#endif
#ifdef RDV4
capabilities.is_rdv4 = true;
#else
capabilities.is_rdv4 = false;
#endif
#ifdef WITH_FLASH
capabilities.compiled_with_flash = true;
capabilities.hw_available_flash = FlashInit();
@ -1220,6 +1227,10 @@ static void PacketReceived(PacketCommandNG *packet) {
em4x70_write_key((em4x70_data_t *)packet->data.asBytes, true);
break;
}
case CMD_LF_EM4X70_BRUTE: {
em4x70_brute((em4x70_data_t *)packet->data.asBytes, true);
break;
}
#endif
#ifdef WITH_ZX8211
@ -1255,12 +1266,27 @@ static void PacketReceived(PacketCommandNG *packet) {
ReaderIso15693(NULL);
break;
}
case CMD_HF_ISO15693_EML_CLEAR: {
EmlClearIso15693();
break;
}
case CMD_HF_ISO15693_EML_SETMEM: {
struct p {
uint32_t offset;
uint8_t count;
uint8_t data[];
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
EmlSetMemIso15693(payload->count, payload->data, payload->offset);
break;
}
case CMD_HF_ISO15693_SIMULATE: {
struct p {
uint8_t uid[8];
uint8_t block_size;
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
SimTagIso15693(payload->uid);
SimTagIso15693(payload->uid, payload->block_size);
break;
}
case CMD_HF_ISO15693_CSETUID: {
@ -1271,20 +1297,76 @@ static void PacketReceived(PacketCommandNG *packet) {
SetTag15693Uid(payload->uid);
break;
}
case CMD_HF_ISO15693_SLIX_L_DISABLE_PRIVACY: {
case CMD_HF_ISO15693_SLIX_DISABLE_EAS: {
struct p {
uint8_t pwd[4];
bool usepwd;
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
DisablePrivacySlixLIso15693(payload->pwd);
DisableEAS_AFISlixIso15693(payload->pwd, payload->usepwd);
break;
}
case CMD_HF_ISO15693_SLIX_L_DISABLE_AESAFI: {
case CMD_HF_ISO15693_SLIX_ENABLE_EAS: {
struct p {
uint8_t pwd[4];
bool usepwd;
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
EnableEAS_AFISlixIso15693(payload->pwd, payload->usepwd);
break;
}
case CMD_HF_ISO15693_SLIX_WRITE_PWD: {
struct p {
uint8_t old_pwd[4];
uint8_t new_pwd[4];
uint8_t pwd_id;
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
WritePasswordSlixIso15693(payload->old_pwd, payload->new_pwd, payload->pwd_id);
break;
}
case CMD_HF_ISO15693_SLIX_DISABLE_PRIVACY: {
struct p {
uint8_t pwd[4];
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
DisableEAS_AFISlixLIso15693(payload->pwd);
DisablePrivacySlixIso15693(payload->pwd);
break;
}
case CMD_HF_ISO15693_SLIX_ENABLE_PRIVACY: {
struct p {
uint8_t pwd[4];
} PACKED;
struct p *payload = (struct p *)packet->data.asBytes;
EnablePrivacySlixIso15693(payload->pwd);
break;
}
case CMD_HF_ISO15693_SLIX_PASS_PROTECT_AFI: {
struct p {
uint8_t pwd[4];
} PACKED;
struct p *payload = (struct p *)packet->data.asBytes;
PassProtectAFISlixIso15693(payload->pwd);
break;
}
case CMD_HF_ISO15693_WRITE_AFI: {
struct p {
uint8_t pwd[4];
bool use_pwd;
uint8_t uid[8];
bool use_uid;
uint8_t afi;
} PACKED;
struct p *payload = (struct p *)packet->data.asBytes;
WriteAFIIso15693(payload->pwd, payload->use_pwd, payload->uid, payload->use_uid, payload->afi);
break;
}
case CMD_HF_ISO15693_SLIX_PASS_PROTECT_EAS: {
struct p {
uint8_t pwd[4];
} PACKED;
struct p *payload = (struct p *)packet->data.asBytes;
PassProtextEASSlixIso15693(payload->pwd);
break;
}
@ -1384,6 +1466,26 @@ static void PacketReceived(PacketCommandNG *packet) {
}
#endif
#ifdef WITH_GENERAL_HF
case CMD_HF_ACQ_RAW_ADC: {
uint32_t samplesCount = 0;
memcpy(&samplesCount, packet->data.asBytes, 4);
HfReadADC(samplesCount, true);
break;
}
case CMD_HF_TEXKOM_SIMULATE: {
struct p {
uint8_t data[8];
uint8_t modulation;
uint32_t timeout;
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
HfSimulateTkm(payload->data, payload->modulation, payload->timeout);
break;
}
#endif
#ifdef WITH_ISO14443a
case CMD_HF_ISO14443A_PRINT_CONFIG: {
printHf14aConfig();
@ -1428,6 +1530,7 @@ static void PacketReceived(PacketCommandNG *packet) {
iso14443a_antifuzz(payload->flag);
break;
}
// EPA related
case CMD_HF_EPA_COLLECT_NONCE: {
EPA_PACE_Collect_Nonce(packet);
break;
@ -1436,6 +1539,11 @@ static void PacketReceived(PacketCommandNG *packet) {
EPA_PACE_Replay(packet);
break;
}
case CMD_HF_EPA_PACE_SIMULATE: {
EPA_PACE_Simulate(packet);
break;
}
case CMD_HF_MIFARE_READER: {
struct p {
uint8_t first_run;
@ -1476,7 +1584,7 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
case CMD_HF_MIFARE_VALUE: {
MifareValue(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
MifareValue(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
break;
}
case CMD_HF_MIFAREU_WRITEBL: {
@ -1578,7 +1686,7 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareECardLoadExt(payload->sectorcnt, payload->keytype);
break;
}
// Work with "magic Chinese" card
// Gen1a / 1b - "magic Chinese" card
case CMD_HF_MIFARE_CSETBL: {
MifareCSetBlock(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
break;
@ -1605,13 +1713,53 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareGen3Freez();
break;
}
// Gen 4 GTU magic cards
case CMD_HF_MIFARE_G4_RDBL: {
struct p {
uint8_t blockno;
uint8_t pwd[4];
uint8_t workFlags;
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
MifareG4ReadBlk(payload->blockno, payload->pwd);
MifareG4ReadBlk(payload->blockno, payload->pwd, payload->workFlags);
break;
}
case CMD_HF_MIFARE_G4_WRBL: {
struct p {
uint8_t blockno;
uint8_t pwd[4];
uint8_t data[16]; // data to be written
uint8_t workFlags;
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
MifareG4WriteBlk(payload->blockno, payload->pwd, payload->data, payload->workFlags);
break;
}
case CMD_HF_MIFARE_G4_GDM_CONFIG: {
struct p {
uint8_t key[6];
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
MifareReadConfigBlockGDM(payload->key);
break;
}
case CMD_HF_MIFARE_G4_GDM_WRCFG: {
struct p {
uint8_t data[16];
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
MifareWriteConfigBlockGDM(payload->data);
break;
}
case CMD_HF_MIFARE_G4_GDM_WRBL: {
struct p {
uint8_t blockno;
uint8_t keytype;
uint8_t key[6];
uint8_t data[16]; // data to be written
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
MifareWriteBlockGDM(payload->blockno, payload->keytype, payload->key, payload->data);
break;
}
case CMD_HF_MIFARE_PERSONALIZE_UID: {
@ -1763,11 +1911,13 @@ static void PacketReceived(PacketCommandNG *packet) {
struct p {
uint32_t samplesToSkip;
uint32_t triggersToSkip;
uint8_t skipMode;
uint8_t skipRatio;
} PACKED;
struct p *payload = (struct p *)packet->data.asBytes;
uint16_t len = 0;
int res = HfSniff(payload->samplesToSkip, payload->triggersToSkip, &len);
int res = HfSniff(payload->samplesToSkip, payload->triggersToSkip, &len, payload->skipMode, payload->skipRatio);
struct {
uint16_t len;
@ -2143,20 +2293,26 @@ static void PacketReceived(PacketCommandNG *packet) {
uint32_t size = packet->oldarg[1];
uint8_t *buff = BigBuf_malloc(size);
rdv40_spiffs_read_as_filetype((char *)filename, (uint8_t *)buff, size, RDV40_SPIFFS_SAFETY_SAFE);
if (buff == NULL) {
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Could not allocate buffer");
// Trigger a finish downloading signal with an PM3_EMALLOC
reply_ng(CMD_SPIFFS_DOWNLOAD, PM3_EMALLOC, NULL, 0);
} else {
rdv40_spiffs_read_as_filetype((char *)filename, (uint8_t *)buff, size, RDV40_SPIFFS_SAFETY_SAFE);
// arg0 = filename
// arg1 = size
// arg2 = RFU
// arg0 = filename
// arg1 = size
// arg2 = RFU
for (size_t i = 0; i < size; i += PM3_CMD_DATA_SIZE) {
size_t len = MIN((size - i), PM3_CMD_DATA_SIZE);
int result = reply_old(CMD_SPIFFS_DOWNLOADED, i, len, 0, buff + i, len);
if (result != PM3_SUCCESS)
Dbprintf("transfer to client failed :: | bytes between %d - %d (%d) | result: %d", i, i + len, len, result);
for (size_t i = 0; i < size; i += PM3_CMD_DATA_SIZE) {
size_t len = MIN((size - i), PM3_CMD_DATA_SIZE);
int result = reply_old(CMD_SPIFFS_DOWNLOADED, i, len, 0, buff + i, len);
if (result != PM3_SUCCESS)
Dbprintf("transfer to client failed :: | bytes between %d - %d (%d) | result: %d", i, i + len, len, result);
}
// Trigger a finish downloading signal with an ACK frame
reply_ng(CMD_SPIFFS_DOWNLOAD, PM3_SUCCESS, NULL, 0);
BigBuf_free();
}
// Trigger a finish downloading signal with an ACK frame
reply_ng(CMD_SPIFFS_DOWNLOAD, PM3_SUCCESS, NULL, 0);
LED_B_OFF();
break;
}
@ -2263,6 +2419,30 @@ static void PacketReceived(PacketCommandNG *packet) {
LED_B_OFF();
break;
}
case CMD_SPIFFS_ELOAD: {
LED_B_ON();
uint8_t *em = BigBuf_get_EM_addr();
if (em == NULL) {
reply_ng(CMD_SPIFFS_ELOAD, PM3_EMALLOC, NULL, 0);
LED_B_OFF();
break;
}
char *fn = (char *)packet->data.asBytes;
uint32_t size = size_in_spiffs(fn);
if (size == 0) {
reply_ng(CMD_SPIFFS_ELOAD, PM3_SUCCESS, NULL, 0);
LED_B_OFF();
break;
}
rdv40_spiffs_read_as_filetype(fn, em, size, RDV40_SPIFFS_SAFETY_SAFE);
reply_ng(CMD_SPIFFS_ELOAD, PM3_SUCCESS, NULL, 0);
LED_B_OFF();
break;
}
case CMD_FLASHMEM_SET_SPIBAUDRATE: {
if (packet->length != sizeof(uint32_t))
break;
@ -2318,8 +2498,11 @@ static void PacketReceived(PacketCommandNG *packet) {
LED_B_OFF();
break;
}
if (page < 3)
if (page < 3) {
isok = Flash_WipeMemoryPage(page);
// let spiffs check and update its info post flash erase
rdv40_spiffs_check();
}
reply_mix(CMD_ACK, isok, 0, 0, 0, 0);
LED_B_OFF();
@ -2521,7 +2704,18 @@ void __attribute__((noreturn)) AppMain(void) {
#endif
#ifdef WITH_SMARTCARD
I2C_init();
I2C_init(false);
#endif
#ifdef WITH_FLASH
if (FlashInit()) {
uint64_t flash_uniqueID = 0;
if (!Flash_CheckBusy(BUSY_TIMEOUT)) { // OK because firmware was built for devices with flash
Flash_UniqueID((uint8_t *)(&flash_uniqueID));
}
FlashStop();
usb_update_serial(flash_uniqueID);
}
#endif
#ifdef WITH_FPC_USART

View file

@ -131,7 +131,7 @@ static int reply_ng_internal(uint16_t cmd, int16_t status, const uint8_t *data,
return PM3_SUCCESS;
}
int reply_ng(uint16_t cmd, int16_t status, uint8_t *data, size_t len) {
int reply_ng(uint16_t cmd, int16_t status, const uint8_t *data, size_t len) {
return reply_ng_internal(cmd, status, data, len, true);
}

View file

@ -28,7 +28,7 @@ extern bool g_reply_via_fpc;
extern bool g_reply_via_usb;
int reply_old(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len);
int reply_ng(uint16_t cmd, int16_t status, uint8_t *data, size_t len);
int reply_ng(uint16_t cmd, int16_t status, const uint8_t *data, size_t len);
int reply_mix(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len);
int receive_ng(PacketCommandNG *rx);

View file

@ -755,7 +755,7 @@ void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect,
memcpy(ovect, data, block_size);
}
uint8_t edata[DESFIRE_MAX_CRYPTO_BLOCK_SIZE];
uint8_t edata[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
switch (key->type) {
case T_DES:

View file

@ -21,6 +21,7 @@
#include "dbprint.h"
#include "lfadc.h"
#include "commonutil.h"
#include "optimized_cipherutils.h"
#include "em4x70.h"
#include "appmain.h" // tear
@ -85,7 +86,7 @@ static int em4x70_receive(uint8_t *bits, size_t length);
static bool find_listen_window(bool command);
static void init_tag(void) {
memset(tag.data, 0x00, ARRAYLEN(tag.data));
memset(tag.data, 0x00, sizeof(tag.data));
}
static void em4x70_setup_read(void) {
@ -298,14 +299,14 @@ static bool check_ack(void) {
// returns true if signal structue corresponds to ACK, anything else is
// counted as NAK (-> false)
// ACK 64 + 64
// NACK 64 + 48
// NAK 64 + 48
if (check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD) &&
check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) {
// ACK
return true;
}
// Othewise it was a NACK or Listen Window
// Otherwise it was a NAK or Listen Window
return false;
}
@ -339,7 +340,7 @@ static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *respon
uint8_t grnd[EM4X70_MAX_RECEIVE_LENGTH] = {0};
int num = em4x70_receive(grnd, 20);
if (num < 20) {
Dbprintf("Auth failed");
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Auth failed");
return PM3_ESOFT;
}
bits2bytes(grnd, 24, response);
@ -349,6 +350,80 @@ static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *respon
return PM3_ESOFT;
}
static int set_byte(uint8_t *target, int value) {
int c = value > 0xFF;
*target = reflect8(value);
return c;
}
static int bruteforce(const uint8_t address, const uint8_t *rnd, const uint8_t *frnd, uint16_t start_key, uint8_t *response) {
uint8_t auth_resp[3] = {0};
uint8_t rev_rnd[7];
uint8_t temp_rnd[7];
reverse_arraycopy((uint8_t *)rnd, rev_rnd, sizeof(rev_rnd));
memcpy(temp_rnd, rnd, sizeof(temp_rnd));
for (int k = start_key; k <= 0xFFFF; ++k) {
int c = 0;
WDT_HIT();
uint16_t rev_k = reflect16(k);
switch (address) {
case 9:
c = set_byte(&temp_rnd[0], rev_rnd[0] + (rev_k & 0xFF));
c = set_byte(&temp_rnd[1], rev_rnd[1] + c + ((rev_k >> 8) & 0xFF));
c = set_byte(&temp_rnd[2], rev_rnd[2] + c);
c = set_byte(&temp_rnd[3], rev_rnd[3] + c);
c = set_byte(&temp_rnd[4], rev_rnd[4] + c);
c = set_byte(&temp_rnd[5], rev_rnd[5] + c);
set_byte(&temp_rnd[6], rev_rnd[6] + c);
break;
case 8:
c = set_byte(&temp_rnd[2], rev_rnd[2] + (rev_k & 0xFF));
c = set_byte(&temp_rnd[3], rev_rnd[3] + c + ((rev_k >> 8) & 0xFF));
c = set_byte(&temp_rnd[4], rev_rnd[4] + c);
c = set_byte(&temp_rnd[5], rev_rnd[5] + c);
set_byte(&temp_rnd[6], rev_rnd[6] + c);
break;
case 7:
c = set_byte(&temp_rnd[4], rev_rnd[4] + (rev_k & 0xFF));
c = set_byte(&temp_rnd[5], rev_rnd[5] + c + ((rev_k >> 8) & 0xFF));
set_byte(&temp_rnd[6], rev_rnd[6] + c);
break;
default:
Dbprintf("Bad block number given: %d", address);
return PM3_ESOFT;
}
// Report progress every 256 attempts
if ((k % 0x100) == 0) {
Dbprintf("Trying: %04X", k);
}
// Due to performance reason, we only try it once. Therefore you need a very stable RFID communcation.
if (authenticate(temp_rnd, frnd, auth_resp) == PM3_SUCCESS) {
if (g_dbglevel >= DBG_INFO)
Dbprintf("Authentication success with rnd: %02X%02X%02X%02X%02X%02X%02X", temp_rnd[0], temp_rnd[1], temp_rnd[2], temp_rnd[3], temp_rnd[4], temp_rnd[5], temp_rnd[6]);
response[0] = (k >> 8) & 0xFF;
response[1] = k & 0xFF;
return PM3_SUCCESS;
}
if (BUTTON_PRESS() || data_available()) {
Dbprintf("EM4x70 Bruteforce Interrupted");
return PM3_EOPABORTED;
}
}
return PM3_ESOFT;
}
static int send_pin(const uint32_t pin) {
// sends pin code for unlocking
@ -576,7 +651,7 @@ static int em4x70_receive(uint8_t *bits, size_t length) {
}
if (!foundheader) {
Dbprintf("Failed to find read header");
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Failed to find read header");
return 0;
}
@ -738,6 +813,27 @@ void em4x70_auth(em4x70_data_t *etd, bool ledcontrol) {
reply_ng(CMD_LF_EM4X70_AUTH, status, response, sizeof(response));
}
void em4x70_brute(em4x70_data_t *etd, bool ledcontrol) {
uint8_t status = 0;
uint8_t response[2] = {0};
command_parity = etd->parity;
init_tag();
em4x70_setup_read();
// Find the Tag
if (get_signalproperties() && find_em4x70_tag()) {
// Bruteforce partial key
status = bruteforce(etd->address, etd->rnd, etd->frnd, etd->start_key, response) == PM3_SUCCESS;
}
StopTicks();
lf_finalize(ledcontrol);
reply_ng(CMD_LF_EM4X70_BRUTE, status, response, sizeof(response));
}
void em4x70_write_pin(em4x70_data_t *etd, bool ledcontrol) {
uint8_t status = 0;

View file

@ -32,6 +32,7 @@ typedef enum {
void em4x70_info(em4x70_data_t *etd, bool ledcontrol);
void em4x70_write(em4x70_data_t *etd, bool ledcontrol);
void em4x70_brute(em4x70_data_t *etd, bool ledcontrol);
void em4x70_unlock(em4x70_data_t *etd, bool ledcontrol);
void em4x70_auth(em4x70_data_t *etd, bool ledcontrol);
void em4x70_write_pin(em4x70_data_t *etd, bool ledcontrol);

View file

@ -592,3 +592,44 @@ int EPA_Setup(void) {
Dbprintf("No card found");
return 1;
}
void EPA_PACE_Simulate(PacketCommandNG *c) {
//---------Initializing---------
// Get password from arguments
unsigned char pwd[6];
memcpy(pwd, c->data.asBytes, 6);
// Set up communication with the card
int res = EPA_Setup();
if (res != 0) {
EPA_PACE_Collect_Nonce_Abort(CMD_HF_EPA_PACE_SIMULATE, 1, res);
return;
}
// Read EF.CardAccess
uint8_t card_access[210] = {0};
int card_access_length = EPA_Read_CardAccess(card_access, 210);
// The response has to be at least this big to hold the OID
if (card_access_length < 18) {
EPA_PACE_Collect_Nonce_Abort(CMD_HF_EPA_PACE_SIMULATE, 2, card_access_length);
return;
}
// PACEInfo of the card
pace_version_info_t pace_version_info;
// Search for the PACE OID
res = EPA_Parse_CardAccess(card_access, card_access_length, &pace_version_info);
if (res != 0 || pace_version_info.version == 0) {
EPA_PACE_Collect_Nonce_Abort(CMD_HF_EPA_PACE_SIMULATE, 3, res);
return;
}
Dbprintf("Standardized Domain Parameter: %i", pace_version_info.parameter_id);
DbpString("");
DbpString("finished");
}

View file

@ -32,9 +32,7 @@ typedef struct {
// general functions
void EPA_Finish(void);
size_t EPA_Parse_CardAccess(uint8_t *data,
size_t length,
pace_version_info_t *pace_info);
size_t EPA_Parse_CardAccess(uint8_t *data, size_t length, pace_version_info_t *pace_info);
int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length);
int EPA_Setup(void);
@ -44,5 +42,6 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce);
void EPA_PACE_Collect_Nonce(PacketCommandNG *c);
void EPA_PACE_Replay(PacketCommandNG *c);
void EPA_PACE_Simulate(PacketCommandNG *c);
#endif /* __EPA_H */

View file

@ -298,7 +298,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
// 8-byte IDm, number of blocks, blocks numbers
// number of blocks limited to 4 for FelicaLite(S)
static void BuildFliteRdblk(const uint8_t *idm, uint8_t blocknum, const uint16_t *blocks) {
if (blocknum > 4 || blocknum <= 0)
if (blocknum > 4 || blocknum == 0)
Dbprintf("Invalid number of blocks, %d != 4", blocknum);
uint8_t c = 0, i = 0;

View file

@ -613,10 +613,12 @@ void switch_off(void) {
if (g_dbglevel > 3) {
Dbprintf("switch_off");
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
if (downloaded_bitstream == FPGA_BITSTREAM_HF || downloaded_bitstream == FPGA_BITSTREAM_HF_15) {
FpgaDisableSscDma();
}
set_tracing(false);
LEDsoff();
}

View file

@ -235,9 +235,10 @@ static int json_get_utf8_char_len(unsigned char ch) {
/* string = '"' { quoted_printable_chars } '"' */
static int json_parse_string(struct frozen *f) {
int n, ch = 0, len = 0;
int ch = 0;
TRY(json_test_and_skip(f, '"'));
{
int len = 0;
SET_STATE(f, f->cur, "", 0);
for (; f->cur < f->end; f->cur += len) {
ch = *(unsigned char *) f->cur;
@ -245,6 +246,7 @@ static int json_parse_string(struct frozen *f) {
EXPECT(ch >= 32 && len > 0, JSON_STRING_INVALID); /* No control chars */
EXPECT(len <= json_left(f), JSON_STRING_INCOMPLETE);
if (ch == '\\') {
int n;
EXPECT((n = json_get_escape_len(f->cur + 1, json_left(f))) > 0, n);
len += n;
} else if (ch == '"') {
@ -295,17 +297,17 @@ static int json_parse_number(struct frozen *f) {
#if JSON_ENABLE_ARRAY
/* array = '[' [ value { ',' value } ] ']' */
static int json_parse_array(struct frozen *f) {
int i = 0, current_path_len;
char buf[20];
CALL_BACK(f, JSON_TYPE_ARRAY_START, NULL, 0);
TRY(json_test_and_skip(f, '['));
{
{
int i = 0;
SET_STATE(f, f->cur - 1, "", 0);
while (json_cur(f) != ']') {
char buf[20];
snprintf(buf, sizeof(buf), "[%d]", i);
i++;
current_path_len = json_append_to_path(f, buf, strlen(buf));
int current_path_len = json_append_to_path(f, buf, strlen(buf));
f->cur_name =
f->path + strlen(f->path) - strlen(buf) + 1 /*opening brace*/;
f->cur_name_len = strlen(buf) - 2 /*braces*/;
@ -1427,9 +1429,12 @@ static void json_next_cb(void *userdata, const char *name, size_t name_len,
static void *json_next(const char *s, int len, void *handle, const char *path,
struct json_token *key, struct json_token *val, int *i) {
struct json_token tmpval, *v = val == NULL ? &tmpval : val;
struct json_token tmpkey, *k = key == NULL ? &tmpkey : key;
int tmpidx, *pidx = i == NULL ? &tmpidx : i;
struct json_token tmpval;
struct json_token *v = val == NULL ? &tmpval : val;
struct json_token tmpkey;
struct json_token *k = key == NULL ? &tmpkey : key;
int tmpidx;
int *pidx = i == NULL ? &tmpidx : i;
struct next_data data = {handle, path, (int) strlen(path), 0, k, v, pidx};
json_walk(s, len, json_next_cb, &data);
return data.found ? data.handle : NULL;

273
armsrc/hfops.c Normal file
View file

@ -0,0 +1,273 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// HF general operations
//-----------------------------------------------------------------------------
#include "hfops.h"
#include <string.h>
#include "appmain.h"
#include "proxmark3_arm.h"
#include "cmd.h"
#include "BigBuf.h"
#include "fpgaloader.h"
#include "ticks.h"
#include "dbprint.h"
#include "util.h"
#include "commonutil.h"
#include "lfsampling.h"
int HfReadADC(uint32_t samplesCount, bool ledcontrol) {
if (ledcontrol) LEDsoff();
BigBuf_Clear_ext(false);
// connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// And put the FPGA in the appropriate mode
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE);
// Setup
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
if (ledcontrol) LED_A_ON();
uint32_t sbs = samplesCount;
initSampleBuffer(&sbs);
uint32_t wdtcntr = 0;
for (;;) {
if (BUTTON_PRESS()) {
break;
}
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
volatile uint16_t sample = AT91C_BASE_SSC->SSC_RHR;
// FPGA side:
// corr_i_out <= {2'b00, corr_amplitude[13:8]};
// corr_q_out <= corr_amplitude[7:0];
if (sample > 0x1fff)
sample = 0xff;
else
sample = sample >> 5;
logSample(sample & 0xff, 1, 8, false);
if (getSampleCounter() >= samplesCount)
break;
if (wdtcntr++ > 512) {
WDT_HIT();
wdtcntr = 0;
}
} else {
continue;
}
}
FpgaDisableTracing();
FpgaSetupSsc(FPGA_MAJOR_MODE_OFF);
// Turn the field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
uint32_t scnt = getSampleCounter();
reply_ng(CMD_HF_ACQ_RAW_ADC, PM3_SUCCESS, (uint8_t *)&scnt, 4);
if (ledcontrol) LEDsoff();
return 0;
}
uint8_t encode_acc = 0;
uint8_t encode_acc_bit_count = 0;
uint32_t encode_indx = 0;
static void EncodeInit(void) {
encode_acc = 0;
encode_acc_bit_count = 0;
encode_indx = 0;
}
static void EncodeAddBit(uint8_t *data, uint8_t bit, uint8_t bit_count) {
for (int i = 0; i < bit_count; i++) {
encode_acc = (encode_acc << 1) | (bit & 0x01);
encode_acc_bit_count++;
if (encode_acc_bit_count > 7) {
data[encode_indx++] = encode_acc;
encode_acc = 0;
encode_acc_bit_count = 0;
}
}
}
static uint32_t EncodeFinish(uint8_t *data) {
if (encode_acc_bit_count > 0) {
encode_acc = encode_acc << (8 - encode_acc_bit_count);
data[encode_indx++] = encode_acc;
}
return encode_indx;
}
static uint32_t HfEncodeTkm(const uint8_t *uid, uint8_t modulation, uint8_t *data) {
uint32_t len = 0;
if (modulation == 0) {
// TK-13
// 74ns 1 field cycle,
// carrier frequency is fc/64 (212kHz), 4.7 mks
// 100 field cycle = impulse 1.6 ( 1 bit from real tag)
// 1000 field cycle = `1` 15.6 (17 bit from real tag)
// 500 field cycle = `0` 7.8 ( 7 bit from real tag)
EncodeInit();
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
if (((uid[i] << j) & 0x80) != 0) {
// `1`
EncodeAddBit(data, 1, 1);
EncodeAddBit(data, 0, 17);
EncodeAddBit(data, 1, 1);
EncodeAddBit(data, 0, 7);
} else {
// `0`
EncodeAddBit(data, 1, 1);
EncodeAddBit(data, 0, 7);
EncodeAddBit(data, 1, 1);
EncodeAddBit(data, 0, 17);
}
}
}
len = EncodeFinish(data);
} else {
// TK-17
// 74ns 1 field cycle,
// carrier frequency is fc/64 (212kHz), 4.7 mks
// 0 --- 8 --- 12-15 --- 18-19 --- 26-28 --- 32
// DO NOT NORMALIZE!!!! it must be with some error like this!!!!
// `00` -- 1-25-1-5
// `01` -- 1-12-1-18
// `10` -- 1-17-1-13
// `11` -- 1-7-1-23
EncodeInit();
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j += 2) {
uint8_t twobit = ((uid[i] >> j) & 0x03);
if (twobit == 0x00) {
// `00`
EncodeAddBit(data, 1, 1);
EncodeAddBit(data, 0, 25);
EncodeAddBit(data, 1, 1);
EncodeAddBit(data, 0, 5);
} else if (twobit == 0x01) {
// `01`
EncodeAddBit(data, 1, 1);
EncodeAddBit(data, 0, 12);
EncodeAddBit(data, 1, 1);
EncodeAddBit(data, 0, 18);
} else if (twobit == 0x02) {
// `10`
EncodeAddBit(data, 1, 1);
EncodeAddBit(data, 0, 17);
EncodeAddBit(data, 1, 1);
EncodeAddBit(data, 0, 13);
} else { // twobit == 0x03
// `11`
EncodeAddBit(data, 1, 1);
EncodeAddBit(data, 0, 7);
EncodeAddBit(data, 1, 1);
EncodeAddBit(data, 0, 23);
}
}
}
EncodeAddBit(data, 1, 1);
len = EncodeFinish(data);
}
return len;
}
int HfSimulateTkm(uint8_t *uid, uint8_t modulation, uint32_t timeout) {
// free eventually allocated BigBuf memory
BigBuf_free_keep_EM();
LEDsoff();
uint8_t *data = BigBuf_calloc(256);
uint32_t elen = HfEncodeTkm(uid, modulation, data);
if (elen == 0) {
DbpString("encode error");
reply_ng(CMD_HF_TEXKOM_SIMULATE, PM3_EAPDU_ENCODEFAIL, NULL, 0);
return PM3_EAPDU_ENCODEFAIL;
}
LED_C_ON();
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_212K);
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
bool button_pressed = false;
bool exit_loop = false;
bool field_on = false;
uint32_t startTime = GetTickCount();
while (exit_loop == false) {
button_pressed = BUTTON_PRESS();
if (button_pressed || data_available()) {
break;
}
WDT_HIT();
if (timeout > 0 && startTime + timeout < GetTickCount())
break;
// in mV
int vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
if (vHf > MF_MINFIELDV) {
if (field_on == false) {
LED_A_ON();
SpinDelay(50);
}
field_on = true;
} else {
if (field_on) {
LED_A_OFF();
}
field_on = false;
continue;
}
SpinDelay(3);
for (int i = 0; i < elen;) {
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
AT91C_BASE_SSC->SSC_THR = data[i++];
}
}
}
switch_off();
if (button_pressed)
DbpString("Exit by press button");
reply_ng(CMD_HF_TEXKOM_SIMULATE, PM3_SUCCESS, NULL, 0);
return PM3_SUCCESS;
}

27
armsrc/hfops.h Normal file
View file

@ -0,0 +1,27 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// HF general operations
//-----------------------------------------------------------------------------
#ifndef HFOPS_H
#define HFOPS_H
#include "common.h"
int HfReadADC(uint32_t samplesCount, bool ledcontrol);
int HfSimulateTkm(uint8_t *uid, uint8_t modulation, uint32_t timeout);
#endif

View file

@ -36,7 +36,56 @@ static void RAMFUNC optimizedSniff(uint16_t *dest, uint16_t dsize) {
}
}
int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len) {
static void RAMFUNC skipSniff(uint8_t *dest, uint16_t dsize, uint8_t skipMode, uint8_t skipRatio) {
uint32_t accum = (skipMode == HF_SNOOP_SKIP_MIN) ? 0xffffffff : 0;
uint8_t ratioindx = 0;
while (dsize > 0) {
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
volatile uint16_t val = (uint16_t)(AT91C_BASE_SSC->SSC_RHR);
switch (skipMode) {
case HF_SNOOP_SKIP_MAX:
if (accum < (val & 0xff))
accum = val & 0xff;
if (accum < (val >> 8))
accum = val >> 8;
break;
case HF_SNOOP_SKIP_MIN:
if (accum > (val & 0xff))
accum = val & 0xff;
if (accum > (val >> 8))
accum = val >> 8;
break;
case HF_SNOOP_SKIP_AVG:
accum += (val & 0xff) + (val & 0xff);
break;
default: { // HF_SNOOP_SKIP_DROP and the rest
if (ratioindx == 0)
accum = val & 0xff;
}
}
ratioindx++;
if (ratioindx >= skipRatio) {
if (skipMode == HF_SNOOP_SKIP_AVG && skipRatio > 0) {
accum = accum / (skipRatio * 2);
if (accum <= 0xff)
*dest = accum;
else
*dest = 0xff;
} else {
*dest = accum;
}
dest++;
dsize --;
accum = (skipMode == HF_SNOOP_SKIP_MIN) ? 0xffffffff : 0;
ratioindx = 0;
}
}
}
}
int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len, uint8_t skipMode, uint8_t skipRatio) {
BigBuf_free();
BigBuf_Clear_ext(false);
@ -105,7 +154,10 @@ int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len) {
}
}
optimizedSniff((uint16_t *)mem, *len);
if (skipMode == 0)
optimizedSniff((uint16_t *)mem, *len);
else
skipSniff(mem, *len, skipMode, skipRatio);
if (g_dbglevel >= DBG_INFO) {
Dbprintf("Trigger kicked in (%d >= 180)", r);
@ -157,6 +209,6 @@ void HfPlotDownload(void) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// Trigger a finish downloading signal with an ACK frame
reply_mix(CMD_ACK, 1, 0, FPGA_TRACE_SIZE, 0, 0);
reply_ng(CMD_FPGAMEM_DOWNLOAD, PM3_SUCCESS, NULL, 0);
LED_B_OFF();
}

View file

@ -18,6 +18,13 @@
#include "proxmark3_arm.h"
int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len);
// what to do with skipped data
#define HF_SNOOP_SKIP_NONE (0)
#define HF_SNOOP_SKIP_DROP (1)
#define HF_SNOOP_SKIP_MAX (2)
#define HF_SNOOP_SKIP_MIN (3)
#define HF_SNOOP_SKIP_AVG (4)
int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len, uint8_t skipMode, uint8_t skipRatio);
void HfPlotDownload(void);
#endif

View file

@ -1268,7 +1268,6 @@ void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol) {
uint8_t rx[HITAG_FRAME_LEN];
size_t rxlen = 0;
uint8_t tx[HITAG_FRAME_LEN];
size_t txlen;
int t_wait = HITAG_T_WAIT_MAX;
@ -1284,7 +1283,7 @@ void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol) {
WDT_HIT();
//send read request
txlen = 0;
size_t txlen = 0;
uint8_t cmd = 0x0c;
txlen = concatbits(tx, txlen, &cmd, 8 - 4, 4);
uint8_t addr = pageNum;

View file

@ -53,7 +53,8 @@ static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) {
#define I2C_DELAY_2CLK I2CSpinDelayClk(2)
#define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x))
#define ISO7618_MAX_FRAME 255
// The SIM module v4 supports up to 384 bytes for the length.
#define ISO7816_MAX_FRAME 270
// try i2c bus recovery at 100kHz = 5us high, 5us low
void I2C_recovery(void) {
@ -90,7 +91,7 @@ void I2C_recovery(void) {
DbpString("I2C bus recovery complete");
}
void I2C_init(void) {
void I2C_init(bool has_ticks) {
// Configure reset pin, close up pull up, push-pull output, default high
AT91C_BASE_PIOA->PIO_PPUDR = GPIO_RST;
AT91C_BASE_PIOA->PIO_MDDR = GPIO_RST;
@ -105,6 +106,10 @@ void I2C_init(void) {
AT91C_BASE_PIOA->PIO_OER |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
AT91C_BASE_PIOA->PIO_PER |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
if (has_ticks) {
WaitMS(2);
}
bool isok = (SCL_read && SDA_read);
if (isok == false)
I2C_recovery();
@ -132,7 +137,7 @@ void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA) {
// Note: the SIM_Adapter will not enter the main program after power up. Please run this function before use SIM_Adapter.
void I2C_Reset_EnterMainProgram(void) {
StartTicks();
I2C_init();
I2C_init(true);
I2C_SetResetStatus(0, 0, 0);
WaitMS(30);
I2C_SetResetStatus(1, 0, 0);
@ -145,7 +150,7 @@ void I2C_Reset_EnterMainProgram(void) {
// Reserve for firmware update.
void I2C_Reset_EnterBootloader(void) {
StartTicks();
I2C_init();
I2C_init(true);
I2C_SetResetStatus(0, 1, 1);
WaitMS(100);
I2C_SetResetStatus(1, 1, 1);
@ -166,7 +171,7 @@ static bool WaitSCL_H_delay(uint32_t delay) {
// 5000 * 3.07us = 15350us. 15.35ms
// 15000 * 3.07us = 46050us. 46.05ms
static bool WaitSCL_H(void) {
return WaitSCL_H_delay(15000);
return WaitSCL_H_delay(5000);
}
static bool WaitSCL_L_delay(uint32_t delay) {
@ -178,19 +183,21 @@ static bool WaitSCL_L_delay(uint32_t delay) {
}
return false;
}
// 5000 * 3.07us = 15350us. 15.35ms
// 15000 * 3.07us = 46050us. 46.05ms
static bool WaitSCL_L(void) {
return WaitSCL_L_delay(15000);
return WaitSCL_L_delay(5000);
}
// Wait max 1800ms or until SCL goes LOW.
// It timeout reading response from card
// Which ever comes first
static bool WaitSCL_L_timeout(void) {
volatile uint32_t delay = 1700;
volatile uint32_t delay = 200;
while (delay--) {
// exit on SCL LOW
if (!SCL_read)
if (SCL_read == false)
return true;
WaitMS(1);
@ -205,12 +212,15 @@ static bool I2C_Start(void) {
SDA_H;
I2C_DELAY_1CLK;
SCL_H;
if (!WaitSCL_H()) return false;
if (!WaitSCL_H())
return false;
I2C_DELAY_2CLK;
if (!SCL_read) return false;
if (!SDA_read) return false;
if (!SCL_read)
return false;
if (!SDA_read)
return false;
SDA_L;
I2C_DELAY_2CLK;
@ -225,8 +235,9 @@ static bool I2C_WaitForSim(void) {
// 8051 speaks with smart card.
// 1000*50*3.07 = 153.5ms
// 1byte transfer == 1ms with max frame being 256bytes
return WaitSCL_H_delay(1000 * 300);
// 1000*110*3.07 = 337.7ms
// 1byte transfer == 1ms with max frame being 256bytes
return WaitSCL_H_delay(1000 * 110);
}
// send i2c STOP
@ -395,8 +406,8 @@ bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address) {
}
//Sends array of data (Array, length, command to be written , SlaveDevice address ).
// len = uint8 (max buffer to write 256bytes)
bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) {
// len = uint16 because we need to write up to 256 bytes
bool I2C_BufferWrite(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address) {
bool bBreak = true;
do {
if (!I2C_Start())
@ -433,8 +444,8 @@ bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t dev
}
// read one array of data (Data array, Readout length, command to be written , SlaveDevice address ).
// len = uint8 (max buffer to read 256bytes)
int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) {
// len = uint16 because we need to read up to 256bytes
int16_t I2C_BufferRead(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address) {
if (!data || len == 0)
return 0;
@ -445,6 +456,7 @@ int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t d
bool bBreak = true;
uint16_t readcount = 0;
uint16_t recv_len = 0;
do {
if (!I2C_Start())
@ -484,11 +496,34 @@ int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t d
len--;
// The first byte in response is the message length
if (!readcount && (len > *data)) {
len = *data;
// Starting firmware v4 the length is encoded on the first two bytes.
// This only applies if command is I2C_DEVICE_CMD_READ.
if (device_cmd == I2C_DEVICE_CMD_READ) {
switch (readcount) {
case 0:
// Length (MSB)
recv_len = (*data) << 8;
break;
case 1:
// Length (LSB)
recv_len += *data;
// Adjust len if needed
if (len > recv_len) {
len = recv_len;
}
break;
default:
// Data byte received
data++;
break;
}
} else {
data++;
// Length is encoded on 1 byte
if ((readcount == 0) && (len > *data)) {
len = *data;
} else {
data++;
}
}
readcount++;
@ -501,8 +536,8 @@ int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t d
I2C_Stop();
// return bytecount - first byte (which is length byte)
return --readcount;
// return bytecount - bytes encoding length
return readcount - (device_cmd == I2C_DEVICE_CMD_READ ? 2 : 1);
}
int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) {
@ -612,10 +647,14 @@ bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t d
void I2C_print_status(void) {
DbpString(_CYAN_("Smart card module (ISO 7816)"));
uint8_t maj, min;
if (I2C_get_version(&maj, &min) == PM3_SUCCESS)
if (I2C_get_version(&maj, &min) == PM3_SUCCESS) {
Dbprintf(" version................. " _YELLOW_("v%x.%02d"), maj, min);
else
if (maj < 4) {
DbpString(" " _RED_("Outdated firmware.") " Please upgrade to v4.x or above.");
}
} else {
DbpString(" version................. " _RED_("FAILED"));
}
}
int I2C_get_version(uint8_t *maj, uint8_t *min) {
@ -631,7 +670,7 @@ int I2C_get_version(uint8_t *maj, uint8_t *min) {
}
// Will read response from smart card module, retries 3 times to get the data.
bool sc_rx_bytes(uint8_t *dest, uint8_t *destlen) {
bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen) {
uint8_t i = 5;
int16_t len = 0;
@ -656,7 +695,7 @@ bool sc_rx_bytes(uint8_t *dest, uint8_t *destlen) {
if (len <= 1)
return false;
*destlen = (uint8_t)len & 0xFF;
*destlen = len;
return true;
}
@ -678,10 +717,14 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
return false;
// read bytes from module
uint8_t len = sizeof(card_ptr->atr);
uint16_t len = sizeof(card_ptr->atr);
if (sc_rx_bytes(card_ptr->atr, &len) == false)
return false;
if (len > sizeof(card_ptr->atr)) {
len = sizeof(card_ptr->atr);
}
uint8_t pos_td = 1;
if ((card_ptr->atr[1] & 0x10) == 0x10) pos_td++;
if ((card_ptr->atr[1] & 0x20) == 0x20) pos_td++;
@ -697,7 +740,7 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
uint8_t chksum = 0;
// xor property. will be zero when xored with chksum.
for (uint8_t i = 1; i < len; ++i)
for (uint16_t i = 1; i < len; ++i)
chksum ^= card_ptr->atr[i];
if (chksum) {
@ -706,7 +749,7 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
}
}
card_ptr->atr_len = len;
card_ptr->atr_len = (uint8_t)(len & 0xff);
if (verbose) {
LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false);
}
@ -732,8 +775,8 @@ void SmartCardAtr(void) {
void SmartCardRaw(smart_card_raw_t *p) {
LED_D_ON();
uint8_t len = 0;
uint8_t *resp = BigBuf_malloc(ISO7618_MAX_FRAME);
uint16_t len = 0;
uint8_t *resp = BigBuf_malloc(ISO7816_MAX_FRAME);
// check if alloacted...
smartcard_command_t flags = p->flags;
@ -777,7 +820,7 @@ void SmartCardRaw(smart_card_raw_t *p) {
}
// read bytes from module
len = ISO7618_MAX_FRAME;
len = ISO7816_MAX_FRAME;
res = sc_rx_bytes(resp, &len);
if (res) {
LogTrace(resp, len, 0, 0, NULL, false);

View file

@ -31,7 +31,7 @@
#define I2C_DEVICE_CMD_SEND_T0 0x07
void I2C_recovery(void);
void I2C_init(void);
void I2C_init(bool has_ticks);
void I2C_Reset(void);
void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA);
@ -41,14 +41,14 @@ void I2C_Reset_EnterBootloader(void);
bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address);
bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address);
bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address);
int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address);
bool I2C_BufferWrite(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address);
int16_t I2C_BufferRead(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address);
// for firmware
int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address);
bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address);
bool sc_rx_bytes(uint8_t *dest, uint8_t *destlen);
bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen);
//
bool GetATR(smart_card_atr_t *card_ptr, bool verbose);

View file

@ -1245,29 +1245,28 @@ send:
}
// THE READER CODE
static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time) {
static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time, bool shallow_mod) {
CodeIso15693AsReader(frame, len);
tosend_t *ts = get_tosend();
TransmitTo15693Tag(ts->buf, ts->max, start_time);
TransmitTo15693Tag(ts->buf, ts->max, start_time, shallow_mod);
*end_time = *start_time + (32 * ((8 * ts->max) - 4)); // subtract the 4 padding bits after EOF
LogTrace_ISO15693(frame, len, (*start_time * 4), (*end_time * 4), NULL, true);
}
static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t *resp, size_t max_resp_size,
uint8_t expected_size, uint8_t tries, uint32_t *start_time,
uint16_t timeout, uint32_t *eof_time) {
uint16_t timeout, uint32_t *eof_time, bool shallow_mod) {
uint16_t resp_len = 0;
int res;
while (tries-- > 0) {
iclass_send_as_reader(cmd, cmdsize, start_time, eof_time);
iclass_send_as_reader(cmd, cmdsize, start_time, eof_time, shallow_mod);
if (resp == NULL) {
return true;
}
res = GetIso15693AnswerFromTag(resp, max_resp_size, timeout, eof_time, false, true, &resp_len);
int res = GetIso15693AnswerFromTag(resp, max_resp_size, timeout, eof_time, false, true, &resp_len);
if (res == PM3_SUCCESS && expected_size == resp_len) {
return true;
}
@ -1282,7 +1281,7 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t *
* @return false = fail
* true = Got all.
*/
static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, uint8_t *status) {
static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, uint8_t *status, bool shallow_mod) {
static uint8_t act_all[] = { ICLASS_CMD_ACTALL };
static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 };
@ -1299,7 +1298,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
// wakeup
uint32_t start_time = GetCountSspClk();
iclass_send_as_reader(act_all, 1, &start_time, eof_time);
iclass_send_as_reader(act_all, 1, &start_time, eof_time, shallow_mod);
int res;
uint16_t resp_len = 0;
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time, false, true, &resp_len);
@ -1308,7 +1307,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
// send Identify
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(identify, 1, &start_time, eof_time);
iclass_send_as_reader(identify, 1, &start_time, eof_time, shallow_mod);
// expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len);
@ -1320,7 +1319,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
// select the card
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(select, sizeof(select), &start_time, eof_time);
iclass_send_as_reader(select, sizeof(select), &start_time, eof_time, shallow_mod);
// expect a 10-byte response here, 8 byte CSN and 2 byte CRC
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len);
@ -1332,7 +1331,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
// card selected, now read config (block1) (only 8 bytes no CRC)
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time, eof_time);
iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time, eof_time, shallow_mod);
// expect a 8-byte response here
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len);
@ -1350,7 +1349,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
// read App Issuer Area block 5
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(read_aia, sizeof(read_aia), &start_time, eof_time);
iclass_send_as_reader(read_aia, sizeof(read_aia), &start_time, eof_time, shallow_mod);
// expect a 10-byte response here
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len);
@ -1364,7 +1363,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
// card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, eof_time);
iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, eof_time, shallow_mod);
// expect a 8-byte response here
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len);
@ -1386,7 +1385,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
read_aia[3] = 0x10;
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(read_aia, sizeof(read_aia), &start_time, eof_time);
iclass_send_as_reader(read_aia, sizeof(read_aia), &start_time, eof_time, shallow_mod);
// expect a 10-byte response here
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len);
@ -1402,9 +1401,9 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
return true;
}
bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time) {
bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, bool shallow_mod) {
uint8_t result = 0;
return select_iclass_tag_ex(hdr, use_credit_key, eof_time, &result);
return select_iclass_tag_ex(hdr, use_credit_key, eof_time, &result, shallow_mod);
}
// Reader iClass Anticollission
@ -1413,6 +1412,7 @@ void ReaderIClass(uint8_t flags) {
// flag to use credit key
bool use_credit_key = ((flags & FLAG_ICLASS_READER_CREDITKEY) == FLAG_ICLASS_READER_CREDITKEY);
bool shallow_mod = (flags & FLAG_ICLASS_READER_SHALLOW_MOD);
if ((flags & FLAG_ICLASS_READER_INIT) == FLAG_ICLASS_READER_INIT) {
Iso15693InitReader();
@ -1427,7 +1427,7 @@ void ReaderIClass(uint8_t flags) {
uint32_t eof_time = 0;
picopass_hdr_t hdr = {0};
if (select_iclass_tag_ex(&hdr, use_credit_key, &eof_time, &res) == false) {
if (select_iclass_tag_ex(&hdr, use_credit_key, &eof_time, &res, shallow_mod) == false) {
reply_ng(CMD_HF_ICLASS_READER, PM3_ERFTRANS, NULL, 0);
goto out;
}
@ -1498,7 +1498,7 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, ui
cmd_check[7] = pmac[2];
cmd_check[8] = pmac[3];
}
return iclass_send_cmd_with_retries(cmd_check, sizeof(cmd_check), resp_auth, sizeof(resp_auth), 4, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time);
return iclass_send_cmd_with_retries(cmd_check, sizeof(cmd_check), resp_auth, sizeof(resp_auth), 4, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time, payload->shallow_mod);
}
@ -1516,6 +1516,8 @@ void iClass_Authentication_fast(iclass_chk_t *p) {
return;
}
bool shallow_mod = p->shallow_mod;
uint8_t check[9] = { ICLASS_CMD_CHECK };
uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
uint8_t readcheck_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 };
@ -1537,7 +1539,7 @@ void iClass_Authentication_fast(iclass_chk_t *p) {
bool isOK = false;
uint32_t start_time = 0, eof_time = 0;
if (select_iclass_tag(&hdr, p->use_credit_key, &eof_time) == false)
if (select_iclass_tag(&hdr, p->use_credit_key, &eof_time, shallow_mod) == false)
goto out;
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
@ -1566,14 +1568,14 @@ void iClass_Authentication_fast(iclass_chk_t *p) {
check[8] = keys[i].mac[3];
// expect 4bytes, 3 retries times..
isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 2, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time);
isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 2, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, shallow_mod);
if (isOK)
goto out;
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
// Auth Sequence MUST begin with reading e-purse. (block2)
// Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
iclass_send_as_reader(readcheck_cc, sizeof(readcheck_cc), &start_time, &eof_time);
iclass_send_as_reader(readcheck_cc, sizeof(readcheck_cc), &start_time, &eof_time, shallow_mod);
LED_B_OFF();
}
@ -1586,11 +1588,11 @@ out:
// Tries to read block.
// retries 3times.
// reply 8 bytes block
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time) {
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time, bool shallow_mod) {
uint8_t resp[10];
uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00};
AddCrc(c + 1, 1);
bool isOK = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time);
bool isOK = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time, shallow_mod);
if (isOK)
memcpy(data, resp, 8);
return isOK;
@ -1602,6 +1604,7 @@ bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, ui
void iClass_ReadBlock(uint8_t *msg) {
iclass_auth_req_t *payload = (iclass_auth_req_t *)msg;
bool shallow_mod = payload->shallow_mod;
iclass_readblock_resp_t response = { .isOK = true };
memset(response.data, 0, sizeof(response.data));
@ -1614,7 +1617,7 @@ void iClass_ReadBlock(uint8_t *msg) {
// select tag.
uint32_t eof_time = 0;
picopass_hdr_t hdr = {0};
bool res = select_iclass_tag(&hdr, payload->use_credit_key, &eof_time);
bool res = select_iclass_tag(&hdr, payload->use_credit_key, &eof_time, shallow_mod);
if (res == false) {
if (payload->send_reply) {
response.isOK = res;
@ -1642,7 +1645,7 @@ void iClass_ReadBlock(uint8_t *msg) {
// read data
uint8_t resp[10];
res = iclass_send_cmd_with_retries(cmd_read, sizeof(cmd_read), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time);
res = iclass_send_cmd_with_retries(cmd_read, sizeof(cmd_read), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, shallow_mod);
if (res) {
memcpy(response.data, resp, sizeof(response.data));
if (payload->send_reply) {
@ -1670,6 +1673,7 @@ void iClass_Dump(uint8_t *msg) {
iclass_dump_req_t *cmd = (iclass_dump_req_t *)msg;
iclass_auth_req_t *req = &cmd->req;
bool shallow_mod = req->shallow_mod;
uint8_t *dataout = BigBuf_malloc(ICLASS_16KS_SIZE);
if (dataout == NULL) {
@ -1689,7 +1693,7 @@ void iClass_Dump(uint8_t *msg) {
picopass_hdr_t hdr = {0};
memset(&hdr, 0xff, sizeof(picopass_hdr_t));
bool res = select_iclass_tag(&hdr, req->use_credit_key, &eof_time);
bool res = select_iclass_tag(&hdr, req->use_credit_key, &eof_time, shallow_mod);
if (res == false) {
if (req->send_reply) {
reply_ng(CMD_HF_ICLASS_DUMP, PM3_ETIMEOUT, NULL, 0);
@ -1724,7 +1728,7 @@ void iClass_Dump(uint8_t *msg) {
uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, i, 0x00, 0x00};
AddCrc(c + 1, 1);
res = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time);
res = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, shallow_mod);
if (res) {
memcpy(dataout + (8 * i), resp, 8);
} else {
@ -1759,7 +1763,7 @@ void iClass_Dump(uint8_t *msg) {
BigBuf_free();
}
static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac, bool use_mac) {
static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac, bool use_mac, bool shallow_mod) {
// write command: cmd, 1 blockno, 8 data, 4 mac
uint8_t write[14] = { 0x80 | ICLASS_CMD_UPDATE, blockno };
@ -1775,7 +1779,7 @@ static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac,
uint8_t resp[10] = {0};
uint32_t eof_time = 0, start_time = 0;
bool isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_UPDATE, &eof_time);
bool isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_UPDATE, &eof_time, shallow_mod);
if (isOK == false) {
return false;
}
@ -1807,6 +1811,7 @@ void iClass_WriteBlock(uint8_t *msg) {
LED_A_ON();
iclass_writeblock_req_t *payload = (iclass_writeblock_req_t *)msg;
bool shallow_mod = payload->req.shallow_mod;
uint8_t write[14] = { 0x80 | ICLASS_CMD_UPDATE, payload->req.blockno };
uint8_t write_len = 14;
@ -1816,7 +1821,7 @@ void iClass_WriteBlock(uint8_t *msg) {
// select tag.
uint32_t eof_time = 0;
picopass_hdr_t hdr = {0};
uint8_t res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time);
uint8_t res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time, shallow_mod);
if (res == false) {
goto out;
}
@ -1846,17 +1851,22 @@ void iClass_WriteBlock(uint8_t *msg) {
AddCrc(write + 1, 9);
write_len -= 2;
} else {
// Secure tags uses MAC
uint8_t wb[9];
wb[0] = payload->req.blockno;
memcpy(wb + 1, payload->data, 8);
if (payload->req.use_credit_key)
doMAC_N(wb, sizeof(wb), hdr.key_c, mac);
else
doMAC_N(wb, sizeof(wb), hdr.key_d, mac);
if (payload->req.use_replay) {
memcpy(write + 10, payload->mac, sizeof(payload->mac));
} else {
// Secure tags uses MAC
uint8_t wb[9];
wb[0] = payload->req.blockno;
memcpy(wb + 1, payload->data, 8);
memcpy(write + 10, mac, sizeof(mac));
if (payload->req.use_credit_key)
doMAC_N(wb, sizeof(wb), hdr.key_c, mac);
else
doMAC_N(wb, sizeof(wb), hdr.key_d, mac);
memcpy(write + 10, mac, sizeof(mac));
}
}
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
@ -1866,7 +1876,7 @@ void iClass_WriteBlock(uint8_t *msg) {
uint8_t tries = 3;
while (tries-- > 0) {
iclass_send_as_reader(write, write_len, &start_time, &eof_time);
iclass_send_as_reader(write, write_len, &start_time, &eof_time, shallow_mod);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
res = false;
@ -1934,6 +1944,8 @@ void iClass_Restore(iclass_restore_req_t *msg) {
return;
}
bool shallow_mod = msg->req.shallow_mod;
LED_A_ON();
Iso15693InitReader();
@ -1942,7 +1954,7 @@ void iClass_Restore(iclass_restore_req_t *msg) {
picopass_hdr_t hdr = {0};
// select
bool res = select_iclass_tag(&hdr, msg->req.use_credit_key, &eof_time);
bool res = select_iclass_tag(&hdr, msg->req.use_credit_key, &eof_time, shallow_mod);
if (res == false) {
goto out;
}
@ -1983,7 +1995,7 @@ void iClass_Restore(iclass_restore_req_t *msg) {
}
// data + mac
if (iclass_writeblock_ext(item.blockno, item.data, mac, use_mac)) {
if (iclass_writeblock_ext(item.blockno, item.data, mac, use_mac, shallow_mod)) {
Dbprintf("Write block [%3d/0x%02X] " _GREEN_("successful"), item.blockno, item.blockno);
written++;
} else {

View file

@ -38,8 +38,8 @@ void iClass_Authentication_fast(iclass_chk_t *p);
bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out);
void iClass_ReadBlock(uint8_t *msg);
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time);
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time, bool shallow_mod);
bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time);
bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, bool shallow_mod);
bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out);
#endif

View file

@ -34,6 +34,7 @@
#include "commonutil.h"
#include "crc16.h"
#include "protocols.h"
#include "generator.h"
#define MAX_ISO14A_TIMEOUT 524288
@ -927,9 +928,13 @@ bool GetIso14443aCommandFromReader(uint8_t *received, uint8_t *par, int *len) {
(void)b;
uint8_t flip = 0;
uint16_t checker = 0;
uint16_t checker = 4000;
for (;;) {
WDT_HIT();
// ever 3 * 4000, check if we got any data from client
// takes long time, usually messes with simualtion
if (flip == 3) {
if (data_available())
return false;
@ -937,14 +942,14 @@ bool GetIso14443aCommandFromReader(uint8_t *received, uint8_t *par, int *len) {
flip = 0;
}
if (checker >= 3000) {
// button press, takes a bit time, might mess with simualtion
if (checker-- == 0) {
if (BUTTON_PRESS())
return false;
flip++;
checker = 0;
checker = 4000;
}
++checker;
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
@ -1034,6 +1039,8 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
// PPS response
static uint8_t rPPS[3] = { 0xD0 };
static uint8_t rPACK[4] = { 0x00, 0x00, 0x00, 0x00 };
switch (tagType) {
case 1: { // MIFARE Classic 1k
rATQA[0] = 0x04;
@ -1046,6 +1053,30 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
// some first pages of UL/NTAG dump is special data
mfu_dump_t *mfu_header = (mfu_dump_t *) BigBuf_get_EM_addr();
*pages = MAX(mfu_header->pages, 15);
// counters and tearing flags
// for old dumps with all zero headers, we need to set default values.
for (uint8_t i = 0; i < 3; i++) {
counters[i] = le24toh(mfu_header->counter_tearing[i]);
if (mfu_header->counter_tearing[i][3] != 0x00) {
tearings[i] = mfu_header->counter_tearing[i][3];
}
}
// GET_VERSION
if (memcmp(mfu_header->version, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) {
memcpy(rVERSION, "\x00\x04\x04\x02\x01\x00\x11\x03", 8);
} else {
memcpy(rVERSION, mfu_header->version, 8);
}
AddCrc14A(rVERSION, sizeof(rVERSION) - 2);
// READ_SIG
memcpy(rSIGN, mfu_header->signature, 32);
AddCrc14A(rSIGN, sizeof(rSIGN) - 2);
}
break;
case 3: { // MIFARE DESFire
@ -1100,6 +1131,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
// READ_SIG
memcpy(rSIGN, mfu_header->signature, 32);
AddCrc14A(rSIGN, sizeof(rSIGN) - 2);
}
break;
case 8: { // MIFARE Classic 4k
@ -1221,6 +1253,19 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
AddCrc14A(rPPS, sizeof(rPPS) - 2);
if (tagType == 7) {
uint8_t pwd[4];
uint8_t gen_pwd[4];
uint16_t start = (*pages - 1) * 4 + MFU_DUMP_PREFIX_LENGTH;
emlGetMemBt(pwd, start, sizeof(pwd));
Uint4byteToMemBe(gen_pwd, ul_ev1_pwdgenB(data));
if (memcmp(pwd, gen_pwd, sizeof(pwd)) == 0) {
rPACK[0] = 0x80;
rPACK[1] = 0x80;
}
}
AddCrc14A(rPACK, sizeof(rPACK) - 2);
static tag_response_info_t responses_init[] = {
{ .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type
{ .response = rUIDc1, .response_n = sizeof(rUIDc1) }, // Anticollision cascade1 - respond with uid
@ -1232,14 +1277,16 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
{ .response = rRATS, .response_n = sizeof(rRATS) }, // dummy ATS (pseudo-ATR), answer to RATS
{ .response = rVERSION, .response_n = sizeof(rVERSION) }, // EV1/NTAG GET_VERSION response
{ .response = rSIGN, .response_n = sizeof(rSIGN) }, // EV1/NTAG READ_SIG response
{ .response = rPPS, .response_n = sizeof(rPPS) } // PPS response
{ .response = rPPS, .response_n = sizeof(rPPS) }, // PPS response
{ .response = rPACK, .response_n = sizeof(rPACK) } // PACK response
};
// "precompile" responses. There are 11 predefined responses with a total of 80 bytes data to transmit.
// "precompile" responses. There are 12 predefined responses with a total of 84 bytes data to transmit.
// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
// 81 * 8 data bits, 81 * 1 parity bits, 11 start bits, 11 stop bits, 11 correction bits
// 81 * 8 + 81 + 11 + 11 + 11 == 762
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 762
// 85 * 8 data bits, 85 * 1 parity bits, 12 start bits, 12 stop bits, 12 correction bits
// 85 * 8 + 85 + 12 + 12 + 12 == 801
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 801
uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE);
// modulation buffer pointer and current buffer free space size
@ -1635,14 +1682,23 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
p_response = NULL;
} else if (receivedCmd[0] == MIFARE_ULEV1_AUTH && len == 7 && tagType == 7) { // NTAG / EV-1 authentication
/*
// PWD stored in dump now
uint8_t pwd[4];
emlGetMemBt(pwd, (pages - 1) * 4 + MFU_DUMP_PREFIX_LENGTH, sizeof(pwd));
if (memcmp(pwd, "\x00\x00\x00\x00", 4) == 0) {
Uint4byteToMemLe(pwd, ul_ev1_pwdgenB(data));
Dbprintf("Calc pwd... %02X %02X %02X %02X", pwd[0], pwd[1], pwd[2], pwd[3]);
}
if (memcmp(receivedCmd + 1, pwd, 4) == 0) {
uint8_t pack[4];
emlGetMemBt(pack, pages * 4 + MFU_DUMP_PREFIX_LENGTH, 2);
if (memcmp(pack, "\x00\x00\x00\x00", 4) == 0) {
memcpy(pack, "\x80\x80\x00\x00", 4);
pack[0] = 0x80;
pack[1] = 0x80;
}
AddCrc14A(pack, sizeof(pack) - 2);
EmSendCmd(pack, sizeof(pack));
@ -1651,6 +1707,8 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Auth attempt: %08x", bytes_to_num(receivedCmd + 1, 4));
}
p_response = NULL;
*/
p_response = &responses[RESP_INDEX_PACK];
} else if (receivedCmd[0] == MIFARE_ULEV1_VCSL && len == 23 && tagType == 7) {
uint8_t cmd[3];
emlGetMemBt(cmd, (pages - 2) * 4 + 1 + MFU_DUMP_PREFIX_LENGTH, 1);
@ -2441,9 +2499,11 @@ static void iso14a_set_ATS_times(const uint8_t *ats) {
static int GetATQA(uint8_t *resp, uint8_t *resp_par, bool use_ecp, bool use_magsafe) {
#define ECP_DELAY 15
#define ECP_DELAY 10
#define ECP_RETRY_TIMEOUT 100
#define WUPA_RETRY_TIMEOUT 10 // 10ms
// 0x26 - REQA
// 0x52 - WAKE-UP
// 0x7A - MAGESAFE WAKE UP
@ -2454,15 +2514,25 @@ static int GetATQA(uint8_t *resp, uint8_t *resp_par, bool use_ecp, bool use_mags
wupa[0] = MAGSAFE_CMD_WUPA_4;
}
if (use_ecp) {
// In case a device was already selected, we send a S-BLOCK deselect to bring it into an idle state so it can be selected again
uint8_t deselect_cmd[] = {0xc2, 0xe0, 0xb4};
ReaderTransmit(deselect_cmd, sizeof(deselect_cmd), NULL);
// Read response if present
(void) ReaderReceive(resp, resp_par);
}
uint32_t save_iso14a_timeout = iso14a_get_timeout();
iso14a_set_timeout(1236 / 128 + 1); // response to WUPA is expected at exactly 1236/fc. No need to wait longer.
bool first_try = true;
uint32_t retry_timeout = use_ecp ? ECP_RETRY_TIMEOUT : WUPA_RETRY_TIMEOUT;
uint32_t start_time = GetTickCount();
int len;
// we may need several tries if we did send an unknown command or a wrong authentication before...
do {
if (use_ecp) {
if (use_ecp && !first_try) {
uint8_t ecp[] = { 0x6a, 0x02, 0xC8, 0x01, 0x00, 0x03, 0x00, 0x02, 0x79, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xD8};
ReaderTransmit(ecp, sizeof(ecp), NULL);
SpinDelay(ECP_DELAY);
@ -2476,12 +2546,13 @@ static int GetATQA(uint8_t *resp, uint8_t *resp_par, bool use_ecp, bool use_mags
}
}
// Broadcast for a card, WUPA (0x52) will force response from all cards in the field
ReaderTransmitBitsPar(wupa, 7, NULL, NULL);
// Receive the ATQA
len = ReaderReceive(resp, resp_par);
} while (len == 0 && GetTickCountDelta(start_time) <= WUPA_RETRY_TIMEOUT);
first_try = false;
} while (len == 0 && GetTickCountDelta(start_time) <= retry_timeout);
iso14a_set_timeout(save_iso14a_timeout);
return len;
@ -2530,7 +2601,7 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint
uint8_t fudan_read[] = { 0x30, 0x01, 0x8B, 0xB9};
ReaderTransmit(fudan_read, sizeof(fudan_read), NULL);
if (!ReaderReceive(resp, resp_par)) {
Dbprintf("Card didn't answer to select all");
if (g_dbglevel >= DBG_INFO) Dbprintf("Card didn't answer to select all");
return 0;
}
@ -2579,7 +2650,7 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint
// SELECT_ALL
ReaderTransmit(sel_all, sizeof(sel_all), NULL);
if (!ReaderReceive(resp, resp_par)) {
Dbprintf("Card didn't answer to CL%i select all", cascade_level + 1);
if (g_dbglevel >= DBG_INFO) Dbprintf("Card didn't answer to CL%i select all", cascade_level + 1);
return 0;
}
@ -2657,7 +2728,7 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint
// Receive the SAK
if (!ReaderReceive(resp, resp_par)) {
Dbprintf("Card didn't answer to select");
if (g_dbglevel >= DBG_INFO) Dbprintf("Card didn't answer to select");
return 0;
}
sak = resp[0];

View file

@ -104,7 +104,8 @@ typedef enum {
RESP_INDEX_RATS,
RESP_INDEX_VERSION,
RESP_INDEX_SIGNATURE,
RESP_INDEX_PPS
RESP_INDEX_PPS,
RESP_INDEX_PACK,
} resp_index_t;
#ifndef AddCrc14A

View file

@ -1381,11 +1381,11 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, uint32_t
}
if (Demod.len > 0) {
uint32_t sof_time = *eof_time
- (Demod.len * (8 + 2)) // time for byte transfers
- (10) // time for TR1
- (10 + 2) // time for SOF transfer
- (10); // time for EOF transfer
uint32_t sof_time = *eof_time - ETU_TO_SSP(
(Demod.len * (8 + 2)) // time for byte transfers
// + (10) // time for TR1
+ (10 + 2) // time for SOF transfer
+ (10)); // time for EOF transfer
LogTrace(Demod.output, Demod.len, sof_time, *eof_time, NULL, false);
}
return Demod.len;
@ -1435,9 +1435,28 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) {
}
WDT_HIT();
}
// transmit remaining bits. we need one-sample granularity now
volatile uint8_t data = ts->buf[ts->max], last_bits = ts->bit;
for (uint8_t i = 0; i < last_bits; i++) {
volatile uint16_t send_word = (data & 0x80) ? 0x0000 : 0xFFFF;
while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ;
AT91C_BASE_SSC->SSC_THR = send_word;
while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ;
AT91C_BASE_SSC->SSC_THR = send_word;
data <<= 1;
}
WDT_HIT();
LED_B_OFF();
*start_time += DELAY_ARM_TO_TAG;
// *start_time += DELAY_ARM_TO_TAG;
// wait for last transfer to complete
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) {};
@ -1447,7 +1466,7 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) {
// Code a layer 2 command (string of octets, including CRC) into ToSend[],
// so that it is ready to transmit to the tag using TransmitFor14443b().
//-----------------------------------------------------------------------------
static void CodeIso14443bAsReader(const uint8_t *cmd, int len) {
static void CodeIso14443bAsReader(const uint8_t *cmd, int len, bool framing) {
/*
* QUESTION: how long is a 1 or 0 in pulses in the xcorr_848 mode?
* 1 "stuffbit" = 1ETU (9us)
@ -1460,14 +1479,18 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) {
int i;
tosend_reset();
// Send SOF
// 10-11 ETUs of ZERO
for (i = 0; i < 10; i++) {
tosend_stuffbit(0);
// add framing enable flag. xerox chips use unframed commands during anticollision
if (framing) {
// Send SOF
// 10-11 ETUs of ZERO
for (i = 0; i < 10; i++) {
tosend_stuffbit(0);
}
// 2-3 ETUs of ONE
tosend_stuffbit(1);
tosend_stuffbit(1);
}
// 2-3 ETUs of ONE
tosend_stuffbit(1);
tosend_stuffbit(1);
// Sending cmd, LSB
// from here we add BITS
@ -1493,28 +1516,36 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) {
// FOR PICC it ranges 0-19us == 0 - 2 ETU
}
// Send EOF
// 10-11 ETUs of ZERO
for (i = 0; i < 10; i++) {
tosend_stuffbit(0);
if (framing) {
// Send EOF
// 10-11 ETUs of ZERO
for (i = 0; i < 10; i++) {
tosend_stuffbit(0);
}
}
int pad = (10 + 2 + (len * 10) + 10) & 0x7;
for (i = 0; i < 16 - pad; ++i)
tosend_stuffbit(1);
// we can't use padding now
/*
int pad = (10 + 2 + (len * 10) + 10) & 0x7;
for (i = 0; i < 16 - pad; ++i)
tosend_stuffbit(1);
*/
}
/*
* Convenience function to encode, transmit and trace iso 14443b comms
*/
static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t *start_time, uint32_t *eof_time) {
static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t *start_time, uint32_t *eof_time, bool framing) {
tosend_t *ts = get_tosend();
CodeIso14443bAsReader(cmd, len);
CodeIso14443bAsReader(cmd, len, framing);
TransmitFor14443b_AsReader(start_time);
if (g_trigger) LED_A_ON();
*eof_time = *start_time + (10 * ts->max) + 10 + 2 + 10;
// eof_time in ssp clocks, but bits was added here!
// *eof_time = *start_time + (10 * ts->max) + 10 + 2 + 10;
*eof_time = *start_time + ETU_TO_SSP(8 * ts->max);
LogTrace(cmd, len, *start_time, *eof_time, NULL, true);
}
@ -1545,7 +1576,7 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
// send
uint32_t start_time = 0;
uint32_t eof_time = 0;
CodeAndTransmit14443bAsReader(real_cmd, msg_len + 3, &start_time, &eof_time);
CodeAndTransmit14443bAsReader(real_cmd, msg_len + 3, &start_time, &eof_time, true);
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
int len = Get14443bAnswerFromTag(rxdata, rxmaxlen, iso14b_timeout, &eof_time);
@ -1578,7 +1609,7 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
AddCrc14B(data_bytes, len - 2);
// transmit S-Block
CodeAndTransmit14443bAsReader(data_bytes, len, &start_time, &eof_time);
CodeAndTransmit14443bAsReader(data_bytes, len, &start_time, &eof_time, true);
// retrieve the result again (with increased timeout)
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
@ -1637,7 +1668,7 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
uint32_t start_time = 0;
uint32_t eof_time = 0;
CodeAndTransmit14443bAsReader(cmdINIT, sizeof(cmdINIT), &start_time, &eof_time);
CodeAndTransmit14443bAsReader(cmdINIT, sizeof(cmdINIT), &start_time, &eof_time, true);
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
int retlen = Get14443bAnswerFromTag(r, sizeof(r), iso14b_timeout, &eof_time);
@ -1657,7 +1688,7 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
}
start_time = eof_time + ISO14B_TR2;
CodeAndTransmit14443bAsReader(cmdMSBUID, sizeof(cmdMSBUID), &start_time, &eof_time);
CodeAndTransmit14443bAsReader(cmdMSBUID, sizeof(cmdMSBUID), &start_time, &eof_time, true);
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
retlen = Get14443bAnswerFromTag(r, sizeof(r), iso14b_timeout, &eof_time);
@ -1675,7 +1706,7 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
}
start_time = eof_time + ISO14B_TR2;
CodeAndTransmit14443bAsReader(cmdLSBUID, sizeof(cmdLSBUID), &start_time, &eof_time);
CodeAndTransmit14443bAsReader(cmdLSBUID, sizeof(cmdLSBUID), &start_time, &eof_time, true);
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
retlen = Get14443bAnswerFromTag(r, sizeof(r), iso14b_timeout, &eof_time);
@ -1706,7 +1737,7 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
uint32_t start_time = 0;
uint32_t eof_time = 0;
CodeAndTransmit14443bAsReader(init_srx, sizeof(init_srx), &start_time, &eof_time);
CodeAndTransmit14443bAsReader(init_srx, sizeof(init_srx), &start_time, &eof_time, true);
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
int retlen = Get14443bAnswerFromTag(r_init, sizeof(r_init), iso14b_timeout, &eof_time);
@ -1728,7 +1759,7 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
AddCrc14B(select_srx, 2);
start_time = eof_time + ISO14B_TR2;
CodeAndTransmit14443bAsReader(select_srx, sizeof(select_srx), &start_time, &eof_time);
CodeAndTransmit14443bAsReader(select_srx, sizeof(select_srx), &start_time, &eof_time, true);
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
retlen = Get14443bAnswerFromTag(r_select, sizeof(r_select), iso14b_timeout, &eof_time);
@ -1752,7 +1783,7 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
AddCrc14B(select_srx, 1);
start_time = eof_time + ISO14B_TR2;
CodeAndTransmit14443bAsReader(select_srx, 3, &start_time, &eof_time); // Only first three bytes for this one
CodeAndTransmit14443bAsReader(select_srx, 3, &start_time, &eof_time, true); // Only first three bytes for this one
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
retlen = Get14443bAnswerFromTag(r_papid, sizeof(r_papid), iso14b_timeout, &eof_time);
@ -1772,6 +1803,178 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
return 0;
}
// Xerox tag connect function: wup, anticoll, attrib, password
// the original chips require all commands in this sequence
// 0: OK, 1: select fail, 2: attrib fail, 3: crc fail, 4: password fail
int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
// AFI
static const uint8_t x_wup1[] = { 0x0D, 0x37, 0x21, 0x92, 0xf2 };
static const uint8_t x_wup2[] = { 0x5D, 0x37, 0x21, 0x71, 0x71 };
uint8_t slot_mark[1];
uint8_t x_atqb[24] = {0x0}; // ATQB len = 18
uint32_t start_time = 0;
uint32_t eof_time = 0;
iso14b_set_timeout(24); // wait for carrier
// wup1
CodeAndTransmit14443bAsReader(x_wup1, sizeof(x_wup1), &start_time, &eof_time, true);
start_time = eof_time + US_TO_SSP(9000); // 9ms before next cmd
// wup2
CodeAndTransmit14443bAsReader(x_wup2, sizeof(x_wup2), &start_time, &eof_time, true);
uint64_t uid = 0;
int retlen;
for (int uid_pos = 0; uid_pos < 64; uid_pos += 2) {
int slot;
for (slot = 0; slot < 4; slot++) {
start_time = eof_time + ETU_TO_SSP(30); //(24); // next slot after 24 ETU
retlen = Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time);
if (retlen > 0) {
FpgaDisableTracing();
Dbprintf("unexpected data %d", retlen);
Dbprintf("crc %s", check_crc(CRC_14443_B, x_atqb, retlen) ? "OK" : "BAD");
return 1;
}
// tx unframed slot-marker
if (Demod.posCount) { // no rx, but subcarrier burst detected
uid |= (uint64_t)slot << uid_pos;
slot_mark[0] = 0xB1 + (slot << 1); // ack slot
CodeAndTransmit14443bAsReader(slot_mark, sizeof(slot_mark), &start_time, &eof_time, false);
break;
} else { // no subcarrier burst
slot_mark[0] = 0xA1 + (slot << 1); // nak slot
CodeAndTransmit14443bAsReader(slot_mark, sizeof(slot_mark), &start_time, &eof_time, false);
}
}
if (4 == slot) {
FpgaDisableTracing();
if (g_dbglevel >= DBG_DEBUG) {
DbpString("no answer to anticollision");
}
return 1;
}
}
retlen = Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time);
if (g_dbglevel >= DBG_DEBUG) {
Dbprintf("anticollision uid %llx", uid);
}
// ATQB too short?
if (retlen < 18) {
return 1;
}
// VALIDATE CRC
if (check_crc(CRC_14443_B, x_atqb, 18) == false) { // use fixed len because unstable EOF catch
return 3;
}
if (x_atqb[0] != 0x50) {
// DbpString("aqtb bad");
return 1;
}
if (card) {
card->uidlen = 8;
memcpy(card->uid, x_atqb + 1, 8);
memcpy(card->atqb, x_atqb + 9, 7);
}
// DbpString("aqtb ok");
// send ATTRIB command
uint8_t txbuf[18];
txbuf[1] = 0x1d;
memcpy(txbuf + 2, &uid, 8);
txbuf[10] = 0;
txbuf[11] = 0xF;
txbuf[12] = 1;
txbuf[13] = 0xF;
AddCrc14B(txbuf + 1, 13);
start_time = eof_time + ISO14B_TR2;
CodeAndTransmit14443bAsReader(txbuf + 1, 15, &start_time, &eof_time, true);
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
retlen = Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time);
FpgaDisableTracing();
if (retlen < 3) {
// DbpString("attrib failed");
return 2;
}
if (check_crc(CRC_14443_B, x_atqb, 3) == false) {
return 3;
}
if (x_atqb[0] != 0) {
// DbpString("attrib failed");
return 2;
}
// DbpString("attrib ok");
// apply PASSWORD command
txbuf[0] = 2;
txbuf[1] = 0x38;
// uid from previous command used
txbuf[10] = 3;
txbuf[11] = 0x4e;
txbuf[12] = 0x4b;
txbuf[13] = 0x53;
txbuf[14] = 0x4F;
AddCrc14B(txbuf, 15);
start_time = eof_time + ISO14B_TR2;
CodeAndTransmit14443bAsReader(txbuf, 17, &start_time, &eof_time, true);
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
retlen = Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time);
if (retlen < 4) {
// DbpString("passwd failed");
return 4;
}
if (check_crc(CRC_14443_B, x_atqb, 4) == false) {
return 3;
}
if (x_atqb[0] != 2 || x_atqb[1] != 0) {
// DbpString("passwd failed");
return 4;
}
// DbpString("passwd ok");
return 0;
}
/* Perform the ISO 14443 B Card Selection procedure
* Currently does NOT do any collision handling.
* It expects 0-1 cards in the device's range.
@ -1794,7 +1997,7 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
// first, wake up the tag
uint32_t start_time = 0;
uint32_t eof_time = 0;
CodeAndTransmit14443bAsReader(wupb, sizeof(wupb), &start_time, &eof_time);
CodeAndTransmit14443bAsReader(wupb, sizeof(wupb), &start_time, &eof_time, true);
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
int retlen = Get14443bAnswerFromTag(r_pupid, sizeof(r_pupid), iso14b_timeout, &eof_time);
@ -1823,7 +2026,7 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
attrib[7] = r_pupid[10] & 0x0F;
AddCrc14B(attrib, 9);
start_time = eof_time + ISO14B_TR2;
CodeAndTransmit14443bAsReader(attrib, sizeof(attrib), &start_time, &eof_time);
CodeAndTransmit14443bAsReader(attrib, sizeof(attrib), &start_time, &eof_time, true);
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
retlen = Get14443bAnswerFromTag(r_attrib, sizeof(r_attrib), iso14b_timeout, &eof_time);
@ -1916,7 +2119,7 @@ static int read_srx_block(uint8_t blocknr, uint8_t *block) {
uint32_t start_time = 0;
uint32_t eof_time = 0;
CodeAndTransmit14443bAsReader(cmd, sizeof(cmd), &start_time, &eof_time);
CodeAndTransmit14443bAsReader(cmd, sizeof(cmd), &start_time, &eof_time, true);
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
int retlen = Get14443bAnswerFromTag(r_block, sizeof(r_block), iso14b_timeout, &eof_time);
@ -2223,6 +2426,13 @@ void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) {
if (status > 0) goto out;
}
if ((p->flags & ISO14B_SELECT_XRX) == ISO14B_SELECT_XRX) {
status = iso14443b_select_xrx_card(&card);
reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, (uint8_t *)&card, sendlen);
// 0: OK, 1: select fail, 2: attrib fail, 3: crc fail, 4: password fail
if (status != 0) goto out;
}
if ((p->flags & ISO14B_APDU) == ISO14B_APDU) {
uint8_t res;
status = iso14443b_apdu(p->raw, p->rawlen, (p->flags & ISO14B_SEND_CHAINING), buf, sizeof(buf), &res);
@ -2239,7 +2449,7 @@ void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) {
}
uint32_t start_time = 0;
uint32_t eof_time = 0;
CodeAndTransmit14443bAsReader(p->raw, p->rawlen, &start_time, &eof_time);
CodeAndTransmit14443bAsReader(p->raw, p->rawlen, &start_time, &eof_time, true);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
FpgaDisableTracing();

View file

@ -39,6 +39,7 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
int iso14443b_select_card(iso14b_card_select_t *card);
int iso14443b_select_card_srx(iso14b_card_select_t *card);
int iso14443b_select_xrx_card(iso14b_card_select_t *card);
void SimulateIso14443bTag(uint8_t *pupi);
void AcquireRawAdcSamplesIso14443b(uint32_t parameter);

View file

@ -116,7 +116,6 @@
#define CMD_READ_RESP 13
#define CMD_INV_RESP 12
#define CMD_SYSINFO_RESP 17
#define CMD_READBLOCK_RESP 7
//#define Crc(data, len) Crc(CRC_15693, (data), (len))
#define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len))
@ -178,6 +177,36 @@ static void CodeIso15693AsReaderEOF(void) {
}
static int get_uid_slix(uint32_t start_time, uint32_t *eof_time, uint8_t *uid) {
uint8_t *answer = BigBuf_malloc(ISO15693_MAX_RESPONSE_LENGTH);
memset(answer, 0x00, ISO15693_MAX_RESPONSE_LENGTH);
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
uint8_t cmd[5] = {0};
BuildIdentifyRequest(cmd);
uint16_t recvlen = 0;
SendDataTag(cmd, sizeof(cmd), false, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, eof_time, &recvlen);
if (recvlen != 12) {
return PM3_ETIMEOUT;
}
uid[0] = answer[2];
uid[1] = answer[3];
uid[2] = answer[4];
uid[3] = answer[5];
uid[4] = answer[6];
uid[5] = answer[7];
uid[6] = answer[8];
uid[7] = answer[9];
BigBuf_free();
return PM3_SUCCESS;
}
// encode data using "1 out of 256" scheme
// data rate is 1,66 kbit/s (fc/8192)
// is designed for more robust communication over longer distances
@ -263,9 +292,9 @@ void CodeIso15693AsTag(const uint8_t *cmd, size_t len) {
}
// Transmit the command (to the tag) that was placed in cmd[].
void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) {
void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time, bool shallow_mod) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | (shallow_mod ? FPGA_HF_READER_MODE_SEND_SHALLOW_MOD : FPGA_HF_READER_MODE_SEND_FULL_MOD));
if (*start_time < DELAY_ARM_TO_TAG) {
*start_time = DELAY_ARM_TO_TAG;
@ -1586,7 +1615,7 @@ void AcquireRawAdcSamplesIso15693(void) {
tosend_t *ts = get_tosend();
uint32_t start_time = 0;
TransmitTo15693Tag(ts->buf, ts->max, &start_time);
TransmitTo15693Tag(ts->buf, ts->max, &start_time, false);
// wait for last transfer to complete
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) ;
@ -1673,7 +1702,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
dma_start_time = GetCountSspClk() & 0xfffffff0;
}
volatile uint16_t sniffdata;
volatile uint16_t sniffdata = 0;
volatile uint16_t sniffdata_prev = sniffdata;
sniffdata = *upTo++;
@ -1900,7 +1929,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t
}
tosend_t *ts = get_tosend();
TransmitTo15693Tag(ts->buf, ts->max, &start_time);
TransmitTo15693Tag(ts->buf, ts->max, &start_time, false);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
*resp_len = 0;
@ -1923,7 +1952,7 @@ int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, ui
CodeIso15693AsReaderEOF();
tosend_t *ts = get_tosend();
TransmitTo15693Tag(ts->buf, ts->max, &start_time);
TransmitTo15693Tag(ts->buf, ts->max, &start_time, false);
uint32_t end_time = start_time + 32 * (8 * ts->max - 4); // subtract the 4 padding bits after EOF
LogTrace_ISO15693(NULL, 0, (start_time * 4), (end_time * 4), NULL, true);
@ -2098,9 +2127,28 @@ void Iso15693InitTag(void) {
StartCountSspClk();
}
void EmlClearIso15693(void) {
// Resetting the bitstream also frees the BigBuf memory, so we do this here to prevent
// an inconvenient reset in the future by Iso15693InitTag
FpgaDownloadAndGo(FPGA_BITSTREAM_HF_15);
BigBuf_Clear_EM();
reply_ng(CMD_HF_ISO15693_EML_CLEAR, PM3_SUCCESS, NULL, 0);
}
void EmlSetMemIso15693(uint8_t count, uint8_t *data, uint32_t offset) {
uint8_t *emCARD = BigBuf_get_EM_addr();
memcpy(emCARD + offset, data, count);
}
void EmlGetMemIso15693(uint8_t count, uint8_t *output, uint32_t offset) {
uint8_t *emCARD = BigBuf_get_EM_addr();
memcpy(output, emCARD + offset, count);
}
// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands
// all demodulation performed in arm rather than host. - greg
void SimTagIso15693(uint8_t *uid) {
void SimTagIso15693(uint8_t *uid, uint8_t block_size) {
// free eventually allocated BigBuf memory
BigBuf_free_keep_EM();
@ -2109,12 +2157,10 @@ void SimTagIso15693(uint8_t *uid) {
LED_A_ON();
Dbprintf("ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X", uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7]);
Dbprintf("ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X block size %d", uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7], block_size);
LED_C_ON();
enum { NO_FIELD, IDLE, ACTIVATED, SELECTED, HALTED } chip_state = NO_FIELD;
bool button_pressed = false;
@ -2188,7 +2234,7 @@ void SimTagIso15693(uint8_t *uid) {
bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH);
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM;
// Build GET_SYSTEM_INFO command
// Build GET_SYSTEM_INFO response
uint8_t resp_sysinfo[CMD_SYSINFO_RESP] = {0};
resp_sysinfo[0] = 0; // Response flags.
@ -2207,8 +2253,8 @@ void SimTagIso15693(uint8_t *uid) {
resp_sysinfo[10] = 0; // DSFID
resp_sysinfo[11] = 0; // AFI
resp_sysinfo[12] = 0x1B; // Memory size.
resp_sysinfo[13] = 0x03; // Memory size.
resp_sysinfo[12] = 0x1F; // Block count
resp_sysinfo[13] = block_size - 1; // Block size.
resp_sysinfo[14] = 0x01; // IC reference.
// CRC
@ -2221,28 +2267,97 @@ void SimTagIso15693(uint8_t *uid) {
LogTrace_ISO15693(resp_sysinfo, CMD_SYSINFO_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false);
}
// READ_BLOCK
if ((cmd[1] == ISO15693_READBLOCK)) {
// READ_BLOCK and READ_MULTI_BLOCK
if ((cmd[1] == ISO15693_READBLOCK) || (cmd[1] == ISO15693_READ_MULTI_BLOCK)) {
bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH);
bool addressed = cmd[0] & ISO15_REQ_ADDRESS;
bool option = cmd[0] & ISO15_REQ_OPTION;
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM;
// Build GET_SYSTEM_INFO command
uint8_t resp_readblock[CMD_READBLOCK_RESP] = {0};
uint8_t address_offset = 0;
if (addressed) {
address_offset = 8;
}
resp_readblock[0] = 0; // Response flags.
resp_readblock[1] = 0; // Block data.
resp_readblock[2] = 0; // Block data.
resp_readblock[3] = 0; // Block data.
resp_readblock[4] = 0; // Block data.
uint8_t block_idx = cmd[2 + address_offset];
uint8_t block_count = 1;
if (cmd[1] == ISO15693_READ_MULTI_BLOCK) {
block_count = cmd[3 + address_offset] + 1;
}
// Build READ_(MULTI_)BLOCK response
int response_length = 3 + block_size * block_count;
int security_offset = 0;
if (option) {
response_length += block_count;
security_offset = 1;
}
uint8_t resp_readblock[response_length];
memset(resp_readblock, 0, response_length);
resp_readblock[0] = 0; // Response flags
for (int j = 0; j < block_count; j++) {
// where to put the data of the current block
int work_offset = 1 + j * (block_size + security_offset);
if (option) {
resp_readblock[work_offset] = 0; // Security status
}
// Block data
if (block_size * (block_idx + j + 1) <= CARD_MEMORY_SIZE) {
EmlGetMemIso15693(block_size, resp_readblock + (work_offset + security_offset),
block_size * (block_idx + j));
} else {
memset(resp_readblock + work_offset + security_offset, 0, block_size);
}
}
// CRC
AddCrc15(resp_readblock, 5);
CodeIso15693AsTag(resp_readblock, CMD_READBLOCK_RESP);
AddCrc15(resp_readblock, response_length - 2);
CodeIso15693AsTag(resp_readblock, response_length);
tosend_t *ts = get_tosend();
TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow);
LogTrace_ISO15693(resp_readblock, CMD_READBLOCK_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false);
LogTrace_ISO15693(resp_readblock, response_length, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false);
}
// WRITE_BLOCK and WRITE_MULTI_BLOCK
if ((cmd[1] == ISO15693_WRITEBLOCK) || (cmd[1] == ISO15693_WRITE_MULTI_BLOCK)) {
bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH);
bool addressed = cmd[0] & ISO15_REQ_ADDRESS;
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM;
uint8_t address_offset = 0;
if (addressed) {
address_offset = 8;
}
uint8_t block_idx = cmd[2 + address_offset];
uint8_t block_count = 1;
uint8_t multi_offset = 0;
if (cmd[1] == ISO15693_WRITE_MULTI_BLOCK) {
block_count = cmd[3 + address_offset] + 1;
multi_offset = 1;
}
uint8_t *data = cmd + 3 + address_offset + multi_offset;
// write data
EmlSetMemIso15693(block_count * block_size, data, block_idx * block_size);
// Build WRITE_(MULTI_)BLOCK response
int response_length = 3;
uint8_t resp_writeblock[response_length];
memset(resp_writeblock, 0, response_length);
resp_writeblock[0] = 0; // Response flags
// CRC
AddCrc15(resp_writeblock, response_length - 2);
CodeIso15693AsTag(resp_writeblock, response_length);
tosend_t *ts = get_tosend();
TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow);
LogTrace_ISO15693(resp_writeblock, response_length, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false);
}
}
@ -2346,6 +2461,8 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint
case ISO15693_WRITE_AFI:
case ISO15693_LOCK_AFI:
case ISO15693_WRITE_DSFID:
case ISO15693_WRITE_PASSWORD:
case ISO15693_PASSWORD_PROTECT_EAS:
case ISO15693_LOCK_DSFID:
timeout = ISO15693_READER_TIMEOUT_WRITE;
request_answer = data[0] & ISO15_REQ_OPTION;
@ -2555,7 +2672,7 @@ void SetTag15693Uid(const uint8_t *uid) {
switch_off();
}
static void init_password_15693_slixl(uint8_t *buffer, uint8_t *pwd, const uint8_t *rnd) {
static void init_password_15693_Slix(uint8_t *buffer, uint8_t *pwd, const uint8_t *rnd) {
memcpy(buffer, pwd, 4);
if (rnd) {
buffer[0] ^= rnd[0];
@ -2565,14 +2682,14 @@ static void init_password_15693_slixl(uint8_t *buffer, uint8_t *pwd, const uint8
}
}
static bool get_rnd_15693_slixl(uint32_t start_time, uint32_t *eof_time, uint8_t *rnd) {
static bool get_rnd_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *rnd) {
// 0x04, == NXP from manufacture id list.
uint8_t c[] = {ISO15_REQ_DATARATE_HIGH, ISO15693_GET_RANDOM_NUMBER, 0x04, 0x00, 0x00 };
AddCrc15(c, 3);
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
uint16_t recvlen = 0;
int res = SendDataTag(c, sizeof(c), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time, &recvlen);
int res = SendDataTag(c, sizeof(c), true, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time, &recvlen);
if (res != PM3_SUCCESS && recvlen != 5) {
return false;
}
@ -2583,15 +2700,16 @@ static bool get_rnd_15693_slixl(uint32_t start_time, uint32_t *eof_time, uint8_t
return true;
}
static uint32_t set_pass_15693_slixl(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, uint8_t *password) {
static uint32_t disable_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, uint8_t *password) {
uint8_t rnd[2];
if (get_rnd_15693_slixl(start_time, eof_time, rnd) == false) {
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
return PM3_ETIMEOUT;
}
// 0x04, == NXP from manufacture id list.
uint8_t c[] = {ISO15_REQ_DATARATE_HIGH, ISO15693_SET_PASSWORD, 0x04, pass_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
init_password_15693_slixl(&c[4], password, rnd);
uint8_t c[] = { ISO15_REQ_DATARATE_HIGH, ISO15693_SET_PASSWORD, 0x04, pass_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
init_password_15693_Slix(&c[4], password, rnd);
AddCrc15(c, 8);
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
@ -2604,16 +2722,226 @@ static uint32_t set_pass_15693_slixl(uint32_t start_time, uint32_t *eof_time, ui
return PM3_SUCCESS;
}
/*
static uint32_t enable_privacy_15693_slixl(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t pass_id, uint8_t *password) {
static uint32_t set_pass_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, uint8_t *password, uint8_t *uid) {
uint8_t rnd[2];
if (get_rnd_15693_slixl(start_time, eof_time, rnd) == false) {
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
return PM3_ETIMEOUT;
}
// 0x04, == NXP from manufacture id list.
uint8_t c[] = { (ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS), ISO15693_SET_PASSWORD, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, pass_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
init_password_15693_Slix(&c[12], password, rnd);
memcpy(&c[3], uid, 8);
AddCrc15(c, 16);
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
uint16_t recvlen = 0;
int res = SendDataTag(c, sizeof(c), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time, &recvlen);
if (res != PM3_SUCCESS && recvlen != 3) {
return PM3_EWRONGANSWER;
}
return PM3_SUCCESS;
}
static uint32_t set_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *password) {
uint8_t rnd[2];
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
return PM3_ETIMEOUT;
}
// 0x04, == NXP from manufacture id list.
uint8_t c[] = { ISO15_REQ_DATARATE_HIGH, 0xBA, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
init_password_15693_Slix(&c[3], password, rnd);
AddCrc15(c, 7);
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
uint16_t recvlen = 0;
int res = SendDataTag(c, sizeof(c), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time, &recvlen);
if (res != PM3_SUCCESS && recvlen != 3) {
return PM3_EWRONGANSWER;
}
return PM3_SUCCESS;
}
static uint32_t disable_eas_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *password, bool usepwd) {
uint8_t uid[8];
get_uid_slix(start_time, eof_time, uid);
uint8_t rnd[2];
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
return PM3_ETIMEOUT;
}
if (usepwd) {
int res_setpass = set_pass_15693_Slix(start_time, eof_time, 0x10, password, uid);
if (res_setpass != PM3_SUCCESS) {
return PM3_EWRONGANSWER;
}
}
// 0x04, == NXP from manufacture id list.
uint8_t c[] = { ISO15_REQ_DATARATE_HIGH, 0xA3, 0x04, 0x00, 0x00};
AddCrc15(c, 3);
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
uint16_t recvlen = 0;
int res = SendDataTag(c, sizeof(c), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time, &recvlen);
if (res != PM3_SUCCESS && recvlen != 3) {
return PM3_EWRONGANSWER;
}
return PM3_SUCCESS;
}
static uint32_t enable_eas_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *password, bool usepwd) {
uint8_t uid[8];
get_uid_slix(start_time, eof_time, uid);
uint8_t rnd[2];
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
return PM3_ETIMEOUT;
}
if (usepwd) {
int res_setpass = set_pass_15693_Slix(start_time, eof_time, 0x10, password, uid);
if (res_setpass != PM3_SUCCESS) {
return PM3_EWRONGANSWER;
}
}
// 0x04, == NXP from manufacture id list.
uint8_t c[] = { ISO15_REQ_DATARATE_HIGH, 0xA2, 0x04, 0x00, 0x00};
//init_password_15693_Slix(&c[3], password, rnd);
AddCrc15(c, 3);
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
uint16_t recvlen = 0;
int res = SendDataTag(c, sizeof(c), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time, &recvlen);
if (res != PM3_SUCCESS && recvlen != 3) {
return PM3_EWRONGANSWER;
}
return PM3_SUCCESS;
}
static uint32_t write_password_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pwd_id, uint8_t *password, uint8_t *uid) {
uint8_t new_pwd_cmd[] = { (ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS), ISO15693_WRITE_PASSWORD, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, pwd_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
memcpy(&new_pwd_cmd[3], uid, 8);
memcpy(&new_pwd_cmd[12], password, 4);
AddCrc15(new_pwd_cmd, 16);
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
uint16_t recvlen = 0;
int res_wrp = SendDataTag(new_pwd_cmd, sizeof(new_pwd_cmd), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time, &recvlen);
if (res_wrp != PM3_SUCCESS && recvlen != 3) {
return PM3_EWRONGANSWER;
}
return PM3_SUCCESS;
}
static uint32_t pass_protect_EASAFI_15693_Slix(uint32_t start_time, uint32_t *eof_time, bool set_option_flag, uint8_t *password) {
uint8_t flags;
if (set_option_flag)
flags = ISO15_REQ_DATARATE_HIGH | ISO15_REQ_OPTION;
else
flags = ISO15_REQ_DATARATE_HIGH;
uint8_t uid[8];
get_uid_slix(start_time, eof_time, uid);
uint8_t rnd[2];
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
return PM3_ETIMEOUT;
}
int res_setpass = set_pass_15693_Slix(start_time, eof_time, 0x10, password, uid);
if (res_setpass != PM3_SUCCESS) {
return PM3_EWRONGANSWER;
}
uint8_t new_pass_protect_cmd[] = { flags, ISO15693_PASSWORD_PROTECT_EAS, 0x04, 0x00, 0x00};
AddCrc15(new_pass_protect_cmd, 3);
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
uint16_t recvlen = 0;
int res = SendDataTag(new_pass_protect_cmd, sizeof(new_pass_protect_cmd), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time, &recvlen);
if (res != PM3_SUCCESS && recvlen != 3) {
return PM3_EWRONGANSWER;
}
return PM3_SUCCESS;
}
static uint32_t write_afi_15693(uint32_t start_time, uint32_t *eof_time, uint8_t *password, bool usepwd, uint8_t *uid, bool use_uid, uint8_t afi) {
if (!use_uid) {
int res_getuid = get_uid_slix(start_time, eof_time, uid);
if (res_getuid != PM3_SUCCESS) {
return res_getuid;
}
}
if (usepwd) {
int res_setpass = set_pass_15693_Slix(start_time, eof_time, 0x10, password, uid);
if (res_setpass != PM3_SUCCESS) {
return PM3_EWRONGANSWER;
}
}
uint8_t cmd[] = { ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS, ISO15693_WRITE_AFI, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
memcpy(&cmd[2], uid, 8);
cmd[10] = afi;
AddCrc15(cmd, 11);
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
uint16_t recvlen = 0;
int res = SendDataTag(cmd, sizeof(cmd), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time, &recvlen);
if (res != PM3_SUCCESS || recvlen != 3) {
return PM3_EWRONGANSWER;
}
return PM3_SUCCESS;
}
/*
static uint32_t enable_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t pass_id, uint8_t *password) {
uint8_t rnd[2];
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
return PM3_ETIMEOUT;
}
uint8_t c[] = {ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS, ISO15693_ENABLE_PRIVACY, pass_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
memcpy(&c[3], uid, 8);
init_password_15693_slixl(&c[11], password, rnd);
init_password_15693_Slix(&c[11], password, rnd);
AddCrc15(c, 15);
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
@ -2626,16 +2954,16 @@ static uint32_t enable_privacy_15693_slixl(uint32_t start_time, uint32_t *eof_ti
return PM3_SUCCESS;
}
static uint32_t write_password_15693_slixl(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t pass_id, uint8_t *password) {
static uint32_t write_password_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t pass_id, uint8_t *password) {
uint8_t rnd[2];
if (get_rnd_15693_slixl(start_time, eof_time, rnd) == false) {
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
return PM3_ETIMEOUT;
}
uint8_t c[] = {ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS, ISO15693_WRITE_PASSWORD, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
memcpy(&c[3], uid, 8);
c[11] = pass_id;
init_password_15693_slixl(&c[12], password, NULL);
init_password_15693_Slix(&c[12], password, NULL);
AddCrc15(c, 16);
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
@ -2649,16 +2977,16 @@ static uint32_t write_password_15693_slixl(uint32_t start_time, uint32_t *eof_ti
return PM3_SUCCESS;
}
static uint32_t destroy_15693_slixl(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t *password) {
static uint32_t destroy_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t *password) {
uint8_t rnd[2];
if (get_rnd_15693_slixl(start_time, eof_time, rnd) == false) {
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
return PM3_ETIMEOUT;
}
uint8_t c[] = {ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS, ISO15693_DESTROY, ISO15693_ENABLE_PRIVACY, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
memcpy(&c[3], uid, 8);
init_password_15693_slixl(&c[11], password, rnd);
init_password_15693_Slix(&c[11], password, rnd);
AddCrc15(c, 15);
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
@ -2673,8 +3001,32 @@ static uint32_t destroy_15693_slixl(uint32_t start_time, uint32_t *eof_time, uin
*/
// Sets a PRIVACY password to all ZEROS
void DisablePrivacySlixLIso15693(uint8_t *password) {
void WritePasswordSlixIso15693(uint8_t *old_password, uint8_t *new_password, uint8_t pwd_id) {
LED_D_ON();
Iso15693InitReader();
StartCountSspClk();
uint32_t start_time = 0, eof_time = 0;
int res = PM3_EFAILED;
uint8_t uid[8];
get_uid_slix(start_time, &eof_time, uid);
res = set_pass_15693_Slix(start_time, &eof_time, pwd_id, old_password, uid);
if (res != PM3_SUCCESS) {
reply_ng(CMD_HF_ISO15693_SLIX_WRITE_PWD, res, NULL, 0);
switch_off();
return;
}
res = write_password_15693_Slix(start_time, &eof_time, pwd_id, new_password, uid);
reply_ng(CMD_HF_ISO15693_SLIX_WRITE_PWD, res, NULL, 0);
switch_off();
}
void DisablePrivacySlixIso15693(uint8_t *password) {
LED_D_ON();
Iso15693InitReader();
StartCountSspClk();
@ -2684,13 +3036,12 @@ void DisablePrivacySlixLIso15693(uint8_t *password) {
// 0x04 Privacy
// 0x08 Destroy SLIX-L
// 0x10 EAS/AFI
int res = set_pass_15693_slixl(start_time, &eof_time, 0x04, password);
reply_ng(CMD_HF_ISO15693_SLIX_L_DISABLE_PRIVACY, res, NULL, 0);
int res = disable_privacy_15693_Slix(start_time, &eof_time, 0x04, password);
reply_ng(CMD_HF_ISO15693_SLIX_DISABLE_PRIVACY, res, NULL, 0);
switch_off();
}
// Sets a EAS/AFI password to all ZEROS
void DisableEAS_AFISlixLIso15693(uint8_t *password) {
void EnablePrivacySlixIso15693(uint8_t *password) {
LED_D_ON();
Iso15693InitReader();
StartCountSspClk();
@ -2700,8 +3051,71 @@ void DisableEAS_AFISlixLIso15693(uint8_t *password) {
// 0x04 Privacy
// 0x08 Destroy SLIX-L
// 0x10 EAS/AFI
int res = set_pass_15693_slixl(start_time, &eof_time, 0x10, password);
reply_ng(CMD_HF_ISO15693_SLIX_L_DISABLE_AESAFI, res, NULL, 0);
int res = set_privacy_15693_Slix(start_time, &eof_time, password);
reply_ng(CMD_HF_ISO15693_SLIX_ENABLE_PRIVACY, res, NULL, 0);
switch_off();
}
void DisableEAS_AFISlixIso15693(uint8_t *password, bool usepwd) {
LED_D_ON();
Iso15693InitReader();
StartCountSspClk();
uint32_t start_time = 0, eof_time = 0;
// Password identifier Password byte
// 0x04 Privacy
// 0x08 Destroy SLIX-L
// 0x10 EAS/AFI
int res = disable_eas_15693_Slix(start_time, &eof_time, password, usepwd);
reply_ng(CMD_HF_ISO15693_SLIX_DISABLE_EAS, res, NULL, 0);
switch_off();
}
void EnableEAS_AFISlixIso15693(uint8_t *password, bool usepwd) {
LED_D_ON();
Iso15693InitReader();
StartCountSspClk();
uint32_t start_time = 0, eof_time = 0;
// Password identifier Password byte
// 0x04 Privacy
// 0x08 Destroy SLIX-L
// 0x10 EAS/AFI
int res = enable_eas_15693_Slix(start_time, &eof_time, password, usepwd);
reply_ng(CMD_HF_ISO15693_SLIX_ENABLE_EAS, res, NULL, 0);
switch_off();
}
void PassProtextEASSlixIso15693(uint8_t *password) {
LED_D_ON();
Iso15693InitReader();
StartCountSspClk();
uint32_t start_time = 0, eof_time = 0;
int res = pass_protect_EASAFI_15693_Slix(start_time, &eof_time, false, password);
reply_ng(CMD_HF_ISO15693_SLIX_PASS_PROTECT_EAS, res, NULL, 0);
switch_off();
}
void PassProtectAFISlixIso15693(uint8_t *password) {
LED_D_ON();
Iso15693InitReader();
StartCountSspClk();
uint32_t start_time = 0, eof_time = 0;
int res = pass_protect_EASAFI_15693_Slix(start_time, &eof_time, true, password);
reply_ng(CMD_HF_ISO15693_SLIX_PASS_PROTECT_AFI, res, NULL, 0);
switch_off();
}
void WriteAFIIso15693(uint8_t *password, bool use_pwd, uint8_t *uid, bool use_uid, uint8_t afi) {
LED_D_ON();
Iso15693InitReader();
StartCountSspClk();
uint32_t start_time = 0, eof_time = 0;
int res = write_afi_15693(start_time, &eof_time, password, use_pwd, uid, use_uid, afi);
//int res = PM3_SUCCESS;
reply_ng(CMD_HF_ISO15693_WRITE_AFI, res, NULL, 0);
switch_off();
}

View file

@ -40,13 +40,16 @@ void CodeIso15693AsTag(const uint8_t *cmd, size_t len);
void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow);
int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time);
void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time);
void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time, bool shallow_mod);
int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time, bool fsk, bool recv_speed, uint16_t *resp_len);
//void RecordRawAdcSamplesIso15693(void);
void AcquireRawAdcSamplesIso15693(void);
void ReaderIso15693(iso15_card_select_t *p_card); // ISO15693 reader
void SimTagIso15693(uint8_t *uid); // simulate an ISO15693 tag
void EmlClearIso15693(void);
void EmlSetMemIso15693(uint8_t count, uint8_t *data, uint32_t offset);
void EmlGetMemIso15693(uint8_t count, uint8_t *output, uint32_t offset);
void SimTagIso15693(uint8_t *uid, uint8_t block_size); // simulate an ISO15693 tag
void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag
void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data); // send arbitrary commands from CLI
@ -59,6 +62,12 @@ int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, ui
void SetTag15693Uid(const uint8_t *uid);
void DisablePrivacySlixLIso15693(uint8_t *password);
void DisableEAS_AFISlixLIso15693(uint8_t *password);
void WritePasswordSlixIso15693(uint8_t *old_password, uint8_t *new_password, uint8_t pwd_id);
void DisablePrivacySlixIso15693(uint8_t *password);
void EnablePrivacySlixIso15693(uint8_t *password);
void DisableEAS_AFISlixIso15693(uint8_t *password, bool usepwd);
void EnableEAS_AFISlixIso15693(uint8_t *password, bool usepwd);
void PassProtextEASSlixIso15693(uint8_t *password);
void PassProtectAFISlixIso15693(uint8_t *password);
void WriteAFIIso15693(uint8_t *password, bool usepwd, uint8_t *uid, bool use_uid, uint8_t afi);
#endif

View file

@ -79,6 +79,7 @@ static uint16_t rx_frame_from_fpga(void) {
return AT91C_BASE_SSC->SSC_RHR;
}
}
return 0;
}
//-----------------------------------------------------------------------------

View file

@ -296,7 +296,9 @@ void LFSetupFPGAForADC(int divisor, bool reader_field) {
uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, int16_t trigger_threshold,
bool verbose, uint32_t sample_size, uint32_t cancel_after, int32_t samples_to_skip, bool ledcontrol) {
initSampleBuffer(&sample_size);
initSampleBuffer(&sample_size); // sample size in bytes
sample_size <<= 3; // sample size in bits
sample_size /= bits_per_sample; // sample count
if (g_dbglevel >= DBG_DEBUG) {
printSamples();
@ -368,8 +370,11 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
}
// Ensure that DC offset removal and noise check is performed for any device-side processing
removeSignalOffset(data.buffer, samples.total_saved);
computeSignalProperties(data.buffer, samples.total_saved);
if (bits_per_sample == 8) {
// these functions only consider bps==8
removeSignalOffset(data.buffer, samples.total_saved);
computeSignalProperties(data.buffer, samples.total_saved);
}
return data.numbits;
}
/**

View file

@ -214,6 +214,65 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
LEDsoff();
}
void MifareReadConfigBlockGDM(uint8_t *key) {
int retval = PM3_SUCCESS;
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
if (par == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
uint8_t *uid = BigBuf_malloc(10);
if (uid == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
// variables
uint32_t cuid = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
uint64_t ui64key = bytes_to_num(key, 6);
uint8_t outbuf[16] = {0x00};
if (iso14443a_select_card(uid, NULL, &cuid, true, 0, true) == false) {
retval = PM3_ESOFT;
goto OUT;
}
if (mifare_classic_authex_2(pcs, cuid, 0, 0, ui64key, AUTH_FIRST, NULL, NULL, true)) {
retval = PM3_ESOFT;
goto OUT;
};
if (mifare_classic_readblock_ex(pcs, cuid, 0, outbuf, MIFARE_MAGIC_GDM_READ_CFG)) {
retval = PM3_ESOFT;
goto OUT;
};
if (mifare_classic_halt(pcs, cuid)) {
retval = PM3_ESOFT;
goto OUT;
};
OUT:
crypto1_deinit(pcs);
reply_ng(CMD_HF_MIFARE_G4_GDM_CONFIG, retval, outbuf, sizeof(outbuf));
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(false);
BigBuf_free();
}
//-----------------------------------------------------------------------------
// Select, Authenticate, Read a MIFARE tag.
// read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes)
@ -394,7 +453,6 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
memcpy(blockdata, datain + 10, 16);
// variables
uint8_t isOK = 0;
uint8_t uid[10] = {0x00};
uint32_t cuid = 0;
struct Crypto1State mpcs = {0, 0};
@ -410,57 +468,202 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
LED_B_OFF();
LED_C_OFF();
while (true) {
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card");
break;
};
uint8_t retval = 0;
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Auth error");
break;
};
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card");
goto OUT;
};
if (mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
break;
};
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Auth error");
goto OUT;
};
if (mifare_classic_halt(pcs, cuid)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
int res = mifare_classic_writeblock(pcs, cuid, blockNo, blockdata);
if (res == PM3_ETEAROFF) {
retval = PM3_ETEAROFF;
goto OUT;
} else if (res) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
retval = PM3_ESOFT;
goto OUT;
}
if (mifare_classic_halt(pcs, cuid)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Halt error");
goto OUT;
};
retval = 1;
OUT:
crypto1_deinit(pcs);
if (g_dbglevel >= 2) DbpString("WRITE BLOCK FINISHED");
reply_mix(CMD_ACK, isOK, 0, 0, 0, 0);
reply_mix(CMD_ACK, retval, 0, 0, 0, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(false);
}
void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t *datain) {
int retval = PM3_SUCCESS;
// check args
if (datain == NULL) {
retval = PM3_EINVARG;
goto OUT;
}
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
if (par == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
uint8_t *uid = BigBuf_malloc(10);
if (uid == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
// variables
uint32_t cuid = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
uint64_t ui64key = bytes_to_num(key, 6);
if (iso14443a_select_card(uid, NULL, &cuid, true, 0, true) == false) {
retval = PM3_ESOFT;
goto OUT;
}
if (mifare_classic_authex_2(pcs, cuid, blockno, keytype, ui64key, AUTH_FIRST, NULL, NULL, true)) {
retval = PM3_ESOFT;
goto OUT;
};
int res = mifare_classic_writeblock_ex(pcs, cuid, blockno, datain, true);
if (res == PM3_ETEAROFF) {
retval = PM3_ETEAROFF;
goto OUT;
} else if (res) {
retval = PM3_ESOFT;
goto OUT;
}
if (mifare_classic_halt(pcs, cuid)) {
retval = PM3_ESOFT;
goto OUT;
};
OUT:
crypto1_deinit(pcs);
reply_ng(CMD_HF_MIFARE_G4_GDM_WRBL, retval, NULL, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(false);
BigBuf_free();
}
void MifareWriteConfigBlockGDM(uint8_t *datain) {
int retval = PM3_SUCCESS;
// check args
if (datain == NULL) {
retval = PM3_EINVARG;
goto OUT;
}
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
if (par == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
uint8_t *uid = BigBuf_malloc(10);
if (uid == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
// variables
uint32_t cuid = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
if (iso14443a_select_card(uid, NULL, &cuid, true, 0, true) == false) {
retval = PM3_ESOFT;
goto OUT;
}
uint64_t key = 0;
if (mifare_classic_authex_2(pcs, cuid, 0, 0, key, AUTH_FIRST, NULL, NULL, true)) {
retval = PM3_ESOFT;
goto OUT;
};
int res = mifare_classic_write_cfg_block_gdm(pcs, cuid, datain);
if (res == PM3_ETEAROFF) {
retval = PM3_ETEAROFF;
goto OUT;
} else if (res) {
retval = PM3_ESOFT;
goto OUT;
}
if (mifare_classic_halt(pcs, cuid)) {
retval = PM3_ESOFT;
goto OUT;
};
OUT:
crypto1_deinit(pcs);
reply_ng(CMD_HF_MIFARE_G4_GDM_WRCFG, retval, NULL, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(false);
BigBuf_free();
}
void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) {
// params
uint8_t blockNo = arg0;
uint8_t keyType = arg1;
uint8_t transferKeyType = arg2;
uint64_t ui64Key = 0;
uint64_t transferUi64Key = 0;
uint8_t blockdata[16] = {0x00};
ui64Key = bytes_to_num(datain, 6);
memcpy(blockdata, datain + 10, 16);
memcpy(blockdata, datain + 11, 16);
transferUi64Key = bytes_to_num(datain + 27, 6);
// variables
uint8_t action = datain[9];
uint8_t transferBlk = datain[10];
bool needAuth = datain[33];
uint8_t isOK = 0;
uint8_t uid[10] = {0x00};
uint32_t cuid = 0;
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t len = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
@ -490,6 +693,21 @@ void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
break;
};
if (needAuth) {
// transfer to other sector
if (mifare_classic_auth(pcs, cuid, transferBlk, transferKeyType, transferUi64Key, AUTH_NESTED)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Nested auth error");
break;
}
}
// send transfer (commit the change)
len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_TRANSFER, (transferBlk != 0) ? transferBlk : blockNo, receivedAnswer, NULL, NULL);
if (len != 1 && receivedAnswer[0] != 0x0A) { // 0x0a - ACK
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error in transfer: %02x", receivedAnswer[0]);
break;
}
if (mifare_classic_halt(pcs, cuid)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Halt error");
break;
@ -775,7 +993,7 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t flags) {
if (!have_uid) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info;
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (ALL)");
continue;
}
@ -794,7 +1012,7 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t flags) {
}
have_uid = true;
} else { // no need for anticollision. We can directly select the card
if (!iso14443a_fast_select_card(uid, cascade_levels)) {
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (UID)");
continue;
}
@ -852,7 +1070,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
uint64_t ui64Key = bytes_to_num(datain, 6);
uint32_t cuid = 0;
int16_t isOK = 0;
int16_t isOK = PM3_SUCCESS;
uint16_t num_nonces = 0;
uint8_t nt_par_enc = 0;
uint8_t cascade_levels = 0;
@ -878,18 +1096,21 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
LED_C_ON();
uint8_t prev_enc_nt[] = {0, 0, 0, 0};
uint8_t prev_counter = 0;
for (uint16_t i = 0; i <= PM3_CMD_DATA_SIZE - 9;) {
// Test if the action was cancelled
if (BUTTON_PRESS()) {
isOK = 2;
isOK = PM3_EOPABORTED;
field_off = true;
break;
}
if (!have_uid) { // need a full select cycle to get the uid first
if (have_uid == false) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info;
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireEncryptedNonces: Can't select card (ALL)");
continue;
}
@ -908,7 +1129,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
}
have_uid = true;
} else { // no need for anticollision. We can directly select the card
if (!iso14443a_fast_select_card(uid, cascade_levels)) {
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireEncryptedNonces: Can't select card (UID)");
continue;
}
@ -917,7 +1138,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
if (slow)
SpinDelayUs(HARDNESTED_PRE_AUTHENTICATION_LEADTIME);
uint32_t nt1;
uint32_t nt1 = 0;
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireEncryptedNonces: Auth1 error");
continue;
@ -939,11 +1160,32 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
memcpy(buf + i, receivedAnswer, 4);
nt_par_enc = par_enc[0] & 0xf0;
} else {
nt_par_enc |= par_enc[0] >> 4;
nt_par_enc |= par_enc[0] >> 4;
memcpy(buf + i + 4, receivedAnswer, 4);
memcpy(buf + i + 8, &nt_par_enc, 1);
i += 9;
}
if (prev_enc_nt[0] == receivedAnswer[0] &&
prev_enc_nt[1] == receivedAnswer[1] &&
prev_enc_nt[2] == receivedAnswer[2] &&
prev_enc_nt[3] == receivedAnswer[3]
) {
prev_counter++;
}
memcpy(prev_enc_nt, receivedAnswer, 4);
if (prev_counter == 5) {
if (g_dbglevel >= DBG_EXTENDED) {
DbpString("Static encrypted nonce detected, exiting...");
uint32_t a = bytes_to_num(prev_enc_nt, 4);
uint32_t b = bytes_to_num(receivedAnswer, 4);
Dbprintf("( %08x vs %08x )", a, b);
}
isOK = PM3_ESTATIC_NONCE;
break;
}
}
LED_C_OFF();
@ -952,7 +1194,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
reply_old(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf));
LED_B_OFF();
if (g_dbglevel >= 3) DbpString("AcquireEncryptedNonces finished");
if (g_dbglevel >= DBG_ERROR) DbpString("AcquireEncryptedNonces finished");
if (field_off) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
@ -1009,6 +1251,9 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
LED_B_ON();
WDT_HIT();
uint32_t prev_enc_nt = 0;
uint8_t prev_counter = 0;
uint16_t unsuccessful_tries = 0;
uint16_t davg = 0;
dmax = 0;
@ -1030,7 +1275,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
continue;
}
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (iso14443a_select_card(uid, NULL, &cuid, true, 0, true) == 0) {
if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Can't select card");
rtr--;
continue;
@ -1051,10 +1296,12 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
};
// cards with fixed nonce
/*
if (nt1 == nt2) {
Dbprintf("Nested: %08x vs %08x", nt1, nt2);
break;
}
*/
uint32_t nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160
for (i = 101; i < 1200; i++) {
@ -1077,6 +1324,21 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
isOK = PM3_EFAILED;
}
}
if (nt1 == nt2) {
prev_counter++;
}
prev_enc_nt = nt2;
if (prev_counter == 5) {
if (g_dbglevel >= DBG_EXTENDED) {
DbpString("Static encrypted nonce detected, exiting...");
Dbprintf("( %08x vs %08x )", prev_enc_nt, nt2);
}
isOK = PM3_ESTATIC_NONCE;
break;
}
}
if (rtr > 1)
@ -1094,10 +1356,13 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
LED_C_ON();
// get crypted nonces for target sector
for (i = 0; i < 2 && !isOK; i++) { // look for exactly two different nonces
for (i = 0; ((i < 2) && (isOK == PM3_SUCCESS)); i++) {
// look for exactly two different nonces
target_nt[i] = 0;
while (target_nt[i] == 0) { // continue until we have an unambiguous nonce
// continue until we have an unambiguous nonce
while (target_nt[i] == 0) {
// Test if the action was cancelled
if (BUTTON_PRESS() || data_available()) {
@ -1111,7 +1376,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
continue;
}
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (iso14443a_select_card(uid, NULL, &cuid, true, 0, true) == false) {
if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Can't select card");
continue;
};
@ -1190,6 +1455,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
memcpy(payload.nt_b, &target_nt[1], 4);
memcpy(payload.ks_b, &target_ks[1], 4);
LED_B_ON();
reply_ng(CMD_HF_MIFARE_NESTED, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload));
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
@ -1235,13 +1501,13 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
continue;
};
// first colleciton
// first collection
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
continue;
};
// pre-generate nonces
if (keyType == 1 && nt1 == 0x009080A2) {
if (targetKeyType == 1 && nt1 == 0x009080A2) {
target_nt[0] = prng_successor(nt1, 161);
target_nt[1] = prng_successor(nt1, 321);
} else {
@ -1257,7 +1523,7 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
nt2 = bytes_to_num(receivedAnswer, 4);
target_ks[0] = nt2 ^ target_nt[0];
// second colleciton
// second collection
if (mifare_classic_halt(pcs, cuid)) {
continue;
@ -1812,13 +2078,14 @@ void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem) {
uint64_t key = 0;
uint32_t cuid = 0;
int i, res;
uint8_t cascade_levels = 0;
struct {
uint8_t key[6];
bool found;
} PACKED keyresult;
keyresult.found = false;
memset(keyresult.key, 0x00, sizeof(keyresult.key));
bool have_uid = false;
uint8_t keyType = datain[0];
@ -1849,12 +2116,12 @@ void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem) {
set_tracing(false);
for (i = 0; i < key_count; i++) {
for (uint16_t i = 0; i < key_count; i++) {
// Iceman: use piwi's faster nonce collecting part in hardnested.
if (!have_uid) { // need a full select cycle to get the uid first
if (have_uid == false) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info;
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == false) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("ChkKeys: Can't select card (ALL)");
--i; // try same key once again
continue;
@ -1874,7 +2141,7 @@ void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem) {
}
have_uid = true;
} else { // no need for anticollision. We can directly select the card
if (!iso14443a_select_card(uid, NULL, NULL, false, cascade_levels, true)) {
if (iso14443a_select_card(uid, NULL, NULL, false, cascade_levels, true) == false) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("ChkKeys: Can't select card (UID)");
--i; // try same key once again
continue;
@ -1882,12 +2149,10 @@ void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem) {
}
key = bytes_to_num(datain + i * 6, 6);
res = mifare_classic_auth(pcs, cuid, blockNo, keyType, key, AUTH_FIRST);
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, key, AUTH_FIRST)) {
// CHK_TIMEOUT();
if (res)
continue;
}
memcpy(keyresult.key, datain + i * 6, 6);
keyresult.found = true;
@ -1895,14 +2160,12 @@ void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem) {
}
LED_B_ON();
crypto1_deinit(pcs);
reply_ng(CMD_HF_MIFARE_CHKKEYS, PM3_SUCCESS, (uint8_t *)&keyresult, sizeof(keyresult));
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(false);
crypto1_deinit(pcs);
g_dbglevel = oldbg;
}
@ -2334,9 +2597,12 @@ void MifareCIdent(bool is_mfc) {
uint8_t isGen = 0;
uint8_t rec[1] = {0x00};
uint8_t recpar[1] = {0x00};
uint8_t rats[4] = { ISO14443A_CMD_RATS, 0x80, 0x31, 0x73 };
uint8_t rdblf0[4] = { ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f};
uint8_t rdbl00[4] = { ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa8};
uint8_t rats[4] = {ISO14443A_CMD_RATS, 0x80, 0x31, 0x73};
uint8_t rdblf0[4] = {ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f};
uint8_t rdbl00[4] = {ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa8};
uint8_t gen4gmd[4] = {MIFARE_MAGIC_GDM_AUTH_KEY, 0x00, 0x6C, 0x92};
uint8_t gen4GetConf[8] = {GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_GETCNF, 0, 0};
uint8_t superGen1[9] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
uint8_t *uid = BigBuf_malloc(10);
@ -2368,6 +2634,24 @@ void MifareCIdent(bool is_mfc) {
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
int res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
if (res == 2) {
// Check for Magic Gen4 GTU with default password:
// Get config should return 30 or 32 bytes
AddCrc14A(gen4GetConf, sizeof(gen4GetConf) - 2);
ReaderTransmit(gen4GetConf, sizeof(gen4GetConf), NULL);
res = ReaderReceive(buf, par);
if (res == 32 || res == 34) {
isGen = MAGIC_GEN_4GTU;
goto OUT;
}
}
// reset card
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(40);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
if (res == 2) {
if (cuid == 0xAA55C396) {
isGen = MAGIC_GEN_UNFUSED;
@ -2377,19 +2661,29 @@ void MifareCIdent(bool is_mfc) {
ReaderTransmit(rats, sizeof(rats), NULL);
res = ReaderReceive(buf, par);
if (res) {
// test for super card
ReaderTransmit(superGen1, sizeof(superGen1), NULL);
res = ReaderReceive(buf, par);
if (res == 22) {
isGen = MAGIC_SUPER_GEN1;
// test for some MFC gen2
if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10\xF0\x05", 11) == 0) {
// check for super card gen2
// not available after RATS, reset card before executing
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(40);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// super card ident
uint8_t super[] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};
ReaderTransmit(super, sizeof(super), NULL);
iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
ReaderTransmit(rdbl00, sizeof(rdbl00), NULL);
res = ReaderReceive(buf, par);
if (res == 22) {
isGen = MAGIC_SUPER;
goto OUT;
if (res == 18) {
isGen = MAGIC_SUPER_GEN2;
}
goto OUT;
}
// test for some MFC gen2
if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10\xF0\x05", 11) == 0) {
isGen = MAGIC_GEN_2;
goto OUT;
}
@ -2439,7 +2733,7 @@ void MifareCIdent(bool is_mfc) {
}
}
} else {
// magic MFC Gen3 test
// magic MFC Gen3 test 1
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(40);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
@ -2451,6 +2745,21 @@ void MifareCIdent(bool is_mfc) {
isGen = MAGIC_GEN_3;
}
}
// magic MFC Gen4 GDM test
if (isGen != MAGIC_GEN_3) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(40);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
if (res == 2) {
ReaderTransmit(gen4gmd, sizeof(gen4gmd), NULL);
res = ReaderReceive(buf, par);
if (res == 4) {
isGen = MAGIC_GEN_4GDM;
}
}
}
}
};
@ -2465,6 +2774,8 @@ OUT:
void MifareHasStaticNonce(void) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// variables
int retval = PM3_SUCCESS;
uint32_t nt = 0;
@ -2682,42 +2993,152 @@ OUT:
BigBuf_free();
}
void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd) {
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd, uint8_t workFlags) {
bool setup = ((workFlags & MAGIC_INIT) == MAGIC_INIT) ;
bool done = ((workFlags & MAGIC_OFF) == MAGIC_OFF) ;
int res = 0;
int retval = PM3_SUCCESS;
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
uint8_t *uid = BigBuf_malloc(10);
if (iso14443a_select_card(uid, NULL, NULL, true, 0, true) == false) {
retval = PM3_ESOFT;
if (buf == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
LED_B_ON();
uint32_t save_iso14a_timeout = iso14a_get_timeout();
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 1000); // 2 seconds timeout
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
if (par == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
uint8_t cmd[] = { 0xCF, 0x00, 0x00, 0x00, 0x00, 0xCE, blockno, 0x00, 0x00};
if (setup) {
uint8_t *uid = BigBuf_malloc(10);
if (uid == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
if (iso14443a_select_card(uid, NULL, NULL, true, 0, true) == false) {
retval = PM3_ESOFT;
goto OUT;
}
}
LED_B_ON();
static uint32_t save_iso14a_timeout;
if (setup) {
save_iso14a_timeout = iso14a_get_timeout();
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 1000); // 2 seconds timeout
}
uint8_t cmd[] = { GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_READ, blockno,
0x00, 0x00
};
memcpy(cmd + 1, pwd, 4);
AddCrc14A(cmd, sizeof(cmd) - 2);
ReaderTransmit(cmd, sizeof(cmd), NULL);
int res = ReaderReceive(buf, par);
res = ReaderReceive(buf, par);
if (res != 18) {
retval = PM3_ESOFT;
}
iso14a_set_timeout(save_iso14a_timeout);
if (done || retval != 0) iso14a_set_timeout(save_iso14a_timeout);
LED_B_OFF();
OUT:
reply_ng(CMD_HF_MIFARE_G4_RDBL, retval, buf, 18);
reply_ng(CMD_HF_MIFARE_G4_RDBL, retval, buf, res);
// turns off
OnSuccessMagic();
if (done || retval != 0) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
if (done || retval != 0) set_tracing(false);
BigBuf_free();
}
void MifareG4WriteBlk(uint8_t blockno, uint8_t *pwd, uint8_t *data, uint8_t workFlags) {
bool setup = ((workFlags & MAGIC_INIT) == MAGIC_INIT) ;
bool done = ((workFlags & MAGIC_OFF) == MAGIC_OFF) ;
int res = 0;
int retval = PM3_SUCCESS;
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
if (buf == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
// check args
if (data == NULL) {
retval = PM3_EINVARG;
goto OUT;
}
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
if (par == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
if (setup) {
uint8_t *uid = BigBuf_malloc(10);
if (uid == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
if (iso14443a_select_card(uid, NULL, NULL, true, 0, true) == false) {
retval = PM3_ESOFT;
goto OUT;
}
}
LED_B_ON();
static uint32_t save_iso14a_timeout;
if (setup) {
save_iso14a_timeout = iso14a_get_timeout();
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 1000); // 2 seconds timeout
}
uint8_t cmd[] = { GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_WRITE, blockno,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
};
memcpy(cmd + 1, pwd, 4);
memcpy(cmd + 7, data, 16);
AddCrc14A(cmd, sizeof(cmd) - 2);
ReaderTransmit(cmd, sizeof(cmd), NULL);
res = ReaderReceive(buf, par);
if ((res != 4) || (memcmp(buf, "\x90\x00\xfd\x07", 4) != 0)) {
retval = PM3_ESOFT;
}
if (done || retval != 0) iso14a_set_timeout(save_iso14a_timeout);
LED_B_OFF();
OUT:
reply_ng(CMD_HF_MIFARE_G4_WRBL, retval, buf, res);
// turns off
if (done || retval != 0) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
if (done || retval != 0) set_tracing(false);
BigBuf_free();
}

View file

@ -26,7 +26,7 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes);
void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
@ -46,18 +46,26 @@ void MifareEMemGet(uint8_t blockno, uint8_t blockcnt);
int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype);
int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype);
// MFC GEN1a /1b
void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); // Work with "magic Chinese" card
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain);
void MifareCIdent(bool is_mfc); // is "magic chinese" card?
void MifareHasStaticNonce(void); // Has the tag a static nonce?
// MFC GEN3
int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len);
void MifareGen3UID(uint8_t uidlen, uint8_t *uid); // Gen 3 magic card set UID without manufacturer block
void MifareGen3Blk(uint8_t block_len, uint8_t *block); // Gen 3 magic card overwrite manufacturer block
void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes
// MFC GEN4 GDM
void MifareReadConfigBlockGDM(uint8_t *key);
void MifareWriteConfigBlockGDM(uint8_t *datain);
void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t *datain);
// MFC GEN4 GTU
void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd);
void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd, uint8_t workFlags);
void MifareG4WriteBlk(uint8_t blockno, uint8_t *pwd, uint8_t *data, uint8_t workFlags);
void MifareSetMod(uint8_t *datain);
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);

View file

@ -139,6 +139,7 @@ void MifareDesfireGetInformation(void) {
uint8_t details[14];
} PACKED payload;
memset(&payload, 0x00, sizeof(payload));
/*
1 = PCB 1
2 = cid 2
@ -181,6 +182,12 @@ void MifareDesfireGetInformation(void) {
return;
}
if (len < sizeof(payload.versionHW) + 1) {
Dbprintf("Tag answer to MFDES_GET_VERSION was too short: data in Hardware Information is probably invalid.");
print_result("Answer", resp, len);
memset(resp + len, 0xFF, sizeof(payload.versionHW) + 1 - len); // clear remaining bytes
}
memcpy(payload.versionHW, resp + 1, sizeof(payload.versionHW));
// ADDITION_FRAME 1
@ -193,6 +200,13 @@ void MifareDesfireGetInformation(void) {
switch_off();
return;
}
if (len < sizeof(payload.versionSW) + 1) {
Dbprintf("Tag answer to MFDES_ADDITIONAL_FRAME 1 was too short: data in Software Information is probably invalid.");
print_result("Answer", resp, len);
memset(resp + len, 0xFF, sizeof(payload.versionSW) + 1 - len); // clear remaining bytes
}
memcpy(payload.versionSW, resp + 1, sizeof(payload.versionSW));
// ADDITION_FRAME 2
@ -205,6 +219,12 @@ void MifareDesfireGetInformation(void) {
return;
}
if (len < sizeof(payload.details) + 1) {
Dbprintf("Tag answer to MFDES_ADDITIONAL_FRAME 2 was too short: data in Batch number and Production date is probably invalid");
print_result("Answer", resp, len);
memset(resp + len, 0xFF, sizeof(payload.details) + 1 - len); // clear remaining bytes
}
memcpy(payload.details, resp + 1, sizeof(payload.details));
LED_B_ON();

View file

@ -486,6 +486,13 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
uint8_t *rats = NULL;
uint8_t rats_len = 0;
// if fct is called with NULL we need to assign some memory since this pointer is passaed around
uint8_t datain_tmp[10] = {0};
if (datain == NULL) {
datain = datain_tmp;
}
//Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2
// This will be used in the reader-only attack.

View file

@ -18,6 +18,7 @@
//-----------------------------------------------------------------------------
#include "mifareutil.h"
#include "appmain.h" // tearoff hook
#include "string.h"
#include "BigBuf.h"
#include "iso14443a.h"
@ -137,25 +138,25 @@ uint16_t mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested) {
return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL);
}
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) {
int len;
uint32_t pos, nt, ntpp; // Supplied tag nonce
uint8_t par[1] = {0x00};
return mifare_classic_authex_2(pcs, uid, blockNo, keyType, ui64Key, isNested, ntptr, timing, false);
}
int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing, bool is_gdm) {
// "random" reader nonce:
uint8_t nr[4];
uint8_t mf_nr_ar[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
num_to_bytes(prng_successor(GetTickCount(), 32), 4, nr);
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
// "random" reader nonce:
num_to_bytes(prng_successor(GetTickCount(), 32), 4, nr);
// Transmit MIFARE_CLASSIC_AUTH
len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, receivedAnswerPar, timing);
// Transmit MIFARE_CLASSIC_AUTH 0x60, 0x61 or GDM 0x80
uint8_t cmdbyte = (is_gdm) ? MIFARE_MAGIC_GDM_AUTH_KEY : MIFARE_AUTH_KEYA + (keyType & 0x01);
int len = mifare_sendcmd_short(pcs, isNested, cmdbyte, blockNo, receivedAnswer, receivedAnswerPar, timing);
if (len != 4) return 1;
// Save the tag nonce (nt)
nt = bytes_to_num(receivedAnswer, 4);
uint32_t nt = bytes_to_num(receivedAnswer, 4);
// ----------------------------- crypto1 create
if (isNested)
@ -181,7 +182,9 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
*ntptr = nt;
// Generate (encrypted) nr+parity by loading it into the cipher (Nr)
par[0] = 0;
uint32_t pos;
uint8_t par[1] = {0x00};
uint8_t mf_nr_ar[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
for (pos = 0; pos < 4; pos++) {
mf_nr_ar[pos] = crypto1_byte(pcs, nr[pos], 0) ^ nr[pos];
par[0] |= (((filter(pcs->odd) ^ oddparity8(nr[pos])) & 0x01) << (7 - pos));
@ -217,8 +220,8 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
return 2;
}
ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0, 0);
// Supplied tag nonce
uint32_t ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0, 0);
if (ntpp != bytes_to_num(receivedAnswer, 4)) {
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Authentication failed. Error card response");
return 3;
@ -227,13 +230,14 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
}
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) {
return mifare_classic_readblock_ex(pcs, uid, blockNo, blockData, ISO14443A_CMD_READBLOCK);
}
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t iso_byte) {
int len;
uint8_t bt[2] = {0x00, 0x00};
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
uint16_t len = mifare_sendcmd_short(pcs, 1, iso_byte, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if (len == 1) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error %02x", receivedAnswer[0]);
return 1;
@ -243,6 +247,7 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo
return 2;
}
uint8_t bt[2] = {0x00, 0x00};
memcpy(bt, receivedAnswer + 16, 2);
AddCrc14A(receivedAnswer, 16);
if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) {
@ -411,57 +416,114 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) {
}
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) {
// variables
uint16_t len = 0;
uint32_t pos = 0;
uint8_t par[3] = {0x00, 0x00, 0x00}; // enough for 18 Bytes to send
uint8_t res = 0;
return mifare_classic_writeblock_ex(pcs, uid, blockNo, blockData, false);
}
int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm) {
uint8_t d_block[18], d_block_enc[18];
// variables
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
// command MIFARE_CLASSIC_WRITEBLOCK
len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
// command MIFARE_MAGIC_GDM_WRITEBLOCK
uint16_t len;
if (is_gdm) {
len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
} else {
len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
}
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1;
}
uint8_t d_block[18], d_block_enc[18];
memcpy(d_block, blockData, 16);
AddCrc14A(d_block, 16);
// enough for 18 Bytes to send
uint8_t par[3] = {0x00, 0x00, 0x00};
// crypto
for (pos = 0; pos < 18; pos++) {
for (uint32_t pos = 0; pos < 18; pos++) {
d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos];
par[pos >> 3] |= (((filter(pcs->odd) ^ oddparity8(d_block[pos])) & 0x01) << (7 - (pos & 0x0007)));
}
ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL);
// Receive the response
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
// tearoff occurred
if (tearoff_hook() == PM3_ETEAROFF) {
return PM3_ETEAROFF;
} else {
// Receive the response
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
res = 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
uint8_t res = 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
if ((len != 1) || (res != 0x0A)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
return 2;
if ((len != 1) || (res != 0x0A)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
return 2;
}
}
return 0;
}
int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, uint8_t *blockData) {
// variables
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
uint16_t len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITE_CFG, 0, receivedAnswer, receivedAnswerPar, NULL);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) {
return 1;
}
uint8_t d_block[18], d_block_enc[18];
memcpy(d_block, blockData, 16);
AddCrc14A(d_block, 16);
// enough for 18 Bytes to send
uint8_t par[3] = {0x00, 0x00, 0x00};
// crypto
for (uint32_t pos = 0; pos < 18; pos++) {
d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos];
par[pos >> 3] |= (((filter(pcs->odd) ^ oddparity8(d_block[pos])) & 0x01) << (7 - (pos & 0x0007)));
}
ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL);
// tearoff occurred
if (tearoff_hook() == PM3_ETEAROFF) {
return PM3_ETEAROFF;
} else {
// Receive the response
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
uint8_t res = 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
if ((len != 1) || (res != 0x0A)) {
return 2;
}
}
return 0;
}
int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action) {
// variables
uint16_t len = 0;
uint32_t pos = 0;
uint8_t par[3] = {0x00, 0x00, 0x00}; // enough for 18 Bytes to send
uint8_t res = 0;
uint8_t d_block[18], d_block_enc[18];
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
@ -471,6 +533,8 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
if (action == 0x01)
command = MIFARE_CMD_DEC;
if (action == 0x02)
command = MIFARE_CMD_RESTORE;
// Send increment or decrement command
len = mifare_sendcmd_short(pcs, 1, command, blockNo, receivedAnswer, receivedAnswerPar, NULL);
@ -495,7 +559,7 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
if (len != 0) { // Something not right, len == 0 (no response is ok as its waiting for transfer
res = 0;
uint8_t res = 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2;
@ -505,13 +569,6 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
return 2;
}
} else {
// send trnasfer (commit the change)
len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_TRANSFER, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1;
}
}
return 0;

View file

@ -72,11 +72,17 @@ uint16_t mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t
// mifare classic
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested);
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing);
int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing, bool is_gdm);
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t iso_byte);
int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid);
int mifare_classic_halt_ex(struct Crypto1State *pcs);
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm);
int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action);
int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, uint8_t *blockData);
// Ultralight/NTAG...
int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack);

View file

@ -39,14 +39,14 @@
typedef struct {
uint8_t *buffer;
uint8_t numbits;
uint8_t position;
uint32_t numbits;
uint32_t position;
} BitstreamIn_t;
typedef struct {
uint8_t *buffer;
uint8_t numbits;
uint8_t position;
uint32_t numbits;
uint32_t position;
} BitstreamOut_t;
bool headBit(BitstreamIn_t *stream);

View file

@ -18,7 +18,7 @@
// SPIFFS api for RDV40 Integration
//-----------------------------------------------------------------------------
#define SPIFFS_CFG_PHYS_SZ (1024 * 128)
#define SPIFFS_CFG_PHYS_SZ (1024 * 192)
#define SPIFFS_CFG_PHYS_ERASE_SZ (4 * 1024)
#define SPIFFS_CFG_PHYS_ADDR (0)
#define SPIFFS_CFG_LOG_PAGE_SZ (256)
@ -69,7 +69,7 @@ static s32_t rdv40_spiffs_llread(u32_t addr, u32_t size, u8_t *dst) {
static s32_t rdv40_spiffs_llwrite(u32_t addr, u32_t size, u8_t *src) {
if (!FlashInit()) {
if (FlashInit() == false) {
return 129;
}
Flash_Write(addr, src, size);
@ -77,9 +77,7 @@ static s32_t rdv40_spiffs_llwrite(u32_t addr, u32_t size, u8_t *src) {
}
static s32_t rdv40_spiffs_llerase(u32_t addr, u32_t size) {
uint8_t erased = 0;
if (!FlashInit()) {
if (FlashInit() == false) {
return 130;
}
@ -99,10 +97,12 @@ static s32_t rdv40_spiffs_llerase(u32_t addr, u32_t size) {
if (g_dbglevel >= DBG_DEBUG) Dbprintf("LLERASEDBG : block : %d, sector : %d \n", block, sector);
erased = Flash_Erase4k(block, sector);
uint8_t erased = Flash_Erase4k(block, sector);
Flash_CheckBusy(BUSY_TIMEOUT);
FlashStop();
// iceman: SPIFFS_OK expands to 0, erased is bool from Flash_Erase4k, which returns TRUE if ok.
// so this return logic looks wrong.
return (SPIFFS_OK == erased);
}
@ -151,8 +151,17 @@ int rdv40_spiffs_mount(void) {
// uncached version
// int ret = SPIFFS_mount(&fs, &cfg, spiffs_work_buf, spiffs_fds,
// sizeof(spiffs_fds), 0, 0, 0); cached version, experimental
int ret = SPIFFS_mount(&fs, &cfg, spiffs_work_buf, spiffs_fds, sizeof(spiffs_fds), spiffs_cache_buf,
sizeof(spiffs_cache_buf), 0);
int ret = SPIFFS_mount(
&fs,
&cfg,
spiffs_work_buf,
spiffs_fds,
sizeof(spiffs_fds),
spiffs_cache_buf,
sizeof(spiffs_cache_buf),
0
);
if (ret == SPIFFS_OK) {
RDV40_SPIFFS_MOUNT_STATUS = RDV40_SPIFFS_MOUNTED;
}
@ -189,33 +198,38 @@ int rdv40_spiffs_check(void) {
void write_to_spiffs(const char *filename, uint8_t *src, uint32_t size) {
spiffs_file fd = SPIFFS_open(&fs, filename, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);
if (SPIFFS_write(&fs, fd, src, size) < 0)
Dbprintf("errno %i\n", SPIFFS_errno(&fs));
if (SPIFFS_write(&fs, fd, src, size) < 0) {
Dbprintf("wr errno %i\n", SPIFFS_errno(&fs));
}
SPIFFS_close(&fs, fd);
}
void append_to_spiffs(const char *filename, uint8_t *src, uint32_t size) {
spiffs_file fd = SPIFFS_open(&fs, filename, SPIFFS_APPEND | SPIFFS_RDWR, 0);
if (SPIFFS_write(&fs, fd, src, size) < 0)
if (SPIFFS_write(&fs, fd, src, size) < 0) {
Dbprintf("errno %i\n", SPIFFS_errno(&fs));
}
SPIFFS_close(&fs, fd);
}
void read_from_spiffs(const char *filename, uint8_t *dst, uint32_t size) {
spiffs_file fd = SPIFFS_open(&fs, filename, SPIFFS_RDWR, 0);
if (SPIFFS_read(&fs, fd, dst, size) < 0)
if (SPIFFS_read(&fs, fd, dst, size) < 0) {
Dbprintf("errno %i\n", SPIFFS_errno(&fs));
}
SPIFFS_close(&fs, fd);
}
static void rename_in_spiffs(const char *old_filename, const char *new_filename) {
if (SPIFFS_rename(&fs, old_filename, new_filename) < 0)
if (SPIFFS_rename(&fs, old_filename, new_filename) < 0) {
Dbprintf("errno %i\n", SPIFFS_errno(&fs));
}
}
static void remove_from_spiffs(const char *filename) {
if (SPIFFS_remove(&fs, filename) < 0)
if (SPIFFS_remove(&fs, filename) < 0) {
Dbprintf("errno %i\n", SPIFFS_errno(&fs));
}
}
uint32_t size_in_spiffs(const char *filename) {
@ -233,8 +247,11 @@ static rdv40_spiffs_fsinfo info_of_spiffs(void) {
fsinfo.pageSize = LOG_PAGE_SIZE;
fsinfo.maxOpenFiles = RDV40_SPIFFS_MAX_FD;
fsinfo.maxPathLength = SPIFFS_OBJ_NAME_LEN;
if (SPIFFS_info(&fs, &fsinfo.totalBytes, &fsinfo.usedBytes) < 0)
if (SPIFFS_info(&fs, &fsinfo.totalBytes, &fsinfo.usedBytes) < 0) {
Dbprintf("errno %i\n", SPIFFS_errno(&fs));
}
fsinfo.freeBytes = fsinfo.totalBytes - fsinfo.usedBytes;
// Rounding without float may be improved
fsinfo.usedPercent = ((100 * fsinfo.usedBytes) + (fsinfo.totalBytes / 2)) / fsinfo.totalBytes;
@ -245,16 +262,18 @@ static rdv40_spiffs_fsinfo info_of_spiffs(void) {
int exists_in_spiffs(const char *filename) {
spiffs_stat stat;
int rc = SPIFFS_stat(&fs, filename, &stat);
return rc == SPIFFS_OK;
return (rc == SPIFFS_OK);
}
static RDV40SpiFFSFileType filetype_in_spiffs(const char *filename) {
RDV40SpiFFSFileType filetype = RDV40_SPIFFS_FILETYPE_UNKNOWN;
char symlinked[SPIFFS_OBJ_NAME_LEN];
sprintf(symlinked, "%s.lnk", filename);
if (exists_in_spiffs(filename)) {
filetype = RDV40_SPIFFS_FILETYPE_REAL;
}
if (exists_in_spiffs(symlinked)) {
if (filetype != RDV40_SPIFFS_FILETYPE_UNKNOWN) {
filetype = RDV40_SPIFFS_FILETYPE_BOTH;
@ -262,19 +281,20 @@ static RDV40SpiFFSFileType filetype_in_spiffs(const char *filename) {
filetype = RDV40_SPIFFS_FILETYPE_SYMLINK;
}
}
if (g_dbglevel >= DBG_DEBUG) {
switch (filetype) {
case RDV40_SPIFFS_FILETYPE_REAL:
Dbprintf("Filetype is : RDV40_SPIFFS_FILETYPE_REAL");
Dbprintf("Filetype is " _YELLOW_("RDV40_SPIFFS_FILETYPE_REAL"));
break;
case RDV40_SPIFFS_FILETYPE_SYMLINK:
Dbprintf("Filetype is : RDV40_SPIFFS_FILETYPE_SYMLINK");
Dbprintf("Filetype is " _YELLOW_("RDV40_SPIFFS_FILETYPE_SYMLINK"));
break;
case RDV40_SPIFFS_FILETYPE_BOTH:
Dbprintf("Filetype is : RDV40_SPIFFS_FILETYPE_BOTH");
Dbprintf("Filetype is " _YELLOW_("RDV40_SPIFFS_FILETYPE_BOTH"));
break;
case RDV40_SPIFFS_FILETYPE_UNKNOWN:
Dbprintf("Filetype is : RDV40_SPIFFS_FILETYPE_UNKNOWN");
Dbprintf("Filetype is " _YELLOW_("RDV40_SPIFFS_FILETYPE_UNKNOWN"));
break;
}
}
@ -386,10 +406,13 @@ just get back to this state. If not, just don't.
// went well, it will return SPIFFS_OK if everything went well, and a report
// back the chain a SPI_ERRNO if not.
int rdv40_spiffs_lazy_mount_rollback(int changed) {
if (!changed)
if (!changed) {
return SPIFFS_OK;
if (rdv40_spiffs_mounted())
}
if (rdv40_spiffs_mounted()) {
return rdv40_spiffs_unmount();
}
return rdv40_spiffs_mount();
}
///////////////////////////////////////////////////////////////////////////////
@ -410,15 +433,41 @@ int rdv40_spiffs_lazy_mount_rollback(int changed) {
// statement or some function taking function parameters
// TODO : forbid writing to a filename which already exists as lnk !
// TODO : forbid writing to a filename.lnk which already exists without lnk !
// Note: Writing in SPIFFS_WRITE_CHUNK_SIZE (8192) byte chucks helps to ensure "free space" has been erased by GC (Garbage collection)
int rdv40_spiffs_write(const char *filename, uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level) {
RDV40_SPIFFS_SAFE_FUNCTION(
write_to_spiffs(filename, src, size);
uint32_t idx;
if (size <= SPIFFS_WRITE_CHUNK_SIZE) {
// write small file
write_to_spiffs(filename, src, size);
size = 0;
} else { //
// write first SPIFFS_WRITE_CHUNK_SIZE bytes
// need to write the first chuck of data, then append
write_to_spiffs(filename, src, SPIFFS_WRITE_CHUNK_SIZE);
}
// append remaing SPIFFS_WRITE_CHUNK_SIZE byte chuncks
for (idx = 1; idx < (size / SPIFFS_WRITE_CHUNK_SIZE); idx++) {
append_to_spiffs(filename, &src[SPIFFS_WRITE_CHUNK_SIZE * idx], SPIFFS_WRITE_CHUNK_SIZE);
}
// append remaing bytes
if (((int64_t)size - (SPIFFS_WRITE_CHUNK_SIZE * idx)) > 0) {
append_to_spiffs(filename, &src[SPIFFS_WRITE_CHUNK_SIZE * idx], size - (SPIFFS_WRITE_CHUNK_SIZE * idx));
}
)
}
int rdv40_spiffs_append(const char *filename, uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level) {
RDV40_SPIFFS_SAFE_FUNCTION(
append_to_spiffs(filename, src, size);
uint32_t idx;
// Append any SPIFFS_WRITE_CHUNK_SIZE byte chunks
for (idx = 0; idx < (size / SPIFFS_WRITE_CHUNK_SIZE); idx++) {
append_to_spiffs(filename, &src[SPIFFS_WRITE_CHUNK_SIZE * idx], SPIFFS_WRITE_CHUNK_SIZE);
}
// Append remain bytes
if (((int64_t)size - (SPIFFS_WRITE_CHUNK_SIZE * idx)) > 0) {
append_to_spiffs(filename, &src[SPIFFS_WRITE_CHUNK_SIZE * idx], size - (SPIFFS_WRITE_CHUNK_SIZE * idx));
}
)
}
@ -433,24 +482,24 @@ int rdv40_spiffs_read(const char *filename, uint8_t *dst, uint32_t size, RDV40Sp
// TODO : forbid writing to a filename.lnk which already exists without lnk !
int rdv40_spiffs_rename(char *old_filename, char *new_filename, RDV40SpiFFSSafetyLevel level) {
RDV40_SPIFFS_SAFE_FUNCTION( //
rename_in_spiffs((char *)old_filename, (char *)new_filename); //
rename_in_spiffs(old_filename, new_filename); //
)
}
int rdv40_spiffs_remove(char *filename, RDV40SpiFFSSafetyLevel level) {
RDV40_SPIFFS_SAFE_FUNCTION( //
remove_from_spiffs((char *)filename); //
remove_from_spiffs(filename); //
)
}
int rdv40_spiffs_copy(char *src, char *dst, RDV40SpiFFSSafetyLevel level) {
RDV40_SPIFFS_SAFE_FUNCTION( //
copy_in_spiffs((char *)src, (char *)dst); //
copy_in_spiffs(src, dst); //
)
}
int rdv40_spiffs_stat(char *filename, uint32_t *buf, RDV40SpiFFSSafetyLevel level) {
RDV40_SPIFFS_SAFE_FUNCTION( //
*buf = size_in_spiffs((char *)filename); //
*buf = size_in_spiffs(filename); //
)
}
@ -489,12 +538,12 @@ int rdv40_spiffs_read_as_symlink(char *filename, uint8_t *dst, uint32_t size, RD
sprintf(linkfilename, "%s.lnk", filename);
if (g_dbglevel >= DBG_DEBUG)
Dbprintf("Linkk real filename is : " _YELLOW_("%s"), linkfilename);
Dbprintf("Linkk real filename is " _YELLOW_("%s"), linkfilename);
read_from_spiffs((char *)linkfilename, (uint8_t *)linkdest, SPIFFS_OBJ_NAME_LEN);
if (g_dbglevel >= DBG_DEBUG)
Dbprintf("Symlink destination is : " _YELLOW_("%s"), linkdest);
Dbprintf("Symlink destination is " _YELLOW_("%s"), linkdest);
read_from_spiffs((char *)linkdest, (uint8_t *)dst, size);
)
@ -534,12 +583,12 @@ int rdv40_spiffs_read_as_filetype(char *filename, uint8_t *dst, uint32_t size, R
rdv40_spiffs_read((char *)filename, (uint8_t *)dst, size, level);
break;
case RDV40_SPIFFS_FILETYPE_SYMLINK:
rdv40_spiffs_read_as_symlink((char *)filename, (uint8_t *)dst, size, level);
rdv40_spiffs_read_as_symlink(filename, (uint8_t *)dst, size, level);
break;
case RDV40_SPIFFS_FILETYPE_BOTH:
case RDV40_SPIFFS_FILETYPE_UNKNOWN:
default:
;
break;
}
)
}
@ -559,18 +608,20 @@ void rdv40_spiffs_safe_print_fsinfo(void) {
rdv40_spiffs_fsinfo fsinfo;
rdv40_spiffs_getfsinfo(&fsinfo, RDV40_SPIFFS_SAFETY_SAFE);
Dbprintf(" Logical block size......... " _YELLOW_("%d")" bytes", fsinfo.blockSize);
Dbprintf(" Logical page size.......... " _YELLOW_("%d")" bytes", fsinfo.pageSize);
Dbprintf(" Max open files............. " _YELLOW_("%d")" file descriptors", fsinfo.maxOpenFiles);
Dbprintf(" Max path length............ " _YELLOW_("%d")" chars", fsinfo.maxPathLength);
Dbprintf(" Logical block size... " _YELLOW_("%d")" bytes", fsinfo.blockSize);
Dbprintf(" Logical page size.... " _YELLOW_("%d")" bytes", fsinfo.pageSize);
Dbprintf(" Max open files....... " _YELLOW_("%d")" file descriptors", fsinfo.maxOpenFiles);
Dbprintf(" Max path length...... " _YELLOW_("%d")" chars", fsinfo.maxPathLength);
DbpString("");
Dbprintf(" Filesystem size used available use% mounted");
DbpString("------------------------------------------------------------------");
Dbprintf(" spiffs %6d B %6d B %6d B " _YELLOW_("%2d%")" /"
, fsinfo.totalBytes
, fsinfo.usedBytes
, fsinfo.freeBytes
, fsinfo.usedPercent
);
DbpString("");
}
// this function is safe and WILL rollback since it is only a PRINTING function,

View file

@ -24,7 +24,11 @@ extern "C" {
#include "spiffs_config.h"
typedef enum spiffs_safety_level { RDV40_SPIFFS_SAFETY_NORMAL, RDV40_SPIFFS_SAFETY_LAZY, RDV40_SPIFFS_SAFETY_SAFE } RDV40SpiFFSSafetyLevel;
typedef enum spiffs_safety_level {
RDV40_SPIFFS_SAFETY_NORMAL,
RDV40_SPIFFS_SAFETY_LAZY,
RDV40_SPIFFS_SAFETY_SAFE
} RDV40SpiFFSSafetyLevel;
typedef enum spiffs_file_type {
RDV40_SPIFFS_FILETYPE_REAL,
@ -125,6 +129,8 @@ void rdv40_spiffs_safe_wipe(void);
#define SPIFFS_ERR_TEST -10100
// Amount of data to write/append to a file in one go.
#define SPIFFS_WRITE_CHUNK_SIZE 8192
// spiffs file descriptor index type. must be signed
typedef s16_t spiffs_file;
@ -198,16 +204,16 @@ typedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op,
#ifndef SPIFFS_DBG
#define SPIFFS_DBG(...) \
printf(__VA_ARGS__)
Dbprintf(__VA_ARGS__)
#endif
#ifndef SPIFFS_GC_DBG
#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__)
#define SPIFFS_GC_DBG(...) Dbprintf(__VA_ARGS__)
#endif
#ifndef SPIFFS_CACHE_DBG
#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__)
#define SPIFFS_CACHE_DBG(...) Dbprintf(__VA_ARGS__)
#endif
#ifndef SPIFFS_CHECK_DBG
#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__)
#define SPIFFS_CHECK_DBG(...) Dbprintf(__VA_ARGS__)
#endif
/* Any write to the filehandle is appended to end of the file */

View file

@ -136,7 +136,7 @@ typedef uint8_t u8_t;
// Define maximum number of gc runs to perform to reach desired free pages.
#ifndef SPIFFS_GC_MAX_RUNS
#define SPIFFS_GC_MAX_RUNS 5
#define SPIFFS_GC_MAX_RUNS 10
#endif
// Enable/disable statistics on gc. Debug/test purpose only.
@ -236,7 +236,7 @@ typedef uint8_t u8_t;
// Instead of giving parameters in config struct, singleton build must
// give parameters in defines below.
#ifndef SPIFFS_CFG_PHYS_SZ
#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*128)
#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*192)
#endif
#ifndef SPIFFS_CFG_PHYS_ERASE_SZ
#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (4*1024)

View file

@ -34,11 +34,17 @@ VERSIONSRC = version_pm3.c
# THUMBSRC :=
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
APP_CFLAGS = -I. -ffunction-sections -fdata-sections
APP_CFLAGS = -I. -ffunction-sections -fdata-sections -DAS_BOOTROM
# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc, no-common makes sure uninitialized vars don't end up in COMMON area
APP_CFLAGS += -fno-stack-protector -fno-pie -fno-common
ifneq (,$(findstring WITH_FLASH,$(PLATFORM_DEFS)))
APP_CFLAGS += -DWITH_FLASH
APP_CFLAGS += -I../common_arm
THUMBSRC += flashmem.c ticks.c
endif
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
include ../common_arm/Makefile.common
@ -48,7 +54,7 @@ INSTALLFW = $(OBJDIR)/bootrom.elf
OBJS = $(OBJDIR)/bootrom.s19
# version_pm3.c should be remade on every compilation
version_pm3.c: default_version_pm3.c
version_pm3.c: default_version_pm3.c .FORCE
$(info [=] GEN $@)
$(Q)$(SH) ../tools/mkversion.sh > $@ || $(PERL) ../tools/mkversion.pl > $@ || $(CP) $< $@
@ -82,7 +88,7 @@ uninstall:
$(info [@] Uninstalling bootrom from $(DESTDIR)$(PREFIX)...)
$(Q)$(INSTALLSUDO) $(RM) $(foreach fw,$(INSTALLFW),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(notdir $(fw)))
.PHONY: all clean help install showinfo
.PHONY: all clean help install showinfo .FORCE
help:
@echo Multi-OS Makefile, you are running on $(DETECTED_OS)
@echo Possible targets:

View file

@ -20,6 +20,10 @@
#include "clocks.h"
#include "usb_cdc.h"
#ifdef WITH_FLASH
#include "flashmem.h"
#endif
#include "proxmark3_arm.h"
#define DEBUG 0
@ -214,8 +218,18 @@ static void flash_mode(void) {
bootrom_unlocked = false;
uint8_t rx[sizeof(PacketCommandOLD)];
g_common_area.command = COMMON_AREA_COMMAND_NONE;
if (!g_common_area.flags.button_pressed && BUTTON_PRESS())
if (!g_common_area.flags.button_pressed && BUTTON_PRESS()) {
g_common_area.flags.button_pressed = 1;
}
#ifdef WITH_FLASH
if (FlashInit()) { // checks for existence of flash also ... OK because bootrom was built for devices with flash
uint64_t flash_uniqueID = 0;
Flash_UniqueID((uint8_t *)&flash_uniqueID);
FlashStop();
usb_update_serial(flash_uniqueID);
}
#endif
usb_enable();
@ -296,10 +310,10 @@ void BootROM(void) {
LED_B_OFF();
LED_A_OFF();
// Set the first 256kb memory flashspeed
// Set the first 256KB memory flashspeed
AT91C_BASE_EFC0->EFC_FMR = AT91C_MC_FWS_1FWS | MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48);
// 9 = 256, 10+ is 512kb
// 9 = 256, 10+ is 512KB
uint8_t id = (*(AT91C_DBGU_CIDR) & 0xF00) >> 8;
if (id > 9)
AT91C_BASE_EFC1->EFC_FMR = AT91C_MC_FWS_1FWS | MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48);

View file

@ -53,6 +53,7 @@ SECTIONS
*(.rodata.*)
*(.data)
*(.data.*)
*(.ramfunc)
. = ALIGN(4);
} >ram AT>bootphase2 :phase2

View file

@ -121,7 +121,7 @@ if (NOT SKIPREADLINE EQUAL 1)
ExternalProject_Add_StepTargets(ncurses configure build install)
ExternalProject_Add(readline
URL ftp://ftp.gnu.org/gnu/readline/readline-8.1.tar.gz
URL ftp://ftp.gnu.org/gnu/readline/readline-8.2.tar.gz
PREFIX deps/readline
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/readline
CONFIGURE_COMMAND ./configure CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} LD=${CMAKE_C_COMPILER} AR=${CMAKE_AR} RANLIB=${CMAKE_RANLIB} ${CFLAGS_EXTERNAL_LIB} --host=arm --enable-static
@ -163,11 +163,12 @@ endif (NOT SKIPJANSSONSYSTEM EQUAL 1)
if(EMBED_BZIP2)
set(BZIP2_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/deps/bzip2/src/bzip2)
# Specify SOURCE_DIR will cause some errors
ExternalProject_Add(bzip2
GIT_REPOSITORY https://android.googlesource.com/platform/external/bzip2
GIT_TAG platform-tools-30.0.2
PREFIX deps/bzip2
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/bzip2
# SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/bzip2
CONFIGURE_COMMAND mkdir -p ${BZIP2_BUILD_DIR} && git archive --format tar HEAD | tar -C ${BZIP2_BUILD_DIR} -x
BUILD_IN_SOURCE ON
BUILD_COMMAND make -C ${BZIP2_BUILD_DIR} -j4 CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} LD=${CMAKE_C_COMPILER} AR=${CMAKE_AR} RANLIB=${CMAKE_RANLIB} ${CFLAGS_EXTERNAL_LIB} libbz2.a
@ -275,6 +276,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdhfepa.c
${PM3_ROOT}/client/src/cmdhffelica.c
${PM3_ROOT}/client/src/cmdhffido.c
${PM3_ROOT}/client/src/cmdhffudan.c
${PM3_ROOT}/client/src/cmdhfgallagher.c
${PM3_ROOT}/client/src/cmdhfcipurse.c
${PM3_ROOT}/client/src/cmdhficlass.c
@ -292,9 +294,12 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdhfseos.c
${PM3_ROOT}/client/src/cmdhfst.c
${PM3_ROOT}/client/src/cmdhfst25ta.c
${PM3_ROOT}/client/src/cmdhftesla.c
${PM3_ROOT}/client/src/cmdhftexkom.c
${PM3_ROOT}/client/src/cmdhfthinfilm.c
${PM3_ROOT}/client/src/cmdhftopaz.c
${PM3_ROOT}/client/src/cmdhfwaveshare.c
${PM3_ROOT}/client/src/cmdhfxerox.c
${PM3_ROOT}/client/src/cmdhw.c
${PM3_ROOT}/client/src/cmdlf.c
${PM3_ROOT}/client/src/cmdlfawid.c
@ -333,6 +338,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdmain.c
${PM3_ROOT}/client/src/cmdnfc.c
${PM3_ROOT}/client/src/cmdparser.c
${PM3_ROOT}/client/src/cmdpiv.c
${PM3_ROOT}/client/src/cmdscript.c
${PM3_ROOT}/client/src/cmdsmartcard.c
${PM3_ROOT}/client/src/cmdtrace.c
@ -579,6 +585,9 @@ if (MINGW)
set(CMAKE_C_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_CXX_FLAGS}")
# link Winsock2
set(ADDITIONAL_LNK ws2_32 ${ADDITIONAL_LNK})
endif (MINGW)
target_include_directories(proxmark3 PRIVATE

View file

@ -37,8 +37,7 @@ OBJDIR = obj
ifeq ($(USE_BREW),1)
INCLUDES += -I$(BREW_PREFIX)/include
LDLIBS += -L$(BREW_PREFIX)/lib
PKG_CONFIG_ENV := PKG_CONFIG_PATH=$(BREW_PREFIX)/opt/qt/lib/pkgconfig
PKG_CONFIG_ENV := PKG_CONFIG_PATH=$(BREW_PREFIX)/opt/qt5/lib/pkgconfig
PKG_CONFIG_ENV := PKG_CONFIG_PATH=$(BREW_PREFIX)/lib/pkgconfig:$(BREW_PREFIX)/opt/qt/lib/pkgconfig:$(BREW_PREFIX)/opt/qt5/lib/pkgconfig
endif
ifdef ($(USE_MACPORTS),1)
@ -94,7 +93,6 @@ LUALIBLD =
LUAPLATFORM = generic
ifneq (,$(findstring MINGW,$(platform)))
LUAPLATFORM = mingw
LDLIBS += -lws2_32
else
ifeq ($(platform),Darwin)
LUAPLATFORM = macosx
@ -104,6 +102,11 @@ else
endif
endif
## Winsock2
ifneq (,$(findstring MINGW,$(platform)))
LDLIBS += -lws2_32
endif
## Reveng
REVENGLIBPATH = ./deps/reveng
REVENGLIBINC = -I$(REVENGLIBPATH)
@ -290,6 +293,7 @@ ifneq ($(SKIPQT),1)
QTLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs Qt5Core Qt5Widgets 2>/dev/null)
MOC = $(shell $(PKG_CONFIG_ENV) pkg-config --variable=host_bins Qt5Core)/moc
UIC = $(shell $(PKG_CONFIG_ENV) pkg-config --variable=host_bins Qt5Core)/uic
QMAKE = $(shell $(PKG_CONFIG_ENV) pkg-config --variable=host_bins Qt5Core)/qmake
ifneq ($(QTLDLIBS),)
QT5_FOUND = 1
else
@ -298,6 +302,7 @@ ifneq ($(SKIPQT),1)
QTLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs QtCore QtGui 2>/dev/null)
MOC = $(shell $(PKG_CONFIG_ENV) pkg-config --variable=moc_location QtCore)
UIC = $(shell $(PKG_CONFIG_ENV) pkg-config --variable=uic_location QtCore)
QMAKE = $(shell $(PKG_CONFIG_ENV) pkg-config --variable=exec_prefix QtCore)/bin/qmake
endif
ifeq ($(QTLDLIBS),)
# if both pkg-config commands failed, search in common places
@ -314,6 +319,7 @@ ifneq ($(SKIPQT),1)
endif
MOC = $(QTDIR)/bin/moc
UIC = $(QTDIR)/bin/uic
QMAKE = $(QTDIR)/bin/qmake
endif
endif
ifneq ($(QTLDLIBS),)
@ -363,9 +369,11 @@ endif
#######################################################################################################
CFLAGS ?= $(DEFCFLAGS)
CFLAGS += $(MYDEFS) $(MYCFLAGS) $(MYINCLUDES)
# We cannot just use CFLAGS+=... because it has impact on sub-makes if CFLAGS is defined in env:
PM3CFLAGS = $(CFLAGS)
PM3CFLAGS += -I./src -I./include -I../include -I../common -I../common_fpga $(PM3INCLUDES) $(INCLUDES)
PM3CFLAGS += -g -I./src -I./include -I../include -I../common -I../common_fpga $(PM3INCLUDES) $(INCLUDES)
# WIP Testing
#PM3CFLAGS += -std=c11 -pedantic
@ -405,6 +413,8 @@ endif
PM3CFLAGS += -DHAVE_SNPRINTF
CXXFLAGS ?= -Wall -Werror -O3
CXXFLAGS += $(MYDEFS) $(MYCXXFLAGS) $(MYINCLUDES)
PM3CXXFLAGS = $(CXXFLAGS)
PM3CXXFLAGS += -I../include -I./include
@ -420,6 +430,8 @@ endif
PM3CXXFLAGS += -DHAVE_SNPRINTF
LDFLAGS ?= $(DEFLDFLAGS)
LDFLAGS += $(MYLDFLAGS)
PM3LDFLAGS = $(LDFLAGS)
ifeq ($(platform),Darwin)
PM3LDFLAGS += -framework Foundation -framework AppKit
@ -438,9 +450,9 @@ ifeq ($(SKIPQT),1)
else
ifeq ($(QT_FOUND),1)
ifeq ($(QT5_FOUND),1)
$(info GUI support: QT5 found, enabled ($(shell QT_SELECT=5 qmake -v 2>/dev/null|grep -o 'Qt version.*')))
$(info GUI support: QT5 found, enabled ($(shell QT_SELECT=5 $(QMAKE) -v 2>/dev/null|grep -o 'Qt version.*')))
else
$(info GUI support: QT4 found, enabled ($(shell QT_SELECT=4 qmake -v 2>/dev/null|grep -o 'Qt version.*')))
$(info GUI support: QT4 found, enabled ($(shell QT_SELECT=4 $(QMAKE) -v 2>/dev/null|grep -o 'Qt version.*')))
endif
else
$(info GUI support: QT not found, disabled)
@ -479,7 +491,7 @@ ifeq ($(SKIPPYTHON),1)
$(info Python3 library: skipped)
else
ifeq ($(PYTHON_FOUND),1)
$(info Python3 library: Python3 v$(shell pkg-config --modversion python3) found, enabled)
$(info Python3 library: Python3 v$(shell $(PKG_CONFIG_ENV) pkg-config --modversion python3) found, enabled)
else
$(info Python3 library: Python3 not found, disabled)
endif
@ -557,6 +569,7 @@ SRCS = mifare/aiddesfire.c \
cmdhfemrtd.c \
cmdhffelica.c \
cmdhffido.c \
cmdhffudan.c \
cmdhfgallagher.c \
cmdhfksx6924.c \
cmdhfcipurse.c \
@ -574,9 +587,12 @@ SRCS = mifare/aiddesfire.c \
cmdhfseos.c \
cmdhfst.c \
cmdhfst25ta.c \
cmdhftesla.c \
cmdhfthinfilm.c \
cmdhftopaz.c \
cmdhftexkom.c \
cmdhfwaveshare.c \
cmdhfxerox.c \
cmdhw.c \
cmdlf.c \
cmdlfawid.c \
@ -615,6 +631,7 @@ SRCS = mifare/aiddesfire.c \
cmdmain.c \
cmdnfc.c \
cmdparser.c \
cmdpiv.c \
cmdscript.c \
cmdsmartcard.c \
cmdtrace.c \
@ -747,8 +764,9 @@ all-static: LDLIBS:=-static $(LDLIBS)
all-static: $(BINS)
proxmark3: $(OBJS) $(STATICLIBS) lualibs/pm3_cmd.lua lualibs/mfc_default_keys.lua
$(info [=] LD $@)
$(Q)$(LD) $(PM3LDFLAGS) $(OBJS) $(STATICLIBS) $(LDLIBS) -o $@
$(info [=] CXX $@)
# $(Q)$(CXX) $(PM3LDFLAGS) $(OBJS) $(STATICLIBS) $(LDLIBS) -o $@
$(Q)$(CXX) $(PM3CFLAGS) $(PM3LDFLAGS) $(OBJS) $(STATICLIBS) $(LDLIBS) -o $@
src/proxgui.cpp: src/ui/ui_overlays.h src/ui/ui_image.h

View file

@ -11,10 +11,10 @@
#include "cliparser.h"
#include <string.h>
#include <stdlib.h>
#include <util.h> // Get color constants
#include <ui.h> // get PrintAndLogEx
#include <ctype.h> // tolower
#include <inttypes.h> // PRIu64
#include <util.h> // color constants
#include <ui.h> // PrintAndLogEx
#include <ctype.h> // tolower
#include <inttypes.h> // PRIu64
#ifndef ARRAYLEN
# define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0]))
@ -22,10 +22,10 @@
// Custom Colors
// To default the color return s
#define _SectionTagColor_(s) _GREEN_(s)
#define _ExampleColor_(s) _YELLOW_(s)
#define _CommandColor_(s) _RED_(s)
#define _DescriptionColor_(s) _CYAN_(s)
#define _SectionTagColor_(s) _GREEN_(s)
#define _ExampleColor_(s) _YELLOW_(s)
#define _CommandColor_(s) _RED_(s)
#define _DescriptionColor_(s) _CYAN_(s)
#define _ArgColor_(s) s
#define _ArgHelpColor_(s) s
// End Custom Colors
@ -33,66 +33,79 @@
// Example width set to 50 to allow help descriptions to align. approx line 93
int CLIParserInit(CLIParserContext **ctx, const char *vprogramName, const char *vprogramHint, const char *vprogramHelp) {
*ctx = malloc(sizeof(CLIParserContext));
if (!*ctx) {
*ctx = calloc(sizeof(CLIParserContext), sizeof(uint8_t));
if (*ctx == NULL) {
PrintAndLogEx(ERR, "ERROR: Insufficient memory\n");
return 2;
}
(*ctx)->argtable = NULL;
(*ctx)->argtableLen = 0;
(*ctx)->programName = vprogramName;
(*ctx)->programHint = vprogramHint;
(*ctx)->programHelp = vprogramHelp;
memset((*ctx)->buf, 0x00, sizeof((*ctx)->buf));
return 0;
return PM3_SUCCESS;
}
void CLIParserPrintHelp(CLIParserContext *ctx) {
if (ctx->programHint)
if (ctx->programHint) {
PrintAndLogEx(NORMAL, "\n"_DescriptionColor_("%s"), ctx->programHint);
}
PrintAndLogEx(NORMAL, "\n"_SectionTagColor_("usage:"));
PrintAndLogEx(NORMAL, " "_CommandColor_("%s")NOLF, ctx->programName);
arg_print_syntax(stdout, ctx->argtable, "\n\n");
PrintAndLogEx(NORMAL, _SectionTagColor_("options:"));
arg_print_glossary(stdout, ctx->argtable, " "_ArgColor_("%-30s")" "_ArgHelpColor_("%s")"\n");
PrintAndLogEx(NORMAL, "");
if (ctx->programHelp) {
PrintAndLogEx(NORMAL, _SectionTagColor_("examples/notes:"));
char *buf = NULL;
int idx = 0;
buf = realloc(buf, strlen(ctx->programHelp) + 1); // more then enough as we are splitting
char *p2; // pointer to split example from comment.
if (ctx->programHelp) {
// allocate more then enough memory as we are splitting
char *s = calloc(strlen(ctx->programHelp) + 1, sizeof(uint8_t));
if (s == NULL) {
PrintAndLogEx(FAILED, "cannot allocate memory");
return;
}
PrintAndLogEx(NORMAL, _SectionTagColor_("examples/notes:"));
// pointer to split example from comment.
char *p2;
int idx = 0;
int egWidth = 30;
for (int i = 0; i <= strlen(ctx->programHelp); i++) { // <= so to get string terminator.
buf[idx++] = ctx->programHelp[i];
s[idx++] = ctx->programHelp[i];
if ((ctx->programHelp[i] == '\n') || (ctx->programHelp[i] == 0x00)) {
buf[idx - 1] = 0x00;
p2 = strstr(buf, "->"); // See if the example has a comment.
s[idx - 1] = 0x00;
p2 = strstr(s, "->"); // See if the example has a comment.
if (p2 != NULL) {
*(p2 - 1) = 0x00;
if (strlen(buf) > 28)
egWidth = strlen(buf) + 5;
if (strlen(s) > 28)
egWidth = strlen(s) + 5;
else
egWidth = 30;
PrintAndLogEx(NORMAL, " "_ExampleColor_("%-*s")" %s", egWidth, buf, p2);
PrintAndLogEx(NORMAL, " "_ExampleColor_("%-*s")" %s", egWidth, s, p2);
} else {
PrintAndLogEx(NORMAL, " "_ExampleColor_("%-*s"), egWidth, buf);
PrintAndLogEx(NORMAL, " "_ExampleColor_("%-*s"), egWidth, s);
}
idx = 0;
}
}
free(s);
PrintAndLogEx(NORMAL, "");
free(buf);
}
fflush(stdout);
}
@ -127,7 +140,7 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
return 3;
}
return 0;
return PM3_SUCCESS;
}
enum ParserState {
@ -144,21 +157,25 @@ int CLIParserParseString(CLIParserContext *ctx, const char *str, void *vargtable
int CLIParserParseStringEx(CLIParserContext *ctx, const char *str, void *vargtable[], size_t vargtableLen, bool allowEmptyExec, bool clueData) {
int argc = 0;
char *argv[200] = {NULL};
char *argv[MAX_INPUT_ARG_LENGTH] = {NULL};
int len = strlen(str);
memset(ctx->buf, 0x00, ARRAYLEN(ctx->buf));
char *bufptr = ctx->buf;
char *bufptrend = ctx->buf + ARRAYLEN(ctx->buf) - 1;
char *spaceptr = NULL;
enum ParserState state = PS_FIRST;
argv[argc++] = bufptr;
// param0 = program name
memcpy(ctx->buf, ctx->programName, strlen(ctx->programName) + 1); // with 0x00
// param0 = program name + with 0x00
memcpy(ctx->buf, ctx->programName, strlen(ctx->programName) + 1);
bufptr += strlen(ctx->programName) + 1;
if (len)
if (len) {
argv[argc++] = bufptr;
}
// parse params
for (int i = 0; i < len; i++) {
@ -214,10 +231,9 @@ int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
*datalen = 0;
int tmplen = 0;
uint8_t tmpstr[(256 * 2) + 1] = {0};
uint8_t tmpstr[MAX_INPUT_ARG_LENGTH + 1] = {0};
// concat all strings in argstr into tmpstr[]
//
int res = CLIParamStrToBuf(argstr, tmpstr, sizeof(tmpstr), &tmplen);
if (res || (tmplen == 0)) {
return res;
@ -242,7 +258,7 @@ int CLIParamBinToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
*datalen = 0;
int tmplen = 0;
uint8_t tmpstr[(256 * 2) + 1] = {0};
uint8_t tmpstr[MAX_INPUT_ARG_LENGTH + 1] = {0};
// concat all strings in argstr into tmpstr[]
//
@ -268,7 +284,7 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
if (!argstr->count)
return 0;
uint8_t tmpstr[(512 * 2) + 1] = {0};
uint8_t tmpstr[MAX_INPUT_ARG_LENGTH + 1] = {0};
int ibuf = 0;
for (int i = 0; i < argstr->count; i++) {
@ -303,7 +319,7 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array, int *value) {
char data[200] = {0};
int datalen = 0;
int datalen = 200;
int res = CLIParamStrToBuf(argstr, (uint8_t *)data, sizeof(data), &datalen);
if (res)
return res;
@ -316,7 +332,7 @@ int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array
int val = -1;
int cntr = 0;
for (int i = 0; i < CLI_MAX_OPTLIST_LEN && option_array[i].text != NULL; i++) {
for (int i = 0; (i < CLI_MAX_OPTLIST_LEN) && (option_array[i].text != NULL); i++) {
// exact match
if (strcmp(option_array[i].text, data) == 0) {
*value = option_array[i].code;
@ -346,9 +362,10 @@ int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array
const char *CLIGetOptionListStr(const CLIParserOption *option_array, int value) {
static const char *errmsg = "n/a";
for (int i = 0; i < CLI_MAX_OPTLIST_LEN && option_array[i].text != NULL; i++) {
if (option_array[i].code == value)
for (int i = 0; (i < CLI_MAX_OPTLIST_LEN) && (option_array[i].text != NULL); i++) {
if (option_array[i].code == value) {
return option_array[i].text;
}
}
return errmsg;
}

View file

@ -12,6 +12,7 @@
#define __CLIPARSER_H
#include "argtable3.h"
#include <stdlib.h>
#include <stdbool.h>
#include "util.h"
#define arg_param_begin arg_lit0("h", "help", "This help")
@ -53,13 +54,16 @@
#define CLIGetOptionListWithReturn(ctx, paramnum, option_array, option_array_len, value) if (CLIGetOptionList(arg_get_str((ctx), (paramnum)), (option_array), (option_array_len), (value))) {CLIParserFree((ctx)); return PM3_ESOFT;}
#define MAX_INPUT_ARG_LENGTH 4096
typedef struct {
void **argtable;
size_t argtableLen;
const char *programName;
const char *programHint;
const char *programHelp;
char buf[1024 + 60];
char buf[MAX_INPUT_ARG_LENGTH + 60];
} CLIParserContext;
#define CLI_MAX_OPTLIST_LEN 50

View file

@ -17,7 +17,7 @@ target_compile_definitions(pm3rrg_rdv4_hardnested_nosimd PRIVATE NOSIMD_BUILD)
## Mingw platforms: AMD64
set(X86_CPUS x86 x86_64 i686 AMD64)
set(ARM64_CPUS arm64 aarch64)
set(ARM32_CPUS armel armhf)
set(ARM32_CPUS armel armhf armv7-a)
message(STATUS "CMAKE_SYSTEM_PROCESSOR := ${CMAKE_SYSTEM_PROCESSOR}")

View file

@ -163,7 +163,8 @@ static void *malloc_bitslice(size_t x) {
}
#define free_bitslice(x) free(x)
#else
#define malloc_bitslice(x) memalign(MAX_BITSLICES / 8, (x))
//#define malloc_bitslice(x) memalign(MAX_BITSLICES / 8, (x))
#define malloc_bitslice(x) __builtin_assume_aligned(memalign(MAX_BITSLICES / 8, (x)), MAX_BITSLICES / 8);
#define free_bitslice(x) free(x)
#endif
@ -529,7 +530,6 @@ stop_tests:
bucket_states_tested += bucket_size[block_idx];
// prepare to set new states
state_p = &states[KEYSTREAM_SIZE];
continue;
}
}
out:

View file

@ -85,7 +85,8 @@ static void *malloc_bitarray(size_t x) {
}
#define free_bitarray(x) free(x)
#else
#define malloc_bitarray(x) memalign(__BIGGEST_ALIGNMENT__, (x))
//#define malloc_bitarray(x) memalign(__BIGGEST_ALIGNMENT__, (x))
#define malloc_bitarray(x) __builtin_assume_aligned(memalign(__BIGGEST_ALIGNMENT__, (x)), __BIGGEST_ALIGNMENT__);
#define free_bitarray(x) free(x)
#endif

View file

@ -10,3 +10,4 @@
25293C2F
#
# Paxton HT2
BDF5E846

View file

@ -10,7 +10,32 @@ AEA684A6DAB23278 # AA1
F0E1D2C3B4A59687 # Kd from PicoPass 2k documentation
5CBCF1DA45D5FB4F # PicoPass Default Exchange Key
31ad7ebd2f282168 # From HID multiclassSE reader
6EFD46EFCBB3C875 # From pastebin: https://pastebin.com/uHqpjiuU
E033CA419AEE43F9 # From pastebin: https://pastebin.com/uHqpjiuU
2020666666668888 # iCopy-X iCL tags
6666202066668888 # iCopy-X iCS tags reversed from the SOs
#
# From pastebin: https://pastebin.com/uHqpjiuU
6EFD46EFCBB3C875
E033CA419AEE43F9
#
# iCopy-x DRM keys
2020666666668888 # iCL tags
6666202066668888 # iCS tags reversed from the SOs
#
# default picopass KD / Page 0 / Book 1
FDCB5A52EA8F3090
237FF9079863DF44
5ADC25FB27181D32
83B881F2936B2E49
43644E61EE866BA5
897034143D016080
82D17B44C0122963
4895CA7DE65E2025
DADAD4C57BE271B7
E41E9EDEF5719ABF
293D275EC3AF9C7F
C3C169251B8A70FB
F41DAF58B20C8B91
28877A609EC0DD2B
66584C91EE80D5E5
C1B74D7478053AE2
#
# default iCLASS RFIDeas
6B65797374726B72

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,7 @@
# blue gun EM4305
F9DCEBA0
# chinese "handheld RFID writer" blue cloner from circa 2013 (also sold by xfpga.com)
# ID/HID CARD COPER SK-663
65857569
# ref. http://kazus.ru/forums/showpost.php?p=1045937&postcount=77
05D73B9F
@ -25,6 +26,8 @@ A5B4C3D2
1C0B5848
# ref. http://www.proxmark.org/forum/viewtopic.php?pid=35075#p35075
00434343
# default PASS
50415353
# DNGR - DT default pwd
444E4752
4E457854
@ -38,8 +41,6 @@ E9920427
50520901
# iCopy-X
20206666
# ID/HID CARD COPER SK-663
65857569
# password found on discord
5469616E
# wCopy NSR102-IDIC
@ -49,8 +50,8 @@ C0F5009A
07CEE75D
#
# prefered pwds of members in the community
feedbeef
deadc0de
FEEDBEEF
DEADC0DE
# Default pwd, simple:
00000000
11111111
@ -68,13 +69,12 @@ CCCCCCCC
DDDDDDDD
EEEEEEEE
FFFFFFFF
a0a1a2a3
b0b1b2b3
50415353
A0A1A2A3
B0B1B2B3
00000001
00000002
0000000a
0000000b
0000000A
0000000B
01020304
02030405
03040506
@ -118,8 +118,10 @@ F0000000
AABBCCDD
BBCCDDEE
CCDDEEFF
0CB7E7FC # rfidler?
FABADA11 # china?
# rfidler?
0CB7E7FC
# china?
FABADA11
# 20 most common len==8
87654321
12341234
@ -130,23 +132,33 @@ FABADA11 # china?
11112222
13131313
10041004
# pii
31415926
#
31415926 # pii
abcd1234
ABCD1234
20002000
19721972
aa55aa55 # amiboo
55aa55aa # rev amiboo
4f271149 # seeds ul-ev1
07d7bb0b # seeds ul-ev1
9636ef8f # seeds ul-ev1
b5f44686 # seeds ul-ev1
9E3779B9 # TEA
C6EF3720 # TEA
7854794A # xbox tea constant :)
F1EA5EED # burtle
69314718 # ln2
57721566 # euler constant (dec)
93C467E3 # euler constant (hex)
27182818 # natural log
50415353 # PASS
# rev amiboo
AA55AA55
55AA55AA
# seeds ul-ev1
4F271149
07D7BB0B
9636EF8F
B5F44686
# TEA
9E3779B9
C6EF3720
#
# xbox tea constant :)
7854794A
# burtle
F1EA5EED
# ln2
69314718
# euler constant (dec)
57721566
# euler constant (hex)
93C467E3
# natural log
27182818

View file

@ -122,7 +122,7 @@ if (NOT SKIPREADLINE EQUAL 1)
ExternalProject_Add_StepTargets(ncurses configure build install)
ExternalProject_Add(readline
URL ftp://ftp.gnu.org/gnu/readline/readline-8.1.tar.gz
URL ftp://ftp.gnu.org/gnu/readline/readline-8.2.tar.gz
PREFIX deps/readline
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/readline
CONFIGURE_COMMAND ./configure CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} LD=${CMAKE_C_COMPILER} AR=${CMAKE_AR} RANLIB=${CMAKE_RANLIB} ${CFLAGS_EXTERNAL_LIB} --host=arm --enable-static
@ -276,6 +276,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdhfepa.c
${PM3_ROOT}/client/src/cmdhffelica.c
${PM3_ROOT}/client/src/cmdhffido.c
${PM3_ROOT}/client/src/cmdhffudan.c
${PM3_ROOT}/client/src/cmdhfgallagher.c
${PM3_ROOT}/client/src/cmdhfcipurse.c
${PM3_ROOT}/client/src/cmdhficlass.c
@ -293,9 +294,12 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdhfseos.c
${PM3_ROOT}/client/src/cmdhfst.c
${PM3_ROOT}/client/src/cmdhfst25ta.c
${PM3_ROOT}/client/src/cmdhftesla.c
${PM3_ROOT}/client/src/cmdhftexkom.c
${PM3_ROOT}/client/src/cmdhfthinfilm.c
${PM3_ROOT}/client/src/cmdhftopaz.c
${PM3_ROOT}/client/src/cmdhfwaveshare.c
${PM3_ROOT}/client/src/cmdhfxerox.c
${PM3_ROOT}/client/src/cmdhw.c
${PM3_ROOT}/client/src/cmdlf.c
${PM3_ROOT}/client/src/cmdlfawid.c
@ -334,6 +338,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdmain.c
${PM3_ROOT}/client/src/cmdnfc.c
${PM3_ROOT}/client/src/cmdparser.c
${PM3_ROOT}/client/src/cmdpiv.c
${PM3_ROOT}/client/src/cmdscript.c
${PM3_ROOT}/client/src/cmdsmartcard.c
${PM3_ROOT}/client/src/cmdtrace.c

File diff suppressed because it is too large Load diff

View file

@ -62,7 +62,7 @@ function main(args)
local i
local cmds = {}
--check for params
--check for params
for o, a in getopt.getopt(args, 'h') do
if o == 'h' then return help() end
end

View file

@ -0,0 +1,310 @@
local getopt = require('getopt')
local lib14a = require('read14a')
local cmds = require('commands')
local utils = require('utils')
local ansicolors = require('ansicolors')
--- Commands
NTAG_I2C_PLUS_2K = '0004040502021503C859'
GET_VERSION = '60'
SELECT_SECTOR_PKT1 = 'C2FF'
SELECT_SECTOR0_PKT2 = '00000000'
SELECT_SECTOR1_PKT2 = '01000000'
READ_BLOCK = '30'
WRITE_BLOCK = 'A2'
ACK = '0A'
NAK = '00'
---
--- Arguments
copyright = ''
author = 'Shain Lakin'
version = 'v1.0.0'
desc =[[
This script can be used to read blocks, write blocks, dump sectors,
or write a files hex bytes to sector 0 or 1 on the NTAG I2C PLUS 2K tag.
]]
example =[[
Read block 04 from sector 1:
script run hf_i2c_plus_2k_utils -m r -s 1 -b 04
Write FFFFFFFF to block A0 sector 1:
script run hf_i2c_plus_2k_utils -m w -s 1 -b A0 -d FFFFFFFF
Dump sector 1 user memory to console and file:
script run hf_i2c_plus_2k_utils -m d -s 1
Write a files hex bytes to sector 1 starting at block 04:
script run hf_i2c_plus_2k_utils -m f -s 1 -f data.txt
]]
usage = [[
Read mode:
script run hf_i2c_plus_2k_utils -m r -s <sector> -b <block (hex)>
Write mode:
script run hf_i2c_plus_2k_utils -m w -s <sector> -b <block (hex)> -d <data (hex)>
Dump mode:
script run hf_i2c_plus_2k_utils -m d -s <sector>
File mode:
script run hf_i2c_plus_2k_utils -m f -s <sector> -f <file>
]]
arguments = [[
-h this help
-m mode (r/w/f)
-b block (hex)
-f file
-s sector (0/1)
-d data (hex)
]]
---
--- Help function
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
---
--- Message function
local function msg(string)
print(ansicolors.magenta..string.rep('-',29)..ansicolors.reset)
print(ansicolors.cyan..string..ansicolors.reset)
print(ansicolors.magenta..string.rep('-',29)..ansicolors.reset)
end
---
--- Error handling
local function warn(err)
print(ansicolors.magenta.."ERROR:"..ansicolors.reset,err)
core.clearCommandBuffer()
return nil, err
end
---
--- Setup tx/rx
local function sendRaw(rawdata, options)
local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT
+ lib14a.ISO14A_COMMAND.ISO14A_RAW
+ lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC
local c = Command:newMIX{cmd = cmds.CMD_HF_ISO14443A_READER,
arg1 = flags,
arg2 = string.len(rawdata)/2,
data = rawdata}
return c:sendMIX(options.ignore_response)
end
---
--- Function to connect
local function connect()
core.clearCommandBuffer()
info, err = lib14a.read(true, true)
if err then
lib14a.disconnect()
return error(err)
else
return info.uid
end
core.clearCommandBuffer()
end
---
--- Function to disconnect
local function disconnect()
core.clearCommandBuffer()
lib14a.disconnect()
end
---
--- Function to get response data
local function getResponseData(usbpacket)
local resp = Command.parse(usbpacket)
local len = tonumber(resp.arg1) * 2
return string.sub(tostring(resp.data), 0, len);
end
---
--- Function to send raw bytes
local function send(payload)
local usb, err = sendRaw(payload,{ignore_response = false})
if err then return warn(err) end
return getResponseData(usb)
end
---
--- Function to select sector
local function select_sector(sector)
send(SELECT_SECTOR_PKT1)
if sector == '0' then
send(SELECT_SECTOR0_PKT2)
elseif sector == '1' then
send(SELECT_SECTOR1_PKT2)
end
end
---
--- Function to write file to sector
local function filewriter(file,sector)
file_bytes = utils.ReadDumpFile(file)
len = string.len(file_bytes) / 8
start_char = 1
end_char = 8
block_counter = 4
-- NTAG_I2C_PLUS_2K:SECTOR_0:225,SECTOR_1:255
end_block = 225
connect()
select_sector(sector)
for count = 1, len do
block = file_bytes:sub(start_char, end_char)
data = send(WRITE_BLOCK..string.format("%02x",block_counter)..block)
print('[*] Writing bytes '..block..' to page '..string.format("%02x", block_counter))
if data == ACK then
print(ansicolors.cyan..'[*] Received ACK, write successful'..ansicolors.reset)
else
print(ansicolors.magenta..'[!] Write failed'..ansicolors.reset)
end
start_char = start_char + 8
end_char = end_char + 8
block_counter = block_counter + 1
if block_counter == end_block then
print(ansicolors.magenta..'[!] Not enough memory space!'..ansicolors.reset)
break
end
end
disconnect()
end
---
--- Function to dump user memory to console and disk
local function dump(sector,uid)
connect()
select_sector(sector)
counter = 0
dest = uid..'.hex'
file = io.open(dest, 'a')
io.output(file)
print("\n[+] Dumping sector "..sector.."\n")
print(ansicolors.magenta..string.rep('--',16)..ansicolors.reset)
for count = 1, 64 do
result = send(READ_BLOCK..string.format("%02x", counter))
print(ansicolors.cyan..result:sub(1,32)..ansicolors.reset)
io.write(result:sub(1,32))
counter = counter + 4
end
io.close(file)
print(ansicolors.magenta..string.rep('--',16)..ansicolors.reset)
print("\n[+] Memory dump saved to "..uid..".hex")
disconnect()
end
---
--- Function to read and write blocks
local function exec(cmd, sector, block, bytes)
connect()
select_sector(sector)
if cmd == READ_BLOCK then
data = send(cmd..block)
msg(data:sub(1,8))
elseif cmd == WRITE_BLOCK then
if bytes == 'NOP' then
err = '[!] You need to pass some data'
warn(err)
print(usage)
do return end
else
data = send(cmd..block..bytes)
if data == ACK then
print(ansicolors.cyan..'[+] Received ACK, write succesful'..ansicolors.reset)
elseif data ~= ACK then
print(ansicolors.magenta..'[!] Write failed'..ansicolors.reset)
end
end
end
disconnect()
return(data)
end
---
--- Main
local function main(args)
for o, a in getopt.getopt(args, 'm:b:s:d:f:h') do
if o == 'm' then mode = a end
if o == 'b' then block = a end
if o == 's' then sector = a end
if o == 'd' then bytes = a end
if o == 'f' then file = a end
if o == 'h' then return help() end
end
uid = connect()
connect()
version = send(GET_VERSION)
disconnect()
if version == NTAG_I2C_PLUS_2K then
if mode == 'r' then
print('\n[+] Reading sector '..sector..' block '..block)
exec(READ_BLOCK,sector,block,bytes)
elseif mode == 'w' then
print('\n[+] Writing '..bytes..' to sector '..sector..' block '..block)
exec(WRITE_BLOCK,sector,block,bytes)
elseif mode == 'f' then
filewriter(file,sector)
elseif mode == 'd' then
dump(sector,uid)
end
else
return print(usage)
end
if command == '' then return print(usage) end
end
---
main(args)

View file

@ -1,7 +1,7 @@
---
-- This Lua script is designed to run with Iceman/RRG Proxmark3 fork
-- Just copy hf_mf_dump-luxeo.lua to client/luascripts/
-- and run "script run hf_mf_dump-luxeo"
-- and run "script run hf_mf_dump_luxeo"
-- requirements
local cmds = require('commands')
@ -12,16 +12,16 @@ local ansicolors = require('ansicolors')
copyright = ''
author = '0xdrrb'
version = 'v0.1.2'
version = 'v0.1.3'
desc = [[
This is a script that tries to dump and decrypt the data of a specific type of Mifare laundromat token.
OBS! Tag must be on the antenna.
]]
example = [[
script run hf_mf_dump-luxeo
script run hf_mf_dump_luxeo
]]
usage = [[
script run hf_mf_dump-luxeo
script run hf_mf_dump_luxeo
]]
arguments = [[
-h This help

View file

@ -63,8 +63,8 @@ local function card_format(key_a,key_b,ab,user,s70)
core.console(cmd)
print(cmd)
core.clearCommandBuffer()
if s70 == false and k > 15 then
return
if s70 == false and k > 15 then
return
end
end
end

View file

@ -0,0 +1,185 @@
--
-- hf_mf_sim_hid.lua - A tool to clone a large number of tags at once.
-- Adapted from lf_hid_bulkclone.lua
-- Created 16.08.2022
local getopt = require('getopt')
local ansicolors = require('ansicolors')
copyright = ''
author = "Michael Micsen"
version = 'v0.0.1'
desc = [[
Perform simulation of Mifare credentials with HID encoding
This script only supports: H10301
]]
example = [[
--
script run hf_mf_sim_hid.lua -f 1 -c 10000
]]
usage = [[
script run hf_mf_sim_hid.lua -f facility -c card_number
]]
arguments = [[
-h : this help
-f : facility id
-c : starting card id
]]
local DEBUG = true
--local bxor = bit32.bxor
local bor = bit32.bor
local lshift = bit32.lshift
---
-- A debug printout-function
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while args[i] do
dbg(args[i])
i = i+1
end
else
print('###', args)
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, errr
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
---
-- Exit message
local function exitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
--[[Implement a function to simply visualize the bitstream in a text format
--This is especially helpful for troubleshooting bitwise math issues]]--
local function toBits(num,bits)
-- returns a table of bits, most significant first.
bits = bits or math.max(1, select(2, math.frexp(num)))
local t = {} -- will contain the bits
for b = bits, 1, -1 do
t[b] = math.fmod(num, 2)
num = math.floor((num - t[b]) / 2)
end
return table.concat(t)
end
--[[
Likely, I'm an idiot, but I couldn't find any parity functions in Lua
This can also be done with a combination of bitwise operations (in fact,
is the canonically "correct" way to do it, but my brain doesn't just
default to this and so counting some ones is good enough for me
]]--
local function evenparity(s)
local _, count = string.gsub(s, '1', '')
local p = count % 2
if (p == 0) then
return false
else
return true
end
end
local function isempty(s)
return s == nil or s == ''
end
--[[
The Proxmark3 "clone" functions expect the data to be in hex format so
take the card id number and facility ID as arguments and construct the
hex. This should be easy enough to extend to non 26bit formats
]]--
local function cardHex(i, f)
fac = lshift(f, 16)
id = bor(i, fac)
stream = toBits(id, 24)
--As the function defaults to even parity and returns a boolean,
--perform a 'not' function to get odd parity
high = evenparity(string.sub(stream,1,12)) and 1 or 0
low = not evenparity(string.sub(stream,13)) and 1 or 0
bits = bor( lshift(id, 1), low)
bits = bor( bits, lshift(high, 25))
--Add sentinel bit
sentinel = lshift(1, 26)
bits = bor(bits, sentinel)
return ('%08x'):format(bits)
end
---
-- main
local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
print()
if #args == 0 then return help() end
--I really wish a better getopt function would be brought in supporting
--long arguments, but it seems this library was chosen for BSD style
--compatibility
for o, a in getopt.getopt(args, 'f:c:h') do
if o == 'h' then return help() end
if o == 'f' then
if isempty(a) then
print('You did not supply a facility code, using 0')
facility = 0
else
facility = a
end
end
if o == 'c' then
print(a)
if isempty(a) then return oops('You must supply the flag -c (card number)1') end
cardnum = a
end
end
--Due to my earlier complaints about how this specific getopt library
--works, specifying ':' does not enforce supplying a value, thus we
--need to do these checks all over again.
if isempty(cardnum) then return oops('You must supply the flag -c (card number)2') end
--If the facility ID is non specified, ensure we code it as zero
if isempty(facility) then
print('Using 0 for the facility code as -f was not supplied')
facility = 0
end
-- Write the MAD to read for a Mifare HID credential
core.console('hf mf esetblk -b 1 -d 1B014D48000000000000000000000000')
core.console('hf mf esetblk -b 3 -d A0A1A2A3A4A5787788C189ECA97F8C2A')
--Write the sector trailer for the credential sector
core.console('hf mf esetblk -b 7 -d 484944204953787788AA204752454154')
local cardh = cardHex(cardnum, facility)
print('Hex')
print(cardh)
core.console( ('hf mf esetblk -b 5 -d 020000000000000000000000%s'):format(cardh) )
core.console('hf mf sim --1k -i')
end
main(args)

View file

@ -109,8 +109,8 @@ local function main(args)
command = 'hf 14a sim -t 1 -u ' .. uid_format
msg('Bruteforcing Mifare Classic card numbers')
elseif mftype == 'mfc4' then
command = 'hf 14a sim -t 8 -u ' .. uid_format
msg('Bruteforcing Mifare Classic 4K card numbers')
command = 'hf 14a sim -t 8 -u ' .. uid_format
msg('Bruteforcing Mifare Classic 4K card numbers')
elseif mftype == 'mfu' then
command = 'hf 14a sim -t 2 -u ' .. uid_format
msg('Bruteforcing Mifare Ultralight card numbers')

View file

@ -13,7 +13,7 @@ local err_lock = 'use -k or change cfg0 block'
local _print = 0
copyright = ''
author = 'Nathan Glaser'
version = 'v1.0.4'
version = 'v1.0.5'
date = 'Created - Jan 2022'
desc = 'This script enables easy programming of an Ultimate Mifare Magic card'
example = [[
@ -50,17 +50,17 @@ arguments = [[
-c read magic configuration
-u UID (8-14 hexsymbols), set UID on tag
-t tag type to impersonate
1 = Mifare Mini S20 4-byte 12 = NTAG 210
2 = Mifare Mini S20 7-byte 13 = NTAG 212
3 = Mifare 1k S50 4-byte 14 = NTAG 213
4 = Mifare 1k S50 7-byte 15 = NTAG 215
5 = Mifare 4k S70 4-byte 16 = NTAG 216
6 = Mifare 4k S70 7-byte 17 = NTAG I2C 1K
*** 7 = UL - NOT WORKING FULLY 18 = NTAG I2C 2K
*** 8 = UL-C - NOT WORKING FULLY 19 = NTAG I2C 1K PLUS
9 = UL EV1 48b 20 = NTAG I2C 2K PLUS
10 = UL EV1 128b 21 = NTAG 213F
*** 11 = UL Plus - NOT WORKING YET 22 = NTAG 216F
1 = Mifare Mini S20 4-byte 12 = NTAG 210
2 = Mifare Mini S20 7-byte 13 = NTAG 212
3 = Mifare 1k S50 4-byte 14 = NTAG 213
4 = Mifare 1k S50 7-byte 15 = NTAG 215
5 = Mifare 4k S70 4-byte 16 = NTAG 216
6 = Mifare 4k S70 7-byte 17 = NTAG I2C 1K
*** 7 = UL - NOT WORKING FULLY 18 = NTAG I2C 2K
*** 8 = UL-C - NOT WORKING FULLY 19 = NTAG I2C 1K PLUS
9 = UL EV1 48b 20 = NTAG I2C 2K PLUS
10 = UL EV1 128b 21 = NTAG 213F
*** 11 = UL Plus - NOT WORKING YET 22 = NTAG 216F
-p NTAG password (8 hexsymbols), set NTAG password on tag.
-a NTAG pack ( 4 hexsymbols), set NTAG pack on tag.
@ -178,7 +178,7 @@ local function read_config()
if not info then return false, "Can't select card" end
-- read Ultimate Magic Card CONFIG
if magicconfig == nil then
magicconfig = send("CF".._key.."C6")
magicconfig = send("CF".._key.."C6")
else print('No Config')
end
-- extract data from CONFIG - based on CONFIG in https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md#gen-4-gtu
@ -186,7 +186,7 @@ local function read_config()
atqaf = atqa1..' '..atqa2
cardtype, cardprotocol, gtustr, atsstr = 'unknown', 'unknown', 'unknown', 'unknown'
if magicconfig == nil then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end
if #magicconfig ~= 64 then lib14a.disconnect(); return nil, "partial read of configuration, "..err_lock end
if #magicconfig ~= 64 and #magicconfig ~= 68 then lib14a.disconnect(); return nil, "partial read of configuration, "..err_lock end
if gtumode == '00' then gtustr = 'Pre-write/Shadow Mode'
elseif gtumode == '01' then gtustr = 'Restore Mode'
elseif gtumode == '02' then gtustr = 'Disabled'
@ -196,93 +196,92 @@ local function read_config()
else atsstr = (string.sub(ats, 3))
end
if ulprotocol == '00' then
cardprotocol = 'MIFARE Classic Protocol'
ultype = 'Disabled'
if uidlength == '00' then
uid = send("CF".._key.."CE00"):sub(1,8)
if atqaf == '00 04' and sak == '09' then cardtype = 'MIFARE Mini S20 4-byte UID'
elseif atqaf == '00 04' and sak == '08' then cardtype = 'MIFARE 1k S50 4-byte UID'
elseif atqaf == '00 02' and sak == '18' then cardtype = 'MIFARE 4k S70 4-byte UID'
end
elseif uidlength == '01' then
uid = send("CF".._key.."CE00"):sub(1,14)
if atqaf == '00 44' and sak == '09' then cardtype = 'MIFARE Mini S20 7-byte UID'
elseif atqaf == '00 44' and sak == '08' then cardtype = 'MIFARE 1k S50 7-byte UID'
elseif atqaf == '00 42' and sak == '18' then cardtype = 'MIFARE 4k S70 7-byte UID'
end
end
cardprotocol = 'MIFARE Classic Protocol'
ultype = 'Disabled'
if uidlength == '00' then
uid = send("CF".._key.."CE00"):sub(1,8)
if atqaf == '00 04' and sak == '09' then cardtype = 'MIFARE Mini S20 4-byte UID'
elseif atqaf == '00 04' and sak == '08' then cardtype = 'MIFARE 1k S50 4-byte UID'
elseif atqaf == '00 02' and sak == '18' then cardtype = 'MIFARE 4k S70 4-byte UID'
end
elseif uidlength == '01' then
uid = send("CF".._key.."CE00"):sub(1,14)
if atqaf == '00 44' and sak == '09' then cardtype = 'MIFARE Mini S20 7-byte UID'
elseif atqaf == '00 44' and sak == '08' then cardtype = 'MIFARE 1k S50 7-byte UID'
elseif atqaf == '00 42' and sak == '18' then cardtype = 'MIFARE 4k S70 7-byte UID'
end
end
elseif ulprotocol == '01' then
-- Read Ultralight config only if UL protocol is enabled
cardprotocol = 'MIFARE Ultralight/NTAG'
block0 = send("3000")
uid0 = block0:sub(1,6)
uid = uid0..block0:sub(9,16)
if ulmode == '00' then ultype = 'Ultralight EV1'
elseif ulmode == '01' then ultype = 'NTAG21x'
elseif ulmode == '02' then ultype = 'Ultralight-C'
elseif ulmode == '03' then ultype = 'Ultralight'
end
-- read VERSION
cversion = send('30FA'):sub(1,16)
-- pwdblock must be set since the 30F1 and 30F2 special commands don't work on the ntag21x part of the UMC
if ulmode == '03' then versionstr = 'Ultralight'
elseif ulmode == '02' then versionstr = 'Ultralight-C'
elseif cversion == '0004030101000B03' then versionstr = 'UL EV1 48b'
elseif cversion == '0004030101000B03' then versionstr = 'UL EV1 48b'
elseif cversion == '0004030101000E03' then versionstr = 'UL EV1 128b'
elseif cversion == '0004040101000B03' then versionstr = 'NTAG 210'
elseif cversion == '0004040101000E03' then versionstr = 'NTAG 212'
elseif cversion == '0004040201000F03' then versionstr = 'NTAG 213'
elseif cversion == '0004040201001103' then versionstr = 'NTAG 215'
elseif cversion == '0004040201001303' then versionstr = 'NTAG 216'
elseif cversion == '0004040502011303' then versionstr = 'NTAG I2C 1K'
elseif cversion == '0004040502011503' then versionstr = 'NTAG I2C 2K'
elseif cversion == '0004040502021303' then versionstr = 'NTAG I2C 1K PLUS'
elseif cversion == '0004040502021503' then versionstr = 'NTAG I2C 2K PLUS'
elseif cversion == '0004040401000F03' then versionstr = 'NTAG 213F'
elseif cversion == '0004040401001303' then versionstr = 'NTAG 216F'
end
-- read PWD
cpwd = send("30F0"):sub(1,8)
pwd = send("30E5"):sub(1,8)
-- 04 response indicates that blocks has been locked down.
if pwd == '04' then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end
-- read PACK
cpack = send("30F1"):sub(1,4)
pack = send("30E6"):sub(1,4)
-- read SIGNATURE
signature1 = send('30F2'):sub(1,32)
signature2 = send('30F6'):sub(1,32)
lib14a.disconnect()
-- Read Ultralight config only if UL protocol is enabled
cardprotocol = 'MIFARE Ultralight/NTAG'
block0 = send("3000")
uid0 = block0:sub(1,6)
uid = uid0..block0:sub(9,16)
if ulmode == '00' then ultype = 'Ultralight EV1'
elseif ulmode == '01' then ultype = 'NTAG21x'
elseif ulmode == '02' then ultype = 'Ultralight-C'
elseif ulmode == '03' then ultype = 'Ultralight'
end
-- read VERSION
cversion = send('30FA'):sub(1,16)
-- pwdblock must be set since the 30F1 and 30F2 special commands don't work on the ntag21x part of the UMC
if ulmode == '03' then versionstr = 'Ultralight'
elseif ulmode == '02' then versionstr = 'Ultralight-C'
elseif cversion == '0004030101000B03' then versionstr = 'UL EV1 48b'
elseif cversion == '0004030101000E03' then versionstr = 'UL EV1 128b'
elseif cversion == '0004040101000B03' then versionstr = 'NTAG 210'
elseif cversion == '0004040101000E03' then versionstr = 'NTAG 212'
elseif cversion == '0004040201000F03' then versionstr = 'NTAG 213'
elseif cversion == '0004040201001103' then versionstr = 'NTAG 215'
elseif cversion == '0004040201001303' then versionstr = 'NTAG 216'
elseif cversion == '0004040502011303' then versionstr = 'NTAG I2C 1K'
elseif cversion == '0004040502011503' then versionstr = 'NTAG I2C 2K'
elseif cversion == '0004040502021303' then versionstr = 'NTAG I2C 1K PLUS'
elseif cversion == '0004040502021503' then versionstr = 'NTAG I2C 2K PLUS'
elseif cversion == '0004040401000F03' then versionstr = 'NTAG 213F'
elseif cversion == '0004040401001303' then versionstr = 'NTAG 216F'
end
-- read PWD
cpwd = send("30F0"):sub(1,8)
pwd = send("30E5"):sub(1,8)
-- 04 response indicates that blocks has been locked down.
if pwd == '04' then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end
-- read PACK
cpack = send("30F1"):sub(1,4)
pack = send("30E6"):sub(1,4)
-- read SIGNATURE
signature1 = send('30F2'):sub(1,32)
signature2 = send('30F6'):sub(1,32)
lib14a.disconnect()
end
if _print < 1 then
print(string.rep('=', 88))
print('\t\t\tUltimate Magic Card Configuration')
print(string.rep('=', 88))
print(' - Raw Config ', string.sub(magicconfig, 1, -9))
print(' - Card Protocol ', cardprotocol)
print(' - Ultralight Mode ', ultype)
print(' - ULM Backdoor Key ', readpass)
print(' - GTU Mode ', gtustr)
if ulprotocol == '01' then
print(' - Card Type ', versionstr)
else
print(' - Card Type ', cardtype)
end
print(' - UID ', uid)
print(' - ATQA ', atqaf)
print(' - SAK ', sak)
if ulprotocol == '01' then
print('')
print(string.rep('=', 88))
print('\t\t\tMagic UL/NTAG 21* Configuration')
print(string.rep('=', 88))
print(' - ATS ', atsstr)
print(' - Password ', '[0xE5] '..pwd, '[0xF0] '..cpwd)
print(' - Pack ', '[0xE6] '..pack, '[0xF1] '..cpack)
print(' - Version ', cversion)
print(' - Signature ', signature1..signature2)
end
print(string.rep('=', 88))
print('\t\t\tUltimate Magic Card Configuration')
print(string.rep('=', 88))
print(' - Raw Config ', string.sub(magicconfig, 1, -9))
print(' - Card Protocol ', cardprotocol)
print(' - Ultralight Mode ', ultype)
print(' - ULM Backdoor Key ', readpass)
print(' - GTU Mode ', gtustr)
if ulprotocol == '01' then
print(' - Card Type ', versionstr)
else
print(' - Card Type ', cardtype)
end
print(' - UID ', uid)
print(' - ATQA ', atqaf)
print(' - SAK ', sak)
if ulprotocol == '01' then
print('')
print(string.rep('=', 88))
print('\t\t\tMagic UL/NTAG 21* Configuration')
print(string.rep('=', 88))
print(' - ATS ', atsstr)
print(' - Password ', '[0xE5] '..pwd, '[0xF0] '..cpwd)
print(' - Pack ', '[0xE6] '..pack, '[0xF1] '..cpack)
print(' - Version ', cversion)
print(' - Signature ', signature1..signature2)
end
end
lib14a.disconnect()
return true, 'Ok'
@ -292,41 +291,41 @@ end
local function write_uid(useruid)
-- read CONFIG
if not magicconfig then
_print = 1
read_config()
_print = 1
read_config()
end
local info = connect()
if not info then return false, "Can't select card" end
-- Writes a MFC UID with GEN4 magic commands.
if ulprotocol == '00' then
-- uid string checks
if useruid == nil then return nil, 'empty uid string' end
if #useruid == 0 then return nil, 'empty uid string' end
if (#useruid ~= 8) and (#useruid ~= 14) then return nil, 'UID wrong length. Should be 4 or 7 hex bytes' end
print('Writing new UID ', useruid)
local uidbytes = utils.ConvertHexToBytes(useruid)
local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), uidbytes[4])
local block0 = string.format('%02X%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], uidbytes[4], bcc1)
local resp = send('CF'.._key..'CD00'..block0)
-- uid string checks
if useruid == nil then return nil, 'empty uid string' end
if #useruid == 0 then return nil, 'empty uid string' end
if (#useruid ~= 8) and (#useruid ~= 14) then return nil, 'UID wrong length. Should be 4 or 7 hex bytes' end
print('Writing new UID ', useruid)
local uidbytes = utils.ConvertHexToBytes(useruid)
local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), uidbytes[4])
local block0 = string.format('%02X%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], uidbytes[4], bcc1)
local resp = send('CF'.._key..'CD00'..block0)
-- Writes a MFUL UID with bcc1, bcc2 using NTAG21xx commands.
elseif ulprotocol == '01' then
-- uid string checks
if useruid == nil then return nil, 'empty uid string' end
if #useruid == 0 then return nil, 'empty uid string' end
if #useruid ~= 14 then return nil, 'uid wrong length. Should be 7 hex bytes' end
print('Writing new UID ', useruid)
local uidbytes = utils.ConvertHexToBytes(useruid)
local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), 0x88)
local bcc2 = bxor(bxor(bxor(uidbytes[4], uidbytes[5]), uidbytes[6]), uidbytes[7])
local block0 = string.format('%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], bcc1)
local block1 = string.format('%02X%02X%02X%02X', uidbytes[4], uidbytes[5], uidbytes[6], uidbytes[7])
local block2 = string.format('%02X%02X%02X%02X', bcc2, 0x48, 0x00, 0x00)
local resp
resp = send('A200'..block0)
resp = send('A201'..block1)
resp = send('A202'..block2)
-- uid string checks
if useruid == nil then return nil, 'empty uid string' end
if #useruid == 0 then return nil, 'empty uid string' end
if #useruid ~= 14 then return nil, 'uid wrong length. Should be 7 hex bytes' end
print('Writing new UID ', useruid)
local uidbytes = utils.ConvertHexToBytes(useruid)
local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), 0x88)
local bcc2 = bxor(bxor(bxor(uidbytes[4], uidbytes[5]), uidbytes[6]), uidbytes[7])
local block0 = string.format('%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], bcc1)
local block1 = string.format('%02X%02X%02X%02X', uidbytes[4], uidbytes[5], uidbytes[6], uidbytes[7])
local block2 = string.format('%02X%02X%02X%02X', bcc2, 0x48, 0x00, 0x00)
local resp
resp = send('A200'..block0)
resp = send('A201'..block1)
resp = send('A202'..block2)
else
print('Incorrect ul')
print('Incorrect ul')
end
lib14a.disconnect()
if resp ~= nil then
@ -340,8 +339,8 @@ end
local function write_atqasak(atqasak)
-- read CONFIG
if not magicconfig then
_print = 1
read_config()
_print = 1
read_config()
end
if atqasak == nil then return nil, 'Empty ATQA/SAK string' end
if #atqasak == 0 then return nil, 'Empty ATQA/SAK string' end
@ -351,25 +350,25 @@ end
local atqauserf = atqauser2..atqauser1
local sakuser = atqasak:sub(5,6)
if sakuser == '04' then
print('Never set SAK bit 3 (e.g. SAK=04), it indicates an extra cascade level is required')
return nil
print('Never set SAK bit 3 (e.g. SAK=04), it indicates an extra cascade level is required')
return nil
elseif (sakuser == '20' or sakuser == '28') and atslen == '00' then
print('When SAK equals 20 or 28, ATS must be turned on')
return nil
print('When SAK equals 20 or 28, ATS must be turned on')
return nil
elseif atqauser2 == '40' then
print('ATQA of [00 40] will cause the card to not answer.')
return nil
print('ATQA of [00 40] will cause the card to not answer.')
return nil
else
local info = connect()
if not info then return false, "Can't select card" end
print('New ATQA: '..atqauser1..' '..atqauser2..' New SAK: '..sakuser)
local resp = send("CF".._key.."35"..atqauserf..sakuser)
lib14a.disconnect()
if resp == nil then
return nil, oops('Failed to write ATQA/SAK')
else
return true, 'Ok'
end
local info = connect()
if not info then return false, "Can't select card" end
print('New ATQA: '..atqauser1..' '..atqauser2..' New SAK: '..sakuser)
local resp = send("CF".._key.."35"..atqauserf..sakuser)
lib14a.disconnect()
if resp == nil then
return nil, oops('Failed to write ATQA/SAK')
else
return true, 'Ok'
end
end
end
---
@ -377,8 +376,8 @@ end
local function write_ntagpwd(ntagpwd)
-- read CONFIG
if not magicconfig then
_print = 1
read_config()
_print = 1
read_config()
end
if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end
-- PWD string checks
@ -402,8 +401,8 @@ end
local function write_pack(userpack)
-- read CONFIG
if not magicconfig then
_print = 1
read_config()
_print = 1
read_config()
end
if ulprotocol == 0 then return nil, 'Magic Card is not using the Ultralight Protocol' end
-- PACK string checks
@ -427,8 +426,8 @@ local function write_otp(block3)
if #block3 ~= 8 then return nil, 'OTP wrong length. Should be 4 hex bytes' end
-- read CONFIG
if not magicconfig then
_print = 1
read_config()
_print = 1
read_config()
end
if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end
local info = connect()
@ -451,8 +450,8 @@ local function write_version(data)
if #data ~= 16 then return nil, 'version wrong length. Should be 8 hex bytes' end
-- read CONFIG
if not magicconfig then
_print = 1
read_config()
_print = 1
read_config()
end
if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end
print('Writing new version', data)
@ -479,22 +478,34 @@ local function write_signature(data)
if #data ~= 64 then return nil, 'data wrong length. Should be 32 hex bytes' end
-- read CONFIG
if not magicconfig then
_print = 1
read_config()
_print = 1
read_config()
end
local info = connect()
if not info then return false, "Can't select card" end
if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end
print('Writing new signature',data)
local b,c
local cmd = 'A2F%d%s'
local j = 2
for i = 1, #data, 8 do
b = data:sub(i,i+7)
c = cmd:format(j,b)
local resp = send(c)
if resp ~= '0A' then lib14a.disconnect(); return nil, oops('Failed to write signature') end
j = j + 1
if ulprotocol == '00' then
print('Writing new MFC signature',data)
send('CF'.._key..'6B48')
lib14a.disconnect()
connect() -- not 100% sure why it's needed, but without this blocks aren't actually written
local sig1 = data:sub(1, 32)
local sig2 = data:sub(33, 64)
send('CF'.._key..'CD45'..sig1)
send('CF'.._key..'CD46'..sig2)
send('CF'.._key..'CD475C8FF9990DA270F0F8694B791BEA7BCC')
else
print('Writing new MFUL signature',data)
local b,c
local cmd = 'A2F%d%s'
local j = 2
for i = 1, #data, 8 do
b = data:sub(i,i+7)
c = cmd:format(j,b)
local resp = send(c)
if resp ~= '0A' then lib14a.disconnect(); return nil, oops('Failed to write signature') end
j = j + 1
end
end
lib14a.disconnect()
return true, 'Ok'
@ -509,19 +520,19 @@ local function write_gtu(gtu)
local info = connect()
if not info then return false, "Can't select card" end
if gtu == '00' then
print('Enabling GTU Pre-Write')
send('CF'.._key..'32'..gtu)
print('Enabling GTU Pre-Write')
send('CF'.._key..'32'..gtu)
elseif gtu == '01' then
print('Enabling GTU Restore Mode')
send('CF'.._key..'32'..gtu)
print('Enabling GTU Restore Mode')
send('CF'.._key..'32'..gtu)
elseif gtu == '02' then
print('Disabled GTU')
send('CF'.._key..'32'..gtu)
print('Disabled GTU')
send('CF'.._key..'32'..gtu)
elseif gtu == '03' then
print('Disabled GTU, high speed R/W mode for Ultralight')
send('CF'.._key..'32'..gtu)
print('Disabled GTU, high speed R/W mode for Ultralight')
send('CF'.._key..'32'..gtu)
else
print('Failed to set GTU mode')
print('Failed to set GTU mode')
end
lib14a.disconnect()
return true, 'Ok'
@ -537,13 +548,13 @@ local function write_ats(atsuser)
local atscardlendecimal = tonumber(atscardlen, 16)
local atsf = string.sub(atsuser, 3)
if (#atsf / 2) ~= atscardlendecimal then
oops('Given length of ATS ('..atscardlendecimal..') does not match the ATS_length ('..(#atsf / 2)..')')
return true, 'Ok'
oops('Given length of ATS ('..atscardlendecimal..') does not match the ATS_length ('..(#atsf / 2)..')')
return true, 'Ok'
else
local info = connect()
if not info then return false, "Can't select card" end
print('Writing '..atscardlendecimal..' ATS bytes of '..atsf)
send("CF".._key.."34"..atsuser)
local info = connect()
if not info then return false, "Can't select card" end
print('Writing '..atscardlendecimal..' ATS bytes of '..atsf)
send("CF".._key.."34"..atsuser)
end
lib14a.disconnect()
return true, 'Ok'
@ -557,11 +568,11 @@ local function write_ulp(ulp)
local info = connect()
if not info then return false, "Can't select card" end
if ulp == '00' then
print('Changing card to Mifare Classic Protocol')
send("CF".._key.."69"..ulp)
print('Changing card to Mifare Classic Protocol')
send("CF".._key.."69"..ulp)
elseif ulp == '01' then
print('Changing card to Ultralight Protocol')
send("CF".._key.."69"..ulp)
print('Changing card to Ultralight Protocol')
send("CF".._key.."69"..ulp)
else
oops('Protocol needs to be either 00 or 01')
end
@ -577,17 +588,17 @@ local function write_ulm(ulm)
local info = connect()
if not info then return false, "Can't select card" end
if ulm == '00' then
print('Changing card UL mode to Ultralight EV1')
send("CF".._key.."6A"..ulm)
print('Changing card UL mode to Ultralight EV1')
send("CF".._key.."6A"..ulm)
elseif ulm == '01' then
print('Changing card UL mode to NTAG')
send("CF".._key.."6A"..ulm)
print('Changing card UL mode to NTAG')
send("CF".._key.."6A"..ulm)
elseif ulm == '02' then
print('Changing card UL mode to Ultralight-C')
send("CF".._key.."6A"..ulm)
print('Changing card UL mode to Ultralight-C')
send("CF".._key.."6A"..ulm)
elseif ulm == '03' then
print('Changing card UL mode to Ultralight')
send("CF".._key.."6A"..ulm)
print('Changing card UL mode to Ultralight')
send("CF".._key.."6A"..ulm)
else
oops('UL mode needs to be either 00, 01, 02, 03')
end
@ -604,50 +615,50 @@ local function set_type(tagtype)
if tagtype == 1 then
print('Setting: Ultimate Magic card to Mifare mini S20 4-byte')
connect()
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000900")
lib14a.disconnect()
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000900")
lib14a.disconnect()
write_uid('04112233')
-- Setting Mifare mini S20 7-byte
elseif tagtype == 2 then
print('Setting: Ultimate Magic card to Mifare mini S20 7-byte')
connect()
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000900")
lib14a.disconnect()
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000900")
lib14a.disconnect()
write_uid('04112233445566')
-- Setting Mifare 1k S50 4--byte
elseif tagtype == 3 then
print('Setting: Ultimate Magic card to Mifare 1k S50 4-byte')
connect()
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800")
lib14a.disconnect()
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800")
lib14a.disconnect()
write_uid('04112233')
-- Setting Mifare 1k S50 7-byte
elseif tagtype == 4 then
print('Setting: Ultimate Magic card to Mifare 1k S50 7-byte')
connect()
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000800")
lib14a.disconnect()
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000800")
lib14a.disconnect()
write_uid('04112233445566')
-- Setting Mifare 4k S70 4-byte
elseif tagtype == 5 then
print('Setting: Ultimate Magic card to Mifare 4k S70 4-byte')
connect()
send("CF".._key.."F000000000000002000978009102DABC19101011121314151602001800")
lib14a.disconnect()
send("CF".._key.."F000000000000002000978009102DABC19101011121314151602001800")
lib14a.disconnect()
write_uid('04112233')
-- Setting Mifare 4k S70 7-byte
elseif tagtype == 6 then
print('Setting: Ultimate Magic card to Mifare 4k S70 7-byte')
connect()
send("CF".._key.."F000010000000002000978009102DABC19101011121314151642001800")
lib14a.disconnect()
send("CF".._key.."F000010000000002000978009102DABC19101011121314151642001800")
lib14a.disconnect()
write_uid('04112233445566')
-- Setting UL
elseif tagtype == 7 then
print('Setting: Ultimate Magic card to UL')
connect()
send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000003")
lib14a.disconnect()
send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000003")
lib14a.disconnect()
write_uid('04112233445566')
write_otp('00000000') -- Setting OTP to default 00 00 00 00
write_version('0000000000000000') -- UL-C does not have a version
@ -655,48 +666,48 @@ local function set_type(tagtype)
elseif tagtype == 8 then
print('Setting: Ultimate Magic card to UL-C')
connect()
send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000002")
print('Setting default permissions and 3des key')
send('A22A30000000') -- Auth0 page 48/0x30 and above need authentication
send('A22B80000000') -- Auth1 read and write access restricted
send('A22C42524541') -- Default 3des key
send('A22D4B4D4549')
send('A22E46594F55')
send('A22F43414E21')
lib14a.disconnect()
send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000002")
print('Setting default permissions and 3des key')
send('A22A30000000') -- Auth0 page 48/0x30 and above need authentication
send('A22B80000000') -- Auth1 read and write access restricted
send('A22C42524541') -- Default 3des key
send('A22D4B4D4549')
send('A22E46594F55')
send('A22F43414E21')
lib14a.disconnect()
write_uid('04112233445566')
write_otp('00000000') -- Setting OTP to default 00 00 00 00
write_version('0000000000000000') -- UL-C does not have a version
elseif tagtype == 9 then
print('Setting: Ultimate Magic card to UL-EV1 48')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000")
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000")
-- Setting UL-Ev1 default config bl 16,17
send('a2E5FFFFFFFF') -- A2F0 block does not align correctly to actual pwd block
send('a2E6FFFFFFFF') -- A2F1 block does not align correctly to actual pack block
send('a2E5FFFFFFFF') -- A2F0 block does not align correctly to actual pwd block
send('a2E6FFFFFFFF') -- A2F1 block does not align correctly to actual pack block
send('a210000000FF')
send('a21100050000')
lib14a.disconnect()
write_uid('04112233445566')
lib14a.disconnect()
write_uid('04112233445566')
write_otp('00000000') -- Setting OTP to default 00 00 00 00
write_version('0004030101000b03') -- UL-EV1 (48) 00 04 03 01 01 00 0b 03
elseif tagtype == 10 then
print('Setting: Ultimate Magic card to UL-EV1 128')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000")
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000")
-- Setting UL-Ev1 default config bl 37,38
send('a2E5FFFFFFFF') -- A2F0 block does not align correctly to actual pwd block
send('a2E6FFFFFFFF') -- A2F1 block does not align correctly to actual pack block
send('a2E5FFFFFFFF') -- A2F0 block does not align correctly to actual pwd block
send('a2E6FFFFFFFF') -- A2F1 block does not align correctly to actual pack block
send('a225000000FF')
send('a22600050000')
lib14a.disconnect()
write_uid('04112233445566')
lib14a.disconnect()
write_uid('04112233445566')
write_otp('00000000') -- Setting OTP to default 00 00 00 00
write_version('0004030101000e03') -- UL-EV1 (128) 00 04 03 01 01 00 0e 03
elseif tagtype == 12 then
print('Setting: Ultimate Magic card to NTAG 210')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG210 default CC block456
send('a203e1100600')
send('a2040300fe00')
@ -704,13 +715,13 @@ local function set_type(tagtype)
-- Setting cfg1/cfg2
send('a210000000FF')
send('a21100050000')
lib14a.disconnect()
write_uid('04112233445566')
lib14a.disconnect()
write_uid('04112233445566')
write_version('0004040101000b03') -- NTAG210 00 04 04 01 01 00 0b 03
elseif tagtype == 13 then
print('Setting: Ultimate Magic card to NTAG 212')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG212 default CC block456
send('a203e1101000')
send('a2040103900a')
@ -718,13 +729,13 @@ local function set_type(tagtype)
-- Setting cfg1/cfg2
send('a225000000FF')
send('a22600050000')
lib14a.disconnect()
write_uid('04112233445566')
lib14a.disconnect()
write_uid('04112233445566')
write_version('0004040101000E03') -- NTAG212 00 04 04 01 01 00 0E 03
elseif tagtype == 14 then
print('Setting: Ultimate Magic card to NTAG 213')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG213 default CC block456
send('a203e1101200')
send('a2040103a00c')
@ -732,13 +743,13 @@ local function set_type(tagtype)
-- setting cfg1/cfg2
send('a229000000ff')
send('a22a00050000')
lib14a.disconnect()
write_uid('04112233445566')
lib14a.disconnect()
write_uid('04112233445566')
write_version('0004040201000F03') -- NTAG213 00 04 04 02 01 00 0f 03
elseif tagtype == 15 then
print('Setting: Ultimate Magic card to NTAG 215')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG215 default CC block456
send('a203e1103e00')
send('a2040300fe00')
@ -746,13 +757,13 @@ local function set_type(tagtype)
-- setting cfg1/cfg2
send('a283000000ff')
send('a28400050000')
lib14a.disconnect()
write_uid('04112233445566')
lib14a.disconnect()
write_uid('04112233445566')
write_version('0004040201001103') -- NTAG215 00 04 04 02 01 00 11 03
elseif tagtype == 16 then
print('Setting: Ultimate Magic card to NTAG 216')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG216 default CC block456
send('a203e1106d00')
send('a2040300fe00')
@ -760,56 +771,56 @@ local function set_type(tagtype)
-- setting cfg1/cfg2
send('a2e3000000ff')
send('a2e400050000')
lib14a.disconnect()
write_uid('04112233445566')
lib14a.disconnect()
write_uid('04112233445566')
write_version('0004040201001303') -- NTAG216 00 04 04 02 01 00 13 03
elseif tagtype == 17 then
print('Setting: Ultimate Magic card to NTAG I2C 1K')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG I2C 1K default CC block456
send('a203e1106D00')
send('a2040300fe00')
send('a20500000000')
lib14a.disconnect()
write_uid('04112233445566')
lib14a.disconnect()
write_uid('04112233445566')
write_version('0004040502011303') -- NTAG_I2C_1K 00 04 04 05 02 01 13 03
elseif tagtype == 18 then
print('Setting: Ultimate Magic card to NTAG I2C 2K')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG I2C 2K default CC block456
send('a203e110EA00')
send('a2040300fe00')
send('a20500000000')
lib14a.disconnect()
write_uid('04112233445566')
lib14a.disconnect()
write_uid('04112233445566')
write_version('0004040502011503') -- NTAG_I2C_2K 00 04 04 05 02 01 15 03
elseif tagtype == 19 then
print('Setting: Ultimate Magic card to NTAG I2C plus 1K')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG I2C 1K default CC block456
send('a203e1106D00')
send('a2040300fe00')
send('a20500000000')
lib14a.disconnect()
write_uid('04112233445566')
lib14a.disconnect()
write_uid('04112233445566')
write_version('0004040502021303') -- NTAG_I2C_1K 00 04 04 05 02 02 13 03
elseif tagtype == 20 then
print('Setting: Ultimate Magic card to NTAG I2C plus 2K')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG I2C 2K default CC block456
send('a203e1106D00')
send('a2040300fe00')
send('a20500000000')
write_uid('04112233445566')
write_uid('04112233445566')
write_version('0004040502021503') -- NTAG_I2C_2K 00 04 04 05 02 02 15 03
elseif tagtype == 21 then
print('Setting: Ultimate Magic card to NTAG 213F')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG213 default CC block456
send('a203e1101200')
send('a2040103a00c')
@ -817,13 +828,13 @@ local function set_type(tagtype)
-- setting cfg1/cfg2
send('a229000000ff')
send('a22a00050000')
lib14a.disconnect()
write_uid('04112233445566')
lib14a.disconnect()
write_uid('04112233445566')
write_version('0004040401000F03') -- NTAG213F 00 04 04 04 01 00 0f 03
elseif tagtype == 22 then
print('Setting: Ultimate Magic card to NTAG 216F')
connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG216 default CC block456
send('a203e1106d00')
send('a2040300fe00')
@ -831,11 +842,11 @@ local function set_type(tagtype)
-- setting cfg1/cfg2
send('a2e3000000ff')
send('a2e400050000')
lib14a.disconnect()
write_uid('04112233445566')
lib14a.disconnect()
write_uid('04112233445566')
write_version('0004040401001303') -- NTAG216F 00 04 04 04 01 00 13 03
else
oops('No matching tag types')
oops('No matching tag types')
end
lib14a.disconnect()
if resp == '04' then
@ -845,86 +856,101 @@ local function set_type(tagtype)
end
end
---
-- returns true if b is the index of a sector trailer
local function mfIsSectorTrailer(b)
n=b+1
if (n < 32*4 ) then
if (n % 4 == 0) then return true
else return false
end
end
if (n % 16 == 0) then return true
end
return false
end
---
-- wipe tag
local function wipe(wtype)
local info = connect()
if not info then return false, "Can't select card" end
if wtype == '0' then
print('Starting Mifare Wipe')
print('Starting Mifare Wipe')
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800")
send("CF".._key.."CD000102030404080400000000000000BEAF")
local err, msg, resp
local cmd_empty = 'CF'.._key..'CD%02X00000000000000000000000000000000'
local cmd_cfg1 = 'CF'.._key..'CD%02XFFFFFFFFFFFFFF078069FFFFFFFFFFFF'
for b = 1, 0xFB do
if b == 0x03 or b == 0x07 or b == 0x0B or b == 0x0F or b == 0x13 or b == 0x17 or b == 0x1B or b == 0x1F or b == 0x23 or b == 0x27 or b == 0x2B or b == 0x2F or b == 0x33 or b == 0x37 or b == 0x3B or b == 0x3F then
local cmd = (cmd_cfg1):format(b)
resp = send(cmd)
else
local cmd = (cmd_empty):format(b)
resp = send(cmd)
end
if resp == nil then
io.write('\nwrote block '..b, ' failed\n')
err = true
else
io.write('.')
end
io.flush()
end
print('\n')
err, msg = set_type(3)
if err == nil then return err, msg end
lib14a.disconnect()
return true, 'Ok'
local err, msg, resp
local cmd_empty = 'CF'.._key..'CD%02X00000000000000000000000000000000'
local cmd_trail = 'CF'.._key..'CD%02XFFFFFFFFFFFFFF078069FFFFFFFFFFFF'
for b = 1, 0xFF do
if mfIsSectorTrailer(b) then
local cmd = (cmd_trail):format(b)
resp = send(cmd)
else
local cmd = (cmd_empty):format(b)
resp = send(cmd)
end
if resp == nil then
io.write('\nwrote block '..b, ' failed\n')
err = true
else
io.write('.')
end
io.flush()
end
print('\n')
err, msg = set_type(3)
if err == nil then return err, msg end
lib14a.disconnect()
return true, 'Ok'
elseif wtype == '1' then
print('Starting Ultralight Wipe')
local err, msg, resp
local cmd_empty = 'A2%02X00000000'
local cmd_cfg1 = 'A2%02X000000FF'
local cmd_cfg2 = 'A2%02X00050000'
print('Wiping tag')
local info = connect()
if not info then return false, "Can't select card" end
print('Starting Ultralight Wipe')
local err, msg, resp
local cmd_empty = 'A2%02X00000000'
local cmd_cfg1 = 'A2%02X000000FF'
local cmd_cfg2 = 'A2%02X00050000'
print('Wiping tag')
local info = connect()
if not info then return false, "Can't select card" end
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
for b = 3, 0xFB do
--configuration block 0
if b == 0x29 or b == 0x83 or b == 0xe3 then
local cmd = (cmd_cfg1):format(b)
resp = send(cmd)
--configuration block 1
elseif b == 0x2a or b == 0x84 or b == 0xe4 then
local cmd = (cmd_cfg2):format(b)
resp = send(cmd)
else
resp = send(cmd_empty:format(b))
end
if resp == '04' or #resp == 0 then
io.write('\nwrote block '..b, ' failed\n')
err = true
else
io.write('.')
end
io.flush()
end
io.write('\r\n')
lib14a.disconnect()
print('\n')
if err then return nil, "Tag locked down, "..err_lock end
-- set NTAG213 default values
err, msg = set_type(14)
if err == nil then return err, msg end
--set UID
err, msg = write_uid('04112233445566')
if err == nil then return err, msg end
--set NTAG pwd
err, msg = write_ntagpwd('FFFFFFFF')
if err == nil then return err, msg end
--set pack
err, msg = write_pack('0000')
if err == nil then return err, msg end
lib14a.disconnect()
return true, 'Ok'
for b = 3, 0xFB do
--configuration block 0
if b == 0x29 or b == 0x83 or b == 0xe3 then
local cmd = (cmd_cfg1):format(b)
resp = send(cmd)
--configuration block 1
elseif b == 0x2a or b == 0x84 or b == 0xe4 then
local cmd = (cmd_cfg2):format(b)
resp = send(cmd)
else
resp = send(cmd_empty:format(b))
end
if resp == '04' or #resp == 0 then
io.write('\nwrote block '..b, ' failed\n')
err = true
else
io.write('.')
end
io.flush()
end
io.write('\r\n')
lib14a.disconnect()
print('\n')
if err then return nil, "Tag locked down, "..err_lock end
-- set NTAG213 default values
err, msg = set_type(14)
if err == nil then return err, msg end
--set UID
err, msg = write_uid('04112233445566')
if err == nil then return err, msg end
--set NTAG pwd
err, msg = write_ntagpwd('FFFFFFFF')
if err == nil then return err, msg end
--set pack
err, msg = write_pack('0000')
if err == nil then return err, msg end
lib14a.disconnect()
return true, 'Ok'
else oops('Use 0 for Mifare wipe or 1 for Ultralight wipe')
end
end

View file

@ -0,0 +1,164 @@
local cmds = require('commands')
local getopt = require('getopt')
local os = require('os')
local io = require('io')
local bin = require('bin')
local utils = require('utils')
local ansicolors = require('ansicolors')
local amiibo_tools = require('amiibo_tools')
copyright = ''
author = 'George Talusan'
version = 'v0.0.1'
desc = [[
This script will try to restore a binary datadump of an Amiibo to a blank NTAG215.
It will recalculate PWD and PACK if necessary, set the appropriate password and sector lock bytes.
NOTE: PyAmiibo must be installed. The helper script pyscripts/amiibo_change_uid.py depends on PyAmiibo.
YMMV if a non-blank NTAG215 is provided!
]]
example = [[
1. script run hf_mfu_amiibo_restore
2. script run hf_mfu_amiibo_restore -f myfile -k password
]]
usage = [[
script run hf_mfu_amiibo_restore [-h] [-f <filename> -k <password>]
]]
arguments = [[
-h : this help
-f : filename for the datadump to read (bin)
-k : password of blank NTAG 215 (use `hf mfu info` to find it)
]]
local DEBUG = false -- the debug flag
local bxor = bit32.bxor
local sub = string.sub
local format = string.format
---
-- A debug printout-function
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while result[i] do
dbg(result[i])
i = i+1
end
else
print('###', args)
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, err
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
--
-- Exit message
local function ExitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
local result, err, hex
local inputTemplate = 'dumpdata.bin'
local password
for o, a in getopt.getopt(args, 'hf:k:') do
if o == 'h' then return help() end
if o == 'f' then inputTemplate = a end
if o == 'k' then password = a end
end
print(('Loading data from %s'):format(inputTemplate))
hex, err = utils.ReadDumpFile(inputTemplate)
if not hex then return oops(err) end
if not password or #password ~= 8 then
return oops('Expecting 4 byte password (hint: use `hf mfu info` to get it)')
end
-- chomp emu header
if #hex == 1192 then
hex = hex:sub(113)
end
local amiibo_offset = 0
local amiibo_info = hex:sub(amiibo_offset + 169, amiibo_offset + 169 + 15):lower()
local amiibo_game = amiibo_info:sub(1, 3)
local amiibo_type = amiibo_info:sub(7, 8)
local amiibo_series = amiibo_info:sub(13, 14)
dbg('raw: '..ansicolors.green..amiibo_info..ansicolors.reset)
print('game: '..ansicolors.green..amiibo_tools.db.game_series[("0x%s"):format(amiibo_game)]..ansicolors.reset)
print('character: '..ansicolors.green..amiibo_tools.db.amiibos[("0x%s"):format(amiibo_info)].name..ansicolors.reset)
print('type: '..ansicolors.green..amiibo_tools.db.types[("0x%s"):format(amiibo_type)]..ansicolors.reset)
print('series: '..ansicolors.green..amiibo_tools.db.amiibo_series[("0x%s"):format(amiibo_series)]..ansicolors.reset)
local uid = core.ul_read_uid();
if uid == nil then
return oops("Can't read UID of NTAG215 card. Reposition card and try again.")
end
local tmp = ('%s.bin'):format(os.tmpname())
local amiibo_file = io.open(tmp, 'w+b')
amiibo_file:write(bin.pack('H', hex))
amiibo_file:close()
local tmp2 = ('%s.bin'):format(os.tmpname())
print('generating new Amiibo binary for NTAG215 '..ansicolors.green..uid)
core.clearCommandBuffer()
core.console(('script run amiibo_change_uid %s %s %s %s'):format(uid, tmp, tmp2, core.search_file('resources/key_retail', '.bin')))
-- let's sanity check the output
hex, err = utils.ReadDumpFile(tmp2)
if not hex or #hex ~= 1080 then
os.remove(tmp)
os.remove(tmp2)
return oops('There was a problem generating the output Amiibo')
end
core.console(('hf mfu restore -f %s -k %s'):format(tmp2, password))
-- re-write some blocks because `hf mfu restore` won't write out blocks 0-3, and PyAmiibo won't give a PACK/PWD
local pwd, pack = core.keygen_algo_b(uid)
core.console(('hf mfu wrbl -b 3 -d F110FFEE -k %s'):format(password)) -- CC?
core.console(('hf mfu wrbl -b 134 -d %04X0000 -k %s'):format(pack, password)) -- PACK/RFUI
core.console(('hf mfu wrbl -b 133 -d %08X -k %s'):format(pwd, password)) -- PWD
core.console(('hf mfu wrbl -b 131 -d 00000004 -k %08X'):format(pwd)) -- CFG0
core.console(('hf mfu wrbl -b 132 -d 5F000000 -k %08X'):format(pwd)) -- CFG1
local lock_bytes = hex:sub(17, 24)
dbg('lock_bytes: '..lock_bytes)
core.console(('hf mfu wrbl -b 2 -d %s -k %08X'):format(lock_bytes, pwd)) -- BCC1/static lock
core.console(('hf mfu wrbl -b 130 -d 01000FBD -k %08X'):format(pwd)) -- dynamic lock/RFUI
os.remove(tmp)
os.remove(tmp2)
end
main(args)

View file

@ -0,0 +1,152 @@
local cmds = require('commands')
local getopt = require('getopt')
local bin = require('bin')
local utils = require('utils')
local ansicolors = require('ansicolors')
local amiibo_tools = require('amiibo_tools')
copyright = ''
author = 'George Talusan'
version = 'v0.0.2'
desc = [[
This script will try to load a binary datadump of an Amiibo.
It will recalculate PWD and PACK if necessary.
]]
example = [[
1. script run hf_mfu_amiibo_sim
2. script run hf_mfu_amiibo_sim -f myfile
]]
usage = [[
script run hf_mfu_amiibo_sim [-h] [-f <filename>]
]]
arguments = [[
-h : this help
-f : filename for the datadump to read (bin)
]]
local DEBUG = false -- the debug flag
local bxor = bit32.bxor
local sub = string.sub
local format = string.format
---
-- A debug printout-function
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while result[i] do
dbg(result[i])
i = i+1
end
else
print('###', args)
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, err
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
--
-- Exit message
local function ExitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
local function LoadEmulator(uid, blocks)
io.write('Sending Amiibo to emulator memory')
local cmd, blockdata
for i=0,148,1 do
blockdata = blocks[i]
io.write('.')
io.flush()
core.clearCommandBuffer()
cmd = Command:newNG{cmd = cmds.CMD_HF_MIFARE_EML_MEMSET, data = ('%02x%02x%02x%s'):format(i, 1, 4, blockdata)}
local err, msg = cmd:sendNG(true)
if err == nil then return err, msg end
end
io.write('\n')
end
local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
local result, err, hex
local inputTemplate = 'dumpdata.bin'
for o, a in getopt.getopt(args, 'hf:u:') do
if o == 'h' then return help() end
if o == 'f' then inputTemplate = a end
end
print(('Loading data from %s'):format(inputTemplate))
hex, err = utils.ReadDumpFile(inputTemplate)
if not hex then return oops(err) end
-- only deal with missing PWD and PACK, or with 56 emu hdr
if #hex ~= 1064 and #hex ~= 1080 and #hex ~= 1192 then return oops('Expecting either a plain binary or emulator dump') end
local amiibo_offset = (#hex == 1064 or #hex == 1080) and 0 or 112
local amiibo_info = hex:sub(amiibo_offset + 169, amiibo_offset + 169 + 15):lower()
local amiibo_game = amiibo_info:sub(1, 3)
local amiibo_type = amiibo_info:sub(7, 8)
local amiibo_series = amiibo_info:sub(13, 14)
dbg('raw: '..ansicolors.green..amiibo_info..ansicolors.reset)
print('game: '..ansicolors.green..amiibo_tools.db.game_series[("0x%s"):format(amiibo_game)]..ansicolors.reset)
print('character: '..ansicolors.green..amiibo_tools.db.amiibos[("0x%s"):format(amiibo_info)].name..ansicolors.reset)
print('type: '..ansicolors.green..amiibo_tools.db.types[("0x%s"):format(amiibo_type)]..ansicolors.reset)
print('series: '..ansicolors.green..amiibo_tools.db.amiibo_series[("0x%s"):format(amiibo_series)]..ansicolors.reset)
local blocks = {}
local blockindex = 0
-- add empty header if necessary
if (#hex == 1064 or #hex == 1080) then
for i = 0, 13, 1 do
blocks[i] = '00000000'
end
blocks[2] = '00000086'
blockindex = 14
end
for i = 1, #hex, 8 do
blocks[blockindex] = hex:sub(i, i+7)
blockindex = blockindex + 1
end
-- force lock bytes, otherwise the Amiibo won't be recognized
blocks[16] = blocks[16]:sub(1, 4)..'0FE0'
-- add PWD and PACK
local uid = blocks[14]:sub(1, 6)..blocks[15]:sub(1, 8)
blocks[147] = ("%08x"):format(bxor(bxor(tonumber(sub(uid, 2, 10), 16), tonumber(sub(uid, 6, 14), 16)), 0xaa55aa55))
blocks[148] = "80800000"
err = LoadEmulator(uid, blocks)
if err then return oops(err) end
core.clearCommandBuffer()
core.console(("hf mfu sim -t 7 -u %s"):format(uid))
end
main(args)

View file

@ -6,20 +6,20 @@ local ansicolors = require('ansicolors')
copyright = ''
author = "Iceman"
version = 'v1.0.1'
version = 'v1.0.2'
desc = [[
This script calculates mifare Ultralight-EV1 pwd based on uid diversification for an Italian ticketsystem
Algo not found by me.
]]
example =[[
-- if called without, it reads tag uid
script run hf_mfu_uidkeycalc-italy
script run hf_mfu_uidkeycalc_italy
--
script run hf_mfu_uidkeycalc-italy -u 11223344556677
script run hf_mfu_uidkeycalc_italy -u 11223344556677
]]
usage = [[
script run hf_mfu_uidkeycalc-italy -h -u <uid> "
script run hf_mfu_uidkeycalc_italy -h -u <uid> "
]]
arguments = [[
-h : this help

View file

@ -0,0 +1,171 @@
local getopt = require('getopt')
local ansicolors = require('ansicolors')
copyright = ''
author = 'Shain Lakin'
version = 'v1.0.0'
desc =[[
This script modifies the DT NeXT implant (NTAG216) configuration pages.
- NeXT Defaults -
Default hf mfu info:
----------------------------------------------------------------------
[=] --- Tag Configuration
[=] cfg0 [227/0xE3]: 04 00 00 E3
[=] - strong modulation mode disabled
[=] - page 227 and above need authentication
[=] cfg1 [228/0xE4]: 00 05 00 00
[=] - Unlimited password attempts
[=] - NFC counter disabled
[=] - NFC counter not protected
[=] - user configuration writeable
[=] - write access is protected with password
[=] - 05, Virtual Card Type Identifier is default
[=] PWD [229/0xE5]: 00 00 00 00 - (cannot be read)
[=] PACK [230/0xE6]: 00 00 - (cannot be read)
[=] RFU [230/0xE6]: 00 00 - (cannot be read)
----------------------------------------------------------------------
Default blocks 0xE0 to 0xE6:
-------------------------------------
[=] 224/0xE0 | 00 00 00 00 | 0 | ....
[=] 225/0xE1 | 4E 45 78 54 | 0 | NExT
[=] 226/0xE2 | 00 00 7F BD | 0 | ....
[=] 227/0xE3 | 04 00 00 E3 | 0 | ....
[=] 228/0xE4 | 00 05 00 00 | 0 | ....
[=] 229/0xE5 | 44 4E 47 52 | 0 | DNGR
[=] 230/0xE6 | 00 00 00 00 | 0 | ....
-------------------------------------
]]
example =[[
Set a new password of SUDO using the default password of DNGR:
script run hf_ntag_dt -x pass -p DNGR -n SUDO
Enable password protection from hex block 04 onwards (User memory):
script run hf_ntag_dt -x protect -p DNGR -a 04
Enable password protection from hex block E3 onwards (Configuration Pages):
script run hf_ntag_dt -x protect -p DNGR -a E3
Disable password protection:
script run hf_ntag_dt -x protect -p DNGR -a FF
Enable the counter and enable read + write password protection on password protected pages
(protected block start page specified using -x protect mode):
script run hf_ntag_dt -x conf -p DNGR -c enable -m rw
Disable the counter and enable write only password protection on password protected pages
(protected block start specified using -x protect mode):
script run hf_ntag_dt -x conf -p DNGR -c disable -m w
]]
usage = [[
script run hf_ntag_dt -x pass -p <password> -n <new_password>
script run hf_ntag_dt -x protect -p <password> -a <auth0_block>
script run hf_ntag_dt -x conf -p <password> -c <enable/disable> -m <r/rw>
]]
arguments = [[
-h this help
-x mode (pass, protect, conf)
-p password (ascii)
-n new password (ascii)
-a auth0 block (hex)
-c counter (enable/disable)
-m protection mode (r/rw)
]]
---
--- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
---
--- Print user message
local function msg(msg)
print( string.rep('--',20) )
print('')
print(msg)
print('')
print( string.rep('--',20) )
end
---
--- String to hex function
local function strhex(str)
return (str:gsub(".", function(char) return string.format("%2x", char:byte()) end))
end
---
-- Main
local function main(args)
for o, a in getopt.getopt(args, 'b:m:c:a:p:x:n:h') do
if o == 'm' then prot_mode = a end
if o == 'c' then counter = a end
if o == 'a' then auth0_block = a end
if o == 'p' then passwd = strhex(a) end
if o == 'x' then mode = a end
if o == 'n' then new_pass = strhex(a) end
if o == 'h' then return help() end
end
if mode == 'pass' then
command = 'hf mfu wrbl -b 229 -d '..new_pass..' -k '..passwd
msg('Writing '..new_pass..' to PASSWD block (229/0xE5) : \n\n'..command)
core.console(command)
command = 'hf mfu rdbl -b 0 -k '..new_pass..''
msg('Verifying password is correctly set : \n\n'..command)
core.console(command)
elseif mode == 'conf' then
if counter == 'enable' then
if prot_mode == 'r' then
command = 'hf mfu wrbl -b 228 -d 10050000 -k '..passwd
msg('Enabling counter and setting write access to protected pages as password protected : \n\n'..command)
core.console(command)
elseif prot_mode == 'rw' then
command = 'hf mfu wrbl -b 228 -d 90050000 -k '..passwd
msg('Enabling counter and setting read/write access to protected pages as password protected : \n\n'..command)
core.console(command)
end
elseif counter == 'disable' then
if prot_mode == 'w' then
command = 'hf mfu wrbl -b 228 -d 00050000 -k '..passwd
msg('Disabling counter and setting write password protection on protected pages : \n\n'..command)
core.console(command)
elseif prot_mode == 'rw' then
command = 'hf mfu wrbl -b 228 -d 80050000 -k '..passwd
msg('Disabling counter and setting read/write password protection on protected pages : \n\n'..command)
core.console(command)
end
end
elseif mode == 'protect' then
command = 'hf mfu wrbl -k '..passwd..' -b 227 -d 040000'..auth0_block
msg('Enabling password protection from block '..auth0_block..' onwards : \n\n'..command)
core.console(command)
else
return print(usage)
end
if command == '' then return print(usage) end
end
main(args)

View file

@ -6,7 +6,7 @@ local ac = require('ansicolors')
copyright = ''
author = "Christian Herrmann"
version = 'v1.0.0'
version = 'v1.0.1'
desc = [[
This script loads a json format file, with the field "data" and a hexbyte array of data. Ie t55x7 dump,
it tries to identify which system based on block1, and detect block0 settings.
@ -16,7 +16,7 @@ example = [[
script run lf_ident_json -i lf_t55xx.json
]]
usage = [[
script run lf_en4100_bulk.lua [-h] [-c] [-p password] [-s <start cn>] [-v]
script run lf_ident_json.lua [-h] [-c] [-p password] [-s <start cn>] [-v]
]]
arguments = [[
-h : this help

View file

@ -0,0 +1,44 @@
# Requirements:
# python3 -m pip install pyamiibo
import sys
from amiibo import AmiiboDump, AmiiboMasterKey
def main():
if(len(sys.argv) != 5):
print("""
\t{0} - helper script for integrating with PyAmiibo
Usage: {0} <uid> <infile> <outfile> <keyfile>
Example:
\t{0} 04123456789ABC my_amiibo_original.bin my_amiibo_with_new_uid.bin keyfile.bin
\n""".format(sys.argv[0]))
return 1
uid = sys.argv[1]
infile = sys.argv[2]
outfile = sys.argv[3]
keyfile = sys.argv[4]
if len(uid) != 14:
print('expecting 7 byte UID')
return 1
with open(keyfile, 'rb') as keybin:
master_key = AmiiboMasterKey.from_combined_bin(keybin.read())
with open(infile, 'rb') as fin, open(outfile, 'wb') as fout:
dump = AmiiboDump(master_key, fin.read(), is_locked=True)
dump.unlock()
dump.uid_hex = uid
dump.lock()
fout.write(dump.data)
return 0
if __name__ == "__main__":
sys.exit(main())

View file

@ -1247,6 +1247,14 @@
"Description": "PIV End Point Applet. Last 2 bytes designate version",
"Type": ""
},
{
"AID": "A000000308000010000100",
"Vendor": "National Institute of Standards and Technology",
"Country": "United States",
"Name": "Personal Identity Verification (PIV) / ID-ONE PIV BIO",
"Description": "PIV End Point Applet. Last 2 bytes designate version",
"Type": ""
},
{
"AID": "A00000031510100528",
"Vendor": "Currence Holding/PIN BV",
@ -2206,5 +2214,61 @@
"Name": "SL Resekort",
"Description": "transport card",
"Type": "transport"
},
{
"AID": "4F53452E5641532E3031",
"Vendor": "Apple, Google",
"Country": "",
"Name": "Value-Added Services (OSE.VAS.01)",
"Description": "Used by Apple VAS and Google SmartTap",
"Type": "loyalty"
},
{
"AID": "A000000476D0000101",
"Vendor": "Google",
"Country": "",
"Name": "Google SmartTap 1.3 (Deprecated)",
"Description": "",
"Type": "loyalty"
},
{
"AID": "A000000476D0000111",
"Vendor": "Google",
"Country": "",
"Name": "Google SmartTap 2.0",
"Description": "",
"Type": "loyalty"
},
{
"AID": "A0000002480400",
"Vendor": "ISO/IEC JTC1/SC17",
"Country": "",
"Name": "Personal identification (mDL)",
"Description": "ISO/IEC 18013-5:2021 compliant Mobile driving licence (mDL) application.",
"Type": "identity"
},
{
"AID": "A000000676",
"Vendor": "Blackboard",
"Country": "United States",
"Name": "Student ID",
"Description": "Student ID cards",
"Type": "identity"
},
{
"AID": "A000000809434343444B467631",
"Vendor": "Car Connectivity Consortium (CCC)",
"Country": "",
"Name": "Digital Car Key",
"Description": "",
"Type": "access"
},
{
"AID": "A0000008580101",
"Vendor": "Apple",
"Country": "",
"Name": "Apple Home Key",
"Description": "NFC Home Key for select HomeKit-compatible locks",
"Type": "access"
}
]

View file

@ -6097,6 +6097,41 @@
"service_provider": "CDVI",
"system_integrator": "CDVI"
},
{
"application": "(access control and security) VIGIK",
"company": "CDV International",
"mad": "0x4914",
"service_provider": "CDVI",
"system_integrator": "CDVI"
},
{
"application": "(access control and security) VIGIK",
"company": "CDV International",
"mad": "0x4915",
"service_provider": "CDVI",
"system_integrator": "CDVI"
},
{
"application": "(access control and security) VIGIK",
"company": "CDV International",
"mad": "0x4916",
"service_provider": "CDVI",
"system_integrator": "CDVI"
},
{
"application": "(access control and security) VIGIK",
"company": "CDV International",
"mad": "0x4917",
"service_provider": "CDVI",
"system_integrator": "CDVI"
},
{
"application": "(access control and security) VIGIK",
"company": "CDV International",
"mad": "0x4918",
"service_provider": "CDVI",
"system_integrator": "CDVI"
},
{
"application": "(access control and security) VIGIK",
"company": "NORALSY",

BIN
client/resources/sim013.bin Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
3bb6cbd893ce07720d8514d00706b230b4026a54d6c4dc068ca294beea3f3735c75dae65bc153f573b7b891753c85860f6427fb0ad7edb804d58925c50d1fc76 *sim013.bin

View file

@ -17,17 +17,17 @@
//-----------------------------------------------------------------------------
#include "cipursecore.h"
#include <string.h> // memcpy memset
#include "commonutil.h" // ARRAYLEN
#include "comms.h" // DropField
#include "util_posix.h" // msleep
#include <string.h> // memcpy memset
#include "commonutil.h" // ARRAYLEN
#include "comms.h" // DropField
#include "util_posix.h" // msleep
#include "cmdhf14a.h"
#include "../emv/emvcore.h"
#include "../emv/emvjson.h"
#include "../iso7816/apduinfo.h" // sAPDU_t
#include "../iso7816/apduinfo.h" // sAPDU_t
#include "ui.h"
#include "util.h"
#include "protocols.h" // ISO7816 APDU return codes
// context for secure channel
CipurseContext_t cipurseContext;
@ -112,7 +112,7 @@ static int CIPURSEExchangeEx(bool activate_field, bool leave_field_on, sAPDU_t a
*sw = isw;
}
if (isw != 0x9000) {
if (isw != ISO7816_OK) {
if (GetAPDULogging()) {
if (*sw >> 8 == 0x61) {
PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff);
@ -255,7 +255,7 @@ bool CIPURSEChannelAuthenticate(uint8_t keyindex, uint8_t *key, bool verbose) {
// authenticate
res = CIPURSEMutualAuthenticate(keyindex, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000 || len != 16) {
if (res != 0 || sw != ISO7816_OK || len != 16) {
if (sw == 0x6988) {
if (verbose) {
PrintAndLogEx(WARNING, "Authentication ( " _RED_("fail") " ). Wrong key");
@ -412,10 +412,14 @@ void CIPURSEPrintDGI(uint8_t *dgi, size_t dgilen) {
}
for (int i = 0; i < len / 20; i++) {
PrintAndLogEx(INFO, "Key[%d]............ %s", i + 1, sprint_hex_inrow(&dgi[3 + i * 20 + 0], 16));
PrintAndLogEx(INFO, " Additional info.. 0x%02x", dgi[3 + i * 20 + 16]);
uint8_t kvv[CIPURSE_KVV_LENGTH] = {0};
CipurseCGetKVV(&dgi[3 + i * 20 + 0], kvv);
uint8_t aeskey[16] = {0};
memcpy(aeskey, &dgi[3 + i * 20 + 0], sizeof(aeskey));
PrintAndLogEx(INFO, "Key[%d]............ %s", i + 1, sprint_hex_inrow(aeskey, sizeof(aeskey)));
PrintAndLogEx(INFO, " Additional info.. 0x%02x", dgi[3 + i * 20 + 16]);
CipurseCGetKVV(aeskey, kvv);
bool kvvvalid = (memcmp(kvv, &dgi[3 + i * 20 + 17], 3) == 0);
PrintAndLogEx(INFO, " KVV.............. %s (%s)", sprint_hex_inrow(&dgi[3 + i * 20 + 17], 3), (kvvvalid) ? _GREEN_("valid") : _RED_("invalid"));
}

View file

@ -424,8 +424,8 @@ static int CmdrevengSearch(const char *Cmd) {
uint8_t width[NMODELS] = {0};
int count = 0;
char result[30];
char revResult[30];
char result[50 + 1] = {0};
char revResult[50 + 1] = {0};
int ans = GetModels(Models, &count, width);
bool found = false;
if (!ans) {
@ -461,7 +461,7 @@ static int CmdrevengSearch(const char *Cmd) {
continue;
}
memset(result, 0, 30);
memset(result, 0, sizeof(result));
char *inCRC = calloc(crcChars + 1, sizeof(char));
if (inCRC == NULL) {
return 0;

View file

@ -35,6 +35,9 @@
#include "cmdlft55xx.h" // print...
#include "crypto/asn1utils.h" // ASN1 decode / print
#include "cmdflashmemspiffs.h" // SPIFFS flash memory download
#include "mbedtls/bignum.h" // big num
#include "mbedtls/entropy.h" //
#include "mbedtls/ctr_drbg.h" // random generator
uint8_t g_DemodBuffer[MAX_DEMOD_BUF_LEN];
size_t g_DemodBufferLen = 0;
@ -894,7 +897,7 @@ static int CmdAutoCorr(const char *Cmd) {
}
if (window >= g_GraphTraceLen) {
PrintAndLogEx(WARNING, "window must be smaller than trace (" _YELLOW_("%zu") " samples)", g_GraphTraceLen);
PrintAndLogEx(WARNING, "window must be smaller than trace ( " _YELLOW_("%zu") " samples )", g_GraphTraceLen);
return PM3_EINVARG;
}
@ -1230,7 +1233,7 @@ int FSKrawDemod(uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow, bo
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _YELLOW_("%s") " decoded bitstream", GetFSKType(fchigh, fclow, invert));
PrintAndLogEx(INFO, "-----------------------");
printDemodBuff(0, false, invert, false);
printDemodBuff(0, false, false, false);
}
goto out;
} else {
@ -1779,7 +1782,7 @@ int getSamplesEx(uint32_t start, uint32_t end, bool verbose, bool ignore_lf_conf
BitstreamOut_t bout = { got, bits_per_sample * n, 0};
uint32_t j = 0;
for (j = 0; j * bits_per_sample < n * 8 && j < n; j++) {
for (j = 0; j * bits_per_sample < n * 8 && j * bits_per_sample < MAX_GRAPH_TRACE_LEN * 8; j++) {
uint8_t sample = getByte(bits_per_sample, &bout);
g_GraphBuffer[j] = ((int) sample) - 127;
}
@ -1817,7 +1820,7 @@ static int CmdSamples(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_int0("n", NULL, "<dec>", "num of samples (512 - 40000)"),
arg_lit0("v", "verbose", "verbose"),
arg_lit0("v", "verbose", "verbose output"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -2032,6 +2035,8 @@ static int CmdLoad(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<fn>", "file to load"),
arg_lit0("b", "bin", "binary file"),
arg_lit0("n", "no-fix", "Load data from file without any transformations"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -2039,6 +2044,8 @@ static int CmdLoad(const char *Cmd) {
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool is_bin = arg_get_lit(ctx, 2);
bool nofix = arg_get_lit(ctx, 3);
CLIParserFree(ctx);
char *path = NULL;
@ -2048,8 +2055,13 @@ static int CmdLoad(const char *Cmd) {
}
}
FILE *f = fopen(path, "r");
if (!f) {
FILE *f;
if (is_bin)
f = fopen(path, "rb");
else
f = fopen(path, "r");
if (f == NULL) {
PrintAndLogEx(WARNING, "couldn't open '%s'", path);
free(path);
return PM3_EFILE;
@ -2057,24 +2069,38 @@ static int CmdLoad(const char *Cmd) {
free(path);
g_GraphTraceLen = 0;
char line[80];
while (fgets(line, sizeof(line), f)) {
g_GraphBuffer[g_GraphTraceLen] = atoi(line);
g_GraphTraceLen++;
if (g_GraphTraceLen >= MAX_GRAPH_TRACE_LEN)
break;
if (is_bin) {
uint8_t val[2];
while (fread(val, 1, 1, f)) {
g_GraphBuffer[g_GraphTraceLen] = val[0] - 127;
g_GraphTraceLen++;
if (g_GraphTraceLen >= MAX_GRAPH_TRACE_LEN)
break;
}
} else {
char line[80];
while (fgets(line, sizeof(line), f)) {
g_GraphBuffer[g_GraphTraceLen] = atoi(line);
g_GraphTraceLen++;
if (g_GraphTraceLen >= MAX_GRAPH_TRACE_LEN)
break;
}
}
fclose(f);
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " samples", g_GraphTraceLen);
uint8_t bits[g_GraphTraceLen];
size_t size = getFromGraphBuf(bits);
if (nofix == false) {
uint8_t bits[g_GraphTraceLen];
size_t size = getFromGraphBuf(bits);
removeSignalOffset(bits, size);
setGraphBuf(bits, size);
computeSignalProperties(bits, size);
removeSignalOffset(bits, size);
setGraphBuf(bits, size);
computeSignalProperties(bits, size);
}
setClockGrid(0, 0);
g_DemodBufferLen = 0;
@ -2402,6 +2428,19 @@ static int CmdZerocrossings(const char *Cmd) {
return PM3_SUCCESS;
}
static bool data_verify_hex(uint8_t *d, size_t n) {
if (d == NULL)
return false;
for (size_t i = 0; i < n; i++) {
if (isxdigit(d[i]) == false) {
PrintAndLogEx(ERR, "Non hex digit found");
return false;
}
}
return true;
}
/**
* @brief Utility for conversion via cmdline.
* @param Cmd
@ -2478,12 +2517,8 @@ static int Cmdhex2bin(const char *Cmd) {
return PM3_EINVARG;
}
for (int i = 0; i < dlen; i++) {
char x = data[i];
if (isxdigit(x) == false) {
PrintAndLogEx(ERR, "Non hex digit found");
return PM3_EINVARG;
}
if (data_verify_hex((uint8_t *)data, dlen) == false) {
return PM3_EINVARG;
}
PrintAndLogEx(SUCCESS, "" NOLF);
@ -2744,13 +2779,19 @@ static int print_modulation(lf_modulation_t b) {
static int try_detect_modulation(void) {
lf_modulation_t tests[6];
#define LF_NUM_OF_TESTS 6
lf_modulation_t tests[LF_NUM_OF_TESTS];
for (int i = 0; i < ARRAYLEN(tests); i++) {
memset(&tests[i], 0, sizeof(lf_modulation_t));
}
int clk = 0, firstClockEdge = 0;
uint8_t hits = 0, ans = 0;
uint8_t fc1 = 0, fc2 = 0;
uint8_t hits = 0, fc1 = 0, fc2 = 0;
bool st = false;
ans = fskClocks(&fc1, &fc2, (uint8_t *)&clk, &firstClockEdge);
uint8_t ans = fskClocks(&fc1, &fc2, (uint8_t *)&clk, &firstClockEdge);
if (ans && ((fc1 == 10 && fc2 == 8) || (fc1 == 8 && fc2 == 5))) {
@ -2874,8 +2915,8 @@ static int CmdAsn1Decoder(const char *Cmd) {
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int dlen = 256;
uint8_t data[256];
int dlen = 2048;
uint8_t data[2048];
CLIGetHexWithReturn(ctx, 1, data, &dlen);
CLIParserFree(ctx);
@ -2886,8 +2927,6 @@ static int CmdAsn1Decoder(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdDiff(const char *Cmd) {
CLIParserContext *ctx;
@ -3034,8 +3073,8 @@ static int CmdDiff(const char *Cmd) {
}
*/
size_t n = (datalenA > datalenB) ? datalenB : datalenA;
PrintAndLogEx(DEBUG, "data len: %zu A %zu B %zu", n, datalenA, datalenB);
size_t biggest = (datalenA > datalenB) ? datalenA : datalenB;
PrintAndLogEx(DEBUG, "data len: %zu A %zu B %zu", biggest, datalenA, datalenB);
if (inA == NULL)
PrintAndLogEx(INFO, "inA null");
@ -3062,102 +3101,68 @@ static int CmdDiff(const char *Cmd) {
char line[880] = {0};
// print data diff loop
int i;
for (i = 0; i < n; i += width) {
for (int i = 0 ; i < biggest ; i += width) {
char dlnA[240] = {0};
char dlnB[240] = {0};
char dlnAii[180] = {0};
char dlnBii[180] = {0};
memset(line, 0, sizeof(line));
memset(dlnA, 0, sizeof(dlnA));
memset(dlnB, 0, sizeof(dlnB));
memset(dlnAii, 0, sizeof(dlnAii));
memset(dlnBii, 0, sizeof(dlnBii));
int diff = memcmp(inA + i, inB + i, width);
for (int j = i; j < i + width; j++) {
int dlnALen = strlen(dlnA);
int dlnBLen = strlen(dlnB);
int dlnAiiLen = strlen(dlnAii);
int dlnBiiLen = strlen(dlnBii);
// if ok, just print
if (diff == 0) {
hex_to_buffer((uint8_t *)line, inA + i, width, width, 0, 1, true);
ascii_to_buffer((uint8_t *)(line + strlen(line)), inA + i, width, width, 0);
strcat(line + strlen(line), " | ");
hex_to_buffer((uint8_t *)(line + strlen(line)), inB + i, width, width, 0, 1, true);
ascii_to_buffer((uint8_t *)(line + strlen(line)), inB + i, width, width, 0);
} else {
char dlnA[240] = {0};
char dlnB[240] = {0};
char dlnAii[180] = {0};
char dlnBii[180] = {0};
memset(dlnA, 0, sizeof(dlnA));
memset(dlnB, 0, sizeof(dlnB));
memset(dlnAii, 0, sizeof(dlnAii));
memset(dlnBii, 0, sizeof(dlnBii));
// if diff, time to find it
for (int j = i; j < (i + width); j++) {
char ca = inA[j];
char cb = inB[j];
int dlnALen = strlen(dlnA);
int dlnBLen = strlen(dlnB);
int dlnAiiLen = strlen(dlnAii);
int dlnBiiLen = strlen(dlnBii);
if (inA[j] != inB[j]) {
// diff / add colors
snprintf(dlnA + dlnALen, sizeof(dlnA) - dlnALen, _GREEN_("%02X "), inA[j]);
snprintf(dlnB + dlnBLen, sizeof(dlnB) - dlnBLen, _RED_("%02X "), inB[j]);
snprintf(dlnAii + dlnAiiLen, sizeof(dlnAii) - dlnAiiLen, _GREEN_("%c"), ((ca < 32) || (ca == 127)) ? '.' : ca);
snprintf(dlnBii + dlnBiiLen, sizeof(dlnBii) - dlnBiiLen, _RED_("%c"), ((cb < 32) || (cb == 127)) ? '.' : cb);
} else {
// normal
snprintf(dlnA + dlnALen, sizeof(dlnA) - dlnALen, "%02X ", inA[j]);
snprintf(dlnB + dlnBLen, sizeof(dlnB) - dlnBLen, "%02X ", inB[j]);
snprintf(dlnAii + dlnAiiLen, sizeof(dlnAii) - dlnAiiLen, "%c", ((ca < 32) || (ca == 127)) ? '.' : ca);
snprintf(dlnBii + dlnBiiLen, sizeof(dlnBii) - dlnBiiLen, "%c", ((cb < 32) || (cb == 127)) ? '.' : cb);
}
//both files ended
if (j >= datalenA && j >= datalenB) {
snprintf(dlnA + dlnALen, sizeof(dlnA) - dlnALen, "-- ");
snprintf(dlnAii + dlnAiiLen, sizeof(dlnAii) - dlnAiiLen, ".") ;
snprintf(dlnB + dlnBLen, sizeof(dlnB) - dlnBLen, "-- ");
snprintf(dlnBii + dlnBiiLen, sizeof(dlnBii) - dlnBiiLen, ".") ;
continue ;
}
char ca, cb;
if (j >= datalenA) {
// file A ended. print B without colors
cb = inB[j];
snprintf(dlnA + dlnALen, sizeof(dlnA) - dlnALen, "-- ");
snprintf(dlnAii + dlnAiiLen, sizeof(dlnAii) - dlnAiiLen, ".") ;
snprintf(dlnB + dlnBLen, sizeof(dlnB) - dlnBLen, "%02X ", inB[j]);
snprintf(dlnBii + dlnBiiLen, sizeof(dlnBii) - dlnBiiLen, "%c", ((cb < 32) || (cb == 127)) ? '.' : cb);
continue ;
}
ca = inA[j];
if (j >= datalenB) {
// file B ended. print A without colors
snprintf(dlnA + dlnALen, sizeof(dlnA) - dlnALen, "%02X ", inA[j]);
snprintf(dlnAii + dlnAiiLen, sizeof(dlnAii) - dlnAiiLen, "%c", ((ca < 32) || (ca == 127)) ? '.' : ca);
snprintf(dlnB + dlnBLen, sizeof(dlnB) - dlnBLen, "-- ");
snprintf(dlnBii + dlnBiiLen, sizeof(dlnBii) - dlnBiiLen, ".") ;
continue ;
}
cb = inB[j];
if (inA[j] != inB[j]) {
// diff / add colors
snprintf(dlnA + dlnALen, sizeof(dlnA) - dlnALen, _GREEN_("%02X "), inA[j]);
snprintf(dlnB + dlnBLen, sizeof(dlnB) - dlnBLen, _RED_("%02X "), inB[j]);
snprintf(dlnAii + dlnAiiLen, sizeof(dlnAii) - dlnAiiLen, _GREEN_("%c"), ((ca < 32) || (ca == 127)) ? '.' : ca);
snprintf(dlnBii + dlnBiiLen, sizeof(dlnBii) - dlnBiiLen, _RED_("%c"), ((cb < 32) || (cb == 127)) ? '.' : cb);
} else {
// normal
snprintf(dlnA + dlnALen, sizeof(dlnA) - dlnALen, "%02X ", inA[j]);
snprintf(dlnB + dlnBLen, sizeof(dlnB) - dlnBLen, "%02X ", inB[j]);
snprintf(dlnAii + dlnAiiLen, sizeof(dlnAii) - dlnAiiLen, "%c", ((ca < 32) || (ca == 127)) ? '.' : ca);
snprintf(dlnBii + dlnBiiLen, sizeof(dlnBii) - dlnBiiLen, "%c", ((cb < 32) || (cb == 127)) ? '.' : cb);
}
snprintf(line, sizeof(line), "%s%s | %s%s", dlnA, dlnAii, dlnB, dlnBii);
}
PrintAndLogEx(INFO, "%03X | %s", i, line);
}
// mod
// print different length
bool tallestA = (datalenA > datalenB);
if (tallestA) {
n = datalenA;
} else {
n = datalenB;
}
// print data diff loop
for (; i < n; i += width) {
memset(line, 0, sizeof(line));
if (tallestA) {
hex_to_buffer((uint8_t *)line, inA + i, width, width, 0, 1, true);
ascii_to_buffer((uint8_t *)(line + strlen(line)), inA + i, width, width, 0);
strcat(line + strlen(line), " | ");
for (int j = 0; j < width; j++) {
strcat(line + strlen(line), "-- ");
}
for (int j = 0; j < width; j++) {
strcat(line + strlen(line), ".");
}
} else {
for (int j = 0; j < width; j++) {
strcat(line + strlen(line), "-- ");
}
for (int j = 0; j < width; j++) {
strcat(line + strlen(line), ".");
}
strcat(line + strlen(line), " | ");
hex_to_buffer((uint8_t *)(line + strlen(line)), inB + i, width, width, 0, 1, true);
ascii_to_buffer((uint8_t *)(line + strlen(line)), inB + i, width, width, 0);
}
snprintf(line, sizeof(line), "%s%s | %s%s", dlnA, dlnAii, dlnB, dlnBii);
PrintAndLogEx(INFO, "%03X | %s", i, line);
}
@ -3171,6 +3176,129 @@ static int CmdDiff(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdNumCon(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "data num",
"Function takes a decimal or hexdecimal number and print it in decimal/hex/binary\n"
"Will print message if number is a prime number\n",
"data num --dec 2023\n"
"data num --hex 0x1000\n"
);
void *argtable[] = {
arg_param_begin,
arg_str0(NULL, "dec", "<dec>", "decimal value"),
arg_str0(NULL, "hex", "<hex>", "hexadecimal value"),
arg_str0(NULL, "bin", "<bin>", "binary value"),
arg_lit0("i", NULL, "print inverted value"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int dlen = 256;
char dec[256];
memset(dec, 0, sizeof(dec));
int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)dec, sizeof(dec), &dlen);
int hlen = 256;
char hex[256];
memset(hex, 0, sizeof(hex));
res = CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)hex, sizeof(hex), &hlen);
int blen = 256;
char bin[256];
memset(bin, 0, sizeof(bin));
res = CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)bin, sizeof(bin), &blen);
bool shall_invert = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
// sanity checks
if (res) {
PrintAndLogEx(FAILED, "Error parsing bytes");
return PM3_EINVARG;
}
// results for MPI actions
bool ret = false;
// container of big number
mbedtls_mpi N;
mbedtls_mpi_init(&N);
// hex
if (hlen > 0) {
if (data_verify_hex((uint8_t *)hex, hlen) == false) {
return PM3_EINVARG;
}
MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16, hex));
}
// decimal
if (dlen > 0) {
// should have decimal string check here too
MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 10, dec));
}
// binary
if (blen > 0) {
// should have bianry string check here too
MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 2, bin));
}
mbedtls_mpi base;
mbedtls_mpi_init(&base);
mbedtls_mpi_add_int(&base, &base, 10);
if (shall_invert) {
PrintAndLogEx(INFO, "should invert");
MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&N, &N, &base));
}
// printing
typedef struct {
const char *desc;
uint8_t radix;
} radix_t;
radix_t radix[] = {
{"dec..... ", 10},
{"hex..... 0x", 16},
{"bin..... 0b", 2}
};
char s[600] = {0};
size_t slen = 0;
for (uint8_t i = 0; i < ARRAYLEN(radix); i++) {
MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(&N, radix[i].radix, s, sizeof(s), &slen));
if (slen > 0) {
PrintAndLogEx(INFO, "%s%s", radix[i].desc, s);
}
}
// check if number is a prime
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);
MBEDTLS_MPI_CHK(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0));
res = mbedtls_mpi_is_prime_ext(&N, 50, mbedtls_ctr_drbg_random, &ctr_drbg);
if (res == 0) {
PrintAndLogEx(INFO, "prime... " _YELLOW_("yes"));
}
cleanup:
mbedtls_mpi_free(&N);
mbedtls_mpi_free(&base);
mbedtls_entropy_free(&entropy);
mbedtls_ctr_drbg_free(&ctr_drbg);
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
@ -3214,6 +3342,7 @@ static command_t CommandTable[] = {
{"hexsamples", CmdHexsamples, IfPm3Present, "Dump big buffer as hex bytes"},
{"hex2bin", Cmdhex2bin, AlwaysAvailable, "Converts hexadecimal to binary"},
{"load", CmdLoad, AlwaysAvailable, "Load contents of file into graph window"},
{"num", CmdNumCon, AlwaysAvailable, "Converts dec/hex/bin"},
{"print", CmdPrintDemodBuff, AlwaysAvailable, "Print the data in the DemodBuffer"},
{"samples", CmdSamples, IfPm3Present, "Get raw samples for graph window (GraphBuffer)"},
{"save", CmdSave, AlwaysAvailable, "Save signal trace data (from graph window)"},

View file

@ -204,19 +204,23 @@ static int CmdFlashMemLoad(const char *Cmd) {
size_t datalen = 0;
uint32_t keycount = 0;
int res = 0;
uint8_t keylen = 0;
uint8_t *data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t));
switch (d) {
case DICTIONARY_MIFARE:
offset = DEFAULT_MF_KEYS_OFFSET;
res = loadFileDICTIONARY(filename, data + 2, &datalen, 6, &keycount);
keylen = 6;
res = loadFileDICTIONARY(filename, data + 2, &datalen, keylen, &keycount);
if (res || !keycount) {
free(data);
return PM3_EFILE;
}
// limited space on flash mem
if (keycount > 0xFFFF)
keycount &= 0xFFFF;
if (keycount > DEFAULT_MF_KEYS_MAX) {
keycount = DEFAULT_MF_KEYS_MAX;
datalen = keycount * keylen;
}
data[0] = (keycount >> 0) & 0xFF;
data[1] = (keycount >> 8) & 0xFF;
@ -224,14 +228,17 @@ static int CmdFlashMemLoad(const char *Cmd) {
break;
case DICTIONARY_T55XX:
offset = DEFAULT_T55XX_KEYS_OFFSET;
res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &keycount);
keylen = 4;
res = loadFileDICTIONARY(filename, data + 2, &datalen, keylen, &keycount);
if (res || !keycount) {
free(data);
return PM3_EFILE;
}
// limited space on flash mem
if (keycount > 0xFFFF)
keycount &= 0xFFFF;
if (keycount > DEFAULT_T55XX_KEYS_MAX) {
keycount = DEFAULT_T55XX_KEYS_MAX;
datalen = keycount * keylen;
}
data[0] = (keycount >> 0) & 0xFF;
data[1] = (keycount >> 8) & 0xFF;
@ -239,14 +246,16 @@ static int CmdFlashMemLoad(const char *Cmd) {
break;
case DICTIONARY_ICLASS:
offset = DEFAULT_ICLASS_KEYS_OFFSET;
res = loadFileDICTIONARY(filename, data + 2, &datalen, 8, &keycount);
res = loadFileDICTIONARY(filename, data + 2, &datalen, keylen, &keycount);
if (res || !keycount) {
free(data);
return PM3_EFILE;
}
// limited space on flash mem
if (keycount > 0xFFFF)
keycount &= 0xFFFF;
if (keycount > DEFAULT_ICLASS_KEYS_MAX) {
keycount = DEFAULT_ICLASS_KEYS_MAX;
datalen = keycount * keylen;
}
data[0] = (keycount >> 0) & 0xFF;
data[1] = (keycount >> 8) & 0xFF;
@ -632,6 +641,11 @@ static int CmdFlashMemInfo(const char *Cmd) {
// Verify (public key)
bool is_verified = (mbedtls_rsa_pkcs1_verify(rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device) == 0);
if (got_private == false) {
mbedtls_rsa_free(rsa);
free(rsa);
}
mbedtls_pk_free(&pkctx);
PrintAndLogEx(NORMAL, "");

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