This commit is contained in:
Adrian Teuscher 2023-01-27 19:45:06 +01:00
commit 5d17177498
184 changed files with 4180 additions and 2318 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) - [ ] `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_lib` compilation & tests
- [ ] `experimental_client_with_swig` 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) - [ ] GitHub Actions - green across the board ( MacOS, Ubuntu, Windows)
# OS compilation and tests # OS compilation and tests
```bash Run `tools/release_tests.sh` on:
#!/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
```
- [ ] RPI Zero - [ ] RPI Zero
- [ ] Jetson Nano - [ ] Jetson Nano
@ -47,9 +32,9 @@ make hitag2crack/clean && make hitag2crack && tools/pm3_tests.sh hitag2crack ||
- [ ] Kali - [ ] Kali
- [ ] Debian Stable - [ ] Debian Stable
- [ ] Debian Testing - [ ] Debian Testing
- [ ] Ubuntu21 - [ ] Ubuntu 22
- [ ] ParrotOS - [ ] ParrotOS
- [ ] Fedora - [ ] Fedora 37
- [ ] OpenSuse Leap - [ ] OpenSuse Leap
- [ ] OpenSuse Tumbleweed - [ ] OpenSuse Tumbleweed
- [ ] OSX (MacPorts) - [ ] OSX (MacPorts)

View file

@ -36,6 +36,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
continue-on-error: true
- name: Install Python dependencies - name: Install Python dependencies
run: | run: |
@ -77,6 +78,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
continue-on-error: true
- name: Install Python dependencies - name: Install Python dependencies
run: | run: |
@ -119,6 +121,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
continue-on-error: true
- name: Install Python dependencies - name: Install Python dependencies
run: | run: |

View file

@ -3,14 +3,29 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased] ## [unreleased][unreleased]
- Fixed potential NULL array printing (@jmichel) - Added new magic gen4 cards command in docs (@McEloff)
- Added PIV aid to resource file (@jmichel) - Added `hf tesla info` - intital information command to read TESLA cards (@iceman1001)
- Fixed failing compilation on Proxspace environment due to how python is initialized (@jmichel) - Changed `hf emrtd info` - looking for lower case .bin extensions (@iceman1001)
- Fixed length check in sim module communications (@jmichel) - 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) - Changed timings in i2c.c when communicating with sim module (@iceman1001)
- Moved to non-deprecated API to initialize Python interpreter (@jmichel) - 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) - 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 (@jmichel) - 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 `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) - 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) - Added `hf mf gload, gsave, ggetblk, gsetblk` for Gen4 GTU in mifare classic mode (@DidierA)
@ -1353,3 +1368,5 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
### Added ### 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 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. - 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

@ -80,20 +80,20 @@ ifneq (,$(INSTALLSHARES))
endif endif
ifneq (,$(INSTALLDOCS)) ifneq (,$(INSTALLDOCS))
$(Q)$(INSTALLSUDO) $(RMDIR) $(foreach doc,$(INSTALLDOCS),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH)$(PATHSEP)$(notdir $(doc))) $(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 endif
ifneq (,$(INSTALLTOOLS)) ifneq (,$(INSTALLTOOLS))
$(Q)$(INSTALLSUDO) $(RM) $(foreach tool,$(INSTALLTOOLS),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)$(PATHSEP)$(notdir $(tool))) $(Q)$(INSTALLSUDO) $(RM) $(foreach tool,$(INSTALLTOOLS),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)$(PATHSEP)$(notdir $(tool)))
endif endif
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH) $(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)
ifneq (,$(INSTALLSIMFW)) ifneq (,$(INSTALLSIMFW))
$(Q)$(INSTALLSUDO) $(RM) $(foreach fw,$(INSTALLSIMFW),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(notdir $(fw))) $(Q)$(INSTALLSUDO) $(RM) $(foreach fw,$(INSTALLSIMFW),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(notdir $(fw)))
endif endif
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH) $(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)
ifeq ($(platform),Linux) ifeq ($(platform),Linux)
$(Q)$(INSTALLSUDO) $(RM) $(DESTDIR)$(UDEV_PREFIX)/77-pm3-usb-device-blacklist.rules $(Q)$(INSTALLSUDO) $(RM) $(DESTDIR)$(UDEV_PREFIX)/77-pm3-usb-device-blacklist.rules
endif endif
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH) $(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)
# tests # tests
mfkey/check: FORCE mfkey/check: FORCE

View file

@ -29,8 +29,8 @@ GZIP = gzip
MKDIR = mkdir -p MKDIR = mkdir -p
RM = rm -f RM = rm -f
RMDIR = rm -rf RMDIR = rm -rf
# rmdir only if dir is empty, tolerate failure # rmdir only if dir is empty, you must add "-" when using it to tolerate failure
RMDIR_SOFT = -rmdir RMDIR_SOFT = rmdir
MV = mv MV = mv
TOUCH = touch TOUCH = touch
FALSE = false FALSE = false

View file

@ -83,7 +83,7 @@ We define generic Proxmark3 platforms as following devices.
- **Note**: unknown pin assignments. - **Note**: unknown pin assignments.
- ⚠ Ryscorp Proxmark3 Pro - ⚠ Ryscorp Proxmark3 Pro
- **Note**: device has different fpga and unknown pin assignments. - **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 - ⚠ iCopy-X
- **Note**: experimental support, currently incompatible with iCopy-X GUI as Proxmark client commands are now using cliparser. - **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. - **Note**: see also [icopyx-community repos](https://github.com/iCopy-X-Community/) for upstream sources, reversed hw etc.
@ -93,7 +93,13 @@ We define generic Proxmark3 platforms as following devices.
- ⚠ VX - ⚠ VX
- **Note**: unknown device hw - **Note**: unknown device hw
- ⚠ Proxmark3 X - ⚠ 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**

View file

@ -185,7 +185,7 @@ showinfo:
.DELETE_ON_ERROR: .DELETE_ON_ERROR:
# version_pm3.c should be remade on every time fullimage.stage1.elf should be remade # 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 $@) $(info [-] GEN $@)
$(Q)$(SH) ../tools/mkversion.sh > $@ || $(CP) $< $@ $(Q)$(SH) ../tools/mkversion.sh > $@ || $(CP) $< $@
@ -257,7 +257,7 @@ uninstall:
$(info [@] Uninstalling fullimage from $(DESTDIR)$(PREFIX)...) $(info [@] Uninstalling fullimage from $(DESTDIR)$(PREFIX)...)
$(Q)$(INSTALLSUDO) $(RM) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(INSTALLFWTAG) $(Q)$(INSTALLSUDO) $(RM) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(INSTALLFWTAG)
.PHONY: all clean help install uninstall .PHONY: all clean help install uninstall .FORCE
help: help:
@echo Multi-OS Makefile, you are running on $(DETECTED_OS) @echo Multi-OS Makefile, you are running on $(DETECTED_OS)
@echo Possible targets: @echo Possible targets:

View file

@ -50,12 +50,18 @@ define KNOWN_STANDALONE_DEFINITIONS
| LF_ICEHID | LF HID collector to flashmem | | LF_ICEHID | LF HID collector to flashmem |
| (RDV4 only) | | | (RDV4 only) | |
+----------------------------------------------------------+ +----------------------------------------------------------+
| LF_NEDAP_SIM | LF Nedap ID simple simulator |
| | |
+----------------------------------------------------------+
| LF_NEXID | LF Nexwatch collector to flashmem | | LF_NEXID | LF Nexwatch collector to flashmem |
| (RDV4 only) | | | (RDV4 only) | |
+----------------------------------------------------------+ +----------------------------------------------------------+
| LF_PROXBRUTE | HID ProxII bruteforce | | LF_PROXBRUTE | HID ProxII bruteforce |
| | - Brad Antoniewicz | | | - Brad Antoniewicz |
+----------------------------------------------------------+ +----------------------------------------------------------+
| LF_PROX2BRUTE | HID ProxII bruteforce v2 |
| | |
+----------------------------------------------------------+
| LF_SAMYRUN | HID26 read/clone/sim | | LF_SAMYRUN | HID26 read/clone/sim |
| (default) | - Samy Kamkar | | (default) | - Samy Kamkar |
+----------------------------------------------------------+ +----------------------------------------------------------+
@ -118,11 +124,14 @@ define KNOWN_STANDALONE_DEFINITIONS
+----------------------------------------------------------+ +----------------------------------------------------------+
endef 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_BT := HF_REBLAY
STANDALONE_MODES_REQ_SMARTCARD := 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)),) ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),)
STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE) STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE)
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),) 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))) ifneq (,$(findstring WITH_STANDALONE_LF_SKELETON,$(APP_CFLAGS)))
SRC_STANDALONE = lf_skeleton.c SRC_STANDALONE = lf_skeleton.c
endif endif
# WITH_STANDALONE_LF_SAMYRUN # WITH_STANDALONE_LF_EM4100EMUL
ifneq (,$(findstring WITH_STANDALONE_LF_SAMYRUN,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_LF_EM4100EMUL,$(APP_CFLAGS)))
SRC_STANDALONE = lf_samyrun.c SRC_STANDALONE = lf_em4100emul.c
endif endif
# WITH_STANDALONE_LF_PROXBRUTE # WITH_STANDALONE_LF_EM4100RSWB
ifneq (,$(findstring WITH_STANDALONE_LF_PROXBRUTE,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RSWB,$(APP_CFLAGS)))
SRC_STANDALONE = lf_proxbrute.c 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 endif
# WITH_STANDALONE_LF_HIDBRUTE # WITH_STANDALONE_LF_HIDBRUTE
ifneq (,$(findstring WITH_STANDALONE_LF_HIDBRUTE,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_LF_HIDBRUTE,$(APP_CFLAGS)))
@ -37,21 +45,33 @@ endif
ifneq (,$(findstring WITH_STANDALONE_LF_HIDFCBRUTE,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_LF_HIDFCBRUTE,$(APP_CFLAGS)))
SRC_STANDALONE = lf_hidfcbrute.c SRC_STANDALONE = lf_hidfcbrute.c
endif endif
# WITH_STANDALONE_HF_YOUNG # WITH_STANDALONE_LF_ICEHID
ifneq (,$(findstring WITH_STANDALONE_HF_YOUNG,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS)))
SRC_STANDALONE = hf_young.c SRC_STANDALONE = lf_icehid.c
endif endif
# WITH_STANDALONE_HF_MATTYRUN # WITH_STANDALONE_LF_NEDAP_SIM
ifneq (,$(findstring WITH_STANDALONE_HF_MATTYRUN,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_LF_NEDAP_SIM,$(APP_CFLAGS)))
SRC_STANDALONE = hf_mattyrun.c SRC_STANDALONE = lf_nedap_sim.c
endif endif
# WITH_STANDALONE_HF_COLIN # WITH_STANDALONE_LF_NEXID
ifneq (,$(findstring WITH_STANDALONE_HF_COLIN,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_LF_NEXID,$(APP_CFLAGS)))
SRC_STANDALONE = vtsend.c hf_colin.c frozen.c nprintf.c SRC_STANDALONE = lf_nexid.c
endif endif
# WITH_STANDALONE_HF_BOG # WITH_STANDALONE_LF_SAMYRUN
ifneq (,$(findstring WITH_STANDALONE_HF_BOG,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_LF_SAMYRUN,$(APP_CFLAGS)))
SRC_STANDALONE = hf_bog.c 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 endif
# WITH_STANDALONE_HF_14ASNIFF # WITH_STANDALONE_HF_14ASNIFF
ifneq (,$(findstring WITH_STANDALONE_HF_14ASNIFF,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_14ASNIFF,$(APP_CFLAGS)))
@ -69,33 +89,21 @@ endif
ifneq (,$(findstring WITH_STANDALONE_HF_AVEFUL,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_AVEFUL,$(APP_CFLAGS)))
SRC_STANDALONE = hf_aveful.c SRC_STANDALONE = hf_aveful.c
endif endif
# WITH_STANDALONE_HF_TCPRST # WITH_STANDALONE_HF_BOG
ifneq (,$(findstring WITH_STANDALONE_HF_TCPRST,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_BOG,$(APP_CFLAGS)))
SRC_STANDALONE = hf_tcprst.c SRC_STANDALONE = hf_bog.c
endif endif
# WITH_STANDALONE_LF_ICEHID # WITH_STANDALONE_HF_COLIN
ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_COLIN,$(APP_CFLAGS)))
SRC_STANDALONE = lf_icehid.c SRC_STANDALONE = vtsend.c hf_colin.c frozen.c nprintf.c
endif endif
# WITH_STANDALONE_LF_NEXID # WITH_STANDALONE_HF_CRAFTBYTE
ifneq (,$(findstring WITH_STANDALONE_LF_NEXID,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_CRAFTBYTE,$(APP_CFLAGS)))
SRC_STANDALONE = lf_nexid.c SRC_STANDALONE = hf_craftbyte.c
endif endif
# WITH_STANDALONE_LF_EM4100EMUL # WITH_STANDALONE_HF_ICECLASS
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100EMUL,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS)))
SRC_STANDALONE = lf_em4100emul.c SRC_STANDALONE = hf_iceclass.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
endif endif
# WITH_STANDALONE_HF_LEGIC # WITH_STANDALONE_HF_LEGIC
ifneq (,$(findstring WITH_STANDALONE_HF_LEGIC,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_LEGIC,$(APP_CFLAGS)))
@ -105,33 +113,33 @@ endif
ifneq (,$(findstring WITH_STANDALONE_HF_LEGICSIM,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_LEGICSIM,$(APP_CFLAGS)))
SRC_STANDALONE = hf_legicsim.c SRC_STANDALONE = hf_legicsim.c
endif 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 # WITH_STANDALONE_HF_MSDSAL
ifneq (,$(findstring WITH_STANDALONE_HF_MSDSAL,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_MSDSAL,$(APP_CFLAGS)))
SRC_STANDALONE = hf_msdsal.c SRC_STANDALONE = hf_msdsal.c
endif endif
# WITH_STANDALONE_HF_ICECLASS # WITH_STANDALONE_HF_REBLAY
ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_REBLAY,$(APP_CFLAGS)))
SRC_STANDALONE = hf_iceclass.c SRC_STANDALONE = hf_reblay.c
endif endif
# WITH_STANDALONE_LF_THAREXDE # WITH_STANDALONE_HF_TCPRST
ifneq (,$(findstring WITH_STANDALONE_LF_THAREXDE,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_TCPRST,$(APP_CFLAGS)))
SRC_STANDALONE = lf_tharexde.c SRC_STANDALONE = hf_tcprst.c
endif
# WITH_STANDALONE_HF_CRAFTBYTE
ifneq (,$(findstring WITH_STANDALONE_HF_CRAFTBYTE,$(APP_CFLAGS)))
SRC_STANDALONE = hf_craftbyte.c
endif endif
# WITH_STANDALONE_HF_TMUDFORD # WITH_STANDALONE_HF_TMUDFORD
ifneq (,$(findstring WITH_STANDALONE_HF_TMUDFORD,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_TMUDFORD,$(APP_CFLAGS)))
SRC_STANDALONE = hf_tmudford.c SRC_STANDALONE = hf_tmudford.c
endif endif
# WITH_STANDALONE_HF_REBLAY # WITH_STANDALONE_HF_YOUNG
ifneq (,$(findstring WITH_STANDALONE_HF_REBLAY,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_YOUNG,$(APP_CFLAGS)))
SRC_STANDALONE = hf_reblay.c SRC_STANDALONE = hf_young.c
endif
# WITH_STANDALONE_HF_MFCSIM
ifneq (,$(findstring WITH_STANDALONE_HF_MFCSIM,$(APP_CFLAGS)))
SRC_STANDALONE = hf_mfcsim.c
endif endif
ifneq (,$(findstring WITH_STANDALONE_DANKARMULTI,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_DANKARMULTI,$(APP_CFLAGS)))

View file

@ -322,6 +322,7 @@ static int reader_dump_mode(void) {
.use_credit_key = false, .use_credit_key = false,
.do_auth = true, .do_auth = true,
.send_reply = false, .send_reply = false,
.shallow_mod = false,
}; };
memcpy(auth.key, legacy_aa1_key, sizeof(auth.key)); memcpy(auth.key, legacy_aa1_key, sizeof(auth.key));
@ -333,7 +334,7 @@ static int reader_dump_mode(void) {
// select tag. // select tag.
uint32_t eof_time = 0; 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) { if (res == false) {
switch_off(); switch_off();
continue; continue;
@ -382,7 +383,7 @@ static int reader_dump_mode(void) {
// main read loop // main read loop
for (uint16_t i = start_block; i <= app1_limit; i++) { 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++; dumped++;
} }
} }
@ -394,7 +395,7 @@ static int reader_dump_mode(void) {
auth.use_credit_key = true; auth.use_credit_key = true;
memcpy(auth.key, aa2_key, sizeof(auth.key)); 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) { if (res) {
// sanity check of CSN. // sanity check of CSN.
@ -408,7 +409,7 @@ static int reader_dump_mode(void) {
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
for (uint16_t i = app1_limit + 1; i <= app2_limit; i++) { 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++; dumped++;
} }
} }
@ -458,6 +459,7 @@ static int dump_sim_mode(void) {
.use_credit_key = false, .use_credit_key = false,
.do_auth = true, .do_auth = true,
.send_reply = false, .send_reply = false,
.shallow_mod = false,
}; };
memcpy(auth.key, legacy_aa1_key, sizeof(auth.key)); memcpy(auth.key, legacy_aa1_key, sizeof(auth.key));
@ -469,7 +471,7 @@ static int dump_sim_mode(void) {
// select tag. // select tag.
uint32_t eof_time = 0; 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) { if (res == false) {
switch_off(); switch_off();
continue; continue;
@ -518,7 +520,7 @@ static int dump_sim_mode(void) {
// main read loop // main read loop
for (uint16_t i = start_block; i <= app1_limit; i++) { 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++; dumped++;
} }
} }
@ -530,7 +532,7 @@ static int dump_sim_mode(void) {
auth.use_credit_key = true; auth.use_credit_key = true;
memcpy(auth.key, aa2_key, sizeof(auth.key)); 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) { if (res) {
// sanity check of CSN. // sanity check of CSN.
@ -544,7 +546,7 @@ static int dump_sim_mode(void) {
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
for (uint16_t i = app1_limit + 1; i <= app2_limit; i++) { 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++; dumped++;
} }
} }

View file

@ -11,7 +11,7 @@
// then from shell: // then from shell:
// hexdump lf.bin -e '5/1 "%02X" /0 "\n"' // 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: // 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 := STANDALONE_MODES_REQ_BT :=
``` ```
Please respect alphabetic order!
## Update MAKEFILE.INC ## Update MAKEFILE.INC
^[Top](#top) ^[Top](#top)
@ -117,6 +119,8 @@ ifneq (,$(findstring WITH_STANDALONE_LF_FOO,$(APP_CFLAGS)))
endif endif
``` ```
Please respect alphabetic order!
## Adding identification string of your mode ## Adding identification string of your mode
^[Top](#top) ^[Top](#top)
@ -174,9 +178,11 @@ Once you're ready to share your mode, please
* add a line in CHANGELOG.md * 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 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 Once approved, add also your mode in https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode

View file

@ -345,7 +345,7 @@ static void print_debug_level(void) {
char dbglvlstr[20] = {0}; char dbglvlstr[20] = {0};
switch (g_dbglevel) { switch (g_dbglevel) {
case DBG_NONE: case DBG_NONE:
sprintf(dbglvlstr, "none"); sprintf(dbglvlstr, "off");
break; break;
case DBG_ERROR: case DBG_ERROR:
sprintf(dbglvlstr, "error"); sprintf(dbglvlstr, "error");

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

View file

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

View file

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

View file

@ -749,7 +749,7 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
} }
} }
card_ptr->atr_len = (uint8_t) (len & 0xff); card_ptr->atr_len = (uint8_t)(len & 0xff);
if (verbose) { if (verbose) {
LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false); LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false);
} }

View file

@ -1245,29 +1245,28 @@ send:
} }
// THE READER CODE // 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); CodeIso15693AsReader(frame, len);
tosend_t *ts = get_tosend(); 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 *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); 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, 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, 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; uint16_t resp_len = 0;
int res;
while (tries-- > 0) { 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) { if (resp == NULL) {
return true; 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) { if (res == PM3_SUCCESS && expected_size == resp_len) {
return true; return true;
} }
@ -1282,7 +1281,7 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t *
* @return false = fail * @return false = fail
* true = Got all. * 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 act_all[] = { ICLASS_CMD_ACTALL };
static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; 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 // wakeup
uint32_t start_time = GetCountSspClk(); 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; int res;
uint16_t resp_len = 0; uint16_t resp_len = 0;
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time, false, true, &resp_len); 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 // send Identify
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; 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 // 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); 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 // select the card
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; 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 // 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); 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) // card selected, now read config (block1) (only 8 bytes no CRC)
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; 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 // expect a 8-byte response here
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len); 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 // read App Issuer Area block 5
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; 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 // expect a 10-byte response here
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len); 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) // card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; 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 // expect a 8-byte response here
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len); 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; read_aia[3] = 0x10;
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; 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 // expect a 10-byte response here
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len); 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; 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; 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 // Reader iClass Anticollission
@ -1413,6 +1412,7 @@ void ReaderIClass(uint8_t flags) {
// flag to use credit key // flag to use credit key
bool use_credit_key = ((flags & FLAG_ICLASS_READER_CREDITKEY) == FLAG_ICLASS_READER_CREDITKEY); 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) { if ((flags & FLAG_ICLASS_READER_INIT) == FLAG_ICLASS_READER_INIT) {
Iso15693InitReader(); Iso15693InitReader();
@ -1427,7 +1427,7 @@ void ReaderIClass(uint8_t flags) {
uint32_t eof_time = 0; uint32_t eof_time = 0;
picopass_hdr_t hdr = {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); reply_ng(CMD_HF_ICLASS_READER, PM3_ERFTRANS, NULL, 0);
goto out; 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[7] = pmac[2];
cmd_check[8] = pmac[3]; 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; return;
} }
bool shallow_mod = p->shallow_mod;
uint8_t check[9] = { ICLASS_CMD_CHECK }; uint8_t check[9] = { ICLASS_CMD_CHECK };
uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
uint8_t readcheck_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; uint8_t readcheck_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 };
@ -1537,7 +1539,7 @@ void iClass_Authentication_fast(iclass_chk_t *p) {
bool isOK = false; bool isOK = false;
uint32_t start_time = 0, eof_time = 0; 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; goto out;
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; 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]; check[8] = keys[i].mac[3];
// expect 4bytes, 3 retries times.. // 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) if (isOK)
goto out; goto out;
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
// Auth Sequence MUST begin with reading e-purse. (block2) // Auth Sequence MUST begin with reading e-purse. (block2)
// Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) // 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(); LED_B_OFF();
} }
@ -1586,11 +1588,11 @@ out:
// Tries to read block. // Tries to read block.
// retries 3times. // retries 3times.
// reply 8 bytes block // 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 resp[10];
uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00}; uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00};
AddCrc(c + 1, 1); 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) if (isOK)
memcpy(data, resp, 8); memcpy(data, resp, 8);
return isOK; 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) { void iClass_ReadBlock(uint8_t *msg) {
iclass_auth_req_t *payload = (iclass_auth_req_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 }; iclass_readblock_resp_t response = { .isOK = true };
memset(response.data, 0, sizeof(response.data)); memset(response.data, 0, sizeof(response.data));
@ -1614,7 +1617,7 @@ void iClass_ReadBlock(uint8_t *msg) {
// select tag. // select tag.
uint32_t eof_time = 0; uint32_t eof_time = 0;
picopass_hdr_t hdr = {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 (res == false) {
if (payload->send_reply) { if (payload->send_reply) {
response.isOK = res; response.isOK = res;
@ -1642,7 +1645,7 @@ void iClass_ReadBlock(uint8_t *msg) {
// read data // read data
uint8_t resp[10]; 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) { if (res) {
memcpy(response.data, resp, sizeof(response.data)); memcpy(response.data, resp, sizeof(response.data));
if (payload->send_reply) { 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_dump_req_t *cmd = (iclass_dump_req_t *)msg;
iclass_auth_req_t *req = &cmd->req; iclass_auth_req_t *req = &cmd->req;
bool shallow_mod = req->shallow_mod;
uint8_t *dataout = BigBuf_malloc(ICLASS_16KS_SIZE); uint8_t *dataout = BigBuf_malloc(ICLASS_16KS_SIZE);
if (dataout == NULL) { if (dataout == NULL) {
@ -1689,7 +1693,7 @@ void iClass_Dump(uint8_t *msg) {
picopass_hdr_t hdr = {0}; picopass_hdr_t hdr = {0};
memset(&hdr, 0xff, sizeof(picopass_hdr_t)); 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 (res == false) {
if (req->send_reply) { if (req->send_reply) {
reply_ng(CMD_HF_ICLASS_DUMP, PM3_ETIMEOUT, NULL, 0); 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}; uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, i, 0x00, 0x00};
AddCrc(c + 1, 1); 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) { if (res) {
memcpy(dataout + (8 * i), resp, 8); memcpy(dataout + (8 * i), resp, 8);
} else { } else {
@ -1759,7 +1763,7 @@ void iClass_Dump(uint8_t *msg) {
BigBuf_free(); 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 // write command: cmd, 1 blockno, 8 data, 4 mac
uint8_t write[14] = { 0x80 | ICLASS_CMD_UPDATE, blockno }; 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}; uint8_t resp[10] = {0};
uint32_t eof_time = 0, start_time = 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) { if (isOK == false) {
return false; return false;
} }
@ -1807,6 +1811,7 @@ void iClass_WriteBlock(uint8_t *msg) {
LED_A_ON(); LED_A_ON();
iclass_writeblock_req_t *payload = (iclass_writeblock_req_t *)msg; 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[14] = { 0x80 | ICLASS_CMD_UPDATE, payload->req.blockno };
uint8_t write_len = 14; uint8_t write_len = 14;
@ -1816,7 +1821,7 @@ void iClass_WriteBlock(uint8_t *msg) {
// select tag. // select tag.
uint32_t eof_time = 0; uint32_t eof_time = 0;
picopass_hdr_t hdr = {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) { if (res == false) {
goto out; goto out;
} }
@ -1871,7 +1876,7 @@ void iClass_WriteBlock(uint8_t *msg) {
uint8_t tries = 3; uint8_t tries = 3;
while (tries-- > 0) { 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 if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
res = false; res = false;
@ -1939,6 +1944,8 @@ void iClass_Restore(iclass_restore_req_t *msg) {
return; return;
} }
bool shallow_mod = msg->req.shallow_mod;
LED_A_ON(); LED_A_ON();
Iso15693InitReader(); Iso15693InitReader();
@ -1947,7 +1954,7 @@ void iClass_Restore(iclass_restore_req_t *msg) {
picopass_hdr_t hdr = {0}; picopass_hdr_t hdr = {0};
// select // 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) { if (res == false) {
goto out; goto out;
} }
@ -1988,7 +1995,7 @@ void iClass_Restore(iclass_restore_req_t *msg) {
} }
// data + mac // 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); Dbprintf("Write block [%3d/0x%02X] " _GREEN_("successful"), item.blockno, item.blockno);
written++; written++;
} else { } 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); bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out);
void iClass_ReadBlock(uint8_t *msg); 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); 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 #endif

View file

@ -1229,6 +1229,17 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
AddCrc14A(rPPS, sizeof(rPPS) - 2); 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); AddCrc14A(rPACK, sizeof(rPACK) - 2);
static tag_response_info_t responses_init[] = { static tag_response_info_t responses_init[] = {

View file

@ -1814,17 +1814,17 @@ int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
static const uint8_t x_wup2[] = { 0x5D, 0x37, 0x21, 0x71, 0x71 }; static const uint8_t x_wup2[] = { 0x5D, 0x37, 0x21, 0x71, 0x71 };
uint8_t slot_mark[1]; uint8_t slot_mark[1];
uint8_t x_atqb[24] = {0x0}; // ATQB len = 18 uint8_t x_atqb[24] = {0x0}; // ATQB len = 18
uint32_t start_time = 0; uint32_t start_time = 0;
uint32_t eof_time = 0; uint32_t eof_time = 0;
iso14b_set_timeout(24); // wait for carrier iso14b_set_timeout(24); // wait for carrier
// wup1 // wup1
CodeAndTransmit14443bAsReader(x_wup1, sizeof(x_wup1), &start_time, &eof_time, true); CodeAndTransmit14443bAsReader(x_wup1, sizeof(x_wup1), &start_time, &eof_time, true);
start_time = eof_time + US_TO_SSP(9000); // 9ms before next cmd start_time = eof_time + US_TO_SSP(9000); // 9ms before next cmd
// wup2 // wup2
CodeAndTransmit14443bAsReader(x_wup2, sizeof(x_wup2), &start_time, &eof_time, true); CodeAndTransmit14443bAsReader(x_wup2, sizeof(x_wup2), &start_time, &eof_time, true);
@ -1836,7 +1836,7 @@ int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
int slot; int slot;
for (slot = 0; slot < 4; slot++) { for (slot = 0; slot < 4; slot++) {
start_time = eof_time + ETU_TO_SSP(30); //(24); // next slot after 24 ETU 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); retlen = Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time);
@ -1850,14 +1850,14 @@ int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
// tx unframed slot-marker // tx unframed slot-marker
if (Demod.posCount) { // no rx, but subcarrier burst detected if (Demod.posCount) { // no rx, but subcarrier burst detected
uid |= (uint64_t)slot << uid_pos; uid |= (uint64_t)slot << uid_pos;
slot_mark[0] = 0xB1 + (slot << 1); // ack slot slot_mark[0] = 0xB1 + (slot << 1); // ack slot
CodeAndTransmit14443bAsReader(slot_mark, sizeof(slot_mark), &start_time, &eof_time, false); CodeAndTransmit14443bAsReader(slot_mark, sizeof(slot_mark), &start_time, &eof_time, false);
break; break;
} else { // no subcarrier burst } else { // no subcarrier burst
slot_mark[0] = 0xA1 + (slot << 1); // nak slot slot_mark[0] = 0xA1 + (slot << 1); // nak slot
CodeAndTransmit14443bAsReader(slot_mark, sizeof(slot_mark), &start_time, &eof_time, false); CodeAndTransmit14443bAsReader(slot_mark, sizeof(slot_mark), &start_time, &eof_time, false);
} }
} }
@ -1884,7 +1884,7 @@ int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
} }
// VALIDATE CRC // VALIDATE CRC
if (check_crc(CRC_14443_B, x_atqb, 18) == false) { // use fixed len because unstable EOF catch if (check_crc(CRC_14443_B, x_atqb, 18) == false) { // use fixed len because unstable EOF catch
return 3; return 3;
} }

View file

@ -262,9 +262,9 @@ void CodeIso15693AsTag(const uint8_t *cmd, size_t len) {
} }
// Transmit the command (to the tag) that was placed in cmd[]. // 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) { if (*start_time < DELAY_ARM_TO_TAG) {
*start_time = DELAY_ARM_TO_TAG; *start_time = DELAY_ARM_TO_TAG;
@ -1585,7 +1585,7 @@ void AcquireRawAdcSamplesIso15693(void) {
tosend_t *ts = get_tosend(); tosend_t *ts = get_tosend();
uint32_t start_time = 0; 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 // wait for last transfer to complete
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) ; while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) ;
@ -1899,7 +1899,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t
} }
tosend_t *ts = get_tosend(); 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 if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
*resp_len = 0; *resp_len = 0;
@ -1922,7 +1922,7 @@ int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, ui
CodeIso15693AsReaderEOF(); CodeIso15693AsReaderEOF();
tosend_t *ts = get_tosend(); 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 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); LogTrace_ISO15693(NULL, 0, (start_time * 4), (end_time * 4), NULL, true);

View file

@ -40,7 +40,7 @@ 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); 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); 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); 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 RecordRawAdcSamplesIso15693(void);

View file

@ -461,7 +461,6 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
uint16_t len = 0; uint16_t len = 0;
uint32_t pos = 0; uint32_t pos = 0;
uint8_t par[3] = {0x00, 0x00, 0x00}; // enough for 18 Bytes to send 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 d_block[18], d_block_enc[18];
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
@ -495,7 +494,7 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
len = ReaderReceive(receivedAnswer, receivedAnswerPar); len = ReaderReceive(receivedAnswer, receivedAnswerPar);
if (len != 0) { // Something not right, len == 0 (no response is ok as its waiting for transfer 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], 0)) << 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1; 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], 2)) << 2;

View file

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

View file

@ -48,7 +48,7 @@ INSTALLFW = $(OBJDIR)/bootrom.elf
OBJS = $(OBJDIR)/bootrom.s19 OBJS = $(OBJDIR)/bootrom.s19
# version_pm3.c should be remade on every compilation # 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 $@) $(info [=] GEN $@)
$(Q)$(SH) ../tools/mkversion.sh > $@ || $(PERL) ../tools/mkversion.pl > $@ || $(CP) $< $@ $(Q)$(SH) ../tools/mkversion.sh > $@ || $(PERL) ../tools/mkversion.pl > $@ || $(CP) $< $@
@ -82,7 +82,7 @@ uninstall:
$(info [@] Uninstalling bootrom from $(DESTDIR)$(PREFIX)...) $(info [@] Uninstalling bootrom from $(DESTDIR)$(PREFIX)...)
$(Q)$(INSTALLSUDO) $(RM) $(foreach fw,$(INSTALLFW),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(notdir $(fw))) $(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: help:
@echo Multi-OS Makefile, you are running on $(DETECTED_OS) @echo Multi-OS Makefile, you are running on $(DETECTED_OS)
@echo Possible targets: @echo Possible targets:

View file

@ -293,9 +293,10 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdhfseos.c ${PM3_ROOT}/client/src/cmdhfseos.c
${PM3_ROOT}/client/src/cmdhfst.c ${PM3_ROOT}/client/src/cmdhfst.c
${PM3_ROOT}/client/src/cmdhfst25ta.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/cmdhfthinfilm.c
${PM3_ROOT}/client/src/cmdhftopaz.c ${PM3_ROOT}/client/src/cmdhftopaz.c
${PM3_ROOT}/client/src/cmdhftexkom.c
${PM3_ROOT}/client/src/cmdhfwaveshare.c ${PM3_ROOT}/client/src/cmdhfwaveshare.c
${PM3_ROOT}/client/src/cmdhfxerox.c ${PM3_ROOT}/client/src/cmdhfxerox.c
${PM3_ROOT}/client/src/cmdhw.c ${PM3_ROOT}/client/src/cmdhw.c
@ -336,6 +337,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdmain.c ${PM3_ROOT}/client/src/cmdmain.c
${PM3_ROOT}/client/src/cmdnfc.c ${PM3_ROOT}/client/src/cmdnfc.c
${PM3_ROOT}/client/src/cmdparser.c ${PM3_ROOT}/client/src/cmdparser.c
${PM3_ROOT}/client/src/cmdpiv.c
${PM3_ROOT}/client/src/cmdscript.c ${PM3_ROOT}/client/src/cmdscript.c
${PM3_ROOT}/client/src/cmdsmartcard.c ${PM3_ROOT}/client/src/cmdsmartcard.c
${PM3_ROOT}/client/src/cmdtrace.c ${PM3_ROOT}/client/src/cmdtrace.c

View file

@ -583,6 +583,7 @@ SRCS = mifare/aiddesfire.c \
cmdhfseos.c \ cmdhfseos.c \
cmdhfst.c \ cmdhfst.c \
cmdhfst25ta.c \ cmdhfst25ta.c \
cmdhftesla.c \
cmdhfthinfilm.c \ cmdhfthinfilm.c \
cmdhftopaz.c \ cmdhftopaz.c \
cmdhftexkom.c \ cmdhftexkom.c \
@ -626,6 +627,7 @@ SRCS = mifare/aiddesfire.c \
cmdmain.c \ cmdmain.c \
cmdnfc.c \ cmdnfc.c \
cmdparser.c \ cmdparser.c \
cmdpiv.c \
cmdscript.c \ cmdscript.c \
cmdsmartcard.c \ cmdsmartcard.c \
cmdtrace.c \ cmdtrace.c \

View file

@ -530,7 +530,6 @@ stop_tests:
bucket_states_tested += bucket_size[block_idx]; bucket_states_tested += bucket_size[block_idx];
// prepare to set new states // prepare to set new states
state_p = &states[KEYSTREAM_SIZE]; state_p = &states[KEYSTREAM_SIZE];
continue;
} }
} }
out: out:

View file

@ -1909,3 +1909,79 @@ D144BD193063
# Keys Swim # Keys Swim
8627C10A7014 8627C10A7014
453857395635 453857395635
#
##########################################
# added by colonelborkmundus
# "the more, the marriott" mifare project
#
# 1k - graduate hotel
C49DAE1C6049
209A2B910545
#
# 1k - westin
8C29F8320617
5697519A8F02
7D0A1C277C05
2058580A941F
C40964215509
D44CFC178460
#
# 1k - marriott
7B4DFC6D6525
23C9FDD9A366
3119A70628EB
30AAD6A711EF
1330824CD356
43012BD9EB87
035C70558D7B
9966588CB9A0
12AB4C37BB8B
#
# 1k - AC hotels marriott
8EA8EC3F2320
7B56B2B38725
#
# 1k - the ritz-carlton
30FB20D0EFEF
D20289CD9E6E
66A3B064CC4B
D18296CD9E6E
#
# 1k - unknown
722538817225
#
# 1k - aria resort & casino
316B8FAA12EF
A18D9F4E75AF
#
# 1k - fairfield inn & suites marriott
7AEB989A5525
7B3B589A5525
215E9DED9DDF
334E91BE3377
310308EC52EF
#
# 1k - residence inn marriott
F72CD208FDF9
#
# 1k - sheraton
42FC522DE987
#
# 1k - millenium hotels
132F641C948B
#
# 1k - moxy hotels
20C166C00ADB
9EE3896C4530
#
# 1k - residence inn marriott
3122AE5341EB
#
# 1k - americinn
8AC04C1A4A25
#
# 1k - the industrialist
2158E314C3DF
#
# 1k - waldorf astoria
011C6CF459E8

View file

@ -276,6 +276,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdhfepa.c ${PM3_ROOT}/client/src/cmdhfepa.c
${PM3_ROOT}/client/src/cmdhffelica.c ${PM3_ROOT}/client/src/cmdhffelica.c
${PM3_ROOT}/client/src/cmdhffido.c ${PM3_ROOT}/client/src/cmdhffido.c
${PM3_ROOT}/client/src/cmdhffudan.c
${PM3_ROOT}/client/src/cmdhfgallagher.c ${PM3_ROOT}/client/src/cmdhfgallagher.c
${PM3_ROOT}/client/src/cmdhfcipurse.c ${PM3_ROOT}/client/src/cmdhfcipurse.c
${PM3_ROOT}/client/src/cmdhficlass.c ${PM3_ROOT}/client/src/cmdhficlass.c
@ -293,9 +294,12 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdhfseos.c ${PM3_ROOT}/client/src/cmdhfseos.c
${PM3_ROOT}/client/src/cmdhfst.c ${PM3_ROOT}/client/src/cmdhfst.c
${PM3_ROOT}/client/src/cmdhfst25ta.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/cmdhfthinfilm.c
${PM3_ROOT}/client/src/cmdhftopaz.c ${PM3_ROOT}/client/src/cmdhftopaz.c
${PM3_ROOT}/client/src/cmdhfwaveshare.c ${PM3_ROOT}/client/src/cmdhfwaveshare.c
${PM3_ROOT}/client/src/cmdhfxerox.c
${PM3_ROOT}/client/src/cmdhw.c ${PM3_ROOT}/client/src/cmdhw.c
${PM3_ROOT}/client/src/cmdlf.c ${PM3_ROOT}/client/src/cmdlf.c
${PM3_ROOT}/client/src/cmdlfawid.c ${PM3_ROOT}/client/src/cmdlfawid.c
@ -334,6 +338,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdmain.c ${PM3_ROOT}/client/src/cmdmain.c
${PM3_ROOT}/client/src/cmdnfc.c ${PM3_ROOT}/client/src/cmdnfc.c
${PM3_ROOT}/client/src/cmdparser.c ${PM3_ROOT}/client/src/cmdparser.c
${PM3_ROOT}/client/src/cmdpiv.c
${PM3_ROOT}/client/src/cmdscript.c ${PM3_ROOT}/client/src/cmdscript.c
${PM3_ROOT}/client/src/cmdsmartcard.c ${PM3_ROOT}/client/src/cmdsmartcard.c
${PM3_ROOT}/client/src/cmdtrace.c ${PM3_ROOT}/client/src/cmdtrace.c

View file

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

View file

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

View file

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

View file

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

View file

@ -50,17 +50,17 @@ arguments = [[
-c read magic configuration -c read magic configuration
-u UID (8-14 hexsymbols), set UID on tag -u UID (8-14 hexsymbols), set UID on tag
-t tag type to impersonate -t tag type to impersonate
1 = Mifare Mini S20 4-byte 12 = NTAG 210 1 = Mifare Mini S20 4-byte 12 = NTAG 210
2 = Mifare Mini S20 7-byte 13 = NTAG 212 2 = Mifare Mini S20 7-byte 13 = NTAG 212
3 = Mifare 1k S50 4-byte 14 = NTAG 213 3 = Mifare 1k S50 4-byte 14 = NTAG 213
4 = Mifare 1k S50 7-byte 15 = NTAG 215 4 = Mifare 1k S50 7-byte 15 = NTAG 215
5 = Mifare 4k S70 4-byte 16 = NTAG 216 5 = Mifare 4k S70 4-byte 16 = NTAG 216
6 = Mifare 4k S70 7-byte 17 = NTAG I2C 1K 6 = Mifare 4k S70 7-byte 17 = NTAG I2C 1K
*** 7 = UL - NOT WORKING FULLY 18 = NTAG I2C 2K *** 7 = UL - NOT WORKING FULLY 18 = NTAG I2C 2K
*** 8 = UL-C - NOT WORKING FULLY 19 = NTAG I2C 1K PLUS *** 8 = UL-C - NOT WORKING FULLY 19 = NTAG I2C 1K PLUS
9 = UL EV1 48b 20 = NTAG I2C 2K PLUS 9 = UL EV1 48b 20 = NTAG I2C 2K PLUS
10 = UL EV1 128b 21 = NTAG 213F 10 = UL EV1 128b 21 = NTAG 213F
*** 11 = UL Plus - NOT WORKING YET 22 = NTAG 216F *** 11 = UL Plus - NOT WORKING YET 22 = NTAG 216F
-p NTAG password (8 hexsymbols), set NTAG password on tag. -p NTAG password (8 hexsymbols), set NTAG password on tag.
-a NTAG pack ( 4 hexsymbols), set NTAG pack 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 if not info then return false, "Can't select card" end
-- read Ultimate Magic Card CONFIG -- read Ultimate Magic Card CONFIG
if magicconfig == nil then if magicconfig == nil then
magicconfig = send("CF".._key.."C6") magicconfig = send("CF".._key.."C6")
else print('No Config') else print('No Config')
end end
-- extract data from CONFIG - based on CONFIG in https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md#gen-4-gtu -- extract data from CONFIG - based on CONFIG in https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md#gen-4-gtu
@ -196,92 +196,92 @@ local function read_config()
else atsstr = (string.sub(ats, 3)) else atsstr = (string.sub(ats, 3))
end end
if ulprotocol == '00' then if ulprotocol == '00' then
cardprotocol = 'MIFARE Classic Protocol' cardprotocol = 'MIFARE Classic Protocol'
ultype = 'Disabled' ultype = 'Disabled'
if uidlength == '00' then if uidlength == '00' then
uid = send("CF".._key.."CE00"):sub(1,8) uid = send("CF".._key.."CE00"):sub(1,8)
if atqaf == '00 04' and sak == '09' then cardtype = 'MIFARE Mini S20 4-byte UID' 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 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' elseif atqaf == '00 02' and sak == '18' then cardtype = 'MIFARE 4k S70 4-byte UID'
end end
elseif uidlength == '01' then elseif uidlength == '01' then
uid = send("CF".._key.."CE00"):sub(1,14) uid = send("CF".._key.."CE00"):sub(1,14)
if atqaf == '00 44' and sak == '09' then cardtype = 'MIFARE Mini S20 7-byte UID' 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 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' elseif atqaf == '00 42' and sak == '18' then cardtype = 'MIFARE 4k S70 7-byte UID'
end end
end end
elseif ulprotocol == '01' then elseif ulprotocol == '01' then
-- Read Ultralight config only if UL protocol is enabled -- Read Ultralight config only if UL protocol is enabled
cardprotocol = 'MIFARE Ultralight/NTAG' cardprotocol = 'MIFARE Ultralight/NTAG'
block0 = send("3000") block0 = send("3000")
uid0 = block0:sub(1,6) uid0 = block0:sub(1,6)
uid = uid0..block0:sub(9,16) uid = uid0..block0:sub(9,16)
if ulmode == '00' then ultype = 'Ultralight EV1' if ulmode == '00' then ultype = 'Ultralight EV1'
elseif ulmode == '01' then ultype = 'NTAG21x' elseif ulmode == '01' then ultype = 'NTAG21x'
elseif ulmode == '02' then ultype = 'Ultralight-C' elseif ulmode == '02' then ultype = 'Ultralight-C'
elseif ulmode == '03' then ultype = 'Ultralight' elseif ulmode == '03' then ultype = 'Ultralight'
end end
-- read VERSION -- read VERSION
cversion = send('30FA'):sub(1,16) 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 -- 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' if ulmode == '03' then versionstr = 'Ultralight'
elseif ulmode == '02' then versionstr = 'Ultralight-C' 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 == '0004030101000E03' then versionstr = 'UL EV1 128b'
elseif cversion == '0004040101000B03' then versionstr = 'NTAG 210' elseif cversion == '0004040101000B03' then versionstr = 'NTAG 210'
elseif cversion == '0004040101000E03' then versionstr = 'NTAG 212' elseif cversion == '0004040101000E03' then versionstr = 'NTAG 212'
elseif cversion == '0004040201000F03' then versionstr = 'NTAG 213' elseif cversion == '0004040201000F03' then versionstr = 'NTAG 213'
elseif cversion == '0004040201001103' then versionstr = 'NTAG 215' elseif cversion == '0004040201001103' then versionstr = 'NTAG 215'
elseif cversion == '0004040201001303' then versionstr = 'NTAG 216' elseif cversion == '0004040201001303' then versionstr = 'NTAG 216'
elseif cversion == '0004040502011303' then versionstr = 'NTAG I2C 1K' elseif cversion == '0004040502011303' then versionstr = 'NTAG I2C 1K'
elseif cversion == '0004040502011503' then versionstr = 'NTAG I2C 2K' elseif cversion == '0004040502011503' then versionstr = 'NTAG I2C 2K'
elseif cversion == '0004040502021303' then versionstr = 'NTAG I2C 1K PLUS' elseif cversion == '0004040502021303' then versionstr = 'NTAG I2C 1K PLUS'
elseif cversion == '0004040502021503' then versionstr = 'NTAG I2C 2K PLUS' elseif cversion == '0004040502021503' then versionstr = 'NTAG I2C 2K PLUS'
elseif cversion == '0004040401000F03' then versionstr = 'NTAG 213F' elseif cversion == '0004040401000F03' then versionstr = 'NTAG 213F'
elseif cversion == '0004040401001303' then versionstr = 'NTAG 216F' elseif cversion == '0004040401001303' then versionstr = 'NTAG 216F'
end end
-- read PWD -- read PWD
cpwd = send("30F0"):sub(1,8) cpwd = send("30F0"):sub(1,8)
pwd = send("30E5"):sub(1,8) pwd = send("30E5"):sub(1,8)
-- 04 response indicates that blocks has been locked down. -- 04 response indicates that blocks has been locked down.
if pwd == '04' then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end if pwd == '04' then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end
-- read PACK -- read PACK
cpack = send("30F1"):sub(1,4) cpack = send("30F1"):sub(1,4)
pack = send("30E6"):sub(1,4) pack = send("30E6"):sub(1,4)
-- read SIGNATURE -- read SIGNATURE
signature1 = send('30F2'):sub(1,32) signature1 = send('30F2'):sub(1,32)
signature2 = send('30F6'):sub(1,32) signature2 = send('30F6'):sub(1,32)
lib14a.disconnect() lib14a.disconnect()
end end
if _print < 1 then if _print < 1 then
print(string.rep('=', 88)) print(string.rep('=', 88))
print('\t\t\tUltimate Magic Card Configuration') print('\t\t\tUltimate Magic Card Configuration')
print(string.rep('=', 88)) print(string.rep('=', 88))
print(' - Raw Config ', string.sub(magicconfig, 1, -9)) print(' - Raw Config ', string.sub(magicconfig, 1, -9))
print(' - Card Protocol ', cardprotocol) print(' - Card Protocol ', cardprotocol)
print(' - Ultralight Mode ', ultype) print(' - Ultralight Mode ', ultype)
print(' - ULM Backdoor Key ', readpass) print(' - ULM Backdoor Key ', readpass)
print(' - GTU Mode ', gtustr) print(' - GTU Mode ', gtustr)
if ulprotocol == '01' then if ulprotocol == '01' then
print(' - Card Type ', versionstr) print(' - Card Type ', versionstr)
else else
print(' - Card Type ', cardtype) print(' - Card Type ', cardtype)
end end
print(' - UID ', uid) print(' - UID ', uid)
print(' - ATQA ', atqaf) print(' - ATQA ', atqaf)
print(' - SAK ', sak) print(' - SAK ', sak)
if ulprotocol == '01' then if ulprotocol == '01' then
print('') print('')
print(string.rep('=', 88)) print(string.rep('=', 88))
print('\t\t\tMagic UL/NTAG 21* Configuration') print('\t\t\tMagic UL/NTAG 21* Configuration')
print(string.rep('=', 88)) print(string.rep('=', 88))
print(' - ATS ', atsstr) print(' - ATS ', atsstr)
print(' - Password ', '[0xE5] '..pwd, '[0xF0] '..cpwd) print(' - Password ', '[0xE5] '..pwd, '[0xF0] '..cpwd)
print(' - Pack ', '[0xE6] '..pack, '[0xF1] '..cpack) print(' - Pack ', '[0xE6] '..pack, '[0xF1] '..cpack)
print(' - Version ', cversion) print(' - Version ', cversion)
print(' - Signature ', signature1..signature2) print(' - Signature ', signature1..signature2)
end end
end end
lib14a.disconnect() lib14a.disconnect()
return true, 'Ok' return true, 'Ok'
@ -291,41 +291,41 @@ end
local function write_uid(useruid) local function write_uid(useruid)
-- read CONFIG -- read CONFIG
if not magicconfig then if not magicconfig then
_print = 1 _print = 1
read_config() read_config()
end end
local info = connect() local info = connect()
if not info then return false, "Can't select card" end if not info then return false, "Can't select card" end
-- Writes a MFC UID with GEN4 magic commands. -- Writes a MFC UID with GEN4 magic commands.
if ulprotocol == '00' then if ulprotocol == '00' then
-- uid string checks -- uid string checks
if useruid == nil then return nil, 'empty uid string' end if useruid == nil then return nil, 'empty uid string' end
if #useruid == 0 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 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) print('Writing new UID ', useruid)
local uidbytes = utils.ConvertHexToBytes(useruid) local uidbytes = utils.ConvertHexToBytes(useruid)
local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), uidbytes[4]) 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 block0 = string.format('%02X%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], uidbytes[4], bcc1)
local resp = send('CF'.._key..'CD00'..block0) local resp = send('CF'.._key..'CD00'..block0)
-- Writes a MFUL UID with bcc1, bcc2 using NTAG21xx commands. -- Writes a MFUL UID with bcc1, bcc2 using NTAG21xx commands.
elseif ulprotocol == '01' then elseif ulprotocol == '01' then
-- uid string checks -- uid string checks
if useruid == nil then return nil, 'empty uid string' end if useruid == nil then return nil, 'empty uid string' end
if #useruid == 0 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 if #useruid ~= 14 then return nil, 'uid wrong length. Should be 7 hex bytes' end
print('Writing new UID ', useruid) print('Writing new UID ', useruid)
local uidbytes = utils.ConvertHexToBytes(useruid) local uidbytes = utils.ConvertHexToBytes(useruid)
local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), 0x88) 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 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 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 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 block2 = string.format('%02X%02X%02X%02X', bcc2, 0x48, 0x00, 0x00)
local resp local resp
resp = send('A200'..block0) resp = send('A200'..block0)
resp = send('A201'..block1) resp = send('A201'..block1)
resp = send('A202'..block2) resp = send('A202'..block2)
else else
print('Incorrect ul') print('Incorrect ul')
end end
lib14a.disconnect() lib14a.disconnect()
if resp ~= nil then if resp ~= nil then
@ -339,8 +339,8 @@ end
local function write_atqasak(atqasak) local function write_atqasak(atqasak)
-- read CONFIG -- read CONFIG
if not magicconfig then if not magicconfig then
_print = 1 _print = 1
read_config() read_config()
end end
if atqasak == nil then return nil, 'Empty ATQA/SAK string' end if atqasak == nil then return nil, 'Empty ATQA/SAK string' end
if #atqasak == 0 then return nil, 'Empty ATQA/SAK string' end if #atqasak == 0 then return nil, 'Empty ATQA/SAK string' end
@ -350,25 +350,25 @@ end
local atqauserf = atqauser2..atqauser1 local atqauserf = atqauser2..atqauser1
local sakuser = atqasak:sub(5,6) local sakuser = atqasak:sub(5,6)
if sakuser == '04' then if sakuser == '04' then
print('Never set SAK bit 3 (e.g. SAK=04), it indicates an extra cascade level is required') print('Never set SAK bit 3 (e.g. SAK=04), it indicates an extra cascade level is required')
return nil return nil
elseif (sakuser == '20' or sakuser == '28') and atslen == '00' then elseif (sakuser == '20' or sakuser == '28') and atslen == '00' then
print('When SAK equals 20 or 28, ATS must be turned on') print('When SAK equals 20 or 28, ATS must be turned on')
return nil return nil
elseif atqauser2 == '40' then elseif atqauser2 == '40' then
print('ATQA of [00 40] will cause the card to not answer.') print('ATQA of [00 40] will cause the card to not answer.')
return nil return nil
else else
local info = connect() local info = connect()
if not info then return false, "Can't select card" end if not info then return false, "Can't select card" end
print('New ATQA: '..atqauser1..' '..atqauser2..' New SAK: '..sakuser) print('New ATQA: '..atqauser1..' '..atqauser2..' New SAK: '..sakuser)
local resp = send("CF".._key.."35"..atqauserf..sakuser) local resp = send("CF".._key.."35"..atqauserf..sakuser)
lib14a.disconnect() lib14a.disconnect()
if resp == nil then if resp == nil then
return nil, oops('Failed to write ATQA/SAK') return nil, oops('Failed to write ATQA/SAK')
else else
return true, 'Ok' return true, 'Ok'
end end
end end
end end
--- ---
@ -376,8 +376,8 @@ end
local function write_ntagpwd(ntagpwd) local function write_ntagpwd(ntagpwd)
-- read CONFIG -- read CONFIG
if not magicconfig then if not magicconfig then
_print = 1 _print = 1
read_config() read_config()
end end
if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end
-- PWD string checks -- PWD string checks
@ -401,8 +401,8 @@ end
local function write_pack(userpack) local function write_pack(userpack)
-- read CONFIG -- read CONFIG
if not magicconfig then if not magicconfig then
_print = 1 _print = 1
read_config() read_config()
end end
if ulprotocol == 0 then return nil, 'Magic Card is not using the Ultralight Protocol' end if ulprotocol == 0 then return nil, 'Magic Card is not using the Ultralight Protocol' end
-- PACK string checks -- PACK string checks
@ -426,8 +426,8 @@ local function write_otp(block3)
if #block3 ~= 8 then return nil, 'OTP wrong length. Should be 4 hex bytes' end if #block3 ~= 8 then return nil, 'OTP wrong length. Should be 4 hex bytes' end
-- read CONFIG -- read CONFIG
if not magicconfig then if not magicconfig then
_print = 1 _print = 1
read_config() read_config()
end end
if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end
local info = connect() local info = connect()
@ -450,8 +450,8 @@ local function write_version(data)
if #data ~= 16 then return nil, 'version wrong length. Should be 8 hex bytes' end if #data ~= 16 then return nil, 'version wrong length. Should be 8 hex bytes' end
-- read CONFIG -- read CONFIG
if not magicconfig then if not magicconfig then
_print = 1 _print = 1
read_config() read_config()
end end
if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end
print('Writing new version', data) print('Writing new version', data)
@ -478,8 +478,8 @@ local function write_signature(data)
if #data ~= 64 then return nil, 'data wrong length. Should be 32 hex bytes' end if #data ~= 64 then return nil, 'data wrong length. Should be 32 hex bytes' end
-- read CONFIG -- read CONFIG
if not magicconfig then if not magicconfig then
_print = 1 _print = 1
read_config() read_config()
end end
local info = connect() local info = connect()
if not info then return false, "Can't select card" end if not info then return false, "Can't select card" end
@ -508,19 +508,19 @@ local function write_gtu(gtu)
local info = connect() local info = connect()
if not info then return false, "Can't select card" end if not info then return false, "Can't select card" end
if gtu == '00' then if gtu == '00' then
print('Enabling GTU Pre-Write') print('Enabling GTU Pre-Write')
send('CF'.._key..'32'..gtu) send('CF'.._key..'32'..gtu)
elseif gtu == '01' then elseif gtu == '01' then
print('Enabling GTU Restore Mode') print('Enabling GTU Restore Mode')
send('CF'.._key..'32'..gtu) send('CF'.._key..'32'..gtu)
elseif gtu == '02' then elseif gtu == '02' then
print('Disabled GTU') print('Disabled GTU')
send('CF'.._key..'32'..gtu) send('CF'.._key..'32'..gtu)
elseif gtu == '03' then elseif gtu == '03' then
print('Disabled GTU, high speed R/W mode for Ultralight') print('Disabled GTU, high speed R/W mode for Ultralight')
send('CF'.._key..'32'..gtu) send('CF'.._key..'32'..gtu)
else else
print('Failed to set GTU mode') print('Failed to set GTU mode')
end end
lib14a.disconnect() lib14a.disconnect()
return true, 'Ok' return true, 'Ok'
@ -536,13 +536,13 @@ local function write_ats(atsuser)
local atscardlendecimal = tonumber(atscardlen, 16) local atscardlendecimal = tonumber(atscardlen, 16)
local atsf = string.sub(atsuser, 3) local atsf = string.sub(atsuser, 3)
if (#atsf / 2) ~= atscardlendecimal then if (#atsf / 2) ~= atscardlendecimal then
oops('Given length of ATS ('..atscardlendecimal..') does not match the ATS_length ('..(#atsf / 2)..')') oops('Given length of ATS ('..atscardlendecimal..') does not match the ATS_length ('..(#atsf / 2)..')')
return true, 'Ok' return true, 'Ok'
else else
local info = connect() local info = connect()
if not info then return false, "Can't select card" end if not info then return false, "Can't select card" end
print('Writing '..atscardlendecimal..' ATS bytes of '..atsf) print('Writing '..atscardlendecimal..' ATS bytes of '..atsf)
send("CF".._key.."34"..atsuser) send("CF".._key.."34"..atsuser)
end end
lib14a.disconnect() lib14a.disconnect()
return true, 'Ok' return true, 'Ok'
@ -556,11 +556,11 @@ local function write_ulp(ulp)
local info = connect() local info = connect()
if not info then return false, "Can't select card" end if not info then return false, "Can't select card" end
if ulp == '00' then if ulp == '00' then
print('Changing card to Mifare Classic Protocol') print('Changing card to Mifare Classic Protocol')
send("CF".._key.."69"..ulp) send("CF".._key.."69"..ulp)
elseif ulp == '01' then elseif ulp == '01' then
print('Changing card to Ultralight Protocol') print('Changing card to Ultralight Protocol')
send("CF".._key.."69"..ulp) send("CF".._key.."69"..ulp)
else else
oops('Protocol needs to be either 00 or 01') oops('Protocol needs to be either 00 or 01')
end end
@ -576,17 +576,17 @@ local function write_ulm(ulm)
local info = connect() local info = connect()
if not info then return false, "Can't select card" end if not info then return false, "Can't select card" end
if ulm == '00' then if ulm == '00' then
print('Changing card UL mode to Ultralight EV1') print('Changing card UL mode to Ultralight EV1')
send("CF".._key.."6A"..ulm) send("CF".._key.."6A"..ulm)
elseif ulm == '01' then elseif ulm == '01' then
print('Changing card UL mode to NTAG') print('Changing card UL mode to NTAG')
send("CF".._key.."6A"..ulm) send("CF".._key.."6A"..ulm)
elseif ulm == '02' then elseif ulm == '02' then
print('Changing card UL mode to Ultralight-C') print('Changing card UL mode to Ultralight-C')
send("CF".._key.."6A"..ulm) send("CF".._key.."6A"..ulm)
elseif ulm == '03' then elseif ulm == '03' then
print('Changing card UL mode to Ultralight') print('Changing card UL mode to Ultralight')
send("CF".._key.."6A"..ulm) send("CF".._key.."6A"..ulm)
else else
oops('UL mode needs to be either 00, 01, 02, 03') oops('UL mode needs to be either 00, 01, 02, 03')
end end
@ -603,50 +603,50 @@ local function set_type(tagtype)
if tagtype == 1 then if tagtype == 1 then
print('Setting: Ultimate Magic card to Mifare mini S20 4-byte') print('Setting: Ultimate Magic card to Mifare mini S20 4-byte')
connect() connect()
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000900") send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000900")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233') write_uid('04112233')
-- Setting Mifare mini S20 7-byte -- Setting Mifare mini S20 7-byte
elseif tagtype == 2 then elseif tagtype == 2 then
print('Setting: Ultimate Magic card to Mifare mini S20 7-byte') print('Setting: Ultimate Magic card to Mifare mini S20 7-byte')
connect() connect()
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000900") send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000900")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
-- Setting Mifare 1k S50 4--byte -- Setting Mifare 1k S50 4--byte
elseif tagtype == 3 then elseif tagtype == 3 then
print('Setting: Ultimate Magic card to Mifare 1k S50 4-byte') print('Setting: Ultimate Magic card to Mifare 1k S50 4-byte')
connect() connect()
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800") send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233') write_uid('04112233')
-- Setting Mifare 1k S50 7-byte -- Setting Mifare 1k S50 7-byte
elseif tagtype == 4 then elseif tagtype == 4 then
print('Setting: Ultimate Magic card to Mifare 1k S50 7-byte') print('Setting: Ultimate Magic card to Mifare 1k S50 7-byte')
connect() connect()
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000800") send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000800")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
-- Setting Mifare 4k S70 4-byte -- Setting Mifare 4k S70 4-byte
elseif tagtype == 5 then elseif tagtype == 5 then
print('Setting: Ultimate Magic card to Mifare 4k S70 4-byte') print('Setting: Ultimate Magic card to Mifare 4k S70 4-byte')
connect() connect()
send("CF".._key.."F000000000000002000978009102DABC19101011121314151602001800") send("CF".._key.."F000000000000002000978009102DABC19101011121314151602001800")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233') write_uid('04112233')
-- Setting Mifare 4k S70 7-byte -- Setting Mifare 4k S70 7-byte
elseif tagtype == 6 then elseif tagtype == 6 then
print('Setting: Ultimate Magic card to Mifare 4k S70 7-byte') print('Setting: Ultimate Magic card to Mifare 4k S70 7-byte')
connect() connect()
send("CF".._key.."F000010000000002000978009102DABC19101011121314151642001800") send("CF".._key.."F000010000000002000978009102DABC19101011121314151642001800")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
-- Setting UL -- Setting UL
elseif tagtype == 7 then elseif tagtype == 7 then
print('Setting: Ultimate Magic card to UL') print('Setting: Ultimate Magic card to UL')
connect() connect()
send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000003") send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000003")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_otp('00000000') -- Setting OTP to default 00 00 00 00 write_otp('00000000') -- Setting OTP to default 00 00 00 00
write_version('0000000000000000') -- UL-C does not have a version write_version('0000000000000000') -- UL-C does not have a version
@ -654,48 +654,48 @@ local function set_type(tagtype)
elseif tagtype == 8 then elseif tagtype == 8 then
print('Setting: Ultimate Magic card to UL-C') print('Setting: Ultimate Magic card to UL-C')
connect() connect()
send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000002") send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000002")
print('Setting default permissions and 3des key') print('Setting default permissions and 3des key')
send('A22A30000000') -- Auth0 page 48/0x30 and above need authentication send('A22A30000000') -- Auth0 page 48/0x30 and above need authentication
send('A22B80000000') -- Auth1 read and write access restricted send('A22B80000000') -- Auth1 read and write access restricted
send('A22C42524541') -- Default 3des key send('A22C42524541') -- Default 3des key
send('A22D4B4D4549') send('A22D4B4D4549')
send('A22E46594F55') send('A22E46594F55')
send('A22F43414E21') send('A22F43414E21')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_otp('00000000') -- Setting OTP to default 00 00 00 00 write_otp('00000000') -- Setting OTP to default 00 00 00 00
write_version('0000000000000000') -- UL-C does not have a version write_version('0000000000000000') -- UL-C does not have a version
elseif tagtype == 9 then elseif tagtype == 9 then
print('Setting: Ultimate Magic card to UL-EV1 48') print('Setting: Ultimate Magic card to UL-EV1 48')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000")
-- Setting UL-Ev1 default config bl 16,17 -- Setting UL-Ev1 default config bl 16,17
send('a2E5FFFFFFFF') -- A2F0 block does not align correctly to actual pwd 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('a2E6FFFFFFFF') -- A2F1 block does not align correctly to actual pack block
send('a210000000FF') send('a210000000FF')
send('a21100050000') send('a21100050000')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_otp('00000000') -- Setting OTP to default 00 00 00 00 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 write_version('0004030101000b03') -- UL-EV1 (48) 00 04 03 01 01 00 0b 03
elseif tagtype == 10 then elseif tagtype == 10 then
print('Setting: Ultimate Magic card to UL-EV1 128') print('Setting: Ultimate Magic card to UL-EV1 128')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000")
-- Setting UL-Ev1 default config bl 37,38 -- Setting UL-Ev1 default config bl 37,38
send('a2E5FFFFFFFF') -- A2F0 block does not align correctly to actual pwd 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('a2E6FFFFFFFF') -- A2F1 block does not align correctly to actual pack block
send('a225000000FF') send('a225000000FF')
send('a22600050000') send('a22600050000')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_otp('00000000') -- Setting OTP to default 00 00 00 00 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 write_version('0004030101000e03') -- UL-EV1 (128) 00 04 03 01 01 00 0e 03
elseif tagtype == 12 then elseif tagtype == 12 then
print('Setting: Ultimate Magic card to NTAG 210') print('Setting: Ultimate Magic card to NTAG 210')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG210 default CC block456 -- Setting NTAG210 default CC block456
send('a203e1100600') send('a203e1100600')
send('a2040300fe00') send('a2040300fe00')
@ -703,13 +703,13 @@ local function set_type(tagtype)
-- Setting cfg1/cfg2 -- Setting cfg1/cfg2
send('a210000000FF') send('a210000000FF')
send('a21100050000') send('a21100050000')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_version('0004040101000b03') -- NTAG210 00 04 04 01 01 00 0b 03 write_version('0004040101000b03') -- NTAG210 00 04 04 01 01 00 0b 03
elseif tagtype == 13 then elseif tagtype == 13 then
print('Setting: Ultimate Magic card to NTAG 212') print('Setting: Ultimate Magic card to NTAG 212')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG212 default CC block456 -- Setting NTAG212 default CC block456
send('a203e1101000') send('a203e1101000')
send('a2040103900a') send('a2040103900a')
@ -717,13 +717,13 @@ local function set_type(tagtype)
-- Setting cfg1/cfg2 -- Setting cfg1/cfg2
send('a225000000FF') send('a225000000FF')
send('a22600050000') send('a22600050000')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_version('0004040101000E03') -- NTAG212 00 04 04 01 01 00 0E 03 write_version('0004040101000E03') -- NTAG212 00 04 04 01 01 00 0E 03
elseif tagtype == 14 then elseif tagtype == 14 then
print('Setting: Ultimate Magic card to NTAG 213') print('Setting: Ultimate Magic card to NTAG 213')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG213 default CC block456 -- Setting NTAG213 default CC block456
send('a203e1101200') send('a203e1101200')
send('a2040103a00c') send('a2040103a00c')
@ -731,13 +731,13 @@ local function set_type(tagtype)
-- setting cfg1/cfg2 -- setting cfg1/cfg2
send('a229000000ff') send('a229000000ff')
send('a22a00050000') send('a22a00050000')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_version('0004040201000F03') -- NTAG213 00 04 04 02 01 00 0f 03 write_version('0004040201000F03') -- NTAG213 00 04 04 02 01 00 0f 03
elseif tagtype == 15 then elseif tagtype == 15 then
print('Setting: Ultimate Magic card to NTAG 215') print('Setting: Ultimate Magic card to NTAG 215')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG215 default CC block456 -- Setting NTAG215 default CC block456
send('a203e1103e00') send('a203e1103e00')
send('a2040300fe00') send('a2040300fe00')
@ -745,13 +745,13 @@ local function set_type(tagtype)
-- setting cfg1/cfg2 -- setting cfg1/cfg2
send('a283000000ff') send('a283000000ff')
send('a28400050000') send('a28400050000')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_version('0004040201001103') -- NTAG215 00 04 04 02 01 00 11 03 write_version('0004040201001103') -- NTAG215 00 04 04 02 01 00 11 03
elseif tagtype == 16 then elseif tagtype == 16 then
print('Setting: Ultimate Magic card to NTAG 216') print('Setting: Ultimate Magic card to NTAG 216')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG216 default CC block456 -- Setting NTAG216 default CC block456
send('a203e1106d00') send('a203e1106d00')
send('a2040300fe00') send('a2040300fe00')
@ -759,56 +759,56 @@ local function set_type(tagtype)
-- setting cfg1/cfg2 -- setting cfg1/cfg2
send('a2e3000000ff') send('a2e3000000ff')
send('a2e400050000') send('a2e400050000')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_version('0004040201001303') -- NTAG216 00 04 04 02 01 00 13 03 write_version('0004040201001303') -- NTAG216 00 04 04 02 01 00 13 03
elseif tagtype == 17 then elseif tagtype == 17 then
print('Setting: Ultimate Magic card to NTAG I2C 1K') print('Setting: Ultimate Magic card to NTAG I2C 1K')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG I2C 1K default CC block456 -- Setting NTAG I2C 1K default CC block456
send('a203e1106D00') send('a203e1106D00')
send('a2040300fe00') send('a2040300fe00')
send('a20500000000') send('a20500000000')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_version('0004040502011303') -- NTAG_I2C_1K 00 04 04 05 02 01 13 03 write_version('0004040502011303') -- NTAG_I2C_1K 00 04 04 05 02 01 13 03
elseif tagtype == 18 then elseif tagtype == 18 then
print('Setting: Ultimate Magic card to NTAG I2C 2K') print('Setting: Ultimate Magic card to NTAG I2C 2K')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG I2C 2K default CC block456 -- Setting NTAG I2C 2K default CC block456
send('a203e110EA00') send('a203e110EA00')
send('a2040300fe00') send('a2040300fe00')
send('a20500000000') send('a20500000000')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_version('0004040502011503') -- NTAG_I2C_2K 00 04 04 05 02 01 15 03 write_version('0004040502011503') -- NTAG_I2C_2K 00 04 04 05 02 01 15 03
elseif tagtype == 19 then elseif tagtype == 19 then
print('Setting: Ultimate Magic card to NTAG I2C plus 1K') print('Setting: Ultimate Magic card to NTAG I2C plus 1K')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG I2C 1K default CC block456 -- Setting NTAG I2C 1K default CC block456
send('a203e1106D00') send('a203e1106D00')
send('a2040300fe00') send('a2040300fe00')
send('a20500000000') send('a20500000000')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_version('0004040502021303') -- NTAG_I2C_1K 00 04 04 05 02 02 13 03 write_version('0004040502021303') -- NTAG_I2C_1K 00 04 04 05 02 02 13 03
elseif tagtype == 20 then elseif tagtype == 20 then
print('Setting: Ultimate Magic card to NTAG I2C plus 2K') print('Setting: Ultimate Magic card to NTAG I2C plus 2K')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG I2C 2K default CC block456 -- Setting NTAG I2C 2K default CC block456
send('a203e1106D00') send('a203e1106D00')
send('a2040300fe00') send('a2040300fe00')
send('a20500000000') send('a20500000000')
write_uid('04112233445566') write_uid('04112233445566')
write_version('0004040502021503') -- NTAG_I2C_2K 00 04 04 05 02 02 15 03 write_version('0004040502021503') -- NTAG_I2C_2K 00 04 04 05 02 02 15 03
elseif tagtype == 21 then elseif tagtype == 21 then
print('Setting: Ultimate Magic card to NTAG 213F') print('Setting: Ultimate Magic card to NTAG 213F')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG213 default CC block456 -- Setting NTAG213 default CC block456
send('a203e1101200') send('a203e1101200')
send('a2040103a00c') send('a2040103a00c')
@ -816,13 +816,13 @@ local function set_type(tagtype)
-- setting cfg1/cfg2 -- setting cfg1/cfg2
send('a229000000ff') send('a229000000ff')
send('a22a00050000') send('a22a00050000')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_version('0004040401000F03') -- NTAG213F 00 04 04 04 01 00 0f 03 write_version('0004040401000F03') -- NTAG213F 00 04 04 04 01 00 0f 03
elseif tagtype == 22 then elseif tagtype == 22 then
print('Setting: Ultimate Magic card to NTAG 216F') print('Setting: Ultimate Magic card to NTAG 216F')
connect() connect()
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
-- Setting NTAG216 default CC block456 -- Setting NTAG216 default CC block456
send('a203e1106d00') send('a203e1106d00')
send('a2040300fe00') send('a2040300fe00')
@ -830,11 +830,11 @@ local function set_type(tagtype)
-- setting cfg1/cfg2 -- setting cfg1/cfg2
send('a2e3000000ff') send('a2e3000000ff')
send('a2e400050000') send('a2e400050000')
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_version('0004040401001303') -- NTAG216F 00 04 04 04 01 00 13 03 write_version('0004040401001303') -- NTAG216F 00 04 04 04 01 00 13 03
else else
oops('No matching tag types') oops('No matching tag types')
end end
lib14a.disconnect() lib14a.disconnect()
if resp == '04' then if resp == '04' then

View file

@ -105,7 +105,7 @@ local function main(args)
-- chomp emu header -- chomp emu header
if #hex == 1192 then if #hex == 1192 then
hex = hex:sub(112) hex = hex:sub(113)
end end
local amiibo_offset = 0 local amiibo_offset = 0

View file

@ -139,14 +139,10 @@ local function main(args)
-- force lock bytes, otherwise the Amiibo won't be recognized -- force lock bytes, otherwise the Amiibo won't be recognized
blocks[16] = blocks[16]:sub(1, 4)..'0FE0' blocks[16] = blocks[16]:sub(1, 4)..'0FE0'
-- add PWD and PACK if necessary -- add PWD and PACK
local uid = blocks[14]:sub(1, 6)..blocks[15]:sub(1, 8) local uid = blocks[14]:sub(1, 6)..blocks[15]:sub(1, 8)
if blocks[147] == nil or blocks[147] == '00000000' then blocks[147] = ("%08x"):format(bxor(bxor(tonumber(sub(uid, 2, 10), 16), tonumber(sub(uid, 6, 14), 16)), 0xaa55aa55))
blocks[147] = ("%08x"):format(bxor(bxor(tonumber(sub(uid, 2, 10), 16), tonumber(sub(uid, 6, 14), 16)), 0xaa55aa55)) blocks[148] = "80800000"
end
if blocks[148] == nil or blocks[148] == '00000000' then
blocks[148] = "80800000"
end
err = LoadEmulator(uid, blocks) err = LoadEmulator(uid, blocks)
if err then return oops(err) end if err then return oops(err) end

View file

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

View file

@ -6,7 +6,7 @@ local ac = require('ansicolors')
copyright = '' copyright = ''
author = "Christian Herrmann" author = "Christian Herrmann"
version = 'v1.0.0' version = 'v1.0.1'
desc = [[ desc = [[
This script loads a json format file, with the field "data" and a hexbyte array of data. Ie t55x7 dump, 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. 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 script run lf_ident_json -i lf_t55xx.json
]] ]]
usage = [[ 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 = [[ arguments = [[
-h : this help -h : this help

View file

@ -17,17 +17,17 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cipursecore.h" #include "cipursecore.h"
#include <string.h> // memcpy memset #include <string.h> // memcpy memset
#include "commonutil.h" // ARRAYLEN
#include "commonutil.h" // ARRAYLEN #include "comms.h" // DropField
#include "comms.h" // DropField #include "util_posix.h" // msleep
#include "util_posix.h" // msleep
#include "cmdhf14a.h" #include "cmdhf14a.h"
#include "../emv/emvcore.h" #include "../emv/emvcore.h"
#include "../emv/emvjson.h" #include "../emv/emvjson.h"
#include "../iso7816/apduinfo.h" // sAPDU_t #include "../iso7816/apduinfo.h" // sAPDU_t
#include "ui.h" #include "ui.h"
#include "util.h" #include "util.h"
#include "protocols.h" // ISO7816 APDU return codes
// context for secure channel // context for secure channel
CipurseContext_t cipurseContext; CipurseContext_t cipurseContext;
@ -112,7 +112,7 @@ static int CIPURSEExchangeEx(bool activate_field, bool leave_field_on, sAPDU_t a
*sw = isw; *sw = isw;
} }
if (isw != 0x9000) { if (isw != ISO7816_OK) {
if (GetAPDULogging()) { if (GetAPDULogging()) {
if (*sw >> 8 == 0x61) { if (*sw >> 8 == 0x61) {
PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff); PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff);
@ -255,7 +255,7 @@ bool CIPURSEChannelAuthenticate(uint8_t keyindex, uint8_t *key, bool verbose) {
// authenticate // authenticate
res = CIPURSEMutualAuthenticate(keyindex, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw); 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 (sw == 0x6988) {
if (verbose) { if (verbose) {
PrintAndLogEx(WARNING, "Authentication ( " _RED_("fail") " ). Wrong key"); PrintAndLogEx(WARNING, "Authentication ( " _RED_("fail") " ). Wrong key");

View file

@ -1230,7 +1230,7 @@ int FSKrawDemod(uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow, bo
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _YELLOW_("%s") " decoded bitstream", GetFSKType(fchigh, fclow, invert)); PrintAndLogEx(SUCCESS, _YELLOW_("%s") " decoded bitstream", GetFSKType(fchigh, fclow, invert));
PrintAndLogEx(INFO, "-----------------------"); PrintAndLogEx(INFO, "-----------------------");
printDemodBuff(0, false, invert, false); printDemodBuff(0, false, false, false);
} }
goto out; goto out;
} else { } else {

View file

@ -50,6 +50,7 @@
#include "cmdhftexkom.h" // Texkom #include "cmdhftexkom.h" // Texkom
#include "cmdhfxerox.h" // Xerox #include "cmdhfxerox.h" // Xerox
#include "cmdhffudan.h" // Fudan cards #include "cmdhffudan.h" // Fudan cards
#include "cmdhftesla.h" // Tesla
#include "cmdtrace.h" // trace list #include "cmdtrace.h" // trace list
#include "ui.h" #include "ui.h"
#include "proxgui.h" #include "proxgui.h"
@ -123,7 +124,7 @@ int CmdHFSearch(const char *Cmd) {
PROMPT_CLEARLINE; PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, " Searching for iCLASS / PicoPass tag..."); PrintAndLogEx(INPLACE, " Searching for iCLASS / PicoPass tag...");
if (IfPm3Iclass()) { if (IfPm3Iclass()) {
if (read_iclass_csn(false, false) == PM3_SUCCESS) { if (read_iclass_csn(false, false, false) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("iCLASS tag / PicoPass tag") " found\n"); PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("iCLASS tag / PicoPass tag") " found\n");
res = PM3_SUCCESS; res = PM3_SUCCESS;
} }
@ -493,9 +494,10 @@ static command_t CommandTable[] = {
{"ntag424", CmdHF_ntag424, AlwaysAvailable, "{ NXP NTAG 4242 DNA RFIDs... }"}, {"ntag424", CmdHF_ntag424, AlwaysAvailable, "{ NXP NTAG 4242 DNA RFIDs... }"},
{"seos", CmdHFSeos, AlwaysAvailable, "{ SEOS RFIDs... }"}, {"seos", CmdHFSeos, AlwaysAvailable, "{ SEOS RFIDs... }"},
{"st25ta", CmdHFST25TA, AlwaysAvailable, "{ ST25TA RFIDs... }"}, {"st25ta", CmdHFST25TA, AlwaysAvailable, "{ ST25TA RFIDs... }"},
{"tesla", CmdHFTESLA, AlwaysAvailable, "{ TESLA Cards... }"},
{"texkom", CmdHFTexkom, AlwaysAvailable, "{ Texkom RFIDs... }"},
{"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"}, {"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"}, {"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
{"texkom", CmdHFTexkom, AlwaysAvailable, "{ Texkom RFIDs... }"},
{"xerox", CmdHFXerox, AlwaysAvailable, "{ Fuji/Xerox cartridge RFIDs... }"}, {"xerox", CmdHFXerox, AlwaysAvailable, "{ Fuji/Xerox cartridge RFIDs... }"},
{"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"}, {"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"},
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"},

View file

@ -42,7 +42,13 @@
#include "desfire.h" // desfire enums #include "desfire.h" // desfire enums
#include "mifare/desfirecore.h" // desfire context #include "mifare/desfirecore.h" // desfire context
static bool APDUInFramingEnable = true; static bool g_apdu_in_framing_enable = true;
bool Get_apdu_in_framing(void) {
return g_apdu_in_framing_enable;
}
void Set_apdu_in_framing(bool v) {
g_apdu_in_framing_enable = v;
}
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static int waitCmd(bool i_select, uint32_t timeout, bool verbose); static int waitCmd(bool i_select, uint32_t timeout, bool verbose);
@ -1050,7 +1056,7 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
int res; int res;
// 3 byte here - 1b framing header, 2b crc16 // 3 byte here - 1b framing header, 2b crc16
if (APDUInFramingEnable && if (g_apdu_in_framing_enable &&
((gs_frame_len && (datainlen > gs_frame_len - 3)) || (datainlen > PM3_CMD_DATA_SIZE - 3))) { ((gs_frame_len && (datainlen > gs_frame_len - 3)) || (datainlen > PM3_CMD_DATA_SIZE - 3))) {
int clen = 0; int clen = 0;
@ -1454,29 +1460,34 @@ static int CmdHF14AChaining(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf 14a chaining", CLIParserInit(&ctx, "hf 14a chaining",
"Enable/Disable ISO14443a input chaining. Maximum input length goes from ATS.", "Enable/Disable ISO14443a input chaining. Maximum input length goes from ATS.",
"hf 14a chaining disable -> disable chaining\n" "hf 14a chaining --off -> disable chaining\n"
"hf 14a chaining -> show chaining enable/disable state\n"); "hf 14a chaining -> show chaining enable/disable state\n");
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0(NULL, NULL, "<enable/disable or 0/1>", NULL), arg_lit0("1", "on", "enabled chaining"),
arg_lit0("0", "off", "disable chaining"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
struct arg_str *str = arg_get_str(ctx, 1); bool on = arg_get_lit(ctx, 1);
int len = arg_get_str_len(ctx, 1); bool off = arg_get_lit(ctx, 2);
if (len && (!strcmp(str->sval[0], "enable") || !strcmp(str->sval[0], "1"))) if ((on + off) > 1) {
APDUInFramingEnable = true; PrintAndLogEx(INFO, "Select only one option");
return PM3_EINVARG;
}
if (len && (!strcmp(str->sval[0], "disable") || !strcmp(str->sval[0], "0"))) if (on)
APDUInFramingEnable = false; Set_apdu_in_framing(true);
if (off)
Set_apdu_in_framing(false);
CLIParserFree(ctx); CLIParserFree(ctx);
PrintAndLogEx(INFO, "\nISO 14443-4 input chaining %s.\n", APDUInFramingEnable ? "enabled" : "disabled"); PrintAndLogEx(INFO, "\nISO 14443-4 input chaining %s.\n", g_apdu_in_framing_enable ? "enabled" : "disabled");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -2242,8 +2253,8 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} }
} }
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) { if (sw == ISO7816_OK || sw == ISO7816_INVALID_DF || sw == ISO7816_FILE_TERMINATED) {
if (sw == 0x9000) { if (sw == ISO7816_OK) {
if (verbose) PrintAndLogEx(SUCCESS, "Application ( " _GREEN_("ok") " )"); if (verbose) PrintAndLogEx(SUCCESS, "Application ( " _GREEN_("ok") " )");
} else { } else {
if (verbose) PrintAndLogEx(WARNING, "Application ( " _RED_("blocked") " )"); if (verbose) PrintAndLogEx(WARNING, "Application ( " _RED_("blocked") " )");
@ -2380,14 +2391,14 @@ int infoHF14A4Applications(bool verbose) {
if (res) if (res)
break; break;
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) { if (sw == ISO7816_OK || sw == ISO7816_INVALID_DF || sw == ISO7816_FILE_TERMINATED) {
if (!found) { if (!found) {
if (verbose) if (verbose)
PrintAndLogEx(INFO, "----------------- " _CYAN_("Short AID search") " -----------------"); PrintAndLogEx(INFO, "----------------- " _CYAN_("Short AID search") " -----------------");
} }
found++; found++;
if (sw == 0x9000) { if (sw == ISO7816_OK) {
if (verbose) if (verbose)
PrintAndLogEx(SUCCESS, "Application " _CYAN_("%s") " ( " _GREEN_("ok") " )", hintAIDList[i].desc); PrintAndLogEx(SUCCESS, "Application " _CYAN_("%s") " ( " _GREEN_("ok") " )", hintAIDList[i].desc);
cardFound[i] = true; cardFound[i] = true;
@ -2574,7 +2585,7 @@ retry_ins:
// Show response. // Show response.
if (sw_occurrences < error_limit) { if (sw_occurrences < error_limit) {
logLevel_t log_level = INFO; logLevel_t log_level = INFO;
if (sw == 0x9000) { if (sw == ISO7816_OK) {
log_level = SUCCESS; log_level = SUCCESS;
} }
@ -2674,7 +2685,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
} }
uint16_t sw = get_sw(response, resplen); uint16_t sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
// Try NDEF Type 4 Tag v1.0 // Try NDEF Type 4 Tag v1.0
param_gethex_to_eol("00a4040007d2760000850100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); param_gethex_to_eol("00a4040007d2760000850100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
@ -2688,7 +2699,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -2714,7 +2725,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -2729,7 +2740,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
return res; return res;
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -2763,7 +2774,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -2780,7 +2791,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -2819,7 +2830,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
free(ndef_file); free(ndef_file);
@ -2887,7 +2898,7 @@ int CmdHF14ANdefFormat(const char *Cmd) {
bool have_application = true; bool have_application = true;
uint16_t sw = get_sw(response, resplen); uint16_t sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
have_application = false; have_application = false;
PrintAndLogEx(INFO, "no NDEF application found"); PrintAndLogEx(INFO, "no NDEF application found");
} else { } else {

View file

@ -53,4 +53,7 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode); int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode);
int SelectCard14443A_4(bool disconnect, bool verbose, iso14a_card_select_t *card); int SelectCard14443A_4(bool disconnect, bool verbose, iso14a_card_select_t *card);
bool Get_apdu_in_framing(void);
void Set_apdu_in_framing(bool v);
#endif #endif

View file

@ -126,8 +126,8 @@ static void hf14b_aid_search(bool verbose) {
} }
} }
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) { if (sw == ISO7816_OK || sw == ISO7816_INVALID_DF || sw == ISO7816_FILE_TERMINATED) {
if (sw == 0x9000) { if (sw == ISO7816_OK) {
if (verbose) PrintAndLogEx(SUCCESS, "Application ( " _GREEN_("ok") " )"); if (verbose) PrintAndLogEx(SUCCESS, "Application ( " _GREEN_("ok") " )");
} else { } else {
if (verbose) PrintAndLogEx(WARNING, "Application ( " _RED_("blocked") " )"); if (verbose) PrintAndLogEx(WARNING, "Application ( " _RED_("blocked") " )");
@ -2035,7 +2035,7 @@ int CmdHF14BNdefRead(const char *Cmd) {
} }
uint16_t sw = get_sw(response, resplen); uint16_t sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
res = PM3_ESOFT; res = PM3_ESOFT;
goto out; goto out;
@ -2055,7 +2055,7 @@ int CmdHF14BNdefRead(const char *Cmd) {
goto out; goto out;
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
res = PM3_ESOFT; res = PM3_ESOFT;
goto out; goto out;
@ -2071,7 +2071,7 @@ int CmdHF14BNdefRead(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
res = PM3_ESOFT; res = PM3_ESOFT;
goto out; goto out;
@ -2090,7 +2090,7 @@ int CmdHF14BNdefRead(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
res = PM3_ESOFT; res = PM3_ESOFT;
goto out; goto out;

View file

@ -67,7 +67,7 @@ typedef struct {
// structure and database for uid -> tagtype lookups // structure and database for uid -> tagtype lookups
typedef struct { typedef struct {
uint64_t uid; uint64_t uid;
int mask; // how many MSB bits used uint64_t mask; // how many MSB bits used, or mask itself if larger than 64
const char *desc; const char *desc;
} productName_t; } productName_t;
@ -90,17 +90,23 @@ static const productName_t uidmapping[] = {
// E0 04 xx // E0 04 xx
// 04 = Manufacturer code (Philips/NXP) // 04 = Manufacturer code (Philips/NXP)
// XX = IC id (Chip ID Family) // XX = IC id (Chip ID Family)
//I-Code SLI SL2 ICS20 [IC id = 01] //I-Code SLI SL2 ICS20 [IC id = 01 + bit35 set to 0 + bit36 set to 0]
//I-Code SLI-S [IC id = 02] //I-Code SLIX [IC id = 01 + bit35 set to 0 + bit36 set to 1]
//I-Code SLI-L [IC id = 03]
//I-Code SLIX [IC id = 01 + bit36 set to 1 (starting from bit0 - different from normal SLI)]
//I-Code SLIX2 [IC id = 01 + bit35 set to 1 + bit36 set to 0] //I-Code SLIX2 [IC id = 01 + bit35 set to 1 + bit36 set to 0]
//I-Code SLI-S [IC id = 02 + bit36 set to 0]
//I-Code SLIX-S [IC id = 02 + bit36 set to 1] //I-Code SLIX-S [IC id = 02 + bit36 set to 1]
//I-Code SLI-L [IC id = 03 + bit36 set to 0]
//I-Code SLIX-L [IC id = 03 + bit36 set to 1] //I-Code SLIX-L [IC id = 03 + bit36 set to 1]
{ 0xE004000000000000LL, 16, "NXP Semiconductors Germany (Philips)" }, { 0xE004000000000000LL, 16, "NXP Semiconductors Germany (Philips)" },
{ 0xE004010000000000LL, 24, "NXP(Philips); IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX) ICS2602(SLIX2)" }, { 0xE004010000000000LL, 24, "NXP(Philips); IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX) ICS2602(SLIX2)" },
{ 0xE004020000000000LL, 24, "NXP(Philips); IC SL2 ICS53/ICS54(SLI-S) ICS5302/ICS5402(SLIX-S)" }, { 0xE004011800000000LL, 0xFFFFFF1800000000LL, "NXP(Philips); IC NTP53x2/NTP5210/NTA5332(NTAG 5)" },
{ 0xE004030000000000LL, 24, "NXP(Philips); IC SL2 ICS50/ICS51(SLI-L) ICS5002/ICS5102(SLIX-L)" }, { 0xE004010000000000LL, 0xFFFFFF1800000000LL, "NXP(Philips); IC SL2 ICS20/ICS21(SLI)" },
{ 0xE004011000000000LL, 0xFFFFFF1800000000LL, "NXP(Philips); IC SL2 ICS2002/ICS2102(SLIX)" },
{ 0xE004010800000000LL, 0xFFFFFF1800000000LL, "NXP(Philips); IC SL2 ICS2602(SLIX2)" },
{ 0xE004020000000000LL, 0xFFFFFF1000000000LL, "NXP(Philips); IC SL2 ICS53/ICS54(SLI-S)" },
{ 0xE004021000000000LL, 0xFFFFFF1000000000LL, "NXP(Philips); ICS5302/ICS5402(SLIX-S)" },
{ 0xE004030000000000LL, 0xFFFFFF1000000000LL, "NXP(Philips); IC SL2 ICS50/ICS51(SLI-L)" },
{ 0xE004031000000000LL, 0xFFFFFF1000000000LL, "NXP(Philips); ICS5002/ICS5102(SLIX-L)" },
// E0 05 XX .. .. .. // E0 05 XX .. .. ..
// 05 = Manufacturer code (Infineon) // 05 = Manufacturer code (Infineon)
@ -364,7 +370,11 @@ static const char *getTagInfo_15(uint8_t *uid) {
int i = 0, best = -1; int i = 0, best = -1;
memcpy(&myuid, uid, sizeof(uint64_t)); memcpy(&myuid, uid, sizeof(uint64_t));
while (uidmapping[i].mask > 0) { while (uidmapping[i].mask > 0) {
mask = (~0ULL) << (64 - uidmapping[i].mask); if (uidmapping[i].mask > 64) {
mask = uidmapping[i].mask;
} else {
mask = (~0ULL) << (64 - uidmapping[i].mask);
}
if ((myuid & mask) == uidmapping[i].uid) { if ((myuid & mask) == uidmapping[i].uid) {
if (best == -1) { if (best == -1) {
best = i; best = i;
@ -642,6 +652,94 @@ static int CmdHF15Samples(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int NxpTestEAS(uint8_t *uid) {
uint8_t fast = 1;
uint8_t reply = 1;
PacketResponseNG resp;
uint16_t reqlen = 0;
uint8_t req[PM3_CMD_DATA_SIZE] = {0};
req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
req[reqlen++] = ISO15693_EAS_ALARM;
req[reqlen++] = 0x04; // IC manufacturer code
memcpy(req + 3, uid, 8); // add UID
reqlen += 8;
AddCrc15(req, reqlen);
reqlen += 2;
clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, reply, req, reqlen);
if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "iso15693 timeout");
} else {
PrintAndLogEx(NORMAL, "");
if (resp.length < 2) {
PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is not active");
} else {
uint8_t *recv = resp.data.asBytes;
if (!(recv[0] & ISO15_RES_ERROR)) {
PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is active.");
PrintAndLogEx(INFO, " EAS sequence: %s", sprint_hex(recv + 1, 32));
}
}
}
return PM3_SUCCESS;
}
static int NxpCheckSig(uint8_t *uid) {
uint8_t fast = 1;
uint8_t reply = 1;
PacketResponseNG resp;
uint16_t reqlen = 0;
uint8_t req[PM3_CMD_DATA_SIZE] = {0};
// Check if we can also read the signature
req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
req[reqlen++] = ISO15693_READ_SIGNATURE;
req[reqlen++] = 0x04; // IC manufacturer code
memcpy(req + 3, uid, 8); // add UID
reqlen += 8;
AddCrc15(req, reqlen);
reqlen += 2;
clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, reply, req, reqlen);
if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "iso15693 timeout");
DropField();
return PM3_ETIMEOUT;
}
DropField();
if (resp.length < 2) {
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to READ SIGNATURE command");
return PM3_EWRONGANSWER;
}
uint8_t *recv = resp.data.asBytes;
if ((recv[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
return PM3_EWRONGANSWER;
}
uint8_t signature[32] = {0x00};
memcpy(signature, recv + 1, 32);
nxp_15693_print_signature(uid, signature);
return PM3_SUCCESS;
}
// Get NXP system information from SLIX2 tag/VICC // Get NXP system information from SLIX2 tag/VICC
static int NxpSysInfo(uint8_t *uid) { static int NxpSysInfo(uint8_t *uid) {
@ -723,77 +821,11 @@ static int NxpSysInfo(uint8_t *uid) {
PrintAndLogEx(INFO, " * Additional 32 bits feature flags are%s transmitted", ((recv[5] & 0x80) ? "" : " not")); PrintAndLogEx(INFO, " * Additional 32 bits feature flags are%s transmitted", ((recv[5] & 0x80) ? "" : " not"));
if (support_easmode) { if (support_easmode) {
reqlen = 0; NxpTestEAS(uid);
req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
req[reqlen++] = ISO15693_EAS_ALARM;
req[reqlen++] = 0x04; // IC manufacturer code
memcpy(req + 3, uid, 8); // add UID
reqlen += 8;
AddCrc15(req, reqlen);
reqlen += 2;
clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, reply, req, reqlen);
if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "iso15693 timeout");
} else {
PrintAndLogEx(NORMAL, "");
if (resp.length < 2) {
PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is not active");
} else {
recv = resp.data.asBytes;
if (!(recv[0] & ISO15_RES_ERROR)) {
PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is active.");
PrintAndLogEx(INFO, " EAS sequence: %s", sprint_hex(recv + 1, 32));
}
}
}
} }
if (support_signature) { if (support_signature) {
// Check if we can also read the signature NxpCheckSig(uid);
reqlen = 0;
req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
req[reqlen++] = ISO15693_READ_SIGNATURE;
req[reqlen++] = 0x04; // IC manufacturer code
memcpy(req + 3, uid, 8); // add UID
reqlen += 8;
AddCrc15(req, reqlen);
reqlen += 2;
clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, reply, req, reqlen);
if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "iso15693 timeout");
DropField();
return PM3_ETIMEOUT;
}
DropField();
if (resp.length < 2) {
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to READ SIGNATURE command");
return PM3_EWRONGANSWER;
}
recv = resp.data.asBytes;
if ((recv[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
return PM3_EWRONGANSWER;
}
uint8_t signature[32] = {0x00};
memcpy(signature, recv + 1, 32);
nxp_15693_print_signature(uid, signature);
} }
return PM3_SUCCESS; return PM3_SUCCESS;
@ -935,6 +967,12 @@ static int CmdHF15Info(const char *Cmd) {
if (data[8] == 0x04 && data[7] == 0x01 && nxp_version == 0x08) { if (data[8] == 0x04 && data[7] == 0x01 && nxp_version == 0x08) {
PrintAndLogEx(DEBUG, "SLIX2 Detected, getting NXP System Info"); PrintAndLogEx(DEBUG, "SLIX2 Detected, getting NXP System Info");
return NxpSysInfo(uid); return NxpSysInfo(uid);
} else if (data[8] == 0x04 && data[7] == 0x01 && nxp_version == 0x18) { //If it is an NTAG 5
PrintAndLogEx(DEBUG, "NTAG 5 Detected, getting NXP System Info");
return NxpSysInfo(uid);
} else if (data[8] == 0x04 && (data[7] == 0x01 || data[7] == 0x02 || data[7] == 0x03)) { //If SLI, SLIX, SLIX-l, or SLIX-S check EAS status
PrintAndLogEx(DEBUG, "SLI, SLIX, SLIX-L, or SLIX-S Detected checking EAS status");
return NxpTestEAS(uid);
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
@ -1375,11 +1413,11 @@ static int CmdHF15WriteAfi(const char *Cmd) {
// arg0 (datalen, cmd len? .arg0 == crc?) // arg0 (datalen, cmd len? .arg0 == crc?)
// arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 ) // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 )
// arg2 (recv == 1 == expect a response) // arg2 (recv == 1 == expect a response)
uint8_t read_respone = 1; uint8_t read_response = 1;
PacketResponseNG resp; PacketResponseNG resp;
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_respone, req, reqlen); SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_response, req, reqlen);
if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) { if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) {
PrintAndLogEx(ERR, "iso15693 timeout"); PrintAndLogEx(ERR, "iso15693 timeout");

View file

@ -40,6 +40,7 @@
#include "util.h" #include "util.h"
#include "fileutils.h" // laodFileJSONroot #include "fileutils.h" // laodFileJSONroot
#include "crypto/libpcrypto.h" #include "crypto/libpcrypto.h"
#include "protocols.h" // ISO7816 APDU return codes
const uint8_t PxSE_AID[] = {0xA0, 0x00, 0x00, 0x05, 0x07, 0x01, 0x00}; const uint8_t PxSE_AID[] = {0xA0, 0x00, 0x00, 0x05, 0x07, 0x01, 0x00};
#define PxSE_AID_LENGTH 7 #define PxSE_AID_LENGTH 7
@ -104,11 +105,11 @@ static int SelectAndPrintInfoFile(void) {
uint16_t sw = 0; uint16_t sw = 0;
int res = CIPURSESelectFile(0x2ff7, buf, sizeof(buf), &len, &sw); int res = CIPURSESelectFile(0x2ff7, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) if (res != 0 || sw != ISO7816_OK)
return PM3_EAPDU_FAIL; return PM3_EAPDU_FAIL;
res = CIPURSEReadBinary(0, buf, sizeof(buf), &len, &sw); res = CIPURSEReadBinary(0, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) if (res != 0 || sw != ISO7816_OK)
return PM3_EAPDU_FAIL; return PM3_EAPDU_FAIL;
if (len > 0) { if (len > 0) {
@ -151,7 +152,7 @@ static int CmdHFCipurseInfo(const char *Cmd) {
bool mfExist = false; bool mfExist = false;
bool infoPrinted = false; bool infoPrinted = false;
int res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw); int res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
if (res == PM3_SUCCESS && sw == 0x9000) { if (res == PM3_SUCCESS && sw == ISO7816_OK) {
mfExist = true; mfExist = true;
PrintAndLogEx(INFO, _YELLOW_("MasterFile") " exist and can be selected."); PrintAndLogEx(INFO, _YELLOW_("MasterFile") " exist and can be selected.");
@ -161,7 +162,7 @@ static int CmdHFCipurseInfo(const char *Cmd) {
for (int i = 0; i < ARRAYLEN(PxSE_AID_LIST); i++) { for (int i = 0; i < ARRAYLEN(PxSE_AID_LIST); i++) {
res = CIPURSESelectAID(false, true, (uint8_t *)PxSE_AID_LIST[i].aid, PxSE_AID_LENGTH, buf, sizeof(buf), &len, &sw); res = CIPURSESelectAID(false, true, (uint8_t *)PxSE_AID_LIST[i].aid, PxSE_AID_LENGTH, buf, sizeof(buf), &len, &sw);
if (res == PM3_SUCCESS && sw == 0x9000) { if (res == PM3_SUCCESS && sw == ISO7816_OK) {
mfExist = true; mfExist = true;
PrintAndLogEx(INFO, _CYAN_("PxSE") " exist: %s", PxSE_AID_LIST[i].name); PrintAndLogEx(INFO, _CYAN_("PxSE") " exist: %s", PxSE_AID_LIST[i].name);
if (len > 0) { if (len > 0) {
@ -179,7 +180,7 @@ static int CmdHFCipurseInfo(const char *Cmd) {
} }
PrintAndLogEx(INFO, "Application `" _YELLOW_("AF F1") "` selected " _GREEN_("successfully")); PrintAndLogEx(INFO, "Application `" _YELLOW_("AF F1") "` selected " _GREEN_("successfully"));
if (sw != 0x9000) { if (sw != ISO7816_OK) {
if (sw == 0x0000) { if (sw == 0x0000) {
PrintAndLogEx(ERR, "APDU exchange error. Card returns 0x0000"); PrintAndLogEx(ERR, "APDU exchange error. Card returns 0x0000");
} else { } else {
@ -362,7 +363,7 @@ static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, si
if (useAID && aidLen > 0) { if (useAID && aidLen > 0) {
res = CIPURSESelectAID(true, true, aid, aidLen, buf, bufSize, len, sw); res = CIPURSESelectAID(true, true, aid, aidLen, buf, bufSize, len, sw);
if (res != 0 || *sw != 0x9000) { if (res != 0 || *sw != ISO7816_OK) {
if (verbose) { if (verbose) {
PrintAndLogEx(ERR, "Cipurse select application " _GREEN_("%s ") _RED_("error") ". Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), *sw); PrintAndLogEx(ERR, "Cipurse select application " _GREEN_("%s ") _RED_("error") ". Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), *sw);
} }
@ -375,7 +376,7 @@ static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, si
} else if (useFID) { } else if (useFID) {
res = CIPURSESelectFileEx(true, true, fileId, buf, bufSize, len, sw); res = CIPURSESelectFileEx(true, true, fileId, buf, bufSize, len, sw);
if (res != 0 || *sw != 0x9000) { if (res != 0 || *sw != ISO7816_OK) {
if (verbose) { if (verbose) {
PrintAndLogEx(ERR, "Cipurse select file 0x%04x ( %s )", fileId, _RED_("fail")); PrintAndLogEx(ERR, "Cipurse select file 0x%04x ( %s )", fileId, _RED_("fail"));
PrintAndLogEx(ERR, "Card returns 0x%04x", *sw); PrintAndLogEx(ERR, "Card returns 0x%04x", *sw);
@ -389,7 +390,7 @@ static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, si
} else if (selectDefaultFile) { } else if (selectDefaultFile) {
res = CIPURSESelectMFDefaultFileEx(true, true, buf, bufSize, len, sw); res = CIPURSESelectMFDefaultFileEx(true, true, buf, bufSize, len, sw);
if (res != 0 || *sw != 0x9000) { if (res != 0 || *sw != ISO7816_OK) {
if (verbose) { if (verbose) {
PrintAndLogEx(ERR, "Cipurse select default file " _RED_("error") ". Card returns 0x%04x", *sw); PrintAndLogEx(ERR, "Cipurse select default file " _RED_("error") ". Card returns 0x%04x", *sw);
} }
@ -402,7 +403,7 @@ static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, si
} else { } else {
res = CIPURSESelect(true, true, buf, bufSize, len, sw); res = CIPURSESelect(true, true, buf, bufSize, len, sw);
if (res != 0 || *sw != 0x9000) { if (res != 0 || *sw != ISO7816_OK) {
if (verbose) { if (verbose) {
PrintAndLogEx(ERR, "Cipurse select default application " _RED_("error") ". Card returns 0x%04x", *sw); PrintAndLogEx(ERR, "Cipurse select default application " _RED_("error") ". Card returns 0x%04x", *sw);
} }
@ -419,7 +420,7 @@ static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, si
} }
res = CIPURSESelectFileEx(false, true, childFileId, buf, bufSize, len, sw); res = CIPURSESelectFileEx(false, true, childFileId, buf, bufSize, len, sw);
if (res != 0 || *sw != 0x9000) { if (res != 0 || *sw != ISO7816_OK) {
if (verbose) { if (verbose) {
PrintAndLogEx(ERR, "Select child file 0x%04x " _RED_("error") ". Card returns 0x%04x", childFileId, *sw); PrintAndLogEx(ERR, "Select child file 0x%04x " _RED_("error") ". Card returns 0x%04x", childFileId, *sw);
} }
@ -487,7 +488,7 @@ static int CmdHFCipurseSelect(const char *Cmd) {
size_t len = 0; size_t len = 0;
uint16_t sw = 0; uint16_t sw = 0;
res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, true, buf, sizeof(buf), &len, &sw); res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, true, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -553,7 +554,7 @@ static int CmdHFCipurseAuth(const char *Cmd) {
uint8_t buf[APDU_RES_LEN] = {0}; uint8_t buf[APDU_RES_LEN] = {0};
res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, true, buf, sizeof(buf), &len, &sw); res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, true, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -635,7 +636,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
uint8_t buf[APDU_RES_LEN] = {0}; uint8_t buf[APDU_RES_LEN] = {0};
res = CIPURSESelectAID(true, true, aid, aidLen, buf, sizeof(buf), &len, &sw); res = CIPURSESelectAID(true, true, aid, aidLen, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Cipurse select application " _CYAN_("%s") " ( " _RED_("error") " ). Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), sw); PrintAndLogEx(ERR, "Cipurse select application " _CYAN_("%s") " ( " _RED_("error") " ). Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), sw);
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -660,7 +661,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
} }
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
if (verbose == false) if (verbose == false)
PrintAndLogEx(ERR, "File select ( " _RED_("error") " ). Card returns 0x%04x", sw); PrintAndLogEx(ERR, "File select ( " _RED_("error") " ). Card returns 0x%04x", sw);
DropField(); DropField();
@ -671,7 +672,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
PrintAndLogEx(INFO, "Select file 0x%x ( %s )", fileId, _GREEN_("ok")); PrintAndLogEx(INFO, "Select file 0x%x ( %s )", fileId, _GREEN_("ok"));
res = CIPURSEReadBinary(offset, buf, sizeof(buf), &len, &sw); res = CIPURSEReadBinary(offset, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
if (verbose == false) if (verbose == false)
PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x", sw); PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x", sw);
DropField(); DropField();
@ -758,7 +759,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
uint8_t buf[APDU_RES_LEN] = {0}; uint8_t buf[APDU_RES_LEN] = {0};
res = CIPURSESelectAID(true, true, aid, aidLen, buf, sizeof(buf), &len, &sw); res = CIPURSESelectAID(true, true, aid, aidLen, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Cipurse select application " _CYAN_("%s") " ( " _RED_("error") " ). Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), sw); PrintAndLogEx(ERR, "Cipurse select application " _CYAN_("%s") " ( " _RED_("error") " ). Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), sw);
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -789,7 +790,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
} }
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
if (verbose == false) if (verbose == false)
PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw); PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw);
DropField(); DropField();
@ -800,7 +801,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
PrintAndLogEx(INFO, "Select file 0x%x ( %s )", fileId, _GREEN_("ok")); PrintAndLogEx(INFO, "Select file 0x%x ( %s )", fileId, _GREEN_("ok"));
res = CIPURSEUpdateBinary(offset, hdata, hdatalen, buf, sizeof(buf), &len, &sw); res = CIPURSEUpdateBinary(offset, hdata, hdatalen, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
if (verbose == false) if (verbose == false)
PrintAndLogEx(ERR, "File write " _RED_("ERROR") ". Card returns 0x%04x", sw); PrintAndLogEx(ERR, "File write " _RED_("ERROR") ". Card returns 0x%04x", sw);
DropField(); DropField();
@ -812,7 +813,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
if (needCommit) { if (needCommit) {
sw = 0; sw = 0;
res = CIPURSECommitTransaction(&sw); res = CIPURSECommitTransaction(&sw);
if (res != 0 || sw != 0x9000) if (res != 0 || sw != ISO7816_OK)
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw); PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
if (verbose) if (verbose)
@ -883,7 +884,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
uint16_t sw = 0; uint16_t sw = 0;
res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, verbose, buf, sizeof(buf), &len, &sw); res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, verbose, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )"); PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -921,7 +922,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
} }
res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw); res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
if (verbose == false) if (verbose == false)
PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x", sw); PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x", sw);
DropField(); DropField();
@ -1020,7 +1021,7 @@ static int CmdHFCipurseWriteFileAttr(const char *Cmd) {
uint16_t sw = 0; uint16_t sw = 0;
res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, verbose, buf, sizeof(buf), &len, &sw); res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, verbose, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )"); PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -1058,7 +1059,7 @@ static int CmdHFCipurseWriteFileAttr(const char *Cmd) {
} }
res = CIPURSEUpdateFileAttributes(hdata, hdatalen, buf, sizeof(buf), &len, &sw); res = CIPURSEUpdateFileAttributes(hdata, hdatalen, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
if (verbose == false) if (verbose == false)
PrintAndLogEx(ERR, "File attributes update " _RED_("ERROR") ". Card returns 0x%04x", sw); PrintAndLogEx(ERR, "File attributes update " _RED_("ERROR") ". Card returns 0x%04x", sw);
DropField(); DropField();
@ -1070,7 +1071,7 @@ static int CmdHFCipurseWriteFileAttr(const char *Cmd) {
if (needCommit) { if (needCommit) {
sw = 0; sw = 0;
res = CIPURSECommitTransaction(&sw); res = CIPURSECommitTransaction(&sw);
if (res != 0 || sw != 0x9000) if (res != 0 || sw != ISO7816_OK)
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw); PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
if (verbose) if (verbose)
@ -1125,7 +1126,7 @@ static int CmdHFCipurseFormatAll(const char *Cmd) {
uint16_t sw = 0; uint16_t sw = 0;
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw); res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw); PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -1154,7 +1155,7 @@ static int CmdHFCipurseFormatAll(const char *Cmd) {
} }
res = CIPURSEFormatAll(&sw); res = CIPURSEFormatAll(&sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Format " _RED_("ERROR") ". Card returns 0x%04x", sw); PrintAndLogEx(ERR, "Format " _RED_("ERROR") ". Card returns 0x%04x", sw);
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -1239,14 +1240,14 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
if (useAID || useFID || selmfd) { if (useAID || useFID || selmfd) {
res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw); res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )"); PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
} }
} else { } else {
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw); res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw); PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -1277,7 +1278,7 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
} }
res = CIPURSECreateFile(hdata, hdatalen, buf, sizeof(buf), &len, &sw); res = CIPURSECreateFile(hdata, hdatalen, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Create file command " _RED_("ERROR")); PrintAndLogEx(ERR, "Create file command " _RED_("ERROR"));
PrintAndLogEx(ERR, "0x%04x - %s", sw, PrintAndLogEx(ERR, "0x%04x - %s", sw,
GetSpecificAPDUCodeDesc(SelectAPDUCodeDescriptions, ARRAYLEN(SelectAPDUCodeDescriptions), sw)); GetSpecificAPDUCodeDesc(SelectAPDUCodeDescriptions, ARRAYLEN(SelectAPDUCodeDescriptions), sw));
@ -1289,7 +1290,7 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
if (needCommit) { if (needCommit) {
sw = 0; sw = 0;
res = CIPURSECommitTransaction(&sw); res = CIPURSECommitTransaction(&sw);
if (res != 0 || sw != 0x9000) if (res != 0 || sw != ISO7816_OK)
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw); PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
if (verbose) if (verbose)
@ -1376,14 +1377,14 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
if (useChildFID) { if (useChildFID) {
res = SelectCommand(false, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw); res = SelectCommand(false, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Top level select " _RED_("error") ". Card returns 0x%04x", sw); PrintAndLogEx(ERR, "Top level select " _RED_("error") ". Card returns 0x%04x", sw);
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
} }
} else { } else {
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw); res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw); PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -1405,7 +1406,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
if (useChildFID) { if (useChildFID) {
res = CIPURSEDeleteFile(childFileId, buf, sizeof(buf), &len, &sw); res = CIPURSEDeleteFile(childFileId, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Delete child file " _CYAN_("%04x ") " %s", childFileId, _RED_("ERROR")); PrintAndLogEx(ERR, "Delete child file " _CYAN_("%04x ") " %s", childFileId, _RED_("ERROR"));
PrintAndLogEx(ERR, "0x%04x - %s", PrintAndLogEx(ERR, "0x%04x - %s",
sw, sw,
@ -1417,7 +1418,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
PrintAndLogEx(INFO, "Child file id " _CYAN_("%04x") " deleted " _GREEN_("succesfully"), childFileId); PrintAndLogEx(INFO, "Child file id " _CYAN_("%04x") " deleted " _GREEN_("succesfully"), childFileId);
} else if (useFID) { } else if (useFID) {
res = CIPURSEDeleteFile(fileId, buf, sizeof(buf), &len, &sw); res = CIPURSEDeleteFile(fileId, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Delete file " _CYAN_("%04x ") " %s", fileId, _RED_("ERROR")); PrintAndLogEx(ERR, "Delete file " _CYAN_("%04x ") " %s", fileId, _RED_("ERROR"));
PrintAndLogEx(ERR, "0x%04x - %s", PrintAndLogEx(ERR, "0x%04x - %s",
sw, sw,
@ -1429,7 +1430,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
PrintAndLogEx(INFO, "File id " _CYAN_("%04x") " deleted " _GREEN_("succesfully"), fileId); PrintAndLogEx(INFO, "File id " _CYAN_("%04x") " deleted " _GREEN_("succesfully"), fileId);
} else { } else {
res = CIPURSEDeleteFileAID(aid, aidLen, buf, sizeof(buf), &len, &sw); res = CIPURSEDeleteFileAID(aid, aidLen, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Delete application " _CYAN_("%s ") " %s", sprint_hex_inrow(aid, aidLen), _RED_("ERROR")); PrintAndLogEx(ERR, "Delete application " _CYAN_("%s ") " %s", sprint_hex_inrow(aid, aidLen), _RED_("ERROR"));
PrintAndLogEx(ERR, "0x%04x - %s", PrintAndLogEx(ERR, "0x%04x - %s",
sw, sw,
@ -1444,7 +1445,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
if (needCommit) { if (needCommit) {
sw = 0; sw = 0;
res = CIPURSECommitTransaction(&sw); res = CIPURSECommitTransaction(&sw);
if (res != 0 || sw != 0x9000) if (res != 0 || sw != ISO7816_OK)
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw); PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
if (verbose) if (verbose)
@ -1588,14 +1589,14 @@ static int CmdHFCipurseUpdateKey(const char *Cmd) {
if (useAID || useFID || selmfd) { if (useAID || useFID || selmfd) {
res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw); res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )"); PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
} }
} else { } else {
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw); res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw); PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -1626,7 +1627,7 @@ static int CmdHFCipurseUpdateKey(const char *Cmd) {
} }
res = CIPURSEUpdateKey(encKeyId, newKeyId, keydata, sizeof(keydata), buf, sizeof(buf), &len, &sw); res = CIPURSEUpdateKey(encKeyId, newKeyId, keydata, sizeof(keydata), buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Update key command " _RED_("ERROR")); PrintAndLogEx(ERR, "Update key command " _RED_("ERROR"));
PrintAndLogEx(ERR, "0x%04x - %s", sw, PrintAndLogEx(ERR, "0x%04x - %s", sw,
GetSpecificAPDUCodeDesc(UAPDpdateKeyCodeDescriptions, ARRAYLEN(UAPDpdateKeyCodeDescriptions), sw)); GetSpecificAPDUCodeDesc(UAPDpdateKeyCodeDescriptions, ARRAYLEN(UAPDpdateKeyCodeDescriptions), sw));
@ -1638,7 +1639,7 @@ static int CmdHFCipurseUpdateKey(const char *Cmd) {
if (needCommit) { if (needCommit) {
sw = 0; sw = 0;
res = CIPURSECommitTransaction(&sw); res = CIPURSECommitTransaction(&sw);
if (res != 0 || sw != 0x9000) if (res != 0 || sw != ISO7816_OK)
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw); PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
if (verbose) if (verbose)
@ -1736,14 +1737,14 @@ static int CmdHFCipurseUpdateKeyAttr(const char *Cmd) {
if (useAID || useFID || selmfd) { if (useAID || useFID || selmfd) {
res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw); res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )"); PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
} }
} else { } else {
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw); res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw); PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -1774,7 +1775,7 @@ static int CmdHFCipurseUpdateKeyAttr(const char *Cmd) {
} }
res = CIPURSEUpdateKeyAttrib(trgKeyId, hdata[0], buf, sizeof(buf), &len, &sw); res = CIPURSEUpdateKeyAttrib(trgKeyId, hdata[0], buf, sizeof(buf), &len, &sw);
if (res != 0 || sw != 0x9000) { if (res != 0 || sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Update key attributes command " _RED_("ERROR")); PrintAndLogEx(ERR, "Update key attributes command " _RED_("ERROR"));
PrintAndLogEx(ERR, "0x%04x - %s", sw, PrintAndLogEx(ERR, "0x%04x - %s", sw,
GetSpecificAPDUCodeDesc(UAPDpdateKeyAttrCodeDescriptions, ARRAYLEN(UAPDpdateKeyAttrCodeDescriptions), sw)); GetSpecificAPDUCodeDesc(UAPDpdateKeyAttrCodeDescriptions, ARRAYLEN(UAPDpdateKeyAttrCodeDescriptions), sw));
@ -1786,7 +1787,7 @@ static int CmdHFCipurseUpdateKeyAttr(const char *Cmd) {
if (needCommit) { if (needCommit) {
sw = 0; sw = 0;
res = CIPURSECommitTransaction(&sw); res = CIPURSECommitTransaction(&sw);
if (res != 0 || sw != 0x9000) if (res != 0 || sw != ISO7816_OK)
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw); PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
if (verbose) if (verbose)
@ -1803,7 +1804,7 @@ bool CheckCardCipurse(void) {
uint16_t sw = 0; uint16_t sw = 0;
int res = CIPURSESelect(true, false, buf, sizeof(buf), &len, &sw); int res = CIPURSESelect(true, false, buf, sizeof(buf), &len, &sw);
return (res == 0 && sw == 0x9000); return (res == 0 && sw == ISO7816_OK);
} }
static int CmdHFCipurseTest(const char *Cmd) { static int CmdHFCipurseTest(const char *Cmd) {

View file

@ -194,7 +194,7 @@ static bool emrtd_exchange_commands(sAPDU_t apdu, bool include_le, uint16_t le,
return false; return false;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(DEBUG, "Command failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(DEBUG, "Command failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
return false; return false;
} }
@ -1957,14 +1957,16 @@ int infoHF_EMRTD_offline(const char *path) {
uint8_t *data; uint8_t *data;
size_t datalen = 0; size_t datalen = 0;
char *filepath = calloc(strlen(path) + 100, sizeof(char)); char *filepath = calloc(strlen(path) + 100, sizeof(char));
if (filepath == NULL) if (filepath == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
}
strcpy(filepath, path); strcpy(filepath, path);
strncat(filepath, PATHSEP, 2); strncat(filepath, PATHSEP, 2);
strcat(filepath, dg_table[EF_COM].filename); strcat(filepath, dg_table[EF_COM].filename);
if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) { if ((loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) &&
PrintAndLogEx(ERR, "Failed to read EF_COM."); (loadFile_safeEx(filepath, ".bin", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS)) {
PrintAndLogEx(ERR, "Failed to read EF_COM");
free(filepath); free(filepath);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -1996,19 +1998,21 @@ int infoHF_EMRTD_offline(const char *path) {
strncat(filepath, PATHSEP, 2); strncat(filepath, PATHSEP, 2);
strcat(filepath, dg_table[EF_CardAccess].filename); strcat(filepath, dg_table[EF_CardAccess].filename);
if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) { if ((loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) ||
(loadFile_safeEx(filepath, ".bin", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS)) {
emrtd_print_ef_cardaccess_info(data, datalen); emrtd_print_ef_cardaccess_info(data, datalen);
free(data); free(data);
} else { } else {
PrintAndLogEx(HINT, "The error above this is normal. It just means that your eMRTD lacks PACE."); PrintAndLogEx(HINT, "The error above this is normal. It just means that your eMRTD lacks PACE");
} }
strcpy(filepath, path); strcpy(filepath, path);
strncat(filepath, PATHSEP, 2); strncat(filepath, PATHSEP, 2);
strcat(filepath, dg_table[EF_SOD].filename); strcat(filepath, dg_table[EF_SOD].filename);
if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) { if ((loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) &&
PrintAndLogEx(ERR, "Failed to read EF_SOD."); (loadFile_safeEx(filepath, ".bin", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS)) {
PrintAndLogEx(ERR, "Failed to read EF_SOD");
free(filepath); free(filepath);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -2020,7 +2024,7 @@ int infoHF_EMRTD_offline(const char *path) {
res = emrtd_parse_ef_sod_hashes(data, datalen, *dg_hashes_sod, &hash_algo); res = emrtd_parse_ef_sod_hashes(data, datalen, *dg_hashes_sod, &hash_algo);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD. Hash checks will fail."); PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD. Hash checks will fail");
} }
free(data); free(data);
@ -2035,10 +2039,12 @@ int infoHF_EMRTD_offline(const char *path) {
strcpy(filepath, path); strcpy(filepath, path);
strncat(filepath, PATHSEP, 2); strncat(filepath, PATHSEP, 2);
strcat(filepath, dg->filename); strcat(filepath, dg->filename);
if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) { if ((loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) ||
(loadFile_safeEx(filepath, ".bin", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS)) {
// we won't halt on parsing errors // we won't halt on parsing errors
if (dg->parser != NULL) if (dg->parser != NULL) {
dg->parser(data, datalen); dg->parser(data, datalen);
}
PrintAndLogEx(DEBUG, "EF_DG%i hash algo: %i", dg->dgnum, hash_algo); PrintAndLogEx(DEBUG, "EF_DG%i hash algo: %i", dg->dgnum, hash_algo);
// Check file hash // Check file hash
@ -2058,13 +2064,6 @@ int infoHF_EMRTD_offline(const char *path) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static void text_to_upper(uint8_t *data, int datalen) {
// Loop over text to make lowercase text uppercase
for (int i = 0; i < datalen; i++) {
data[i] = toupper(data[i]);
}
}
static bool validate_date(uint8_t *data, int datalen) { static bool validate_date(uint8_t *data, int datalen) {
// Date has to be 6 chars // Date has to be 6 chars
if (datalen != 6) { if (datalen != 6) {
@ -2085,7 +2084,9 @@ static int CmdHFeMRTDDump(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf emrtd dump", CLIParserInit(&ctx, "hf emrtd dump",
"Dump all files on an eMRTD", "Dump all files on an eMRTD",
"hf emrtd dump" "hf emrtd dump\n"
"hf emrtd dump --dir ../dump\n"
"hf emrtd dump -n 123456789 -d 19890101 -e 20250401"
); );
void *argtable[] = { void *argtable[] = {
@ -2094,7 +2095,7 @@ static int CmdHFeMRTDDump(const char *Cmd) {
arg_str0("d", "dateofbirth", "<YYMMDD>", "date of birth in YYMMDD format"), arg_str0("d", "dateofbirth", "<YYMMDD>", "date of birth in YYMMDD format"),
arg_str0("e", "expiry", "<YYMMDD>", "expiry in YYMMDD format"), arg_str0("e", "expiry", "<YYMMDD>", "expiry in YYMMDD format"),
arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars"), arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars"),
arg_str0(NULL, "path", "<dirpath>", "save dump to the given dirpath"), arg_str0(NULL, "dir", "<str>", "save dump to the given dirpath"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -2110,7 +2111,7 @@ static int CmdHFeMRTDDump(const char *Cmd) {
if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) {
BAC = false; BAC = false;
} else { } else {
text_to_upper(docnum, slen); strn_upper((char *)docnum, slen);
if (slen != 9) { if (slen != 9) {
// Pad to 9 with < // Pad to 9 with <
memset(docnum + slen, '<', 9 - slen); memset(docnum + slen, '<', 9 - slen);
@ -2143,7 +2144,7 @@ static int CmdHFeMRTDDump(const char *Cmd) {
error = true; error = true;
} else { } else {
BAC = true; BAC = true;
text_to_upper(mrz, slen); strn_upper((char *)mrz, slen);
memcpy(docnum, &mrz[0], 9); memcpy(docnum, &mrz[0], 9);
memcpy(dob, &mrz[13], 6); memcpy(dob, &mrz[13], 6);
memcpy(expiry, &mrz[21], 6); memcpy(expiry, &mrz[21], 6);
@ -2183,7 +2184,10 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf emrtd info", CLIParserInit(&ctx, "hf emrtd info",
"Display info about an eMRTD", "Display info about an eMRTD",
"hf emrtd info" "hf emrtd info\n"
"hf emrtd info --dir ../dumps\n"
"hf emrtd info -n 123456789 -d 19890101 -e 20250401\n"
"hf emrtd info -n 123456789 -d 19890101 -e 20250401 -i"
); );
void *argtable[] = { void *argtable[] = {
@ -2192,7 +2196,7 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
arg_str0("d", "dateofbirth", "<YYMMDD>", "date of birth in YYMMDD format"), arg_str0("d", "dateofbirth", "<YYMMDD>", "date of birth in YYMMDD format"),
arg_str0("e", "expiry", "<YYMMDD>", "expiry in YYMMDD format"), arg_str0("e", "expiry", "<YYMMDD>", "expiry in YYMMDD format"),
arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars (passports only)"), arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars (passports only)"),
arg_str0(NULL, "path", "<dirpath>", "display info from offline dump stored in dirpath"), arg_str0(NULL, "dir", "<str>", "display info from offline dump stored in dirpath"),
arg_lit0("i", "images", "show images"), arg_lit0("i", "images", "show images"),
arg_param_end arg_param_end
}; };
@ -2209,7 +2213,7 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) {
BAC = false; BAC = false;
} else { } else {
text_to_upper(docnum, slen); strn_upper((char *)docnum, slen);
if (slen != 9) { if (slen != 9) {
memset(docnum + slen, '<', 9 - slen); memset(docnum + slen, '<', 9 - slen);
} }
@ -2241,7 +2245,7 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
error = true; error = true;
} else { } else {
BAC = true; BAC = true;
text_to_upper(mrz, slen); strn_upper((char *)mrz, slen);
memcpy(docnum, &mrz[0], 9); memcpy(docnum, &mrz[0], 9);
memcpy(dob, &mrz[13], 6); memcpy(dob, &mrz[13], 6);
memcpy(expiry, &mrz[21], 6); memcpy(expiry, &mrz[21], 6);
@ -2262,7 +2266,7 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
bool is_offline = CLIParamStrToBuf(arg_get_str(ctx, 5), path, sizeof(path), &slen) == 0 && slen > 0; bool is_offline = CLIParamStrToBuf(arg_get_str(ctx, 5), path, sizeof(path), &slen) == 0 && slen > 0;
bool show_images = arg_get_lit(ctx, 6); bool show_images = arg_get_lit(ctx, 6);
CLIParserFree(ctx); CLIParserFree(ctx);
if ((! IfPm3Iso14443()) && (! is_offline)) { if ((IfPm3Iso14443() == false) && (is_offline == false)) {
PrintAndLogEx(WARNING, "Only offline mode is available"); PrintAndLogEx(WARNING, "Only offline mode is available");
error = true; error = true;
} }

View file

@ -228,7 +228,7 @@ static int CmdHFEPAPACESimulate(const char *Cmd) {
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
// bool use_pc = arg_get_lit(ctx, 1); // bool use_pc = arg_get_lit(ctx, 1);
// uint8_t pwd_type = 0; // uint8_t pwd_type = 0;
int plen = 0; int plen = 0;
uint8_t pwd[6] = {0}; uint8_t pwd[6] = {0};
@ -273,7 +273,7 @@ static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"cnonces", CmdHFEPACollectPACENonces, IfPm3Iso14443, "Acquire encrypted PACE nonces of specific size"}, {"cnonces", CmdHFEPACollectPACENonces, IfPm3Iso14443, "Acquire encrypted PACE nonces of specific size"},
{"replay", CmdHFEPAPACEReplay, IfPm3Iso14443, "Perform PACE protocol by replaying given APDUs"}, {"replay", CmdHFEPAPACEReplay, IfPm3Iso14443, "Perform PACE protocol by replaying given APDUs"},
{"sim", CmdHFEPAPACESimulate, IfPm3Iso14443, "Simulate PACE protocol"}, {"sim", CmdHFEPAPACESimulate, IfPm3Iso14443, "Simulate PACE protocol"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -44,6 +44,7 @@
#include "cmdtrace.h" #include "cmdtrace.h"
#include "util.h" #include "util.h"
#include "fileutils.h" // laodFileJSONroot #include "fileutils.h" // laodFileJSONroot
#include "protocols.h" // ISO7816 APDU return codes
#define DEF_FIDO_SIZE 2048 #define DEF_FIDO_SIZE 2048
#define DEF_FIDO_PARAM_FILE "hf_fido2_defparams.json" #define DEF_FIDO_PARAM_FILE "hf_fido2_defparams.json"
@ -84,7 +85,7 @@ static int CmdHFFidoInfo(const char *Cmd) {
return res; return res;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
if (sw) if (sw)
PrintAndLogEx(INFO, "Not a FIDO card! APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(INFO, "Not a FIDO card! APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
else else
@ -111,7 +112,7 @@ static int CmdHFFidoInfo(const char *Cmd) {
if (res) { if (res) {
return res; return res;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "FIDO2 version doesn't exist (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "FIDO2 version doesn't exist (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -262,7 +263,7 @@ static int CmdHFFidoRegister(const char *cmd) {
return res; return res;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
json_decref(root); json_decref(root);
@ -277,7 +278,7 @@ static int CmdHFFidoRegister(const char *cmd) {
return res; return res;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "ERROR execute register command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "ERROR execute register command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -584,7 +585,7 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
return res; return res;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
json_decref(root); json_decref(root);
@ -599,7 +600,7 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
return res; return res;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "ERROR execute authentication command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "ERROR execute authentication command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
json_decref(root); json_decref(root);
return PM3_ESOFT; return PM3_ESOFT;
@ -724,7 +725,7 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
return res; return res;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
json_decref(root); json_decref(root);
@ -752,7 +753,7 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
return res; return res;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "ERROR execute make credential command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "ERROR execute make credential command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
json_decref(root); json_decref(root);
return PM3_EFILE; return PM3_EFILE;
@ -843,7 +844,7 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
return res; return res;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
json_decref(root); json_decref(root);
@ -871,7 +872,7 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
return res; return res;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "ERROR execute get assertion command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "ERROR execute get assertion command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
json_decref(root); json_decref(root);
return PM3_ESOFT; return PM3_ESOFT;

View file

@ -285,7 +285,7 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
// get header from card // get header from card
PrintAndLogEx(INFO, "trying to read a card.."); PrintAndLogEx(INFO, "trying to read a card..");
int res = read_iclass_csn(false, false); int res = read_iclass_csn(false, false, false);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
cc = &iclass_last_known_card; cc = &iclass_last_known_card;
// calc diversified key for selected card // calc diversified key for selected card
@ -905,19 +905,25 @@ static int CmdHFiClassInfo(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
bool shallow_mod = arg_get_lit(ctx, 1);
CLIParserFree(ctx); CLIParserFree(ctx);
return info_iclass(); return info_iclass(shallow_mod);
} }
int read_iclass_csn(bool loop, bool verbose) { int read_iclass_csn(bool loop, bool verbose, bool shallow_mod) {
iclass_card_select_t payload = { iclass_card_select_t payload = {
.flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE) .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
}; };
if (shallow_mod) {
payload.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
}
int res = PM3_SUCCESS; int res = PM3_SUCCESS;
do { do {
@ -973,17 +979,19 @@ static int CmdHFiClassReader(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"), arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1); bool cm = arg_get_lit(ctx, 1);
bool shallow_mod = arg_get_lit(ctx, 2);
CLIParserFree(ctx); CLIParserFree(ctx);
if (cm) { if (cm) {
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit"); PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
} }
return read_iclass_csn(cm, true); return read_iclass_csn(cm, true, shallow_mod);
} }
static int CmdHFiClassELoad(const char *Cmd) { static int CmdHFiClassELoad(const char *Cmd) {
@ -1547,12 +1555,16 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) { static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose, bool shallow_mod) {
iclass_card_select_t payload = { iclass_card_select_t payload = {
.flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE) .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
}; };
if (shallow_mod) {
payload.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
}
clearCommandBuffer(); clearCommandBuffer();
PacketResponseNG resp; PacketResponseNG resp;
SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload, sizeof(iclass_card_select_t)); SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload, sizeof(iclass_card_select_t));
@ -1608,6 +1620,7 @@ static int CmdHFiClassDump(const char *Cmd) {
arg_lit0(NULL, "nr", "replay of NR/MAC"), arg_lit0(NULL, "nr", "replay of NR/MAC"),
arg_lit0("z", "dense", "dense dump output style"), arg_lit0("z", "dense", "dense dump output style"),
arg_lit0(NULL, "force", "force unsecure card read"), arg_lit0(NULL, "force", "force unsecure card read"),
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -1693,6 +1706,7 @@ static int CmdHFiClassDump(const char *Cmd) {
bool use_replay = arg_get_lit(ctx, 8); bool use_replay = arg_get_lit(ctx, 8);
bool dense_output = g_session.dense_output || arg_get_lit(ctx, 9); bool dense_output = g_session.dense_output || arg_get_lit(ctx, 9);
bool force = arg_get_lit(ctx, 10); bool force = arg_get_lit(ctx, 10);
bool shallow_mod = arg_get_lit(ctx, 11);
CLIParserFree(ctx); CLIParserFree(ctx);
@ -1711,6 +1725,11 @@ static int CmdHFiClassDump(const char *Cmd) {
iclass_card_select_t payload_rdr = { iclass_card_select_t payload_rdr = {
.flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE) .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
}; };
if (shallow_mod) {
payload_rdr.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
}
clearCommandBuffer(); clearCommandBuffer();
PacketResponseNG resp; PacketResponseNG resp;
SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload_rdr, sizeof(iclass_card_select_t)); SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload_rdr, sizeof(iclass_card_select_t));
@ -1790,6 +1809,7 @@ static int CmdHFiClassDump(const char *Cmd) {
.req.use_replay = use_replay, .req.use_replay = use_replay,
.req.send_reply = true, .req.send_reply = true,
.req.do_auth = auth, .req.do_auth = auth,
.req.shallow_mod = shallow_mod,
.end_block = app_limit1, .end_block = app_limit1,
}; };
memcpy(payload.req.key, key, 8); memcpy(payload.req.key, key, 8);
@ -1950,7 +1970,7 @@ write_dump:
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *macdata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool replay, bool verbose, bool use_secure_pagemode) { static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *macdata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool replay, bool verbose, bool use_secure_pagemode, bool shallow_mod) {
iclass_writeblock_req_t payload = { iclass_writeblock_req_t payload = {
.req.use_raw = rawkey, .req.use_raw = rawkey,
@ -1960,6 +1980,7 @@ static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *macdata
.req.blockno = blockno, .req.blockno = blockno,
.req.send_reply = true, .req.send_reply = true,
.req.do_auth = use_secure_pagemode, .req.do_auth = use_secure_pagemode,
.req.shallow_mod = shallow_mod,
}; };
memcpy(payload.req.key, KEY, 8); memcpy(payload.req.key, KEY, 8);
memcpy(payload.data, bldata, sizeof(payload.data)); memcpy(payload.data, bldata, sizeof(payload.data));
@ -2004,6 +2025,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
arg_lit0(NULL, "raw", "no computations applied to key"), arg_lit0(NULL, "raw", "no computations applied to key"),
arg_lit0(NULL, "nr", "replay of NR/MAC"), arg_lit0(NULL, "nr", "replay of NR/MAC"),
arg_lit0("v", "verbose", "verbose output"), arg_lit0("v", "verbose", "verbose output"),
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -2072,6 +2094,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
bool rawkey = arg_get_lit(ctx, 8); bool rawkey = arg_get_lit(ctx, 8);
bool use_replay = arg_get_lit(ctx, 9); bool use_replay = arg_get_lit(ctx, 9);
bool verbose = arg_get_lit(ctx, 10); bool verbose = arg_get_lit(ctx, 10);
bool shallow_mod = arg_get_lit(ctx, 11);
CLIParserFree(ctx); CLIParserFree(ctx);
@ -2080,7 +2103,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
int isok = iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth); int isok = iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod);
switch (isok) { switch (isok) {
case PM3_SUCCESS: case PM3_SUCCESS:
PrintAndLogEx(SUCCESS, "Wrote block %3d/0x%02X successful", blockno, blockno); PrintAndLogEx(SUCCESS, "Wrote block %3d/0x%02X successful", blockno, blockno);
@ -2116,6 +2139,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
arg_lit0(NULL, "elite", "elite computations applied to key"), arg_lit0(NULL, "elite", "elite computations applied to key"),
arg_lit0(NULL, "raw", "no computations applied to key"), arg_lit0(NULL, "raw", "no computations applied to key"),
arg_lit0("v", "verbose", "verbose output"), arg_lit0("v", "verbose", "verbose output"),
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -2165,6 +2189,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
bool elite = arg_get_lit(ctx, 7); bool elite = arg_get_lit(ctx, 7);
bool rawkey = arg_get_lit(ctx, 8); bool rawkey = arg_get_lit(ctx, 8);
bool verbose = arg_get_lit(ctx, 9); bool verbose = arg_get_lit(ctx, 9);
bool shallow_mod = arg_get_lit(ctx, 10);
CLIParserFree(ctx); CLIParserFree(ctx);
@ -2215,6 +2240,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
payload->req.blockno = startblock; payload->req.blockno = startblock;
payload->req.send_reply = true; payload->req.send_reply = true;
payload->req.do_auth = true; payload->req.do_auth = true;
payload->req.shallow_mod = shallow_mod;
memcpy(payload->req.key, key, 8); memcpy(payload->req.key, key, 8);
payload->item_cnt = (endblock - startblock + 1); payload->item_cnt = (endblock - startblock + 1);
@ -2268,7 +2294,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
return resp.status; return resp.status;
} }
static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool replay, bool verbose, bool auth, uint8_t *out) { static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool replay, bool verbose, bool auth, bool shallow_mod, uint8_t *out) {
iclass_auth_req_t payload = { iclass_auth_req_t payload = {
.use_raw = rawkey, .use_raw = rawkey,
@ -2278,6 +2304,7 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo
.blockno = blockno, .blockno = blockno,
.send_reply = true, .send_reply = true,
.do_auth = auth, .do_auth = auth,
.shallow_mod = shallow_mod,
}; };
memcpy(payload.key, KEY, 8); memcpy(payload.key, KEY, 8);
@ -2331,6 +2358,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
arg_lit0(NULL, "raw", "no computations applied to key"), arg_lit0(NULL, "raw", "no computations applied to key"),
arg_lit0(NULL, "nr", "replay of NR/MAC"), arg_lit0(NULL, "nr", "replay of NR/MAC"),
arg_lit0("v", "verbose", "verbose output"), arg_lit0("v", "verbose", "verbose output"),
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -2381,6 +2409,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
bool rawkey = arg_get_lit(ctx, 6); bool rawkey = arg_get_lit(ctx, 6);
bool use_replay = arg_get_lit(ctx, 7); bool use_replay = arg_get_lit(ctx, 7);
bool verbose = arg_get_lit(ctx, 8); bool verbose = arg_get_lit(ctx, 8);
bool shallow_mod = arg_get_lit(ctx, 9);
CLIParserFree(ctx); CLIParserFree(ctx);
@ -2400,7 +2429,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
} }
uint8_t data[8] = {0}; uint8_t data[8] = {0};
int res = iclass_read_block(key, blockno, keyType, elite, rawkey, use_replay, verbose, auth, data); int res = iclass_read_block(key, blockno, keyType, elite, rawkey, use_replay, verbose, auth, shallow_mod, data);
if (res != PM3_SUCCESS) if (res != PM3_SUCCESS)
return res; return res;
@ -2975,7 +3004,7 @@ static int CmdHFiClassCalcNewKey(const char *Cmd) {
if (givenCSN == false) { if (givenCSN == false) {
uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
if (select_only(csn, CCNR, true) == false) { if (select_only(csn, CCNR, true, false) == false) {
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -3173,6 +3202,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
arg_lit0(NULL, "credit", "key is assumed to be the credit key"), arg_lit0(NULL, "credit", "key is assumed to be the credit key"),
arg_lit0(NULL, "elite", "elite computations applied to key"), arg_lit0(NULL, "elite", "elite computations applied to key"),
arg_lit0(NULL, "raw", "no computations applied to key (raw)"), arg_lit0(NULL, "raw", "no computations applied to key (raw)"),
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -3184,6 +3214,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
bool use_credit_key = arg_get_lit(ctx, 2); bool use_credit_key = arg_get_lit(ctx, 2);
bool use_elite = arg_get_lit(ctx, 3); bool use_elite = arg_get_lit(ctx, 3);
bool use_raw = arg_get_lit(ctx, 4); bool use_raw = arg_get_lit(ctx, 4);
bool shallow_mod = arg_get_lit(ctx, 5);
CLIParserFree(ctx); CLIParserFree(ctx);
@ -3213,7 +3244,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
bool got_csn = false; bool got_csn = false;
for (uint8_t i = 0; i < ICLASS_AUTH_RETRY; i++) { for (uint8_t i = 0; i < ICLASS_AUTH_RETRY; i++) {
got_csn = select_only(CSN, CCNR, false); got_csn = select_only(CSN, CCNR, false, shallow_mod);
if (got_csn == false) if (got_csn == false)
PrintAndLogEx(WARNING, "one more try"); PrintAndLogEx(WARNING, "one more try");
else else
@ -3295,6 +3326,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
} }
packet->use_credit_key = use_credit_key; packet->use_credit_key = use_credit_key;
packet->count = curr_chunk_cnt; packet->count = curr_chunk_cnt;
packet->shallow_mod = shallow_mod;
// copy chunk of pre calculated macs to packet // copy chunk of pre calculated macs to packet
memcpy(packet->items, (pre + chunk_offset), (4 * curr_chunk_cnt)); memcpy(packet->items, (pre + chunk_offset), (4 * curr_chunk_cnt));
@ -3799,6 +3831,7 @@ static int CmdHFiClassEncode(const char *Cmd) {
arg_u64_0(NULL, "fc", "<dec>", "facility code"), arg_u64_0(NULL, "fc", "<dec>", "facility code"),
arg_u64_0(NULL, "cn", "<dec>", "card number"), arg_u64_0(NULL, "cn", "<dec>", "card number"),
arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"), arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -3843,6 +3876,8 @@ static int CmdHFiClassEncode(const char *Cmd) {
int format_len = 0; int format_len = 0;
CLIParamStrToBuf(arg_get_str(ctx, 9), (uint8_t *)format, sizeof(format), &format_len); CLIParamStrToBuf(arg_get_str(ctx, 9), (uint8_t *)format, sizeof(format), &format_len);
bool shallow_mod = arg_get_lit(ctx, 10);
CLIParserFree(ctx); CLIParserFree(ctx);
if ((rawkey + elite) > 1) { if ((rawkey + elite) > 1) {
@ -3964,7 +3999,7 @@ static int CmdHFiClassEncode(const char *Cmd) {
int isok = PM3_SUCCESS; int isok = PM3_SUCCESS;
// write // write
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
isok = iclass_write_block(6 + i, credential + (i * 8), NULL, key, use_credit_key, elite, rawkey, false, false, auth); isok = iclass_write_block(6 + i, credential + (i * 8), NULL, key, use_credit_key, elite, rawkey, false, false, auth, shallow_mod);
switch (isok) { switch (isok) {
case PM3_SUCCESS: case PM3_SUCCESS:
PrintAndLogEx(SUCCESS, "Write block %d/0x0%x ( " _GREEN_("ok") " ) --> " _YELLOW_("%s"), 6 + i, 6 + i, sprint_hex_inrow(credential + (i * 8), 8)); PrintAndLogEx(SUCCESS, "Write block %d/0x0%x ( " _GREEN_("ok") " ) --> " _YELLOW_("%s"), 6 + i, 6 + i, sprint_hex_inrow(credential + (i * 8), 8));
@ -4135,11 +4170,16 @@ int CmdHFiClass(const char *Cmd) {
// DESFIRE| | | // DESFIRE| | |
//} //}
int info_iclass(void) { int info_iclass(bool shallow_mod) {
iclass_card_select_t payload = { iclass_card_select_t payload = {
.flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE) .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
}; };
if (shallow_mod) {
payload.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
}
clearCommandBuffer(); clearCommandBuffer();
PacketResponseNG resp; PacketResponseNG resp;
SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload, sizeof(iclass_card_select_t)); SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload, sizeof(iclass_card_select_t));

View file

@ -24,8 +24,8 @@
int CmdHFiClass(const char *Cmd); int CmdHFiClass(const char *Cmd);
int info_iclass(void); int info_iclass(bool shallow_mod);
int read_iclass_csn(bool loop, bool verbose); int read_iclass_csn(bool loop, bool verbose, bool shallow_mod);
void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize, bool dense_output); void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize, bool dense_output);
void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite); void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite);

View file

@ -46,6 +46,7 @@
#include "emv/tlv.h" #include "emv/tlv.h"
#include "iso7816/apduinfo.h" #include "iso7816/apduinfo.h"
#include "cmdhf14a.h" #include "cmdhf14a.h"
#include "protocols.h" // ISO7816 APDU return codes
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -126,7 +127,7 @@ static int CmdHFKSX6924Info(const char *Cmd) {
return res; return res;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
if (sw) { if (sw) {
PrintAndLogEx(INFO, "Not a KS X 6924 card! APDU response: %04x - %s", PrintAndLogEx(INFO, "Not a KS X 6924 card! APDU response: %04x - %s",
sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));

View file

@ -318,6 +318,18 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i
snprintf(exp, size, "AUTH-B(%d)", cmd[1]); snprintf(exp, size, "AUTH-B(%d)", cmd[1]);
break; break;
} }
case MIFARE_MAGIC_GDM_AUTH_KEYA: {
if (cmdsize > 3) {
snprintf(exp, size, "MAGIC AUTH-A(%d)", cmd[1]);
MifareAuthState = masNt;
}
break;
}
case MIFARE_MAGIC_GDM_AUTH_KEYB: {
MifareAuthState = masNt;
snprintf(exp, size, "MAGIC AUTH-B(%d)", cmd[1]);
break;
}
case MIFARE_MAGICWUPC1: case MIFARE_MAGICWUPC1:
snprintf(exp, size, "MAGIC WUPC1"); snprintf(exp, size, "MAGIC WUPC1");
break; break;
@ -942,14 +954,14 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
break; break;
case MFDES_READ_DATA: case MFDES_READ_DATA:
if (data_size >= 7) { if (data_size >= 7) {
snprintf(exp, size, "READ DATA (fileId %02x, offset %d, len %d)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4)); snprintf(exp, size, "READ DATA (fileId %02x, offset %u, len %u)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4));
} else { } else {
snprintf(exp, size, "READ DATA"); snprintf(exp, size, "READ DATA");
} }
break; break;
case MFDES_WRITE_DATA: case MFDES_WRITE_DATA:
if (data_size >= 7) { if (data_size >= 7) {
snprintf(exp, size, "WRITE DATA (fileId %02x, offset %d, len %d)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4)); snprintf(exp, size, "WRITE DATA (fileId %02x, offset %u, len %u)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4));
} else { } else {
snprintf(exp, size, "WRITE DATA"); snprintf(exp, size, "WRITE DATA");
} }
@ -984,14 +996,14 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
break; break;
case MFDES_WRITE_RECORD: case MFDES_WRITE_RECORD:
if (data_size >= 7) { if (data_size >= 7) {
snprintf(exp, size, "WRITE RECORD (fileId %02x, offset %d, len %d)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4)); snprintf(exp, size, "WRITE RECORD (fileId %02x, offset %u, len %u)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4));
} else { } else {
snprintf(exp, size, "WRITE RECORD"); snprintf(exp, size, "WRITE RECORD");
} }
break; break;
case MFDES_READ_RECORDS: case MFDES_READ_RECORDS:
if (data_size >= 7) { if (data_size >= 7) {
snprintf(exp, size, "READ RECORDS (fileId %02x, offset %d, len %d)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4)); snprintf(exp, size, "READ RECORDS (fileId %02x, offset %u, len %u)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4));
} else { } else {
snprintf(exp, size, "READ RECORDS"); snprintf(exp, size, "READ RECORDS");
} }
@ -1086,21 +1098,21 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
break; break;
case MFDES_AUTHENTICATE: case MFDES_AUTHENTICATE:
if (data_size >= 1) { if (data_size >= 1) {
snprintf(exp, size, "AUTH NATIVE (keyNo %d)", data[0]); snprintf(exp, size, "AUTH NATIVE (keyNo %u)", data[0]);
} else { } else {
snprintf(exp, size, "AUTH NATIVE"); snprintf(exp, size, "AUTH NATIVE");
} }
break; // AUTHENTICATE_NATIVE break; // AUTHENTICATE_NATIVE
case MFDES_AUTHENTICATE_ISO: case MFDES_AUTHENTICATE_ISO:
if (data_size >= 1) { if (data_size >= 1) {
snprintf(exp, size, "AUTH ISO (keyNo %d)", data[0]); snprintf(exp, size, "AUTH ISO (keyNo %u)", data[0]);
} else { } else {
snprintf(exp, size, "AUTH ISO"); snprintf(exp, size, "AUTH ISO");
} }
break; // AUTHENTICATE_STANDARD break; // AUTHENTICATE_STANDARD
case MFDES_AUTHENTICATE_AES: case MFDES_AUTHENTICATE_AES:
if (data_size >= 1) { if (data_size >= 1) {
snprintf(exp, size, "AUTH AES (keyNo %d)", data[0]); snprintf(exp, size, "AUTH AES (keyNo %u)", data[0]);
} else { } else {
snprintf(exp, size, "AUTH AES"); snprintf(exp, size, "AUTH AES");
} }
@ -1119,14 +1131,14 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
break; break;
case MFDES_CHANGE_KEY: case MFDES_CHANGE_KEY:
if (data_size >= 1) { if (data_size >= 1) {
snprintf(exp, size, "CHANGE KEY (keyNo %d)", data[0]); snprintf(exp, size, "CHANGE KEY (keyNo %u)", data[0]);
} else { } else {
snprintf(exp, size, "CHANGE KEY"); snprintf(exp, size, "CHANGE KEY");
} }
break; break;
case MFDES_GET_KEY_VERSION: case MFDES_GET_KEY_VERSION:
if (data_size >= 1) { if (data_size >= 1) {
snprintf(exp, size, "GET KEY VERSION (keyNo %d)", data[0]); snprintf(exp, size, "GET KEY VERSION (keyNo %u)", data[0]);
} else { } else {
snprintf(exp, size, "GET KEY VERSION"); snprintf(exp, size, "GET KEY VERSION");
} }

View file

@ -238,7 +238,7 @@ static bool mfc_value(const uint8_t *d, int32_t *val) {
} }
static void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose) { static void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose) {
if (blockno == 0) { if (blockno == 0) {
PrintAndLogEx(INFO, "%3d | " _RED_("%s"), blockno, sprint_hex_ascii(d, MFBLOCK_SIZE)); PrintAndLogEx(INFO, "%3d | " _RED_("%s"), blockno, sprint_hex_ascii(d, MFBLOCK_SIZE));
} else if (mfIsSectorTrailer(blockno)) { } else if (mfIsSectorTrailer(blockno)) {
PrintAndLogEx(INFO, "%3d | " _YELLOW_("%s"), blockno, sprint_hex_ascii(d, MFBLOCK_SIZE)); PrintAndLogEx(INFO, "%3d | " _YELLOW_("%s"), blockno, sprint_hex_ascii(d, MFBLOCK_SIZE));
@ -369,12 +369,37 @@ static bool mf_write_block(const uint8_t *key, uint8_t keytype, uint8_t blockno,
PacketResponseNG resp; PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) { if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
PrintAndLogEx(FAILED, "Command execute timeout"); PrintAndLogEx(FAILED, "Command execute timeout");
return PM3_ETIMEOUT; return false;
} }
return (resp.oldarg[0] & 0xff); return (resp.oldarg[0] & 0xff);
} }
static void mf_analyse_acl(uint16_t n, uint8_t *d) {
for (uint16_t b = 3; b < n; b++) {
if (mfIsSectorTrailer(b) == false) {
continue;
}
uint8_t block[MFBLOCK_SIZE] = {0x00};
memcpy(block, d + (b * MFBLOCK_SIZE), MFBLOCK_SIZE);
// ensure access right isn't messed up.
if (mfValidateAccessConditions(&block[6]) == false) {
PrintAndLogEx(WARNING, "Invalid Access Conditions on sector " _YELLOW_("%u"), mfSectorNum(b));
}
// Warn if ACL is strict read-only
uint8_t bar = mfNumBlocksPerSector(mfSectorNum(b));
for (uint8_t foo = 0; foo < bar; foo++) {
if (mfReadOnlyAccessConditions(foo, &block[6])) {
PrintAndLogEx(WARNING, _YELLOW_("s%u / b%u") " - Strict ReadOnly Access Conditions detected", mfSectorNum(b), b - bar + 1 + foo);
}
}
}
}
static int CmdHF14AMfAcl(const char *Cmd) { static int CmdHF14AMfAcl(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf acl", CLIParserInit(&ctx, "hf mf acl",
@ -482,7 +507,10 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
"Sector 0 / Block 0 - Manufacturer block\n" "Sector 0 / Block 0 - Manufacturer block\n"
"When writing to block 0 you must use a VALID block 0 data (UID, BCC, SAK, ATQA)\n" "When writing to block 0 you must use a VALID block 0 data (UID, BCC, SAK, ATQA)\n"
"Writing an invalid block 0 means rendering your Magic GEN2 card undetectable. \n" "Writing an invalid block 0 means rendering your Magic GEN2 card undetectable. \n"
"Look in the magic_cards_notes.md file for help to resolve it.", "Look in the magic_cards_notes.md file for help to resolve it.\n"
" \n"
"`--force` param is used to override warnings like bad ACL and BLOCK 0 writes.\n"
" if not specified, it will exit if detected",
"hf mf wrbl --blk 1 -k FFFFFFFFFFFF -d 000102030405060708090a0b0c0d0e0f" "hf mf wrbl --blk 1 -k FFFFFFFFFFFF -d 000102030405060708090a0b0c0d0e0f"
); );
void *argtable[] = { void *argtable[] = {
@ -490,7 +518,7 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
arg_int1(NULL, "blk", "<dec>", "block number"), arg_int1(NULL, "blk", "<dec>", "block number"),
arg_lit0("a", NULL, "input key type is key A (def)"), arg_lit0("a", NULL, "input key type is key A (def)"),
arg_lit0("b", NULL, "input key type is key B"), arg_lit0("b", NULL, "input key type is key B"),
arg_lit0(NULL, "force", "enforce block0 writes"), arg_lit0(NULL, "force", "override warnings"),
arg_str0("k", "key", "<hex>", "key, 6 hex bytes"), arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"), arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
@ -528,6 +556,8 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
if (b > 255) { if (b > 255) {
return PM3_EINVARG; return PM3_EINVARG;
} }
// BLOCK 0 detection
if (b == 0 && force == false) { if (b == 0 && force == false) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "Targeting Sector 0 / Block 0 - Manufacturer block"); PrintAndLogEx(INFO, "Targeting Sector 0 / Block 0 - Manufacturer block");
@ -539,6 +569,38 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
uint8_t blockno = (uint8_t)b; uint8_t blockno = (uint8_t)b;
// Sector trailer sanity checks.
// Warn if ACL is strict read-only, or invalid ACL.
if (mfIsSectorTrailer(blockno)) {
PrintAndLogEx(INFO, "Sector trailer (ST) write detected");
// ensure access right isn't messed up.
if (mfValidateAccessConditions(&block[6]) == false) {
PrintAndLogEx(WARNING, "Invalid Access Conditions detected, replacing with default values");
memcpy(block + 6, "\xFF\x07\x80\x69", 4);
}
bool ro_detected = false;
uint8_t bar = mfNumBlocksPerSector(mfSectorNum(blockno));
for (uint8_t foo = 0; foo < bar; foo++) {
if (mfReadOnlyAccessConditions(foo, &block[6])) {
PrintAndLogEx(WARNING, "Strict ReadOnly Access Conditions on block " _YELLOW_("%u") " detected", blockno - bar + 1 + foo);
ro_detected = true;
}
}
if (ro_detected) {
if (force) {
PrintAndLogEx(WARNING, " --force override, continuing...");
} else {
PrintAndLogEx(INFO, "Exiting, please run `" _YELLOW_("hf mf acl -d %s") "` to understand", sprint_hex_inrow(&block[6], 3));
PrintAndLogEx(INFO, "Use `" _YELLOW_("--force") "` to override and write this data");
return PM3_EINVARG;
}
} else {
PrintAndLogEx(SUCCESS, "ST passed checks, continuing...");
}
}
PrintAndLogEx(INFO, "Writing block no %d, key %c - %s", blockno, (keytype == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(key, sizeof(key))); PrintAndLogEx(INFO, "Writing block no %d, key %c - %s", blockno, (keytype == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(key, sizeof(key)));
PrintAndLogEx(INFO, "data: %s", sprint_hex(block, sizeof(block))); PrintAndLogEx(INFO, "data: %s", sprint_hex(block, sizeof(block)));
@ -909,6 +971,11 @@ static int CmdHF14AMfDump(const char *Cmd) {
for (blockNo = 0; blockNo < mfNumBlocksPerSector(sectorNo); blockNo++) { for (blockNo = 0; blockNo < mfNumBlocksPerSector(sectorNo); blockNo++) {
bool received = false; bool received = false;
current_key = MF_KEY_A; current_key = MF_KEY_A;
uint8_t data_area = (sectorNo < 32) ? blockNo : blockNo / 5;
if (rights[sectorNo][data_area] == 0x07) { // no key would work
PrintAndLogEx(WARNING, "access rights do not allow reading of sector %2d block %3d, skipping", sectorNo, blockNo);
continue;
}
for (tries = 0; tries < MIFARE_SECTOR_RETRY; tries++) { for (tries = 0; tries < MIFARE_SECTOR_RETRY; tries++) {
if (blockNo == mfNumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A. if (blockNo == mfNumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A.
@ -920,7 +987,6 @@ static int CmdHF14AMfDump(const char *Cmd) {
SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500); received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500);
} else { // data block. Check if it can be read with key A or key B } else { // data block. Check if it can be read with key A or key B
uint8_t data_area = (sectorNo < 32) ? blockNo : blockNo / 5;
if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work
payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo; payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo;
@ -930,10 +996,6 @@ static int CmdHF14AMfDump(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500); received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500);
} else if (rights[sectorNo][data_area] == 0x07) { // no key would work
PrintAndLogEx(WARNING, "access rights do not allow reading of sector %2d block %3d", sectorNo, blockNo);
// where do you want to go?? Next sector or block?
break;
} else { // key A would work } else { // key A would work
payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo; payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo;
@ -982,11 +1044,9 @@ static int CmdHF14AMfDump(const char *Cmd) {
PrintAndLogEx(SUCCESS, "successfully read block %2d of sector %2d.", blockNo, sectorNo); PrintAndLogEx(SUCCESS, "successfully read block %2d of sector %2d.", blockNo, sectorNo);
} else { } else {
PrintAndLogEx(FAILED, "could not read block %2d of sector %2d", blockNo, sectorNo); PrintAndLogEx(FAILED, "could not read block %2d of sector %2d", blockNo, sectorNo);
break;
} }
} else { } else {
PrintAndLogEx(WARNING, "command execute timeout when trying to read block %2d of sector %2d.", blockNo, sectorNo); PrintAndLogEx(WARNING, "command execute timeout when trying to read block %2d of sector %2d.", blockNo, sectorNo);
break;
} }
} }
} }
@ -1028,9 +1088,11 @@ static int CmdHF14AMfRestore(const char *Cmd) {
"If access rights in dump file is all zeros, it will be replaced with default values\n" "If access rights in dump file is all zeros, it will be replaced with default values\n"
"\n" "\n"
"`--uid` param is used for filename templates `hf-mf-<uid>-dump.bin` and `hf-mf-<uid>-key.bin.\n" "`--uid` param is used for filename templates `hf-mf-<uid>-dump.bin` and `hf-mf-<uid>-key.bin.\n"
" If not specified, it will read the card uid instead.\n" " if not specified, it will read the card uid instead.\n"
" `--ka` param you can indicate that the key file should be used for authentication instead.\n" " `--ka` param you can indicate that the key file should be used for authentication instead.\n"
" if so we also try both B/A keys", " if so we also try both B/A keys\n"
"`--force` param is used to override warnings and allow bad ACL block writes.\n"
" if not specified, it will skip blocks with bad ACL.\n",
"hf mf restore\n" "hf mf restore\n"
"hf mf restore --1k --uid 04010203\n" "hf mf restore --1k --uid 04010203\n"
"hf mf restore --1k --uid 04010203 -k hf-mf-AABBCCDD-key.bin\n" "hf mf restore --1k --uid 04010203 -k hf-mf-AABBCCDD-key.bin\n"
@ -1047,6 +1109,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
arg_str0("f", "file", "<fn>", "specify dump filename (bin/eml/json)"), arg_str0("f", "file", "<fn>", "specify dump filename (bin/eml/json)"),
arg_str0("k", "kfn", "<fn>", "key filename"), arg_str0("k", "kfn", "<fn>", "key filename"),
arg_lit0(NULL, "ka", "use specified keyfile to authenticate"), arg_lit0(NULL, "ka", "use specified keyfile to authenticate"),
arg_lit0(NULL, "force", "override warnings"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -1069,6 +1132,8 @@ static int CmdHF14AMfRestore(const char *Cmd) {
CLIParamStrToBuf(arg_get_str(ctx, 7), (uint8_t *)keyfilename, FILE_PATH_SIZE, &keyfnlen); CLIParamStrToBuf(arg_get_str(ctx, 7), (uint8_t *)keyfilename, FILE_PATH_SIZE, &keyfnlen);
bool use_keyfile_for_auth = arg_get_lit(ctx, 8); bool use_keyfile_for_auth = arg_get_lit(ctx, 8);
bool force = arg_get_lit(ctx, 9);
CLIParserFree(ctx); CLIParserFree(ctx);
// validations // validations
@ -1172,7 +1237,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", datafilename); PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", datafilename);
// main loop for restoreing. // main loop for restoring.
// a bit more complicated than needed // a bit more complicated than needed
// this is because of two things. // this is because of two things.
// 1. we are setting keys from a key file or using the existing ones in the dump // 1. we are setting keys from a key file or using the existing ones in the dump
@ -1182,7 +1247,6 @@ static int CmdHF14AMfRestore(const char *Cmd) {
for (uint8_t b = 0; b < mfNumBlocksPerSector(s); b++) { for (uint8_t b = 0; b < mfNumBlocksPerSector(s); b++) {
uint8_t bldata[MFBLOCK_SIZE] = {0x00}; uint8_t bldata[MFBLOCK_SIZE] = {0x00};
memcpy(bldata, dump, MFBLOCK_SIZE); memcpy(bldata, dump, MFBLOCK_SIZE);
// if sector trailer // if sector trailer
@ -1206,9 +1270,22 @@ static int CmdHF14AMfRestore(const char *Cmd) {
// ensure access right isn't messed up. // ensure access right isn't messed up.
if (mfValidateAccessConditions(&bldata[6]) == false) { if (mfValidateAccessConditions(&bldata[6]) == false) {
PrintAndLogEx(WARNING, "Invalid Access Conditions on sector %i, replacing by default values", s); PrintAndLogEx(WARNING, "Invalid Access Conditions on sector %i, replacing with default values", s);
memcpy(bldata + 6, "\xFF\x07\x80\x69", 4); memcpy(bldata + 6, "\xFF\x07\x80\x69", 4);
} }
// Warn if ACL is strict read-only
for (uint8_t foo = 0; foo < mfNumBlocksPerSector(s); foo++) {
if (mfReadOnlyAccessConditions(foo, &bldata[6])) {
PrintAndLogEx(WARNING, "Strict ReadOnly Access Conditions on block " _YELLOW_("%u") " detected", foo);
// if --force isn't used, skip writing this block
if (force == false) {
PrintAndLogEx(INFO, "Skipping, use `" _YELLOW_("--force") "` to override and write this data");
continue;
}
}
}
} }
if (bytes_read) { if (bytes_read) {
@ -3609,8 +3686,6 @@ static int CmdHF14AMfSim(const char *Cmd) {
} }
CLIParserFree(ctx); CLIParserFree(ctx);
nonces_t data[1];
sector_t *k_sector = NULL; sector_t *k_sector = NULL;
//Validations //Validations
@ -3701,7 +3776,7 @@ static int CmdHF14AMfSim(const char *Cmd) {
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) continue; if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) continue;
if (!(flags & FLAG_NR_AR_ATTACK)) break; if (!(flags & FLAG_NR_AR_ATTACK)) break;
if ((resp.oldarg[0] & 0xffff) != CMD_HF_MIFARE_SIMULATE) break; if ((resp.oldarg[0] & 0xffff) != CMD_HF_MIFARE_SIMULATE) break;
nonces_t data[1];
memcpy(data, resp.data.asBytes, sizeof(data)); memcpy(data, resp.data.asBytes, sizeof(data));
readerAttack(k_sector, k_sectorsCount, data[0], setEmulatorMem, verbose); readerAttack(k_sector, k_sectorsCount, data[0], setEmulatorMem, verbose);
} }
@ -6818,6 +6893,7 @@ static int CmdHF14AMfView(const char *Cmd) {
if (verbose) { if (verbose) {
mf_print_keys(block_cnt, dump); mf_print_keys(block_cnt, dump);
mf_analyse_acl(block_cnt, dump);
} }
int sector = DetectHID(dump, 0x4910); int sector = DetectHID(dump, 0x4910);
@ -6835,9 +6911,14 @@ static int CmdHF14AMfView(const char *Cmd) {
return res; return res;
} }
typedef union UDATA {
uint8_t *bytes;
mfc_vigik_t *vigik;
} UDATA;
// allocate memory // allocate memory
uint8_t* d = calloc(bytes_read, sizeof(uint8_t)); UDATA d;
if (d == NULL) { d.bytes = calloc(bytes_read, sizeof(uint8_t));
if (d.bytes == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
uint16_t dlen = 0; uint16_t dlen = 0;
@ -6845,14 +6926,14 @@ static int CmdHF14AMfView(const char *Cmd) {
// vigik struture sector 0 // vigik struture sector 0
uint8_t *pdump = dump; uint8_t *pdump = dump;
memcpy(d + dlen, pdump, MFBLOCK_SIZE * 3); memcpy(d.bytes + dlen, pdump, MFBLOCK_SIZE * 3);
dlen += MFBLOCK_SIZE * 3; dlen += MFBLOCK_SIZE * 3;
pdump += (MFBLOCK_SIZE * 4); // skip sectortrailer pdump += (MFBLOCK_SIZE * 4); // skip sectortrailer
// extract memory from MAD sectors // extract memory from MAD sectors
for (int i = 0; i <= madlen; i++) { for (int i = 0; i <= madlen; i++) {
if (0x4910 == mad[i] || 0x4916 == mad[i]) { if (0x4910 == mad[i] || 0x4916 == mad[i]) {
memcpy(d + dlen, pdump, MFBLOCK_SIZE * 3); memcpy(d.bytes + dlen, pdump, MFBLOCK_SIZE * 3);
dlen += MFBLOCK_SIZE * 3; dlen += MFBLOCK_SIZE * 3;
} }
@ -6860,8 +6941,8 @@ static int CmdHF14AMfView(const char *Cmd) {
} }
// convert_mfc_2_arr(pdump, bytes_read, d, &dlen); // convert_mfc_2_arr(pdump, bytes_read, d, &dlen);
vigik_annotate(d); vigik_annotate(d.vigik);
free(d); free(d.bytes);
} }
free(dump); free(dump);
@ -7325,7 +7406,7 @@ static int CmdHF14AGen4Save(const char *Cmd) {
char filename[FILE_PATH_SIZE]; char filename[FILE_PATH_SIZE];
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool fill_emulator = arg_get_lit(ctx,7); bool fill_emulator = arg_get_lit(ctx, 7);
CLIParserFree(ctx); CLIParserFree(ctx);
// validations // validations
@ -7533,7 +7614,6 @@ static int CmdHF14AMfValue(const char *Cmd) {
int64_t decval = (int64_t)arg_get_u64_def(ctx, 5, -1); // Inc by -1 is invalid, so not set. int64_t decval = (int64_t)arg_get_u64_def(ctx, 5, -1); // Inc by -1 is invalid, so not set.
int64_t setval = (int64_t)arg_get_u64_def(ctx, 6, 0x7FFFFFFFFFFFFFFF); // out of bounds (for int32) so not set int64_t setval = (int64_t)arg_get_u64_def(ctx, 6, 0x7FFFFFFFFFFFFFFF); // out of bounds (for int32) so not set
bool getval = arg_get_lit(ctx, 7); bool getval = arg_get_lit(ctx, 7);
uint8_t block[MFBLOCK_SIZE] = {0x00};
int dlen = 0; int dlen = 0;
uint8_t data[16] = {0}; uint8_t data[16] = {0};
CLIGetHexWithReturn(ctx, 9, data, &dlen); CLIGetHexWithReturn(ctx, 9, data, &dlen);
@ -7541,7 +7621,6 @@ static int CmdHF14AMfValue(const char *Cmd) {
uint8_t action = 3; // 0 Increment, 1 - Decrement, 2 - Set, 3 - Get, 4 - Decode from data uint8_t action = 3; // 0 Increment, 1 - Decrement, 2 - Set, 3 - Get, 4 - Decode from data
uint32_t value = 0; uint32_t value = 0;
uint8_t isok = true;
// Need to check we only have 1 of inc/dec/set and get the value from the selected option // Need to check we only have 1 of inc/dec/set and get the value from the selected option
int optionsprovided = 0; int optionsprovided = 0;
@ -7597,11 +7676,12 @@ static int CmdHF14AMfValue(const char *Cmd) {
} }
if (action < 3) { if (action < 3) {
uint8_t isok = true;
if (g_session.pm3_present == false) if (g_session.pm3_present == false)
return PM3_ENOTTY; return PM3_ENOTTY;
if (action <= 1) { // increment/decrement value if (action <= 1) { // increment/decrement value
uint8_t block[MFBLOCK_SIZE] = {0x00};
memcpy(block, (uint8_t *)&value, 4); memcpy(block, (uint8_t *)&value, 4);
uint8_t cmddata[26]; uint8_t cmddata[26];
memcpy(cmddata, key, sizeof(key)); // Key == 6 data went to 10, so lets offset 9 for inc/dec memcpy(cmddata, key, sizeof(key)); // Key == 6 data went to 10, so lets offset 9 for inc/dec

View file

@ -306,7 +306,7 @@ static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) {
} }
// ref: https://www.nxp.com/docs/en/application-note/AN12343.pdf p7 // ref: https://www.nxp.com/docs/en/application-note/AN12343.pdf p7
static nxp_producttype_t getProductType(uint8_t *versionhw) { static nxp_producttype_t getProductType(const uint8_t *versionhw) {
uint8_t product = versionhw[2]; uint8_t product = versionhw[2];
@ -323,7 +323,7 @@ static nxp_producttype_t getProductType(uint8_t *versionhw) {
return DESFIRE_UNKNOWN_PROD; return DESFIRE_UNKNOWN_PROD;
} }
static const char *getProductTypeStr(uint8_t *versionhw) { static const char *getProductTypeStr(const uint8_t *versionhw) {
uint8_t product = versionhw[2]; uint8_t product = versionhw[2];

View file

@ -65,7 +65,7 @@ static uint8_t default_3des_keys[][16] = {
static uint8_t default_pwd_pack[][4] = { static uint8_t default_pwd_pack[][4] = {
{0xFF, 0xFF, 0xFF, 0xFF}, // PACK 0x00,0x00 -- factory default {0xFF, 0xFF, 0xFF, 0xFF}, // PACK 0x00,0x00 -- factory default
{0x4E, 0x45, 0x78, 0x54}, {0x4E, 0x45, 0x78, 0x54}, // NExT
}; };
static uint32_t UL_TYPES_ARRAY[] = { static uint32_t UL_TYPES_ARRAY[] = {
@ -1144,6 +1144,46 @@ Lego Dimensions,
E1 10 12 00 01 03 A0 0C 34 03 13 D1 01 0F 54 02 65 6E E1 10 12 00 01 03 A0 0C 34 03 13 D1 01 0F 54 02 65 6E
*/ */
typedef struct {
const char *desc;
uint8_t mpos;
uint8_t mlen;
const char *match;
uint32_t (*otp)(const uint8_t *uid);
const char *hint;
} mfu_otp_identify_t;
static mfu_otp_identify_t mfu_otp_ident_table[] = {
{ "SALTO", 12, 4, "534C544F", ul_c_otpgenA, NULL },
// { "SAFLOK", 12, 4, NULL, ul_c_otpgenB, NULL },
// { "VINGCARD", 12, 4, NULL, ul_c_otpgenC, NULL },
// { "DORMA KABA", 12, 4, NULL, ul_c_otpgenD, NULL },
{ NULL, 0, 0, NULL, NULL, NULL }
};
static mfu_otp_identify_t *mfu_match_otp_fingerprint(uint8_t *data) {
uint8_t i = 0;
do {
int ml = 0;
uint8_t mtmp[40] = {0};
// static or dynamic created OTP to fingerprint.
if (mfu_otp_ident_table[i].match) {
param_gethex_to_eol(mfu_otp_ident_table[i].match, 0, mtmp, sizeof(mtmp), &ml);
} else {
uint32_t otp = mfu_otp_ident_table[i].otp(data);
num_to_bytes(otp, 4, mtmp);
}
bool m2 = (memcmp(mtmp, data + mfu_otp_ident_table[i].mpos, mfu_otp_ident_table[i].mlen) == 0);
if (m2) {
PrintAndLogEx(DEBUG, "(fingerprint) found %s", mfu_otp_ident_table[i].desc);
return &mfu_otp_ident_table[i];
}
} while (mfu_otp_ident_table[++i].desc);
return NULL;
}
typedef struct { typedef struct {
const char *desc; const char *desc;
const char *version; const char *version;
@ -1184,7 +1224,7 @@ static mfu_identify_t mfu_ident_table[] = {
"Snackworld", "0004040101000B03", "Snackworld", "0004040101000B03",
9, 7, "483000E1100600", 9, 7, "483000E1100600",
NULL, NULL, NULL, NULL,
"hf mfu dump -k %08x" "hf mfu dump -k"
}, },
{ {
"Amiibo", "0004040201001103", "Amiibo", "0004040201001103",
@ -1324,15 +1364,36 @@ static int mfu_fingerprint(TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authke
if (item) { if (item) {
PrintAndLogEx(SUCCESS, "Found " _GREEN_("%s"), item->desc); PrintAndLogEx(SUCCESS, "Found " _GREEN_("%s"), item->desc);
if (item->Pwd) { if (item->hint) {
if (item->Pwd) {
char s[40] = {0};
snprintf(s, sizeof(s), item->hint, item->Pwd(uid));
PrintAndLogEx(HINT, "Use `" _YELLOW_("%s") "`", s);
} else {
PrintAndLogEx(HINT, "Use `" _YELLOW_("%s") "`", item->hint);
}
}
}
}
// OTP checks
mfu_otp_identify_t *item = mfu_match_otp_fingerprint(data);
if (item) {
PrintAndLogEx(SUCCESS, "Found " _GREEN_("%s"), item->desc);
if (item->hint) {
if (item->otp) {
char s[40] = {0}; char s[40] = {0};
snprintf(s, sizeof(s), item->hint, item->Pwd(uid)); snprintf(s, sizeof(s), item->hint, item->otp(uid));
PrintAndLogEx(HINT, "Use `" _YELLOW_("%s") "`", s); PrintAndLogEx(HINT, "Use `" _YELLOW_("%s") "`", s);
} else { } else {
PrintAndLogEx(HINT, "Use `" _YELLOW_("%s") "`", item->hint); PrintAndLogEx(HINT, "Use `" _YELLOW_("%s") "`", item->hint);
} }
} }
} }
//
out: out:
free(data); free(data);
@ -3248,7 +3309,7 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
PrintAndLogEx(INFO, "----------------------------------"); PrintAndLogEx(INFO, "----------------------------------");
PrintAndLogEx(INFO, " algo | pwd | pack"); PrintAndLogEx(INFO, " algo | pwd | pack");
PrintAndLogEx(INFO, "-----------------+----------+-----"); PrintAndLogEx(INFO, "-----------------+----------+-----");
PrintAndLogEx(INFO, " EV1 | %08X | %04X", ul_ev1_pwdgenA(uid), ul_ev1_packgenA(uid)); PrintAndLogEx(INFO, " Transport EV1 | %08X | %04X", ul_ev1_pwdgenA(uid), ul_ev1_packgenA(uid));
PrintAndLogEx(INFO, " Amiibo | %08X | %04X", ul_ev1_pwdgenB(uid), ul_ev1_packgenB(uid)); PrintAndLogEx(INFO, " Amiibo | %08X | %04X", ul_ev1_pwdgenB(uid), ul_ev1_packgenB(uid));
PrintAndLogEx(INFO, " Lego Dimension | %08X | %04X", ul_ev1_pwdgenC(uid), ul_ev1_packgenC(uid)); PrintAndLogEx(INFO, " Lego Dimension | %08X | %04X", ul_ev1_pwdgenC(uid), ul_ev1_packgenC(uid));
PrintAndLogEx(INFO, " XYZ 3D printer | %08X | %04X", ul_ev1_pwdgenD(uid), ul_ev1_packgenD(uid)); PrintAndLogEx(INFO, " XYZ 3D printer | %08X | %04X", ul_ev1_pwdgenD(uid), ul_ev1_packgenD(uid));
@ -3256,6 +3317,9 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
PrintAndLogEx(INFO, " NTAG tools | %08X | %04X", ul_ev1_pwdgenF(uid), ul_ev1_packgen_def(uid)); PrintAndLogEx(INFO, " NTAG tools | %08X | %04X", ul_ev1_pwdgenF(uid), ul_ev1_packgen_def(uid));
PrintAndLogEx(INFO, "-----------------+----------+-----"); PrintAndLogEx(INFO, "-----------------+----------+-----");
PrintAndLogEx(INFO, " Vingcard algo"); PrintAndLogEx(INFO, " Vingcard algo");
PrintAndLogEx(INFO, " Saflok algo");
PrintAndLogEx(INFO, " SALTO algo");
PrintAndLogEx(INFO, " Dorma Kaba algo");
PrintAndLogEx(INFO, "----------------------------------"); PrintAndLogEx(INFO, "----------------------------------");
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -30,6 +30,7 @@
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription #include "iso7816/apduinfo.h" // GetAPDUCodeDescription
#include "crypto/asn1utils.h" // ASN1 decode / print #include "crypto/asn1utils.h" // ASN1 decode / print
#include "commonutil.h" // get_sw #include "commonutil.h" // get_sw
#include "protocols.h" // ISO7816 APDU return codes
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -55,7 +56,7 @@ static int seos_select(void) {
} }
uint16_t sw = get_sw(response, resplen); uint16_t sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting SEOS applet aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting SEOS applet aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -75,7 +76,7 @@ static int seos_select(void) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting ADF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting ADF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;

View file

@ -31,6 +31,7 @@
#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint #include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
#include "cmdnfc.h" // print_type4_cc_info #include "cmdnfc.h" // print_type4_cc_info
#include "commonutil.h" // get_sw #include "commonutil.h" // get_sw
#include "protocols.h" // ISO7816 APDU return codes
#define TIMEOUT 2000 #define TIMEOUT 2000
@ -136,7 +137,7 @@ static int infoHFST25TA(void) {
} }
uint16_t sw = get_sw(response, resplen); uint16_t sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -156,7 +157,7 @@ static int infoHFST25TA(void) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -172,7 +173,7 @@ static int infoHFST25TA(void) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -192,7 +193,7 @@ static int infoHFST25TA(void) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -210,7 +211,7 @@ static int infoHFST25TA(void) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "reading system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "reading system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -329,7 +330,7 @@ int CmdHFST25TANdefRead(const char *Cmd) {
} }
uint16_t sw = get_sw(response, resplen); uint16_t sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -349,7 +350,7 @@ int CmdHFST25TANdefRead(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -378,7 +379,7 @@ int CmdHFST25TANdefRead(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -397,7 +398,7 @@ int CmdHFST25TANdefRead(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -495,7 +496,7 @@ static int CmdHFST25TAProtect(const char *Cmd) {
} }
uint16_t sw = get_sw(response, resplen); uint16_t sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -515,7 +516,7 @@ static int CmdHFST25TAProtect(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -534,7 +535,7 @@ static int CmdHFST25TAProtect(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -553,7 +554,7 @@ static int CmdHFST25TAProtect(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -639,7 +640,7 @@ static int CmdHFST25TAPwd(const char *Cmd) {
} }
uint16_t sw = get_sw(response, resplen); uint16_t sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -659,7 +660,7 @@ static int CmdHFST25TAPwd(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -678,7 +679,7 @@ static int CmdHFST25TAPwd(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -699,7 +700,7 @@ static int CmdHFST25TAPwd(const char *Cmd) {
} }
sw = get_sw(response, resplen); sw = get_sw(response, resplen);
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "password change failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(ERR, "password change failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;

262
client/src/cmdhftesla.c Normal file
View file

@ -0,0 +1,262 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// High frequency ISO14443A / TESLA commands
//-----------------------------------------------------------------------------
#include "cmdhftesla.h"
#include <ctype.h>
#include <string.h>
#include "cmdparser.h" // command_t
#include "comms.h" // clearCommandBuffer
#include "cmdtrace.h"
#include "cliparser.h"
#include "cmdhf14a.h"
#include "protocols.h" // definitions of ISO14A/7816 protocol
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription
#include "commonutil.h" // get_sw
#include "protocols.h" // ISO7816 APDU return co-des
#include "ui.h"
#include "cmdhf14a.h" // apdu chaining
#define TIMEOUT 2000
static int CmdHelp(const char *Cmd);
/**
* 0x80 0x00 0x00 0x00 - get interface object
0x80 0x01 0x00 0x00 - load data from storage
0x80 0x02 KEY_INDEX 0x00 - initialize key pair
0x80 0x03 KEY_INDEX 0x00 - generate key pair
0x80 0x04 KEY_INDEX 0x00 - get public key
0x80 0x05 CRT_INDEX 0x00 - load certificate
0x80 0x06 CRT_INDEX 0x00 - get certificate
0x80 0x07 0x00 0x00 - get version
0x80 0x08 0x00 0x00 - confirm prepersonalization
0x80 0x10 KEY_INDEX 0x00 - sign challenge
0x80 0x11 KEY_INDEX 0x00 - dh key exchange
*/
// TESLA
static int info_hf_tesla(void) {
bool activate_field = true;
bool keep_field_on = true;
uint8_t response[PM3_CMD_DATA_SIZE];
int resplen = 0;
// --------------- Select TESLA application ----------------
uint8_t aSELECT_AID[80];
int aSELECT_AID_n = 0;
param_gethex_to_eol("00a404000a7465736c614c6f676963", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res != PM3_SUCCESS) {
DropField();
return PM3_ESOFT;
}
activate_field = false;
uint16_t sw = get_sw(response, resplen);
if ((resplen < 2) || (sw != ISO7816_OK)) {
param_gethex_to_eol("00a404000af465736c614c6f676963", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res != PM3_SUCCESS) {
DropField();
return res;
}
}
if ((resplen < 2) || (sw != ISO7816_OK)) {
PrintAndLogEx(ERR, "Selecting TESLA aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
// DropField();
// return PM3_ESOFT;
}
keep_field_on = true;
// --------------- ECDH public key file reading ----------------
uint8_t pk[3][65] = {{0}};
for (uint8_t i = 0; i < 3; i++) {
uint8_t aSELECT_PK[5] = {0x80, 0x04, i, 0x00, 0x00};
res = ExchangeAPDU14a(aSELECT_PK, sizeof(aSELECT_PK), activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res != PM3_SUCCESS) {
continue;
}
sw = get_sw(response, resplen);
if (sw == ISO7816_OK) {
memcpy(pk[i], response, resplen - 2);
}
}
uint8_t aREAD_FORM_FACTOR[30];
int aREAD_FORM_FACTOR_n = 0;
param_gethex_to_eol("80140000", 0, aREAD_FORM_FACTOR, sizeof(aREAD_FORM_FACTOR), &aREAD_FORM_FACTOR_n);
res = ExchangeAPDU14a(aREAD_FORM_FACTOR, aREAD_FORM_FACTOR_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res != PM3_SUCCESS) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "reading FORM FACTOR file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
// store form factor for later
uint8_t form_factor[resplen - 2];
memcpy(form_factor, response, sizeof(form_factor));
uint8_t aREAD_VERSION[30];
int aREAD_VERSION_n = 0;
param_gethex_to_eol("80170000", 0, aREAD_VERSION, sizeof(aREAD_VERSION), &aREAD_VERSION_n);
res = ExchangeAPDU14a(aREAD_VERSION, aREAD_VERSION_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res != PM3_SUCCESS) {
DropField();
return res;
}
uint8_t version[resplen - 2];
sw = get_sw(response, resplen);
if (sw == ISO7816_OK) {
// store version for later
memcpy(version, response, sizeof(version));
}
// --------------- CERT reading ----------------
Set_apdu_in_framing(true);
for (uint8_t i = 0; i < 4; i++) {
uint8_t aSELECT_CERT[PM3_CMD_DATA_SIZE] = {0x80, 0x06, i, 0x00, 0x00, 0x00, 0xFF};
int aSELECT_CERT_n = 7;
res = ExchangeAPDU14a(aSELECT_CERT, aSELECT_CERT_n, activate_field, keep_field_on, response, PM3_CMD_DATA_SIZE, &resplen);
if (res != PM3_SUCCESS) {
continue;
}
sw = get_sw(response, resplen);
if (sw == ISO7816_OK) {
// save CETT for later
uint8_t cert[515] = {0};
memcpy(cert, response, resplen - 2);
PrintAndLogEx(INFO, "CERT # %i", i);
PrintAndLogEx(INFO, "%s", sprint_hex_inrow(cert, resplen - 2));
}
}
Set_apdu_in_framing(false);
uint8_t aAUTH[90];
int aAUTH_n = 0;
// vehicle public key , 16 byte CHALLENGE
// 00112233445566778899AABBCCDDEEFF
// 0x51 = 81 dec
// param_gethex_to_eol("8011000051 046F08AE62526ABB5690643458152AC963CF5D7C113949F3C2453D1DDC6E4385B430523524045A22F5747BF236F1B5F60F0EA32DC2B8276D75ACDE9813EF77C330 00112233445566778899AABBCCDDEEFF", 0, aAUTH, sizeof(aAUTH), &aAUTH_n);
param_gethex_to_eol("8011000051046F08AE62526ABB5690643458152AC963CF5D7C113949F3C2453D1DDC6E4385B430523524045A22F5747BF236F1B5F60F0EA32DC2B8276D75ACDE9813EF77C33000112233445566778899AABBCCDDEEFF", 0, aAUTH, sizeof(aAUTH), &aAUTH_n);
res = ExchangeAPDU14a(aAUTH, aAUTH_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res != PM3_SUCCESS) {
DropField();
return res;
}
uint8_t auth[resplen - 2];
sw = get_sw(response, resplen);
if (sw == ISO7816_OK) {
// store CHALLENGE for later
memcpy(auth, response, sizeof(auth));
}
keep_field_on = false;
DropField();
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "PUBLIC KEY");
for (int i = 0; i < 3; i++) {
PrintAndLogEx(INFO, "%d - %s", i, sprint_hex_inrow(pk[i], 65));
}
if (form_factor[1] == 1) {
PrintAndLogEx(INFO, "Form factor... %s (card)", sprint_hex_inrow(form_factor, sizeof(form_factor)));
} else if (form_factor[1] == 2) {
PrintAndLogEx(INFO, "Form factor... %s (phone app)", sprint_hex_inrow(form_factor, sizeof(form_factor)));
}
if (sizeof(version) > 0) {
PrintAndLogEx(INFO, "Version....... %s", sprint_hex_inrow(version, sizeof(version)));
}
PrintAndLogEx(INFO, "CHALL......... %s", sprint_hex_inrow(auth, sizeof(auth)));
PrintAndLogEx(INFO, "Fingerprint");
if ((memcmp(pk[0], pk[1], 65) == 0)) {
PrintAndLogEx(INFO, " GaussKey detected");
}
//
return PM3_SUCCESS;
}
// menu command to get and print all info known about any known ST25TA tag
static int CmdHFTeslaInfo(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf telsa info",
"Get info about TESLA Key tag",
"hf tesla info"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return info_hf_tesla();
}
static int CmdHFTeslaList(const char *Cmd) {
return CmdTraceListAlias(Cmd, "hf tesla", "7816");
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"info", CmdHFTeslaInfo, IfPm3Iso14443a, "Tag information"},
{"list", CmdHFTeslaList, AlwaysAvailable, "List ISO 14443A/7816 history"},
{NULL, NULL, NULL, NULL}
};
static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CmdsHelp(CommandTable);
return PM3_SUCCESS;
}
int CmdHFTESLA(const char *Cmd) {
clearCommandBuffer();
return CmdsParse(CommandTable, Cmd);
}

26
client/src/cmdhftesla.h Normal file
View file

@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// High frequency ISO14443A / TESLA commands
//-----------------------------------------------------------------------------
#ifndef CMDHFTESLA_H__
#define CMDHFTESLA_H__
#include "common.h"
int CmdHFTESLA(const char *Cmd);
#endif

View file

@ -311,7 +311,7 @@ static bool TexcomTK15Decode(uint32_t *implengths, uint32_t implengthslen, char
bool prevbit = (implengths[implengthslen - 3] > implengths[implengthslen - 2]); bool prevbit = (implengths[implengthslen - 3] > implengths[implengthslen - 2]);
bool thesamebit = (abs(lastimplen - (int)implengths[implengthslen - 3]) < abs(lastimplen - (int)implengths[implengthslen - 2])); bool thesamebit = (abs(lastimplen - (int)implengths[implengthslen - 3]) < abs(lastimplen - (int)implengths[implengthslen - 2]));
if (prevbit ^ !thesamebit) { if (prevbit ^ (!thesamebit)) {
strcat(bitstring, "10"); strcat(bitstring, "10");
strcat(cbitstring, "1"); strcat(cbitstring, "1");
} else { } else {

View file

@ -292,7 +292,7 @@ static bool topaz_byte_is_locked(uint16_t byteno) {
} }
} }
static int topaz_set_cc_dynamic(uint8_t *data) { static int topaz_set_cc_dynamic(const uint8_t *data) {
if (data[0] != 0xE1) { if (data[0] != 0xE1) {
topaz_tag.size = TOPAZ_STATIC_MEMORY; topaz_tag.size = TOPAZ_STATIC_MEMORY;
@ -583,9 +583,7 @@ static void topaz_print_lifecycle_state(uint8_t *data) {
// to be done // to be done
} }
static void printTopazDumpContents(uint8_t *dump, size_t size) { static void printTopazDumpContents(topaz_tag_t *dump) {
topaz_tag_t *t = (topaz_tag_t *)dump;
// uses a global var for all // uses a global var for all
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
@ -608,14 +606,14 @@ static void printTopazDumpContents(uint8_t *dump, size_t size) {
PrintAndLogEx(SUCCESS, " %3u / 0x%02x | %s| %s | %s", PrintAndLogEx(SUCCESS, " %3u / 0x%02x | %s| %s | %s",
i, i,
i, i,
sprint_hex(&t->data_blocks[i][0], 8), sprint_hex(&dump->data_blocks[i][0], 8),
lockstr, lockstr,
block_info block_info
); );
} }
PrintAndLogEx(SUCCESS, " %3u / 0x%02x | %s| | %s", 0x0D, 0x0D, sprint_hex(&t->data_blocks[0x0D][0], 8), topaz_ks[2]); PrintAndLogEx(SUCCESS, " %3u / 0x%02x | %s| | %s", 0x0D, 0x0D, sprint_hex(&dump->data_blocks[0x0D][0], 8), topaz_ks[2]);
PrintAndLogEx(SUCCESS, " %3u / 0x%02x | %s| | %s", 0x0E, 0x0E, sprint_hex(&t->data_blocks[0x0E][0], 8), topaz_ks[3]); PrintAndLogEx(SUCCESS, " %3u / 0x%02x | %s| | %s", 0x0E, 0x0E, sprint_hex(&dump->data_blocks[0x0E][0], 8), topaz_ks[3]);
PrintAndLogEx(SUCCESS, "------------+-------------------------+---+------------"); PrintAndLogEx(SUCCESS, "------------+-------------------------+---+------------");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
} }
@ -797,7 +795,7 @@ static int CmdHFTopazDump(const char *Cmd) {
if (status != PM3_SUCCESS) { if (status != PM3_SUCCESS) {
return status; return status;
} }
printTopazDumpContents((uint8_t *)&topaz_tag, sizeof(topaz_tag_t)); printTopazDumpContents(&topaz_tag);
bool set_dynamic = false; bool set_dynamic = false;
if (topaz_set_cc_dynamic(&topaz_tag.data_blocks[1][0]) == PM3_SUCCESS) { if (topaz_set_cc_dynamic(&topaz_tag.data_blocks[1][0]) == PM3_SUCCESS) {
@ -853,14 +851,17 @@ static int CmdHFTopazView(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
// read dump file // read dump file
uint8_t *dump = NULL; topaz_tag_t *dump = NULL;
size_t bytes_read = TOPAZ_MAX_SIZE; size_t bytes_read = TOPAZ_MAX_SIZE;
int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, sizeof(topaz_tag_t) + TOPAZ_MAX_SIZE); int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, sizeof(topaz_tag_t) + TOPAZ_MAX_SIZE);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
return res; return res;
} }
if (bytes_read < sizeof(topaz_tag_t)) {
printTopazDumpContents(dump, bytes_read); free(dump);
return PM3_EFAILED;
}
printTopazDumpContents(dump);
if (topaz_set_cc_dynamic(&topaz_tag.data_blocks[1][0]) == PM3_SUCCESS) { if (topaz_set_cc_dynamic(&topaz_tag.data_blocks[1][0]) == PM3_SUCCESS) {

View file

@ -660,7 +660,6 @@ static int start_drawing_1in54B(uint8_t model_nr, uint8_t *black, uint8_t *red)
} }
static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) { static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
uint8_t progress;
uint8_t step0[2] = {0xcd, 0x0d}; uint8_t step0[2] = {0xcd, 0x0d};
uint8_t step1[3] = {0xcd, 0x00, 10}; // select e-paper type and reset e-paper uint8_t step1[3] = {0xcd, 0x00, 10}; // select e-paper type and reset e-paper
// 4 :2.13inch e-Paper // 4 :2.13inch e-Paper
@ -687,7 +686,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
// uint8_t step13[2]={0xcd,0x0b}; // Judge whether the power supply is turned off successfully // uint8_t step13[2]={0xcd,0x0b}; // Judge whether the power supply is turned off successfully
// uint8_t step14[2]={0xcd,0x0c}; // The end of the transmission // uint8_t step14[2]={0xcd,0x0c}; // The end of the transmission
uint8_t rx[20]; uint8_t rx[20];
uint16_t actrxlen[20], i; uint16_t actrxlen[20];
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
@ -812,6 +811,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
} }
// 1.54B Data transfer is complete and wait for refresh // 1.54B Data transfer is complete and wait for refresh
} else { } else {
uint8_t progress;
PrintAndLogEx(DEBUG, "Step5: e-paper config2"); PrintAndLogEx(DEBUG, "Step5: e-paper config2");
ret = transceive_blocking(step5, 2, rx, 20, actrxlen, true); // cd 05 ret = transceive_blocking(step5, 2, rx, 20, actrxlen, true); // cd 05
if (ret != PM3_SUCCESS) { if (ret != PM3_SUCCESS) {
@ -831,7 +831,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
} }
PrintAndLogEx(DEBUG, "Step8: Start data transfer"); PrintAndLogEx(DEBUG, "Step8: Start data transfer");
if (model_nr == M2in13) { // 2.13inch if (model_nr == M2in13) { // 2.13inch
for (i = 0; i < 250; i++) { for (uint16_t i = 0; i < 250; i++) {
read_black(i, step8, model_nr, black); read_black(i, step8, model_nr, black);
ret = transceive_blocking(step8, 19, rx, 20, actrxlen, true); // cd 08 ret = transceive_blocking(step8, 19, rx, 20, actrxlen, true); // cd 08
if (ret != PM3_SUCCESS) { if (ret != PM3_SUCCESS) {
@ -841,7 +841,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
PrintAndLogEx(INPLACE, "Progress: %d %%", progress); PrintAndLogEx(INPLACE, "Progress: %d %%", progress);
} }
} else if (model_nr == M2in9) { } else if (model_nr == M2in9) {
for (i = 0; i < 296; i++) { for (uint16_t i = 0; i < 296; i++) {
read_black(i, step8, model_nr, black); read_black(i, step8, model_nr, black);
ret = transceive_blocking(step8, 19, rx, 20, actrxlen, true); // cd 08 ret = transceive_blocking(step8, 19, rx, 20, actrxlen, true); // cd 08
if (ret != PM3_SUCCESS) { if (ret != PM3_SUCCESS) {
@ -851,7 +851,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
PrintAndLogEx(INPLACE, "Progress: %d %%", progress); PrintAndLogEx(INPLACE, "Progress: %d %%", progress);
} }
} else if (model_nr == M4in2) { //4.2inch } else if (model_nr == M4in2) { //4.2inch
for (i = 0; i < 150; i++) { for (uint16_t i = 0; i < 150; i++) {
read_black(i, step8, model_nr, black); read_black(i, step8, model_nr, black);
ret = transceive_blocking(step8, 103, rx, 20, actrxlen, true); // cd 08 ret = transceive_blocking(step8, 103, rx, 20, actrxlen, true); // cd 08
if (ret != PM3_SUCCESS) { if (ret != PM3_SUCCESS) {
@ -861,7 +861,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
PrintAndLogEx(INPLACE, "Progress: %d %%", progress); PrintAndLogEx(INPLACE, "Progress: %d %%", progress);
} }
} else if (model_nr == M7in5) { //7.5inch } else if (model_nr == M7in5) { //7.5inch
for (i = 0; i < 400; i++) { for (uint16_t i = 0; i < 400; i++) {
read_black(i, step8, model_nr, black); read_black(i, step8, model_nr, black);
ret = transceive_blocking(step8, 123, rx, 20, actrxlen, true); // cd 08 ret = transceive_blocking(step8, 123, rx, 20, actrxlen, true); // cd 08
if (ret != PM3_SUCCESS) { if (ret != PM3_SUCCESS) {
@ -872,7 +872,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
msleep(6); msleep(6);
} }
} else if (model_nr == M2in13B) { //2.13inch B } else if (model_nr == M2in13B) { //2.13inch B
for (i = 0; i < 26; i++) { for (uint16_t i = 0; i < 26; i++) {
read_black(i, step8, model_nr, black); read_black(i, step8, model_nr, black);
ret = transceive_blocking(step8, 109, rx, 20, actrxlen, false); // cd 08 ret = transceive_blocking(step8, 109, rx, 20, actrxlen, false); // cd 08
if (ret != PM3_SUCCESS) { if (ret != PM3_SUCCESS) {
@ -883,7 +883,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
} }
} else if (model_nr == M7in5HD) { //7.5HD } else if (model_nr == M7in5HD) { //7.5HD
for (i = 0; i < 484; i++) { for (uint16_t i = 0; i < 484; i++) {
read_black(i, step8, model_nr, black); read_black(i, step8, model_nr, black);
//memset(&step8[3], 0xf0, 120); //memset(&step8[3], 0xf0, 120);
ret = transceive_blocking(step8, 123, rx, 20, actrxlen, true); // cd 08 ret = transceive_blocking(step8, 123, rx, 20, actrxlen, true); // cd 08
@ -899,7 +899,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
return ret; return ret;
} }
} else if (model_nr == M2in7) { //2.7inch } else if (model_nr == M2in7) { //2.7inch
for (i = 0; i < 48; i++) { for (uint16_t i = 0; i < 48; i++) {
//read_black(i,step8, model_nr, black); //read_black(i,step8, model_nr, black);
memset(&step8[3], 0xFF, sizeof(step8) - 3); memset(&step8[3], 0xFF, sizeof(step8) - 3);
ret = transceive_blocking(step8, 124, rx, 20, actrxlen, true); // cd 08 ret = transceive_blocking(step8, 124, rx, 20, actrxlen, true); // cd 08
@ -925,7 +925,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
} }
PrintAndLogEx(DEBUG, "Step9b"); PrintAndLogEx(DEBUG, "Step9b");
if (model_nr == M2in7) { if (model_nr == M2in7) {
for (i = 0; i < 48; i++) { for (uint16_t i = 0; i < 48; i++) {
read_black(i, step13, model_nr, black); read_black(i, step13, model_nr, black);
ret = transceive_blocking(step13, 124, rx, 20, actrxlen, true); //CD 19 ret = transceive_blocking(step13, 124, rx, 20, actrxlen, true); //CD 19
if (ret != PM3_SUCCESS) { if (ret != PM3_SUCCESS) {
@ -935,7 +935,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
PrintAndLogEx(INPLACE, "Progress: %d %%", progress); PrintAndLogEx(INPLACE, "Progress: %d %%", progress);
} }
} else if (model_nr == M2in13B) { } else if (model_nr == M2in13B) {
for (i = 0; i < 26; i++) { for (uint16_t i = 0; i < 26; i++) {
read_red(i, step13, model_nr, red); read_red(i, step13, model_nr, red);
//memset(&step13[3], 0xfE, 106); //memset(&step13[3], 0xfE, 106);
ret = transceive_blocking(step13, 109, rx, 20, actrxlen, false); ret = transceive_blocking(step13, 109, rx, 20, actrxlen, false);

View file

@ -15,77 +15,77 @@
#define TIMEOUT 2000 #define TIMEOUT 2000
#define c2l(c,l) (l = ((unsigned long)(*((c)++))), \ #define c2l(c,l) (l = ((unsigned long)(*((c)++))), \
l |= ((unsigned long)(*((c)++))) << 8L, \ l |= ((unsigned long)(*((c)++))) << 8L, \
l |= ((unsigned long)(*((c)++))) << 16L, \ l |= ((unsigned long)(*((c)++))) << 16L, \
l |= ((unsigned long)(*((c)++))) << 24L) l |= ((unsigned long)(*((c)++))) << 24L)
/* NOTE - c is not incremented as per c2l */ /* NOTE - c is not incremented as per c2l */
#define c2ln(c,l1,l2,n) { \ #define c2ln(c,l1,l2,n) { \
c += n; \ c += n; \
l1 = l2 = 0; \ l1 = l2 = 0; \
switch (n) { \ switch (n) { \
case 8: l2 = ((unsigned long)(*(--(c)))) << 24L; \ case 8: l2 = ((unsigned long)(*(--(c)))) << 24L; \
case 7: l2 |= ((unsigned long)(*(--(c)))) << 16L; \ case 7: l2 |= ((unsigned long)(*(--(c)))) << 16L; \
case 6: l2 |= ((unsigned long)(*(--(c)))) << 8L; \ case 6: l2 |= ((unsigned long)(*(--(c)))) << 8L; \
case 5: l2 |= ((unsigned long)(*(--(c)))); \ case 5: l2 |= ((unsigned long)(*(--(c)))); \
case 4: l1 = ((unsigned long)(*(--(c)))) << 24L; \ case 4: l1 = ((unsigned long)(*(--(c)))) << 24L; \
case 3: l1 |= ((unsigned long)(*(--(c)))) << 16L; \ case 3: l1 |= ((unsigned long)(*(--(c)))) << 16L; \
case 2: l1 |= ((unsigned long)(*(--(c)))) << 8L; \ case 2: l1 |= ((unsigned long)(*(--(c)))) << 8L; \
case 1: l1 |= ((unsigned long)(*(--(c)))); \ case 1: l1 |= ((unsigned long)(*(--(c)))); \
} \ } \
} }
#define l2c(l,c) (*((c)++) = (uint8_t)(((l)) & 0xff), \ #define l2c(l,c) (*((c)++) = (uint8_t)(((l)) & 0xff), \
*((c)++) = (uint8_t)(((l) >> 8L) & 0xff), \ *((c)++) = (uint8_t)(((l) >> 8L) & 0xff), \
*((c)++) = (uint8_t)(((l) >> 16L) & 0xff), \ *((c)++) = (uint8_t)(((l) >> 16L) & 0xff), \
*((c)++) = (uint8_t)(((l) >> 24L) & 0xff)) *((c)++) = (uint8_t)(((l) >> 24L) & 0xff))
/* NOTE - c is not incremented as per l2c */ /* NOTE - c is not incremented as per l2c */
#define l2cn(l1,l2,c,n) { \ #define l2cn(l1,l2,c,n) { \
c += n; \ c += n; \
switch (n) { \ switch (n) { \
case 8: *(--(c)) = (uint8_t)(((l2) >> 24L) & 0xff); \ case 8: *(--(c)) = (uint8_t)(((l2) >> 24L) & 0xff); \
case 7: *(--(c)) = (uint8_t)(((l2) >> 16L) & 0xff); \ case 7: *(--(c)) = (uint8_t)(((l2) >> 16L) & 0xff); \
case 6: *(--(c)) = (uint8_t)(((l2) >> 8L) & 0xff); \ case 6: *(--(c)) = (uint8_t)(((l2) >> 8L) & 0xff); \
case 5: *(--(c)) = (uint8_t)(((l2)) & 0xff); \ case 5: *(--(c)) = (uint8_t)(((l2)) & 0xff); \
case 4: *(--(c)) = (uint8_t)(((l1) >> 24L) & 0xff); \ case 4: *(--(c)) = (uint8_t)(((l1) >> 24L) & 0xff); \
case 3: *(--(c)) = (uint8_t)(((l1) >> 16L) & 0xff); \ case 3: *(--(c)) = (uint8_t)(((l1) >> 16L) & 0xff); \
case 2: *(--(c)) = (uint8_t)(((l1) >> 8L) & 0xff); \ case 2: *(--(c)) = (uint8_t)(((l1) >> 8L) & 0xff); \
case 1: *(--(c)) = (uint8_t)(((l1)) & 0xff); \ case 1: *(--(c)) = (uint8_t)(((l1)) & 0xff); \
} \ } \
} }
/* NOTE - c is not incremented as per n2l */ /* NOTE - c is not incremented as per n2l */
#define n2ln(c,l1,l2,n) { \ #define n2ln(c,l1,l2,n) { \
c += n; \ c += n; \
l1 = l2 = 0; \ l1 = l2 = 0; \
switch (n) { \ switch (n) { \
case 8: l2 = ((unsigned long)(*(--(c)))); \ case 8: l2 = ((unsigned long)(*(--(c)))); \
case 7: l2 |= ((unsigned long)(*(--(c)))) << 8; \ case 7: l2 |= ((unsigned long)(*(--(c)))) << 8; \
case 6: l2 |= ((unsigned long)(*(--(c)))) << 16; \ case 6: l2 |= ((unsigned long)(*(--(c)))) << 16; \
case 5: l2 |= ((unsigned long)(*(--(c)))) << 24; \ case 5: l2 |= ((unsigned long)(*(--(c)))) << 24; \
case 4: l1 = ((unsigned long)(*(--(c)))); \ case 4: l1 = ((unsigned long)(*(--(c)))); \
case 3: l1 |= ((unsigned long)(*(--(c)))) << 8; \ case 3: l1 |= ((unsigned long)(*(--(c)))) << 8; \
case 2: l1 |= ((unsigned long)(*(--(c)))) << 16; \ case 2: l1 |= ((unsigned long)(*(--(c)))) << 16; \
case 1: l1 |= ((unsigned long)(*(--(c)))) << 24; \ case 1: l1 |= ((unsigned long)(*(--(c)))) << 24; \
} \ } \
} }
/* NOTE - c is not incremented as per l2n */ /* NOTE - c is not incremented as per l2n */
#define l2nn(l1,l2,c,n) { \ #define l2nn(l1,l2,c,n) { \
c+=n; \ c+=n; \
switch (n) { \ switch (n) { \
case 8: *(--(c)) = (uint8_t)(((l2)) & 0xff); \ case 8: *(--(c)) = (uint8_t)(((l2)) & 0xff); \
case 7: *(--(c)) = (uint8_t)(((l2) >> 8) & 0xff); \ case 7: *(--(c)) = (uint8_t)(((l2) >> 8) & 0xff); \
case 6: *(--(c)) = (uint8_t)(((l2) >> 16) & 0xff); \ case 6: *(--(c)) = (uint8_t)(((l2) >> 16) & 0xff); \
case 5: *(--(c)) = (uint8_t)(((l2) >> 24) & 0xff); \ case 5: *(--(c)) = (uint8_t)(((l2) >> 24) & 0xff); \
case 4: *(--(c)) = (uint8_t)(((l1)) & 0xff); \ case 4: *(--(c)) = (uint8_t)(((l1)) & 0xff); \
case 3: *(--(c)) = (uint8_t)(((l1) >> 8) & 0xff); \ case 3: *(--(c)) = (uint8_t)(((l1) >> 8) & 0xff); \
case 2: *(--(c)) = (uint8_t)(((l1) >> 16) & 0xff); \ case 2: *(--(c)) = (uint8_t)(((l1) >> 16) & 0xff); \
case 1: *(--(c)) = (uint8_t)(((l1) >> 24) & 0xff); \ case 1: *(--(c)) = (uint8_t)(((l1) >> 24) & 0xff); \
} \ } \
} }
#define n2l(c,l) (l = ((unsigned long)(*((c)++))) << 24L, \ #define n2l(c,l) (l = ((unsigned long)(*((c)++))) << 24L, \
l |= ((unsigned long)(*((c)++))) << 16L, \ l |= ((unsigned long)(*((c)++))) << 16L, \
@ -98,17 +98,17 @@
*((c)++) = (uint8_t)(((l)) & 0xff)) *((c)++) = (uint8_t)(((l)) & 0xff))
#define C_RC2(n) \ #define C_RC2(n) \
t = (x0 + (x1 & ~x3) + (x2 & x3) + *(p0++)) & 0xffff; \ t = (x0 + (x1 & ~x3) + (x2 & x3) + *(p0++)) & 0xffff; \
x0 = (t << 1) | (t >> 15); \ x0 = (t << 1) | (t >> 15); \
t = (x1 + (x2 & ~x0) + (x3 & x0) + *(p0++)) & 0xffff; \ t = (x1 + (x2 & ~x0) + (x3 & x0) + *(p0++)) & 0xffff; \
x1 = (t << 2) | (t >> 14); \ x1 = (t << 2) | (t >> 14); \
t = (x2 + (x3 & ~x1) + (x0 & x1) + *(p0++)) & 0xffff; \ t = (x2 + (x3 & ~x1) + (x0 & x1) + *(p0++)) & 0xffff; \
x2 = (t << 3) | (t >> 13); \ x2 = (t << 3) | (t >> 13); \
t = (x3 + (x0 & ~x2) + (x1 & x2) + *(p0++)) & 0xffff; \ t = (x3 + (x0 & ~x2) + (x1 & x2) + *(p0++)) & 0xffff; \
x3 = (t << 5) | (t >> 11); x3 = (t << 5) | (t >> 11);
#define RC2_ENCRYPT 1 #define RC2_ENCRYPT 1
#define RC2_DECRYPT 0 #define RC2_DECRYPT 0
typedef unsigned int RC2_INT; typedef unsigned int RC2_INT;
@ -202,7 +202,7 @@ void RC2_set_key(RC2_KEY *key, int len, const unsigned char *data, int bits) {
void RC2_encrypt(unsigned long *d, RC2_KEY *key) { void RC2_encrypt(unsigned long *d, RC2_KEY *key) {
int i, n; int i, n;
register RC2_INT *p0, *p1; register RC2_INT *p0, *p1;
register RC2_INT x0, x1, x2, x3, t; register RC2_INT x0, x1, x2, x3;
unsigned long l; unsigned long l;
l = d[0]; l = d[0];
@ -217,7 +217,7 @@ void RC2_encrypt(unsigned long *d, RC2_KEY *key) {
p0 = p1 = &(key->data[0]); p0 = p1 = &(key->data[0]);
for (;;) { for (;;) {
t = (x0 + (x1 & ~x3) + (x2 & x3) + * (p0++)) & 0xffff; register RC2_INT t = (x0 + (x1 & ~x3) + (x2 & x3) + * (p0++)) & 0xffff;
x0 = (t << 1) | (t >> 15); x0 = (t << 1) | (t >> 15);
t = (x1 + (x2 & ~x0) + (x3 & x0) + * (p0++)) & 0xffff; t = (x1 + (x2 & ~x0) + (x3 & x0) + * (p0++)) & 0xffff;
x1 = (t << 2) | (t >> 14); x1 = (t << 2) | (t >> 14);
@ -244,7 +244,7 @@ void RC2_encrypt(unsigned long *d, RC2_KEY *key) {
void RC2_decrypt(unsigned long *d, RC2_KEY *key) { void RC2_decrypt(unsigned long *d, RC2_KEY *key) {
int i, n; int i, n;
register RC2_INT *p0, *p1; register RC2_INT *p0, *p1;
register RC2_INT x0, x1, x2, x3, t; register RC2_INT x0, x1, x2, x3;
unsigned long l; unsigned long l;
l = d[0]; l = d[0];
@ -260,7 +260,7 @@ void RC2_decrypt(unsigned long *d, RC2_KEY *key) {
p0 = &(key->data[63]); p0 = &(key->data[63]);
p1 = &(key->data[0]); p1 = &(key->data[0]);
for (;;) { for (;;) {
t = ((x3 << 11) | (x3 >> 5)) & 0xffff; register RC2_INT t = ((x3 << 11) | (x3 >> 5)) & 0xffff;
x3 = (t - (x0 & ~x2) - (x1 & x2) - * (p0--)) & 0xffff; x3 = (t - (x0 & ~x2) - (x1 & x2) - * (p0--)) & 0xffff;
t = ((x2 << 13) | (x2 >> 3)) & 0xffff; t = ((x2 << 13) | (x2 >> 3)) & 0xffff;
x2 = (t - (x3 & ~x1) - (x0 & x1) - * (p0--)) & 0xffff; x2 = (t - (x3 & ~x1) - (x0 & x1) - * (p0--)) & 0xffff;
@ -533,8 +533,8 @@ static int CmdHFXeroxInfo(const char *Cmd) {
packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW); packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW);
packet->rawlen = 11; packet->rawlen = 11;
packet->raw[0] = 0x02; packet->raw[0] = 0x02;
packet->raw[1] = 0x20; // set command: read mem packet->raw[1] = 0x20; // set command: read mem
memcpy(packet->raw + 2, card.uid, 8); // store uid memcpy(packet->raw + 2, card.uid, 8); // store uid
for (int retry = 0; (retry < 5 && blocknum < sizeof(info_blocks)); retry++) { for (int retry = 0; (retry < 5 && blocknum < sizeof(info_blocks)); retry++) {
@ -623,7 +623,7 @@ static int CmdHFXeroxDump(const char *Cmd) {
} }
iso14b_card_select_t card; iso14b_card_select_t card;
int status = findXerox(&card, false); // remain RF on int status = findXerox(&card, false); // remain RF on
if (status != PM3_SUCCESS) { if (status != PM3_SUCCESS) {
free(packet); free(packet);
switch_off_field(); switch_off_field();
@ -632,20 +632,20 @@ static int CmdHFXeroxDump(const char *Cmd) {
PrintAndLogEx(INFO, "Reading memory from tag UID " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(INFO, "Reading memory from tag UID " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
int blocknum = 1; // block 0 all zeros int blocknum = 1; // block 0 all zeros
uint8_t data[256 * 4] = {0}; uint8_t data[256 * 4] = {0};
// set up the read command // set up the read command
packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW); packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW);
packet->rawlen = 11; packet->rawlen = 11;
packet->raw[0] = 0x02; packet->raw[0] = 0x02;
memcpy(packet->raw + 2, card.uid, 8); // store uid memcpy(packet->raw + 2, card.uid, 8); // store uid
PrintAndLogEx(INFO, "." NOLF); PrintAndLogEx(INFO, "." NOLF);
for (int retry = 0; (retry < 5 && blocknum < 0x100); retry++) { for (int retry = 0; (retry < 5 && blocknum < 0x100); retry++) {
packet->raw[1] = (blocknum < 12) ? 0x30 : 0x20; // set command: read ext mem or read mem packet->raw[1] = (blocknum < 12) ? 0x30 : 0x20; // set command: read ext mem or read mem
packet->raw[10] = blocknum & 0xFF; packet->raw[10] = blocknum & 0xFF;
PacketResponseNG resp; PacketResponseNG resp;
@ -657,7 +657,7 @@ static int CmdHFXeroxDump(const char *Cmd) {
resp.cmd, resp.length, resp.magic, resp.status, resp.crc, resp.oldarg[0], resp.oldarg[1], resp.oldarg[2], resp.cmd, resp.length, resp.magic, resp.status, resp.crc, resp.oldarg[0], resp.oldarg[1], resp.oldarg[2],
resp.data.asBytes[0], resp.data.asBytes[1], resp.data.asBytes[2], resp.ng ? 't' : 'f'); resp.data.asBytes[0], resp.data.asBytes[1], resp.data.asBytes[2], resp.ng ? 't' : 'f');
*/ */
if (/*resp.status != 0 ||*/ resp.length < 7) { // 14b raw command send data_len instead of status if (/*resp.status != 0 ||*/ resp.length < 7) { // 14b raw command send data_len instead of status
PrintAndLogEx(FAILED, "retrying one more time"); PrintAndLogEx(FAILED, "retrying one more time");
continue; continue;
} }
@ -722,8 +722,8 @@ static int CmdHFXeroxDump(const char *Cmd) {
memcpy(k1, k2, sizeof(k1)); memcpy(k1, k2, sizeof(k1));
k1[2] = k2[3] ^ data[0x22 * 4 + 0]; k1[2] = k2[3] ^ data[0x22 * 4 + 0];
k1[3] = k2[4] ^ data[0x22 * 4 + 1]; // first_key[7]; k1[3] = k2[4] ^ data[0x22 * 4 + 1]; // first_key[7];
k1[5] = k2[1] ^ 0x01; // 01 = crypto method? rfid[23][2] k1[5] = k2[1] ^ 0x01; // 01 = crypto method? rfid[23][2]
RC2_set_key(&exp_key, 8, k1, 64); RC2_set_key(&exp_key, 8, k1, 64);
@ -747,7 +747,7 @@ static int CmdHFXeroxDump(const char *Cmd) {
uint16_t cs, csd; uint16_t cs, csd;
// calc checksum // calc checksum
for (b = 0, cs = 0; b < sizeof(decr) - 2; b += 2) cs += decr[b] | (decr[b + 1] << 8); for (b = 0, cs = 0; b < sizeof(decr) - 2; b += 2) cs += decr[b] | (decr[b + 1] << 8);
cs = ~cs; cs = ~cs;
csd = (decr[7] << 8) | decr[6]; csd = (decr[7] << 8) | decr[6];
@ -772,7 +772,7 @@ static int CmdHFXeroxDump(const char *Cmd) {
PrintAndLogEx(INFO, "---------+--------------+----------"); PrintAndLogEx(INFO, "---------+--------------+----------");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
if (0 == filename[0]) { // generate filename from uid if (0 == filename[0]) { // generate filename from uid
/* /*
PrintAndLogEx(INFO, "Using UID as filename"); PrintAndLogEx(INFO, "Using UID as filename");

View file

@ -592,12 +592,12 @@ static int CmdLCD(const char *Cmd) {
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
int r_len = 0; int r_len = 0;
uint8_t raw[1] = {0}; uint8_t raw[1] = {0};
CLIGetHexWithReturn(ctx, 1, raw, &r_len); CLIGetHexWithReturn(ctx, 1, raw, &r_len);
int j = arg_get_int_def(ctx, 2, 1); int j = arg_get_int_def(ctx, 2, 1);
CLIParserFree(ctx);
if (j < 1) { if (j < 1) {
PrintAndLogEx(WARNING, "Count must be larger than zero"); PrintAndLogEx(WARNING, "Count must be larger than zero");
return PM3_EINVARG; return PM3_EINVARG;

View file

@ -229,6 +229,8 @@ void printEM410x(uint32_t hi, uint64_t id, bool verbose, int type) {
uint8_t sebury2 = (id >> 16) & 0x7F; uint8_t sebury2 = (id >> 16) & 0x7F;
uint32_t sebury3 = id & 0x7FFFFF; uint32_t sebury3 = id & 0x7FFFFF;
PrintAndLogEx(SUCCESS, "Pattern Sebury : %d %d %d [0x%X 0x%X 0x%X]", sebury1, sebury2, sebury3, sebury1, sebury2, sebury3); PrintAndLogEx(SUCCESS, "Pattern Sebury : %d %d %d [0x%X 0x%X 0x%X]", sebury1, sebury2, sebury3, sebury1, sebury2, sebury3);
PrintAndLogEx(SUCCESS, "VD / ID : %03" PRIu64 " / %010" PRIu64, (id >> 32LL) & 0xFFFF, (id & 0xFFFFFFFF));
PrintAndLogEx(INFO, "------------------------------------------------"); PrintAndLogEx(INFO, "------------------------------------------------");
} }
} }
@ -672,11 +674,6 @@ static int CmdEM410xClone(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
char cardtype[16] = {"T55x7"};
if (q5) {
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
}
PrintAndLogEx(SUCCESS, "Preparing to clone EM4102 to " _YELLOW_("%s") " tag with EM Tag ID " _GREEN_("%010" PRIX64) " (RF/%d)", q5 ? "Q5/T5555" : (em ? "EM4305/4469" : "T55x7"), id, clk); PrintAndLogEx(SUCCESS, "Preparing to clone EM4102 to " _YELLOW_("%s") " tag with EM Tag ID " _GREEN_("%010" PRIX64) " (RF/%d)", q5 ? "Q5/T5555" : (em ? "EM4305/4469" : "T55x7"), id, clk);
struct { struct {

View file

@ -41,6 +41,7 @@
#include "generator.h" #include "generator.h"
#include "cliparser.h" #include "cliparser.h"
#include "cmdhw.h" #include "cmdhw.h"
#include "util.h"
//////////////// 4205 / 4305 commands //////////////// 4205 / 4305 commands
@ -1996,8 +1997,7 @@ int CmdEM4x05Sniff(const char *Cmd) {
const char *cmdText; const char *cmdText;
char dataText[100]; char dataText[100];
char blkAddr[4]; char blkAddr[4];
char bits[80]; int i;
int i, bitidx;
int ZeroWidth; // 32-42 "1" is 32 int ZeroWidth; // 32-42 "1" is 32
int CycleWidth; int CycleWidth;
size_t pulseSamples; size_t pulseSamples;
@ -2018,13 +2018,15 @@ int CmdEM4x05Sniff(const char *Cmd) {
PrintAndLogEx(SUCCESS, "offset | Command | Data | blk | raw"); PrintAndLogEx(SUCCESS, "offset | Command | Data | blk | raw");
PrintAndLogEx(SUCCESS, "-------+-------------+----------+-----+------------------------------------------------------------"); PrintAndLogEx(SUCCESS, "-------+-------------+----------+-----+------------------------------------------------------------");
smartbuf bits = { 0 };
bits.ptr = malloc(EM4X05_BITS_BUFSIZE);
bits.size = EM4X05_BITS_BUFSIZE;
bits.idx = 0;
size_t idx = 0; size_t idx = 0;
// loop though sample buffer // loop though sample buffer
while (idx < g_GraphTraceLen) { while (idx < g_GraphTraceLen) {
bool eop = false;
bool haveData = false; bool haveData = false;
bool pwd = false; bool pwd = false;
uint32_t tmpValue;
idx = em4x05_Sniff_GetNextBitStart(idx, g_GraphTraceLen, g_GraphBuffer, &pulseSamples); idx = em4x05_Sniff_GetNextBitStart(idx, g_GraphTraceLen, g_GraphBuffer, &pulseSamples);
size_t pktOffset = idx; size_t pktOffset = idx;
@ -2037,9 +2039,10 @@ int CmdEM4x05Sniff(const char *Cmd) {
if (ZeroWidth <= 50) { if (ZeroWidth <= 50) {
pktOffset -= ZeroWidth; pktOffset -= ZeroWidth;
memset(bits, 0x00, sizeof(bits)); memset(bits.ptr, 0, bits.size);
bitidx = 0; bits.idx = 0;
bool eop = false;
while ((idx < g_GraphTraceLen) && !eop) { while ((idx < g_GraphTraceLen) && !eop) {
CycleWidth = idx; CycleWidth = idx;
idx = em4x05_Sniff_GetNextBitStart(idx, g_GraphTraceLen, g_GraphBuffer, &pulseSamples); idx = em4x05_Sniff_GetNextBitStart(idx, g_GraphTraceLen, g_GraphBuffer, &pulseSamples);
@ -2047,7 +2050,7 @@ int CmdEM4x05Sniff(const char *Cmd) {
CycleWidth = idx - CycleWidth; CycleWidth = idx - CycleWidth;
if ((CycleWidth > 300) || (CycleWidth < (ZeroWidth - 5))) { // to long or too short if ((CycleWidth > 300) || (CycleWidth < (ZeroWidth - 5))) { // to long or too short
eop = true; eop = true;
bits[bitidx++] = '0'; // Append last zero from the last bit find sb_append_char(&bits, '0'); // Append last zero from the last bit find
cmdText = ""; cmdText = "";
// EM4305 command lengths // EM4305 command lengths
@ -2059,76 +2062,77 @@ int CmdEM4x05Sniff(const char *Cmd) {
// -> disable 1010 11111111 0 11111111 0 11111111 0 11111111 0 00000000 0 // -> disable 1010 11111111 0 11111111 0 11111111 0 11111111 0 00000000 0
// Check to see if we got the leading 0 // Check to see if we got the leading 0
if (((strncmp(bits, "00011", 5) == 0) && (bitidx == 50)) || if (((strncmp(bits.ptr, "00011", 5) == 0) && (bits.idx == 50)) ||
((strncmp(bits, "00101", 5) == 0) && (bitidx == 57)) || ((strncmp(bits.ptr, "00101", 5) == 0) && (bits.idx == 57)) ||
((strncmp(bits, "01001", 5) == 0) && (bitidx == 12)) || ((strncmp(bits.ptr, "01001", 5) == 0) && (bits.idx == 12)) ||
((strncmp(bits, "01100", 5) == 0) && (bitidx == 50)) || ((strncmp(bits.ptr, "01100", 5) == 0) && (bits.idx == 50)) ||
((strncmp(bits, "01010", 5) == 0) && (bitidx == 50))) { ((strncmp(bits.ptr, "01010", 5) == 0) && (bits.idx == 50))) {
memmove(bits, &bits[1], bitidx - 1); memmove(bits.ptr, &bits.ptr[1], bits.idx - 1);
bitidx--; bits.idx--;
PrintAndLogEx(INFO, "Trim leading 0"); PrintAndLogEx(INFO, "Trim leading 0");
} }
bits[bitidx] = 0; sb_append_char(&bits, 0);
bits.idx--;
// logon // logon
if ((strncmp(bits, "0011", 4) == 0) && (bitidx == 49)) { if ((strncmp(bits.ptr, "0011", 4) == 0) && (bits.idx == 49)) {
haveData = true; haveData = true;
pwd = true; pwd = true;
cmdText = "Logon"; cmdText = "Logon";
strncpy(blkAddr, " ", sizeof(blkAddr)); strncpy(blkAddr, " ", sizeof(blkAddr));
tmpValue = em4x05_Sniff_GetBlock(&bits[4], fwd); uint32_t tmpValue = em4x05_Sniff_GetBlock(&bits.ptr[4], fwd);
snprintf(dataText, sizeof(dataText), "%08X", tmpValue); snprintf(dataText, sizeof(dataText), "%08X", tmpValue);
} }
// write // write
if ((strncmp(bits, "0101", 4) == 0) && (bitidx == 56)) { if ((strncmp(bits.ptr, "0101", 4) == 0) && (bits.idx == 56)) {
haveData = true; haveData = true;
cmdText = "Write"; cmdText = "Write";
tmpValue = (bits[4] - '0') + ((bits[5] - '0') << 1) + ((bits[6] - '0') << 2) + ((bits[7] - '0') << 3); uint32_t tmpValue = (bits.ptr[4] - '0') + ((bits.ptr[5] - '0') << 1) + ((bits.ptr[6] - '0') << 2) + ((bits.ptr[7] - '0') << 3);
snprintf(blkAddr, sizeof(blkAddr), "%u", tmpValue); snprintf(blkAddr, sizeof(blkAddr), "%u", tmpValue);
if (tmpValue == 2) { if (tmpValue == 2) {
pwd = true; pwd = true;
} }
tmpValue = em4x05_Sniff_GetBlock(&bits[11], fwd); tmpValue = em4x05_Sniff_GetBlock(&bits.ptr[11], fwd);
snprintf(dataText, sizeof(dataText), "%08X", tmpValue); snprintf(dataText, sizeof(dataText), "%08X", tmpValue);
} }
// read // read
if ((strncmp(bits, "1001", 4) == 0) && (bitidx == 11)) { if ((strncmp(bits.ptr, "1001", 4) == 0) && (bits.idx == 11)) {
haveData = true; haveData = true;
pwd = false; pwd = false;
cmdText = "Read"; cmdText = "Read";
tmpValue = (bits[4] - '0') + ((bits[5] - '0') << 1) + ((bits[6] - '0') << 2) + ((bits[7] - '0') << 3); uint32_t tmpValue = (bits.ptr[4] - '0') + ((bits.ptr[5] - '0') << 1) + ((bits.ptr[6] - '0') << 2) + ((bits.ptr[7] - '0') << 3);
snprintf(blkAddr, sizeof(blkAddr), "%u", tmpValue); snprintf(blkAddr, sizeof(blkAddr), "%u", tmpValue);
strncpy(dataText, " ", sizeof(dataText)); strncpy(dataText, " ", sizeof(dataText));
} }
// protect // protect
if ((strncmp(bits, "1100", 4) == 0) && (bitidx == 49)) { if ((strncmp(bits.ptr, "1100", 4) == 0) && (bits.idx == 49)) {
haveData = true; haveData = true;
pwd = false; pwd = false;
cmdText = "Protect"; cmdText = "Protect";
strncpy(blkAddr, " ", sizeof(blkAddr)); strncpy(blkAddr, " ", sizeof(blkAddr));
tmpValue = em4x05_Sniff_GetBlock(&bits[11], fwd); uint32_t tmpValue = em4x05_Sniff_GetBlock(&bits.ptr[11], fwd);
snprintf(dataText, sizeof(dataText), "%08X", tmpValue); snprintf(dataText, sizeof(dataText), "%08X", tmpValue);
} }
// disable // disable
if ((strncmp(bits, "1010", 4) == 0) && (bitidx == 49)) { if ((strncmp(bits.ptr, "1010", 4) == 0) && (bits.idx == 49)) {
haveData = true; haveData = true;
pwd = false; pwd = false;
cmdText = "Disable"; cmdText = "Disable";
strncpy(blkAddr, " ", sizeof(blkAddr)); strncpy(blkAddr, " ", sizeof(blkAddr));
tmpValue = em4x05_Sniff_GetBlock(&bits[11], fwd); uint32_t tmpValue = em4x05_Sniff_GetBlock(&bits.ptr[11], fwd);
snprintf(dataText, sizeof(dataText), "%08X", tmpValue); snprintf(dataText, sizeof(dataText), "%08X", tmpValue);
} }
// bits[bitidx] = 0; // bits[bitidx] = 0;
} else { } else {
i = (CycleWidth - ZeroWidth) / 28; i = (CycleWidth - ZeroWidth) / 28;
bits[bitidx++] = '0'; sb_append_char(&bits, '0');
for (int ii = 0; ii < i; ii++) { for (int ii = 0; ii < i; ii++) {
bits[bitidx++] = '1'; sb_append_char(&bits, '1');
} }
} }
} }
@ -2139,11 +2143,13 @@ int CmdEM4x05Sniff(const char *Cmd) {
// Print results // Print results
if (haveData) { //&& (minWidth > 1) && (maxWidth > minWidth)){ if (haveData) { //&& (minWidth > 1) && (maxWidth > minWidth)){
if (pwd) if (pwd)
PrintAndLogEx(SUCCESS, "%6zu | %-10s | " _YELLOW_("%8s")" | " _YELLOW_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits); PrintAndLogEx(SUCCESS, "%6zu | %-10s | " _YELLOW_("%8s")" | " _YELLOW_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits.ptr);
else else
PrintAndLogEx(SUCCESS, "%6zu | %-10s | " _GREEN_("%8s")" | " _GREEN_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits); PrintAndLogEx(SUCCESS, "%6zu | %-10s | " _GREEN_("%8s")" | " _GREEN_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits.ptr);
} }
} }
free(bits.ptr);
bits.ptr = NULL;
// footer // footer
PrintAndLogEx(SUCCESS, "---------------------------------------------------------------------------------------------------"); PrintAndLogEx(SUCCESS, "---------------------------------------------------------------------------------------------------");

View file

@ -27,6 +27,8 @@
#define EM4305_PROT2_BLOCK 15 #define EM4305_PROT2_BLOCK 15
#define EM4469_PROT_BLOCK 3 #define EM4469_PROT_BLOCK 3
#define EM4X05_BITS_BUFSIZE 128
// config blocks // config blocks
#define EM4305_DEFAULT_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(4) ) // ASK/MAN , data rate 32, 4 data blocks #define EM4305_DEFAULT_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(4) ) // ASK/MAN , data rate 32, 4 data blocks
//#define EM4305_DEFAULT_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(4) ) // ASK/BIPHASE , data rate 32, 4 data blocks //#define EM4305_DEFAULT_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(4) ) // ASK/BIPHASE , data rate 32, 4 data blocks

View file

@ -404,7 +404,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
uint8_t data[MAX_GRAPH_TRACE_LEN] = {0}; uint8_t data[MAX_GRAPH_TRACE_LEN] = {0};
size_t datasize = getFromGraphBuf(data); size_t datasize = getFromGraphBuf(data);
uint8_t rawbits[4096]; uint8_t rawbits[4096] = {0};
int rawbit = 0; int rawbit = 0;
int worst = 0, worstPos = 0; int worst = 0, worstPos = 0;

View file

@ -230,6 +230,7 @@ static int CmdParadoxClone(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf paradox clone", CLIParserInit(&ctx, "lf paradox clone",
"clone a paradox tag to a T55x7, Q5/T5555 or EM4305/4469 tag.", "clone a paradox tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
"lf paradox clone --fc 96 --cn 40426 -> encode for T55x7 tag with fc and cn\n"
"lf paradox clone --raw 0f55555695596a6a9999a59a -> encode for T55x7 tag\n" "lf paradox clone --raw 0f55555695596a6a9999a59a -> encode for T55x7 tag\n"
"lf paradox clone --raw 0f55555695596a6a9999a59a --q5 -> encode for Q5/T5555 tag\n" "lf paradox clone --raw 0f55555695596a6a9999a59a --q5 -> encode for Q5/T5555 tag\n"
"lf paradox clone --raw 0f55555695596a6a9999a59a --em -> encode for EM4305/4469" "lf paradox clone --raw 0f55555695596a6a9999a59a --em -> encode for EM4305/4469"
@ -238,6 +239,8 @@ static int CmdParadoxClone(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"), arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
arg_u64_0(NULL, "fc", "<dec>", "facility code"),
arg_u64_0(NULL, "cn", "<dec>", "card number"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end arg_param_end
@ -249,8 +252,10 @@ static int CmdParadoxClone(const char *Cmd) {
uint8_t raw[12] = {0}; uint8_t raw[12] = {0};
CLIGetHexWithReturn(ctx, 1, raw, &raw_len); CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
bool q5 = arg_get_lit(ctx, 2); uint32_t fc = arg_get_u32_def(ctx, 2, 0);
bool em = arg_get_lit(ctx, 3); uint32_t cn = arg_get_u32_def(ctx, 3, 0);
bool q5 = arg_get_lit(ctx, 4);
bool em = arg_get_lit(ctx, 5);
CLIParserFree(ctx); CLIParserFree(ctx);
if (q5 && em) { if (q5 && em) {
@ -258,14 +263,56 @@ static int CmdParadoxClone(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
if (raw_len != 12) { uint32_t blocks[4] = {0};
PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
return PM3_EINVARG;
}
uint32_t blocks[4]; if (raw_len != 0) {
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { if (raw_len != 12) {
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t)); PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
return PM3_EINVARG;
}
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
}
} else {
uint8_t manchester[13] = { 0x00 }; // check size needed
uint32_t t1;
manchester[0] = 0x0F; // preamble
manchester[1] = 0x05; // Leading zeros - Note: from this byte on, is part of the CRC calculation
manchester[2] = 0x55; // Leading zeros its 4 bits out for the CRC, so we need too move
manchester[3] = 0x55; // Leading zeros back 4 bits once we have the crc (done below)
// add FC
t1 = manchesterEncode2Bytes(fc);
manchester[4] = (t1 >> 8) & 0xFF;
manchester[5] = t1 & 0xFF;
// add cn
t1 = manchesterEncode2Bytes(cn);
manchester[6] = (t1 >> 24) & 0xFF;
manchester[7] = (t1 >> 16) & 0xFF;
manchester[8] = (t1 >> 8) & 0xFF;
manchester[9] = t1 & 0xFF;
uint8_t crc = (CRC8Maxim(manchester + 1, 9) ^ 0x6) & 0xFF;
// add crc
t1 = manchesterEncode2Bytes(crc);
manchester[10] = (t1 >> 8) & 0xFF;
manchester[11] = t1 & 0xFF;
// move left 4 bits left 4 bits - Now that we have the CRC we need to re-align the data.
for (int i = 1; i < 12; i++)
manchester[i] = (manchester[i] << 4) + (manchester[i + 1] >> 4);
// Add trailing 1010 (11)
manchester[11] |= (1 << 3);
manchester[11] |= (1 << 1);
// move into tag blocks
for (int i = 0; i < 12; i++)
blocks[1 + (i / 4)] += (manchester[i] << (8 * (3 - i % 4)));
} }
// Paradox - FSK2a, data rate 50, 3 data blocks // Paradox - FSK2a, data rate 50, 3 data blocks

View file

@ -2362,7 +2362,7 @@ static int CmdT55xxRestore(const char *Cmd) {
} }
// read dump file // read dump file
uint8_t *dump = NULL; uint32_t *dump = NULL;
size_t bytes_read = 0; size_t bytes_read = 0;
res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (T55x7_BLOCK_COUNT * 4)); res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (T55x7_BLOCK_COUNT * 4));
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
@ -2387,11 +2387,10 @@ static int CmdT55xxRestore(const char *Cmd) {
snprintf(pwdopt, sizeof(pwdopt), "-p %08X", password); snprintf(pwdopt, sizeof(pwdopt), "-p %08X", password);
} }
uint32_t *data = (uint32_t *) dump;
uint8_t idx; uint8_t idx;
// Restore endien for writing to card // Restore endien for writing to card
for (idx = 0; idx < 12; idx++) { for (idx = 0; idx < 12; idx++) {
data[idx] = BSWAP_32(data[idx]); dump[idx] = BSWAP_32(dump[idx]);
} }
// Have data ready, lets write // Have data ready, lets write
@ -2400,12 +2399,12 @@ static int CmdT55xxRestore(const char *Cmd) {
// write blocks 1..3 page 1 // write blocks 1..3 page 1
// update downlink mode (if needed) and write b 0 // update downlink mode (if needed) and write b 0
downlink_mode = 0; downlink_mode = 0;
if ((((data[11] >> 28) & 0xF) == 6) || (((data[11] >> 28) & 0xF) == 9)) if ((((dump[11] >> 28) & 0xF) == 6) || (((dump[11] >> 28) & 0xF) == 9))
downlink_mode = (data[11] >> 10) & 3; downlink_mode = (dump[11] >> 10) & 3;
// write out blocks 1-7 page 0 // write out blocks 1-7 page 0
for (idx = 1; idx <= 7; idx++) { for (idx = 1; idx <= 7; idx++) {
snprintf(wcmd, sizeof(wcmd), "-b %d -d %08X %s", idx, data[idx], pwdopt); snprintf(wcmd, sizeof(wcmd), "-b %d -d %08X %s", idx, dump[idx], pwdopt);
if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) { if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Warning: error writing blk %d", idx); PrintAndLogEx(WARNING, "Warning: error writing blk %d", idx);
@ -2414,12 +2413,12 @@ static int CmdT55xxRestore(const char *Cmd) {
// if password was set on the "blank" update as we may have just changed it // if password was set on the "blank" update as we may have just changed it
if (usepwd) { if (usepwd) {
snprintf(pwdopt, sizeof(pwdopt), "-p %08X", data[7]); snprintf(pwdopt, sizeof(pwdopt), "-p %08X", dump[7]);
} }
// write out blocks 1-3 page 1 // write out blocks 1-3 page 1
for (idx = 9; idx <= 11; idx++) { for (idx = 9; idx <= 11; idx++) {
snprintf(wcmd, sizeof(wcmd), "-b %d --pg1 -d %08X %s", idx - 8, data[idx], pwdopt); snprintf(wcmd, sizeof(wcmd), "-b %d --pg1 -d %08X %s", idx - 8, dump[idx], pwdopt);
if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) { if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Warning: error writing blk %d", idx); PrintAndLogEx(WARNING, "Warning: error writing blk %d", idx);
@ -2430,7 +2429,7 @@ static int CmdT55xxRestore(const char *Cmd) {
config.downlink_mode = downlink_mode; config.downlink_mode = downlink_mode;
// Write the page 0 config // Write the page 0 config
snprintf(wcmd, sizeof(wcmd), "-b 0 -d %08X %s", data[0], pwdopt); snprintf(wcmd, sizeof(wcmd), "-b 0 -d %08X %s", dump[0], pwdopt);
if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) { if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Warning: error writing blk 0"); PrintAndLogEx(WARNING, "Warning: error writing blk 0");
} }
@ -4012,7 +4011,6 @@ static int CmdT55xxSniff(const char *Cmd) {
size_t idx = 0; size_t idx = 0;
uint32_t usedPassword, blockData; uint32_t usedPassword, blockData;
int pulseSamples = 0, pulseIdx = 0; int pulseSamples = 0, pulseIdx = 0;
const char *modeText;
char pwdText[100]; char pwdText[100];
char dataText[100]; char dataText[100];
int pulseBuffer[80] = { 0 }; // max should be 73 +/- - Holds Pulse widths int pulseBuffer[80] = { 0 }; // max should be 73 +/- - Holds Pulse widths
@ -4038,7 +4036,7 @@ static int CmdT55xxSniff(const char *Cmd) {
int maxWidth = 0; int maxWidth = 0;
data[0] = 0; data[0] = 0;
bool have_data = false; bool have_data = false;
modeText = "Default"; const char *modeText = "Default";
strncpy(pwdText, " ", sizeof(pwdText)); strncpy(pwdText, " ", sizeof(pwdText));
strncpy(dataText, " ", sizeof(dataText)); strncpy(dataText, " ", sizeof(dataText));

View file

@ -39,6 +39,7 @@
#include "cmdanalyse.h" #include "cmdanalyse.h"
#include "emv/cmdemv.h" // EMV #include "emv/cmdemv.h" // EMV
#include "cmdflashmem.h" // rdv40 flashmem commands #include "cmdflashmem.h" // rdv40 flashmem commands
#include "cmdpiv.h"
#include "cmdsmartcard.h" // rdv40 smart card ISO7816 commands #include "cmdsmartcard.h" // rdv40 smart card ISO7816 commands
#include "cmdusart.h" // rdv40 FPC USART commands #include "cmdusart.h" // rdv40 FPC USART commands
#include "cmdwiegand.h" // wiegand commands #include "cmdwiegand.h" // wiegand commands
@ -324,6 +325,7 @@ static command_t CommandTable[] = {
{"lf", CmdLF, AlwaysAvailable, "{ Low frequency commands... }"}, {"lf", CmdLF, AlwaysAvailable, "{ Low frequency commands... }"},
{"mem", CmdFlashMem, IfPm3Flash, "{ Flash memory manipulation... }"}, {"mem", CmdFlashMem, IfPm3Flash, "{ Flash memory manipulation... }"},
{"nfc", CmdNFC, AlwaysAvailable, "{ NFC commands... }"}, {"nfc", CmdNFC, AlwaysAvailable, "{ NFC commands... }"},
{"piv", CmdPIV, AlwaysAvailable, "{ PIV commands... }"},
{"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software... }"}, {"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software... }"},
{"smart", CmdSmartcard, AlwaysAvailable, "{ Smart card ISO-7816 commands... }"}, {"smart", CmdSmartcard, AlwaysAvailable, "{ Smart card ISO-7816 commands... }"},
{"script", CmdScript, AlwaysAvailable, "{ Scripting commands... }"}, {"script", CmdScript, AlwaysAvailable, "{ Scripting commands... }"},

988
client/src/cmdpiv.c Normal file
View file

@ -0,0 +1,988 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// PIV commands
//-----------------------------------------------------------------------------
#include "cmdpiv.h"
#include "comms.h" // DropField
#include "cmdsmartcard.h" // smart_select
#include "cmdtrace.h"
#include "cliparser.h"
#include "cmdparser.h"
#include "commonutil.h" // Mem[LB]eToUintXByte
#include "emv/tlv.h"
#include "proxmark3.h"
#include "cmdhf14a.h"
#include "fileutils.h"
#include "crypto/asn1utils.h"
#include "protocols.h"
static int CmdHelp(const char *Cmd);
static uint8_t PIV_APPLET[9] = "\xA0\x00\x00\x03\x08\x00\x00\x10\x00";
enum piv_condition_t {
PIV_MANDATORY,
PIV_CONDITIONAL,
PIV_OPTIONAL,
PIV_INVALID = 0xff,
};
struct piv_container {
uint32_t id;
const uint8_t *tlv_tag; // tag is between 1 and 3 bytes.
size_t len; // length of the hex-form if the tag (i.e. twice the byte size) for pretty printing
enum piv_condition_t cond;
const char *name;
};
#define PIV_TAG_ID(x) ((const uint8_t *)(x))
#define PIV_CONTAINER_FINISH { (~0), NULL, 0, PIV_INVALID, NULL }
// Source: SP800-73-4, Annex A
// https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-73-4.pdf
static const struct piv_container PIV_CONTAINERS[] = {
{0xDB00, PIV_TAG_ID("\x5F\xC1\x07"), 3, PIV_MANDATORY, "Card Capability Container"},
{0x3000, PIV_TAG_ID("\x5F\xC1\x02"), 3, PIV_MANDATORY, "Card Holder Unique Identifier"},
{0x0101, PIV_TAG_ID("\x5F\xC1\x05"), 3, PIV_MANDATORY, "X.509 Certificate for PIV Authentication (key ref 9A)"},
{0x6010, PIV_TAG_ID("\x5F\xC1\x03"), 3, PIV_MANDATORY, "Cardholder Fingerprints"},
{0x9000, PIV_TAG_ID("\x5F\xC1\x06"), 3, PIV_MANDATORY, "Security Object"},
{0x6030, PIV_TAG_ID("\x5F\xC1\x08"), 3, PIV_MANDATORY, "Cardholder Facial Image"},
{0x0500, PIV_TAG_ID("\x5F\xC1\x01"), 3, PIV_MANDATORY, "X.509 Certificate for Card Authentication (key ref 9E)"},
{0x0100, PIV_TAG_ID("\x5F\xC1\x0A"), 3, PIV_CONDITIONAL, "X.509 Certificate for Digital Signature (key ref 9C)"},
{0x0102, PIV_TAG_ID("\x5F\xC1\x0B"), 3, PIV_CONDITIONAL, "X.509 Certificate for Key Management (key ref 9D)"},
{0x3001, PIV_TAG_ID("\x5F\xC1\x09"), 3, PIV_OPTIONAL, "Printed Information"},
{0x6050, PIV_TAG_ID("\x7E"), 1, PIV_OPTIONAL, "Discovery Object"},
{0x6060, PIV_TAG_ID("\x5F\xC1\x0C"), 3, PIV_OPTIONAL, "Key History Object"},
{0x1001, PIV_TAG_ID("\x5F\xC1\x0D"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 1 (key ref 82)"},
{0x1002, PIV_TAG_ID("\x5F\xC1\x0E"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 2 (key ref 83)"},
{0x1003, PIV_TAG_ID("\x5F\xC1\x0F"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 3 (key ref 84)"},
{0x1004, PIV_TAG_ID("\x5F\xC1\x10"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 4 (key ref 85)"},
{0x1005, PIV_TAG_ID("\x5F\xC1\x11"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 5 (key ref 86)"},
{0x1006, PIV_TAG_ID("\x5F\xC1\x12"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 6 (key ref 87)"},
{0x1007, PIV_TAG_ID("\x5F\xC1\x13"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 7 (key ref 88)"},
{0x1008, PIV_TAG_ID("\x5F\xC1\x14"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 8 (key ref 89)"},
{0x1009, PIV_TAG_ID("\x5F\xC1\x15"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 9 (key ref 8A)"},
{0x100A, PIV_TAG_ID("\x5F\xC1\x16"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 10 (key ref 8B)"},
{0x100B, PIV_TAG_ID("\x5F\xC1\x17"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 11 (key ref 8C)"},
{0x100C, PIV_TAG_ID("\x5F\xC1\x18"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 12 (key ref 8D)"},
{0x100D, PIV_TAG_ID("\x5F\xC1\x19"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 13 (key ref 8E)"},
{0x100E, PIV_TAG_ID("\x5F\xC1\x1A"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 14 (key ref 8F)"},
{0x100F, PIV_TAG_ID("\x5F\xC1\x1B"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 15 (key ref 90)"},
{0x1010, PIV_TAG_ID("\x5F\xC1\x1C"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 16 (key ref 91)"},
{0x1011, PIV_TAG_ID("\x5F\xC1\x1D"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 17 (key ref 92)"},
{0x1012, PIV_TAG_ID("\x5F\xC1\x1E"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 18 (key ref 93)"},
{0x1013, PIV_TAG_ID("\x5F\xC1\x1F"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 19 (key ref 94)"},
{0x1014, PIV_TAG_ID("\x5F\xC1\x20"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 20 (key ref 95)"},
{0x1015, PIV_TAG_ID("\x5F\xC1\x21"), 3, PIV_OPTIONAL, "Cardholder Iris Images"},
{0x1016, PIV_TAG_ID("\x7F\x61"), 2, PIV_OPTIONAL, "Biometric Information Templates Group Template"},
{0x1017, PIV_TAG_ID("\x5F\xC1\x22"), 3, PIV_OPTIONAL, "Secure Messaging Certificate Signer"},
{0x1018, PIV_TAG_ID("\x5F\xC1\x23"), 3, PIV_OPTIONAL, "Pairing Code Reference Data Container"},
PIV_CONTAINER_FINISH,
};
enum piv_tag_t {
PIV_TAG_GENERIC,
PIV_TAG_HEXDUMP,
PIV_TAG_STRING,
PIV_TAG_PRINTSTR,
PIV_TAG_NUMERIC,
PIV_TAG_YYYYMMDD,
PIV_TAG_ENUM,
PIV_TAG_TLV,
PIV_TAG_GUID,
PIV_TAG_CERT,
PIV_TAG_FASCN,
};
struct piv_tag {
tlv_tag_t tag;
const char *name;
enum piv_tag_t type;
const void *data;
};
struct piv_tag_enum {
unsigned long value;
const char *name;
};
#define PIV_ENUM_FINISH { (~0), NULL }
// From table 6-2 in SP800-78 specification
static const struct piv_tag_enum PIV_CRYPTO_ALG[] = {
{0x00, "3 Key 3DES - ECB"},
{0x03, "3 Key 3DES - ECB"}, // Not a typo, 2 identifiers for the same algorithm
{0x06, "RSA 1024 bit"},
{0x07, "RSA 2048 bit"},
{0x08, "AES-128 ECB"},
{0x0A, "AES-192 ECB"},
{0x0C, "AES-256 ECB"},
{0x11, "ECC P-256"},
{0x14, "ECC P-384"},
{0x27, "Cipher Suite 2"},
{0x2E, "Cipher Suite 7"},
PIV_ENUM_FINISH,
};
static const struct piv_tag_enum PIV_CERT_INFO[] = {
{0x00, "Uncompressed"},
{0x01, "GZIP Compressed"},
PIV_ENUM_FINISH,
};
static const struct piv_tag piv_tags[] = {
{ 0x00, "Unknown ???", PIV_TAG_HEXDUMP, NULL },
{ 0x01, "Name", PIV_TAG_PRINTSTR, NULL },
{ 0x02, "Employee Affiliation", PIV_TAG_PRINTSTR, NULL },
{ 0x04, "Expiry Date", PIV_TAG_PRINTSTR, NULL },
{ 0x05, "Agency Card Serial Number", PIV_TAG_PRINTSTR, NULL },
{ 0x06, "Issuer identification", PIV_TAG_PRINTSTR, NULL },
{ 0x07, "Organization Affiliation (Line 1)", PIV_TAG_PRINTSTR, NULL },
{ 0x08, "Organization Affiliation (Line 2)", PIV_TAG_PRINTSTR, NULL },
{ 0x30, "FASC-N", PIV_TAG_FASCN, NULL },
{ 0x32, "Organizational Identifier [deprecated]", PIV_TAG_HEXDUMP, NULL },
{ 0x33, "DUNS [deprecated]", PIV_TAG_HEXDUMP, NULL },
{ 0x34, "GUID", PIV_TAG_GUID, NULL },
{ 0x35, "Expiry Date", PIV_TAG_YYYYMMDD, NULL },
{ 0x36, "Cardholder UUID", PIV_TAG_GUID, NULL },
{ 0x3d, "Authentication Key Map", PIV_TAG_HEXDUMP, NULL },
{ 0x3e, "Issuer Asymmetric Signature", PIV_TAG_CERT, NULL },
{ 0x4f, "Application Identifier (AID)", PIV_TAG_STRING, NULL },
{ 0x50, "Application Label", PIV_TAG_PRINTSTR, NULL },
{ 0x53, "Discretionary data (or template)", PIV_TAG_TLV, NULL },
{ 0x5f2f, "PIN Usage Policy", PIV_TAG_HEXDUMP, NULL },
{ 0x5f50, "Issuer URL", PIV_TAG_PRINTSTR, NULL },
{ 0x61, "Application Property Template", PIV_TAG_GENERIC, NULL },
{ 0x70, "Certificate", PIV_TAG_CERT, NULL },
{ 0x71, "CertInfo", PIV_TAG_ENUM, PIV_CERT_INFO },
{ 0x72, "MSCUID [deprecated]", PIV_TAG_HEXDUMP, NULL },
{ 0x79, "Coexistent tag allocation authority", PIV_TAG_HEXDUMP, NULL },
{ 0x7f21, "Intermediate CVC", PIV_TAG_HEXDUMP, NULL },
{ 0x7f60, "Biometric Information Template", PIV_TAG_GENERIC, NULL },
{ 0x80, "Cryptographic algorithm identifier", PIV_TAG_ENUM, PIV_CRYPTO_ALG },
{ 0x99, "Pairing Code", PIV_TAG_PRINTSTR, NULL },
{ 0xac, "Cryptographic algorithms supported", PIV_TAG_GENERIC, NULL },
{ 0xb4, "Security Object Buffer (deprecated)", PIV_TAG_GENERIC, NULL },
{ 0xba, "Mapping of DG to Container ID", PIV_TAG_HEXDUMP, NULL },
{ 0xbb, "Security Object", PIV_TAG_CERT, NULL },
{ 0xbc, "Fingerprint I & II or Image for Visual Verification", PIV_TAG_GENERIC, NULL },
{ 0xc1, "keysWithOnCardCerts", PIV_TAG_NUMERIC, NULL },
{ 0xc2, "keysWithOffCardCerts", PIV_TAG_NUMERIC, NULL },
{ 0xe3, "Extended Application CardURL [deprecated]", PIV_TAG_GENERIC, NULL },
{ 0xee, "Buffer Length [deprecated]", PIV_TAG_NUMERIC, NULL },
{ 0xf0, "Card Identifier", PIV_TAG_STRING, NULL },
{ 0xf1, "Capability Container version number", PIV_TAG_NUMERIC, NULL },
{ 0xf2, "Capability Grammar version number", PIV_TAG_NUMERIC, NULL },
{ 0xf3, "Application Card URL", PIV_TAG_PRINTSTR, NULL },
{ 0xf4, "PKCS#15", PIV_TAG_NUMERIC, NULL },
{ 0xf5, "Registered Data Model Number", PIV_TAG_NUMERIC, NULL },
{ 0xf6, "Access Control Rule Table", PIV_TAG_HEXDUMP, NULL },
{ 0xf7, "Card APDUs", PIV_TAG_GENERIC, NULL },
{ 0xfa, "Redirection Tag", PIV_TAG_GENERIC, NULL },
{ 0xfb, "Capability Tuples (CT)", PIV_TAG_GENERIC, NULL },
{ 0xfc, "Status Tuples (ST)", PIV_TAG_GENERIC, NULL },
{ 0xfd, "Next CCC", PIV_TAG_GENERIC, NULL },
{ 0xfe, "Error Detection Code", PIV_TAG_GENERIC, NULL },
};
struct guid {
uint32_t part1;
uint16_t part2;
uint16_t part3;
uint8_t data[8];
};
static void parse_guid(const uint8_t *data, struct guid *guid) {
if (guid == NULL) {
return;
}
size_t ofs = 0;
guid->part1 = MemBeToUint4byte(&data[ofs]);
ofs += sizeof(uint32_t);
guid->part2 = MemBeToUint2byte(&data[ofs]);
ofs += sizeof(uint16_t);
guid->part3 = MemBeToUint2byte(&data[ofs]);
ofs += sizeof(uint16_t);
for (size_t i = 0; i < sizeof(guid->data); i++) {
guid->data[i] = data[ofs + i];
}
}
static void piv_print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf);
static bool piv_tag_dump(const struct tlv *tlv, int level);
static void PrintChannel(Iso7816CommandChannel channel) {
switch (channel) {
case CC_CONTACTLESS:
PrintAndLogEx(INFO, "Selected channel... " _GREEN_("CONTACTLESS (T=CL)"));
break;
case CC_CONTACT:
PrintAndLogEx(INFO, "Selected channel... " _GREEN_("CONTACT"));
break;
}
}
static int piv_sort_tag(tlv_tag_t tag) {
return (int)(tag >= 0x100 ? tag : tag << 8);
}
static int piv_tlv_compare(const void *a, const void *b) {
const struct tlv *tlv = a;
const struct piv_tag *tag = b;
return piv_sort_tag(tlv->tag) - (piv_sort_tag(tag->tag));
}
static const struct piv_tag *piv_get_tag(const struct tlv *tlv) {
const struct piv_tag *tag = bsearch(tlv, piv_tags, ARRAYLEN(piv_tags),
sizeof(piv_tags[0]), piv_tlv_compare);
return tag != NULL ? tag : &piv_tags[0];
}
static unsigned long piv_value_numeric(const struct tlv *tlv, unsigned start, unsigned end) {
unsigned long ret = 0;
int i;
if (end > tlv->len * 2)
return ret;
if (start >= end)
return ret;
if (start & 1) {
ret += tlv->value[start / 2] & 0xf;
i = start + 1;
} else
i = start;
for (; i < end - 1; i += 2) {
ret *= 10;
ret += tlv->value[i / 2] >> 4;
ret *= 10;
ret += tlv->value[i / 2] & 0xf;
}
if (end & 1) {
ret *= 10;
ret += tlv->value[end / 2] >> 4;
}
return ret;
}
static void piv_tag_dump_yyyymmdd(const struct tlv *tlv, const struct piv_tag *tag, int level) {
bool is_printable = true;
for (size_t i = 0; i < tlv->len; i++) {
if ((tlv->value[i] < 0x30) || (tlv->value[i] > 0x39)) {
is_printable = false;
break;
}
}
if (is_printable) {
PrintAndLogEx(NORMAL, " " _YELLOW_("%c%c%c%c.%c%c.%c%c"),
tlv->value[0], tlv->value[1], tlv->value[2], tlv->value[3],
tlv->value[4], tlv->value[5],
tlv->value[6], tlv->value[7]
);
} else {
PrintAndLogEx(NORMAL, " " _YELLOW_("%04lu.%02lu.%02lu"),
piv_value_numeric(tlv, 0, 4),
piv_value_numeric(tlv, 4, 6),
piv_value_numeric(tlv, 6, 8)
);
}
}
static void piv_tag_dump_enum(const struct tlv *tlv, const struct piv_tag *tag, int level) {
const struct piv_tag_enum *values = tag->data;
for (size_t i = 0; values[i].name != NULL; i++) {
if (values[i].value == tlv->value[0]) {
PrintAndLogEx(NORMAL, " %u - '" _YELLOW_("%s")"'",
tlv->value[0], values[i].name);
return;
}
}
PrintAndLogEx(NORMAL, " %u - " _RED_("Unknown??"), tlv->value[0]);
}
static void piv_tag_dump_tlv(const struct tlv *tlv, const struct piv_tag *tag, int level) {
// We don't use parsing methods because we need to discard constructed tags
const unsigned char *buf = tlv->value;
size_t left = tlv->len;
while (left) {
struct tlv sub_tlv;
//const struct piv_tag *sub_tag;
if (!tlv_parse_tl(&buf, &left, &sub_tlv)) {
PrintAndLogEx(INFO, "%*sInvalid Tag-Len", (level * 4), " ");
continue;
}
sub_tlv.value = buf;
piv_tag_dump(&sub_tlv, level + 1);
buf += sub_tlv.len;
left -= sub_tlv.len;
}
}
static void piv_print_cert(const uint8_t *buf, const size_t len, int level) {
char prefix[256] = {0};
PrintAndLogEx(NORMAL, "");
snprintf(prefix, sizeof(prefix), "%*s", 4 * level, " ");
// TODO: when mbedTLS has a new release with the PCKS7 parser, we can replace the generic ASN.1 print
// The pull request has been merged end of Nov 2022.
asn1_print((uint8_t *) buf, len, prefix);
}
static void piv_print_fascn(const uint8_t *buf, const size_t len, int level) {
const char *encoded[32] = {
_RED_("?"), // 0b00000
"0", // 0b00001
"8", // 0b00010
_RED_("?"), // 0b00011
"4", // 0b00100
_RED_("?"), // 0b00101
_RED_("?"), // 0b00110
_RED_("?"), // 0b00111
"2", // 0b01000
_RED_("?"), // 0b01001
_RED_("?"), // 0b01010
_RED_("?"), // 0b01011
_RED_("?"), // 0b01100
"6", // 0b01101
_RED_("?"), // 0b01110
_RED_("?"), // 0b01111
"1", // 0b10000
_RED_("?"), // 0b10001
_RED_("?"), // 0b10010
"9", // 0b10011
_RED_("?"), // 0b10100
"5", // 0b10101
_GREEN_(" FS "), // 0b10110
_RED_("?"), // 0b10111
_RED_("?"), // 0b11000
"3", // 0b11001
_YELLOW_("SS "), // 0b11010
_RED_("?"), // 0b11011
"7", // 0b11100
_RED_("?"), // 0b11101
_RED_("?"), // 0b11110
_YELLOW_(" ES"), // 0b11111
};
const uint8_t cycle[8] = {5, 2, 7, 4, 1, 6, 3, 8};
PrintAndLogEx(INFO, "%*s" NOLF, 4 * level, " ");
// Buffer is 40 bytes but last byte is LRC that we process separately
for (int i = 0; i < 39; i++) {
uint8_t tmp = buf[(5 * i) >> 3];
uint8_t rot = cycle[i & 7];
// rotate left to get the bits in place
tmp = (tmp << rot) | (tmp >> (8 - rot));
// append bits from next byte if needed
if (rot < 5) {
uint8_t tmp2 = buf[(5 * (i + 1)) >> 3];
tmp2 = (tmp2 << rot) | (tmp2 >> (8 - rot));
tmp &= 0x1f << rot;
tmp |= tmp2 & ((1 << rot) - 1);
}
PrintAndLogEx(NORMAL, "%s" NOLF, encoded[tmp & 0x1f]);
}
uint8_t lrc = buf[24] & 0x1f;
PrintAndLogEx(NORMAL, " LRC=[" _YELLOW_("%02x") "]", lrc);
}
static bool piv_tag_dump(const struct tlv *tlv, int level) {
if (tlv == NULL) {
PrintAndLogEx(FAILED, "NULL");
return false;
}
const struct piv_tag *tag = piv_get_tag(tlv);
PrintAndLogEx(INFO, "%*s--%2x[%02zx] '%s':" NOLF, (level * 4), " ", tlv->tag, tlv->len, tag->name);
switch (tag->type) {
case PIV_TAG_GENERIC:
PrintAndLogEx(NORMAL, "");
break;
case PIV_TAG_HEXDUMP:
PrintAndLogEx(NORMAL, "");
print_buffer(tlv->value, tlv->len, level + 1);
break;
case PIV_TAG_STRING:
PrintAndLogEx(NORMAL, " '" _YELLOW_("%s")"'", sprint_hex_inrow(tlv->value, tlv->len));
break;
case PIV_TAG_NUMERIC:
PrintAndLogEx(NORMAL, " " _YELLOW_("%lu"), piv_value_numeric(tlv, 0, tlv->len * 2));
break;
case PIV_TAG_YYYYMMDD:
piv_tag_dump_yyyymmdd(tlv, tag, level);
break;
case PIV_TAG_ENUM:
piv_tag_dump_enum(tlv, tag, level + 1);
break;
case PIV_TAG_TLV:
PrintAndLogEx(NORMAL, "");
piv_tag_dump_tlv(tlv, tag, level);
break;
case PIV_TAG_PRINTSTR:
PrintAndLogEx(NORMAL, " '" NOLF);
for (size_t i = 0; i < tlv->len; i++) {
PrintAndLogEx(NORMAL, _YELLOW_("%c") NOLF, tlv->value[i]);
}
PrintAndLogEx(NORMAL, "'");
break;
case PIV_TAG_GUID:
if (tlv->len != 16) {
PrintAndLogEx(NORMAL, _RED_("<Invalid>"));
} else {
struct guid guid = {0};
parse_guid(tlv->value, &guid);
PrintAndLogEx(NORMAL, " " _YELLOW_("{%08x-%04x-%04x-") NOLF, guid.part1, guid.part2, guid.part3);
for (size_t i = 0; i < 8; i++) {
PrintAndLogEx(NORMAL, _YELLOW_("%02x") NOLF, guid.data[i]);
}
PrintAndLogEx(NORMAL, _YELLOW_("}"));
}
break;
case PIV_TAG_CERT:
piv_print_cert(tlv->value, tlv->len, level + 2);
break;
case PIV_TAG_FASCN:
PrintAndLogEx(NORMAL, " '" _YELLOW_("%s")"'", sprint_hex_inrow(tlv->value, tlv->len));
if (tlv->len == 25) {
piv_print_fascn(tlv->value, tlv->len, level + 2);
}
break;
};
return true;
}
static void piv_print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf) {
piv_tag_dump(tlv, level);
if (is_leaf) {
print_buffer(tlv->value, tlv->len, level);
}
}
static void PrintTLV(const struct tlvdb *tlvdb) {
if (tlvdb) {
tlvdb_visit(tlvdb, piv_print_cb, NULL, 0);
}
}
static void PrintTLVFromBuffer(const uint8_t *buf, size_t len) {
if (buf == NULL || len == 0) {
return;
}
struct tlvdb_root *root = calloc(1, sizeof(*root) + len);
if (root == NULL) {
return;
}
root->len = len;
memcpy(root->buf, buf, len);
if (tlvdb_parse_root_multi(root) == true) {
PrintTLV(&(root->db));
} else {
PrintAndLogEx(WARNING, "TLV ERROR: Can't parse buffer as TLV tree.");
}
tlvdb_root_free(root);
}
static int PivGetData(Iso7816CommandChannel channel, const uint8_t tag[], size_t tag_len, bool verbose, struct tlvdb_root **result, uint16_t *sw) {
uint8_t apdu_data[5] = {0x5c, 0x00};
*result = NULL;
*sw = 0;
if (tag_len < 1 || tag_len > 3) {
return PM3_EINVARG;
}
apdu_data[1] = tag_len;
memcpy(&apdu_data[2], tag, tag_len);
sAPDU_t apdu = {
.CLA = 0x00,
.INS = 0xCB,
.P1 = 0x3F,
.P2 = 0xFF,
.Lc = tag_len + 2,
.data = apdu_data
};
// Answer can be chained. Let's use a dynamically allocated buffer.
size_t capacity = PM3_CMD_DATA_SIZE;
struct tlvdb_root *root = calloc(1, sizeof(*root) + capacity);
if (root == NULL) {
return PM3_EMALLOC;
}
root->len = 0;
size_t more_data = 0;
do {
size_t received = 0;
int res = Iso7816ExchangeEx(channel, false, true, apdu, (more_data != 0), more_data, &(root->buf[root->len]), capacity - root->len, &received, sw);
if (res != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "Sending APDU failed with code %d", res);
free(root);
return res;
}
root->len += received;
if (((*sw) & 0xff00) == 0x6100) {
// More data
more_data = (*sw) & 0xff;
if (more_data == 0x00 || more_data > MAX_APDU_SIZE) {
more_data = MAX_APDU_SIZE;
}
apdu.CLA = 0x00;
apdu.INS = 0xC0;
apdu.P1 = 0x00;
apdu.P2 = 0x00;
apdu.Lc = 0;
apdu.data = NULL;
if ((capacity - root->len) < PM3_CMD_DATA_SIZE) {
PrintAndLogEx(DEBUG, "Adding more capacity to buffer...");
capacity += PM3_CMD_DATA_SIZE;
struct tlvdb_root *new_root = realloc(root, sizeof(*root) + capacity);
if (new_root == NULL) {
PrintAndLogEx(FAILED, "Running out of memory while re-allocating buffer");
free(root);
return PM3_EMALLOC;
}
root = new_root;
}
}
if ((*sw) == ISO7816_OK) {
more_data = 0;
}
} while (more_data > 0);
// Now we can try parse the TLV and return it
*result = root;
if (*sw == ISO7816_OK && tlvdb_parse_root(root) == true) {
return PM3_SUCCESS;
}
if (verbose == true) {
PrintAndLogEx(WARNING, "Couldn't parse TLV answer.");
}
return PM3_SUCCESS;
}
static int PivGetDataByCidAndPrint(Iso7816CommandChannel channel, const struct piv_container *cid, bool decodeTLV, bool verbose) {
struct tlvdb_root *root = NULL;
if (cid == NULL) {
return PM3_SUCCESS;
}
PrintAndLogEx(INFO, "Getting %s [" _GREEN_("%s") "]", cid->name, sprint_hex_inrow(cid->tlv_tag, cid->len));
uint16_t sw = 0;
if (PivGetData(channel, cid->tlv_tag, cid->len, verbose, &root, &sw) == PM3_SUCCESS) {
switch (sw) {
case ISO7816_OK:
if (decodeTLV == true) {
PrintTLV(&(root->db));
} else {
print_buffer(root->buf, root->len, 0);
}
break;
case ISO7816_FILE_NOT_FOUND:
PrintAndLogEx(FAILED, "Container not found.");
break;
case ISO7816_SECURITY_STATUS_NOT_SATISFIED:
PrintAndLogEx(WARNING, "Security conditions not met.");
break;
default:
if (verbose == true) {
PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
}
break;
}
tlvdb_root_free(root);
}
return PM3_SUCCESS;
}
static int PivGetDataByTagAndPrint(Iso7816CommandChannel channel, const uint8_t tag[], size_t tag_len, bool decodeTLV, bool verbose) {
int idx = 0;
for (; PIV_CONTAINERS[idx].len != 0; idx++) {
if ((tag_len == PIV_CONTAINERS[idx].len) && (memcmp(tag, PIV_CONTAINERS[idx].tlv_tag, tag_len) == 0)) {
break;
}
}
if (PIV_CONTAINERS[idx].len == 0) {
struct piv_container cid = {0x00, tag, tag_len, PIV_OPTIONAL, "Getting unknown contained ID"};
return PivGetDataByCidAndPrint(channel, &cid, decodeTLV, verbose);
}
return PivGetDataByCidAndPrint(channel, &(PIV_CONTAINERS[idx]), decodeTLV, verbose);
}
static int PivAuthenticateSign(Iso7816CommandChannel channel, uint8_t alg_id, uint8_t key_id, uint8_t nonce[], size_t nonce_len, void **result, bool decodeTLV, bool verbose) {
const size_t MAX_NONCE_LEN = 0x7a;
if (nonce_len > MAX_NONCE_LEN) {
if (verbose == true) {
PrintAndLogEx(WARNING, "Nonce cannot exceed %zu bytes. Got %zu bytes.", MAX_NONCE_LEN, nonce_len);
}
return PM3_EINVARG;
}
uint8_t apdu_buf[APDU_RES_LEN] = {0x7c, nonce_len + 4, 0x82, 0x00, 0x81, nonce_len};
memcpy(&apdu_buf[6], nonce, nonce_len);
sAPDU_t apdu = {
0x00, 0x87, alg_id, key_id,
6 + nonce_len, apdu_buf
};
uint16_t sw = 0;
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
int res = Iso7816ExchangeEx(channel, false, true, apdu, false, 0, buf, APDU_RES_LEN, &len, &sw);
if (res != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "Sending APDU failed with code %d", res);
return res;
}
if (sw != ISO7816_OK) {
if (verbose == true) {
PrintAndLogEx(INFO, "Unexpected APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
}
return PM3_EFAILED;
}
if (verbose == true) {
if (decodeTLV == true) {
PrintTLVFromBuffer(buf, len);
} else {
print_buffer(buf, len, 0);
}
}
return PM3_SUCCESS;
}
static int PivSelect(Iso7816CommandChannel channel, bool activateField, bool leaveFieldOn, bool decodeTLV, bool silent, uint8_t applet[], size_t appletLen) {
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
uint16_t sw = 0;
int res = Iso7816Select(channel, activateField, leaveFieldOn, applet, appletLen, buf, sizeof(buf), &len, &sw);
if ((sw != 0) && (silent == false)) {
PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
}
if (res != PM3_SUCCESS || sw != ISO7816_OK) {
PrintAndLogEx(FAILED, "Applet selection failed. Card is not a PIV card.");
return res;
}
if (silent == false) {
if (decodeTLV == true) {
PrintTLVFromBuffer(buf, len);
} else {
print_buffer(buf, len, 0);
}
}
return PM3_SUCCESS;
}
static int CmdPIVSelect(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "piv select",
"Executes select applet command",
"piv select -s -> select card, select applet\n"
"piv select -st --aid a00000030800001000 -> select card, select applet a00000030800001000, show result in TLV\n");
void *argtable[] = {
arg_param_begin,
arg_lit0("sS", "select", "Activate field and select applet"),
arg_lit0("kK", "keep", "Keep field for next command"),
arg_lit0("aA", "apdu", "Show APDU requests and responses"),
arg_lit0("tT", "tlv", "TLV decode results"),
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
arg_str0(NULL, "aid", "<hex>", "Applet ID to select. By default A0000003080000100 will be used"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool activateField = arg_get_lit(ctx, 1);
bool leaveSignalON = arg_get_lit(ctx, 2);
bool APDULogging = arg_get_lit(ctx, 3);
bool decodeTLV = arg_get_lit(ctx, 4);
Iso7816CommandChannel channel = CC_CONTACTLESS;
if (arg_get_lit(ctx, 5))
channel = CC_CONTACT;
PrintChannel(channel);
uint8_t applet_id[APDU_AID_LEN] = {0};
int aid_len = 0;
CLIGetHexWithReturn(ctx, 6, applet_id, &aid_len);
if (aid_len == 0) {
memcpy(applet_id, PIV_APPLET, sizeof(PIV_APPLET));
aid_len = sizeof(PIV_APPLET);
}
CLIParserFree(ctx);
SetAPDULogging(APDULogging);
return PivSelect(channel, activateField, leaveSignalON, decodeTLV, false, applet_id, aid_len);
}
static int CmdPIVGetData(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "piv getdata",
"Get a data container of a given tag",
"piv getdata -s 5fc102 -> select card, select applet, get card holder unique identifer\n"
"piv getdata -st 5fc102 -> select card, select applet, get card holder unique identifer, show result in TLV\n");
void *argtable[] = {
arg_param_begin,
arg_lit0("sS", "select", "Activate field and select applet"),
arg_lit0("kK", "keep", "Keep field for next command"),
arg_lit0("aA", "apdu", "Show APDU requests and responses"),
arg_lit0("tT", "tlv", "TLV decode results"),
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
arg_str0(NULL, "aid", "<hex>", "Applet ID to select. By default A0000003080000100 will be used"),
arg_str1(NULL, NULL, "<hex>", "Tag ID to read, between 1 and 3 bytes."),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool activateField = arg_get_lit(ctx, 1);
bool leaveSignalON = arg_get_lit(ctx, 2);
bool APDULogging = arg_get_lit(ctx, 3);
bool decodeTLV = arg_get_lit(ctx, 4);
Iso7816CommandChannel channel = CC_CONTACTLESS;
if (arg_get_lit(ctx, 5))
channel = CC_CONTACT;
PrintChannel(channel);
uint8_t applet_id[APDU_AID_LEN] = {0};
int aid_len = 0;
CLIGetHexWithReturn(ctx, 6, applet_id, &aid_len);
if (aid_len == 0) {
memcpy(applet_id, PIV_APPLET, sizeof(PIV_APPLET));
aid_len = sizeof(PIV_APPLET);
}
uint8_t tag[4] = {0};
int tag_len = 0;
CLIGetHexWithReturn(ctx, 7, tag, &tag_len);
CLIParserFree(ctx);
if ((tag_len < 1) || (tag_len > 3)) {
PrintAndLogEx(WARNING, "Tag should be between 1 and 3 bytes. Got %i", tag_len);
return PM3_EINVARG;
}
SetAPDULogging(APDULogging);
int res = 0;
if (activateField == true) {
res = PivSelect(channel, activateField, true, decodeTLV, true, applet_id, aid_len);
if (res != PM3_SUCCESS) {
if (leaveSignalON == false) {
DropFieldEx(channel);
}
return res;
}
}
res = PivGetDataByTagAndPrint(channel, tag, tag_len, decodeTLV, false);
if (leaveSignalON == false) {
DropFieldEx(channel);
}
return res;
}
static int CmdPIVAuthenticateSign(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "piv sign",
"Send a nonce and ask the PIV card to sign it",
"piv sign -sk -> select card, select applet, sign a NULL nonce\n");
void *argtable[] = {
arg_param_begin,
arg_lit0("sS", "select", "Activate field and select applet"),
arg_lit0("kK", "keep", "Keep field for next command"),
arg_lit0("aA", "apdu", "Show APDU requests and responses"),
arg_lit0("tT", "tlv", "TLV decode results"),
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
arg_str0(NULL, "aid", "<hex>", "Applet ID to select. By default A0000003080000100 will be used"),
arg_str1(NULL, "nonce", "<hex>", "Nonce to sign."),
arg_int0(NULL, "slot", "<dec id>", "Slot number. Default will be 0x9E (card auth cert)."),
arg_int0(NULL, "alg", "<dec>", "Algorithm to use to sign. Example values: 06=RSA-1024, 07=RSA-2048, 11=ECC-P256 (default), 14=ECC-P384"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool activateField = arg_get_lit(ctx, 1);
bool leaveSignalON = arg_get_lit(ctx, 2);
bool APDULogging = arg_get_lit(ctx, 3);
bool decodeTLV = arg_get_lit(ctx, 4);
Iso7816CommandChannel channel = CC_CONTACTLESS;
if (arg_get_lit(ctx, 5))
channel = CC_CONTACT;
PrintChannel(channel);
uint8_t applet_id[APDU_AID_LEN] = {0};
int aid_len = 0;
CLIGetHexWithReturn(ctx, 6, applet_id, &aid_len);
if (aid_len == 0) {
memcpy(applet_id, PIV_APPLET, sizeof(PIV_APPLET));
aid_len = sizeof(PIV_APPLET);
}
uint8_t nonce[APDU_RES_LEN] = {0};
int nonce_len = 0;
CLIGetHexWithReturn(ctx, 7, nonce, &nonce_len);
int key_slot = arg_get_int_def(ctx, 8, 0x9e);
int alg_id = arg_get_int_def(ctx, 9, 0x11);
CLIParserFree(ctx);
if (key_slot > 0xff) {
PrintAndLogEx(FAILED, "Key slot must fit on 1 byte.");
return PM3_EINVARG;
}
if (alg_id > 0xff) {
PrintAndLogEx(FAILED, "Algorithm ID must fit on 1 byte");
return PM3_EINVARG;
}
SetAPDULogging(APDULogging);
int res = 0;
if (activateField == true) {
res = PivSelect(channel, activateField, true, decodeTLV, true, applet_id, aid_len);
if (res != PM3_SUCCESS) {
if (leaveSignalON == false) {
DropFieldEx(channel);
}
return res;
}
}
res = PivAuthenticateSign(channel, (uint8_t)(alg_id & 0xff), (uint8_t)(key_slot & 0xff), nonce, nonce_len, NULL, decodeTLV, true);
if (leaveSignalON == false) {
DropFieldEx(channel);
}
return res;
}
static int CmdPIVScan(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "piv scan",
"Scan a PIV card for known containers",
"piv scan -s -> select card, select applet and run scan\n"
"piv scan -st --aid a00000030800001000 -> select card, select applet a00000030800001000, show result of the scan in TLV\n");
void *argtable[] = {
arg_param_begin,
arg_lit0("sS", "select", "Activate field and select applet"),
arg_lit0("kK", "keep", "Keep field for next command"),
arg_lit0("aA", "apdu", "Show APDU requests and responses"),
arg_lit0("tT", "tlv", "TLV decode results"),
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
arg_str0(NULL, "aid", "<hex>", "Applet ID to select. By default A0000003080000100 will be used"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool activateField = arg_get_lit(ctx, 1);
bool leaveSignalON = arg_get_lit(ctx, 2);
bool APDULogging = arg_get_lit(ctx, 3);
bool decodeTLV = arg_get_lit(ctx, 4);
Iso7816CommandChannel channel = CC_CONTACTLESS;
if (arg_get_lit(ctx, 5))
channel = CC_CONTACT;
PrintChannel(channel);
uint8_t applet_id[APDU_AID_LEN] = {0};
int aid_len = 0;
CLIGetHexWithReturn(ctx, 6, applet_id, &aid_len);
if (aid_len == 0) {
memcpy(applet_id, PIV_APPLET, sizeof(PIV_APPLET));
aid_len = sizeof(PIV_APPLET);
}
CLIParserFree(ctx);
SetAPDULogging(APDULogging);
if (aid_len == 0) {
memcpy(applet_id, PIV_APPLET, sizeof(PIV_APPLET));
aid_len = sizeof(PIV_APPLET);
}
if (activateField == true) {
int res = PivSelect(channel, activateField, true, decodeTLV, true, applet_id, aid_len);
if (res != PM3_SUCCESS) {
if (leaveSignalON == false) {
DropFieldEx(channel);
}
return res;
}
}
for (int i = 0; PIV_CONTAINERS[i].len != 0; i++) {
PivGetDataByCidAndPrint(channel, &(PIV_CONTAINERS[i]), decodeTLV, false);
PrintAndLogEx(NORMAL, "");
}
if (leaveSignalON == false) {
DropFieldEx(channel);
}
return PM3_SUCCESS;
}
static int CmdPIVList(const char *Cmd) {
return CmdTraceListAlias(Cmd, "piv", "7816");
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"select", CmdPIVSelect, IfPm3Iso14443, "Select the PIV applet"},
{"getdata", CmdPIVGetData, IfPm3Iso14443, "Gets a container on a PIV card"},
{"authsign", CmdPIVAuthenticateSign, IfPm3Iso14443, "Authenticate with the card"},
{"scan", CmdPIVScan, IfPm3Iso14443, "Scan PIV card for known containers"},
{"list", CmdPIVList, AlwaysAvailable, "List ISO7816 history"},
{NULL, NULL, NULL, NULL}
};
static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CmdsHelp(CommandTable);
return PM3_SUCCESS;
}
int CmdPIV(const char *Cmd) {
clearCommandBuffer();
return CmdsParse(CommandTable, Cmd);
}

26
client/src/cmdpiv.h Normal file
View file

@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// PIV commands
//-----------------------------------------------------------------------------
#ifndef CMDPIV_H__
#define CMDPIV_H__
#include "common.h"
int CmdPIV(const char *Cmd);
#endif

View file

@ -147,7 +147,7 @@ static int split(char *str, char **arr) {
return word_cnt; return word_cnt;
} }
static void set_python_path(char *path) { static void set_python_path(const char *path) {
PyObject *syspath = PySys_GetObject("path"); PyObject *syspath = PySys_GetObject("path");
if (syspath == 0) { if (syspath == 0) {
PrintAndLogEx(WARNING, "Python failed to getobject"); PrintAndLogEx(WARNING, "Python failed to getobject");
@ -172,7 +172,7 @@ static void set_python_paths(void) {
char scripts_path[strlen(exec_path) + strlen(PYTHON_SCRIPTS_SUBDIR) + strlen(PYTHON_LIBRARIES_WILDCARD) + 1]; char scripts_path[strlen(exec_path) + strlen(PYTHON_SCRIPTS_SUBDIR) + strlen(PYTHON_LIBRARIES_WILDCARD) + 1];
strcpy(scripts_path, exec_path); strcpy(scripts_path, exec_path);
strcat(scripts_path, PYTHON_SCRIPTS_SUBDIR); strcat(scripts_path, PYTHON_SCRIPTS_SUBDIR);
// strcat(scripts_path, PYTHON_LIBRARIES_WILDCARD); // strcat(scripts_path, PYTHON_LIBRARIES_WILDCARD);
set_python_path(scripts_path); set_python_path(scripts_path);
} }
@ -183,7 +183,7 @@ static void set_python_paths(void) {
strcpy(scripts_path, user_path); strcpy(scripts_path, user_path);
strcat(scripts_path, PM3_USER_DIRECTORY); strcat(scripts_path, PM3_USER_DIRECTORY);
strcat(scripts_path, PYTHON_SCRIPTS_SUBDIR); strcat(scripts_path, PYTHON_SCRIPTS_SUBDIR);
// strcat(scripts_path, PYTHON_LIBRARIES_WILDCARD); // strcat(scripts_path, PYTHON_LIBRARIES_WILDCARD);
set_python_path(scripts_path); set_python_path(scripts_path);
} }
@ -194,7 +194,7 @@ static void set_python_paths(void) {
strcpy(scripts_path, exec_path); strcpy(scripts_path, exec_path);
strcat(scripts_path, PM3_SHARE_RELPATH); strcat(scripts_path, PM3_SHARE_RELPATH);
strcat(scripts_path, PYTHON_SCRIPTS_SUBDIR); strcat(scripts_path, PYTHON_SCRIPTS_SUBDIR);
// strcat(scripts_path, PYTHON_LIBRARIES_WILDCARD); // strcat(scripts_path, PYTHON_LIBRARIES_WILDCARD);
set_python_path(scripts_path); set_python_path(scripts_path);
} }
} }
@ -404,15 +404,19 @@ static int CmdScriptRun(const char *Cmd) {
PyImport_AppendInittab("_pm3", PyInit__pm3); PyImport_AppendInittab("_pm3", PyInit__pm3);
#endif #endif
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 10 #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 10
Py_Initialize(); Py_Initialize();
#else #else
PyConfig py_conf; PyConfig py_conf;
PyConfig_InitIsolatedConfig(&py_conf); // We need to use Python mode instead of isolated to avoid breaking stuff.
// Despite being isolated we probably want to allow users to use PyConfig_InitPythonConfig(&py_conf);
// the Python packages they installed on their user directory as well // Let's still make things bit safer by being as close as possible to isolated mode.
// as system ones. But it seems isolated mode still enforces them off. py_conf.configure_c_stdio = -1;
py_conf.use_environment = 1; py_conf.faulthandler = 0;
py_conf.use_hash_seed = 0;
py_conf.install_signal_handlers = 0;
py_conf.parse_argv = 0;
py_conf.user_site_directory = 1; py_conf.user_site_directory = 1;
py_conf.use_environment = 0;
#endif #endif
//int argc, char ** argv //int argc, char ** argv
@ -429,8 +433,13 @@ static int CmdScriptRun(const char *Cmd) {
#else #else
// The following line will implicitly pre-initialize Python // The following line will implicitly pre-initialize Python
PyConfig_SetBytesArgv(&py_conf, argc + 1, argv); PyConfig_SetBytesArgv(&py_conf, argc + 1, argv);
// We disallowed in py_conf environment variables interfering with python interpreter's behavior.
// Let's manually enable the ones we truly need.
// This is required by Proxspace to work with an isolated Python configuration // This is required by Proxspace to work with an isolated Python configuration
PyConfig_SetBytesString(&py_conf, &py_conf.home, getenv("PYTHONHOME")); PyConfig_SetBytesString(&py_conf, &py_conf.home, getenv("PYTHONHOME"));
// This is required for allowing `import pm3` in python scripts
PyConfig_SetBytesString(&py_conf, &py_conf.pythonpath_env, getenv("PYTHONPATH"));
Py_InitializeFromConfig(&py_conf); Py_InitializeFromConfig(&py_conf);

View file

@ -719,7 +719,7 @@ static int CmdSmartInfo(const char *Cmd) {
// print header // print header
PrintAndLogEx(INFO, "--- " _CYAN_("Smartcard Information") " ---------"); PrintAndLogEx(INFO, "--- " _CYAN_("Smartcard Information") " ---------");
PrintAndLogEx(INFO, "ISO7618-3 ATR... %s", sprint_hex(card.atr, card.atr_len)); PrintAndLogEx(INFO, "ISO7816-3 ATR... %s", sprint_hex(card.atr, card.atr_len));
// convert bytes to str. // convert bytes to str.
char *hexstr = calloc((card.atr_len << 1) + 1, sizeof(uint8_t)); char *hexstr = calloc((card.atr_len << 1) + 1, sizeof(uint8_t));
if (hexstr == NULL) { if (hexstr == NULL) {

View file

@ -485,8 +485,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
uint32_t end_of_transmission_timestamp = 0; uint32_t end_of_transmission_timestamp = 0;
uint8_t topaz_reader_command[9]; uint8_t topaz_reader_command[9];
char explanation[40] = {0}; char explanation[40] = {0};
uint8_t mfData[32] = {0};
size_t mfDataLen = 0;
tracelog_hdr_t *first_hdr = (tracelog_hdr_t *)(trace); tracelog_hdr_t *first_hdr = (tracelog_hdr_t *)(trace);
tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + tracepos); tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + tracepos);
@ -573,7 +571,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
//2 Not crc-command //2 Not crc-command
//--- Draw the data column //--- Draw the data column
char line[18][140] = {{0}}; char line[18][160] = {{0}};
if (data_len == 0) { if (data_len == 0) {
if (protocol == ICLASS && duration == 2048) { if (protocol == ICLASS && duration == 2048) {
@ -633,8 +631,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
} }
uint8_t crc_format_string_offset = 0; uint8_t crc_format_string_offset = 0;
if (markCRCBytes) { if (markCRCBytes && data_len > 2) {
//CRC-command //CRC-command
if (((protocol == PROTO_HITAG1) || (protocol == PROTO_HITAGS)) && (data_len > 1)) { if (((protocol == PROTO_HITAG1) || (protocol == PROTO_HITAGS)) && (data_len > 1)) {
// Note that UID REQUEST response has no CRC, but we don't know // Note that UID REQUEST response has no CRC, but we don't know
@ -647,6 +646,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
} else { } else {
if (crcStatus == 0 || crcStatus == 1) { if (crcStatus == 0 || crcStatus == 1) {
char *pos1 = line[(data_len - 2) / 18]; char *pos1 = line[(data_len - 2) / 18];
pos1 += (((data_len - 2) % 18) * 4) - 1; pos1 += (((data_len - 2) % 18) * 4) - 1;
@ -869,6 +869,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
} }
if (protocol == PROTO_MIFARE) { if (protocol == PROTO_MIFARE) {
uint8_t mfData[32] = {0};
size_t mfDataLen = 0;
if (DecodeMifareData(frame, data_len, parityBytes, hdr->isResponse, mfData, &mfDataLen, mfDicKeys, mfDicKeysCount)) { if (DecodeMifareData(frame, data_len, parityBytes, hdr->isResponse, mfData, &mfDataLen, mfDicKeys, mfDicKeysCount)) {
memset(explanation, 0x00, sizeof(explanation)); memset(explanation, 0x00, sizeof(explanation));
annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen, hdr->isResponse); annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen, hdr->isResponse);
@ -898,16 +900,16 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
if (use_us) { if (use_us) {
PrintAndLogEx(NORMAL, " %10.1f | %10.1f | %s |fdt (Frame Delay Time): " _YELLOW_("%.1f"), PrintAndLogEx(NORMAL, " %10.1f | %10.1f | %s |fdt (Frame Delay Time): " _YELLOW_("%.1f"),
(float)time1 / 13.56, (float)time1 / 13.56,
(float)time2 / 13.56, (float)time2 / 13.56,
" ", " ",
(float)(next_hdr->timestamp - end_of_transmission_timestamp) / 13.56); (float)(next_hdr->timestamp - end_of_transmission_timestamp) / 13.56);
} else { } else {
PrintAndLogEx(NORMAL, " %10u | %10u | %s |fdt (Frame Delay Time): " _YELLOW_("%d"), PrintAndLogEx(NORMAL, " %10u | %10u | %s |fdt (Frame Delay Time): " _YELLOW_("%d"),
time1, time1,
time2, time2,
" ", " ",
(next_hdr->timestamp - end_of_transmission_timestamp)); (next_hdr->timestamp - end_of_transmission_timestamp));
} }
} }

View file

@ -17,11 +17,9 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdemv.h" #include "cmdemv.h"
#include <string.h> #include <string.h>
#include "comms.h" // DropField
#include "comms.h" // DropField #include "cmdsmartcard.h" // smart_select
#include "cmdsmartcard.h" // smart_select
#include "cmdtrace.h" #include "cmdtrace.h"
#include "emvjson.h" #include "emvjson.h"
#include "test/cryptotest.h" #include "test/cryptotest.h"
@ -35,6 +33,7 @@
#include "ui.h" #include "ui.h"
#include "emv_tags.h" #include "emv_tags.h"
#include "fileutils.h" #include "fileutils.h"
#include "protocols.h" // ISO7816 APDU return codes
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -1564,7 +1563,7 @@ static int CmdEMVScan(const char *Cmd) {
PrintAndLogEx(INFO, "PPSE"); PrintAndLogEx(INFO, "PPSE");
res = EMVSelectPSE(channel, true, true, 2, buf, sizeof(buf), &len, &sw); res = EMVSelectPSE(channel, true, true, 2, buf, sizeof(buf), &len, &sw);
if (!res && sw == 0x9000) { if (!res && sw == ISO7816_OK) {
if (decodeTLV) if (decodeTLV)
TLVPrintFromBuffer(buf, len); TLVPrintFromBuffer(buf, len);

View file

@ -17,13 +17,11 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "emvcore.h" #include "emvcore.h"
#include <string.h> #include <string.h>
#include "commonutil.h" // ARRAYLEN
#include "commonutil.h" // ARRAYLEN #include "comms.h" // DropField
#include "comms.h" // DropField
#include "cmdparser.h" #include "cmdparser.h"
#include "cmdsmartcard.h" // ExchangeAPDUSC #include "cmdsmartcard.h" // ExchangeAPDUSC
#include "ui.h" #include "ui.h"
#include "cmdhf14a.h" #include "cmdhf14a.h"
#include "cmdhf14b.h" #include "cmdhf14b.h"
@ -31,6 +29,7 @@
#include "emv_tags.h" #include "emv_tags.h"
#include "emvjson.h" #include "emvjson.h"
#include "util_posix.h" #include "util_posix.h"
#include "protocols.h" // ISO7816 APDU return codes
// Got from here. Thanks! // Got from here. Thanks!
// https://eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix // https://eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix
@ -382,8 +381,6 @@ static int EMVCheckAID(Iso7816CommandChannel channel, bool decodeTLV, struct tlv
int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) { int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) {
uint8_t data[APDU_RES_LEN] = {0}; uint8_t data[APDU_RES_LEN] = {0};
size_t datalen = 0; size_t datalen = 0;
uint8_t sfidata[0x11][APDU_RES_LEN];
size_t sfidatalen[0x11] = {0};
uint16_t sw = 0; uint16_t sw = 0;
int res; int res;
const char *PSE_or_PPSE = PSENum == 1 ? "PSE" : "PPSE"; const char *PSE_or_PPSE = PSENum == 1 ? "PSE" : "PPSE";
@ -392,7 +389,7 @@ int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFi
res = EMVSelectPSE(channel, ActivateField, true, PSENum, data, sizeof(data), &datalen, &sw); res = EMVSelectPSE(channel, ActivateField, true, PSENum, data, sizeof(data), &datalen, &sw);
if (!res) { if (!res) {
if (sw != 0x9000) { if (sw != ISO7816_OK) {
PrintAndLogEx(FAILED, "Select PSE error. APDU error: %04x.", sw); PrintAndLogEx(FAILED, "Select PSE error. APDU error: %04x.", sw);
return 1; return 1;
} }
@ -403,6 +400,8 @@ int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFi
// PSE/PPSE with SFI // PSE/PPSE with SFI
struct tlvdb *tsfi = tlvdb_find_path(t, (tlv_tag_t[]) {0x6f, 0xa5, 0x88, 0x00}); struct tlvdb *tsfi = tlvdb_find_path(t, (tlv_tag_t[]) {0x6f, 0xa5, 0x88, 0x00});
if (tsfi) { if (tsfi) {
uint8_t sfidata[0x11][APDU_RES_LEN];
size_t sfidatalen[0x11] = {0};
uint8_t sfin = 0; uint8_t sfin = 0;
tlv_get_uint8(tlvdb_get_tlv(tsfi), &sfin); tlv_get_uint8(tlvdb_get_tlv(tsfi), &sfin);
PrintAndLogEx(INFO, "* PPSE get SFI: 0x%02x.", sfin); PrintAndLogEx(INFO, "* PPSE get SFI: 0x%02x.", sfin);
@ -419,7 +418,7 @@ int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFi
} }
// error catch! // error catch!
if (sw != 0x9000) { if (sw != ISO7816_OK) {
sfidatalen[ui] = 0; sfidatalen[ui] = 0;
PrintAndLogEx(FAILED, "PPSE get Error. APDU error: %04x.", sw); PrintAndLogEx(FAILED, "PPSE get Error. APDU error: %04x.", sw);
break; break;
@ -670,10 +669,6 @@ static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04};
static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value }; static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value };
int trDDA(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { int trDDA(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
uint16_t sw = 0;
struct emv_pk *pk = get_ca_pk(tlv); struct emv_pk *pk = get_ca_pk(tlv);
if (!pk) { if (!pk) {
PrintAndLogEx(ERR, "Error: Key not found, exiting"); PrintAndLogEx(ERR, "Error: Key not found, exiting");
@ -768,6 +763,9 @@ int trDDA(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
tlvdb_free(atc_db); tlvdb_free(atc_db);
} else { } else {
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
uint16_t sw = 0;
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
if (dac_db) { if (dac_db) {
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);

View file

@ -44,19 +44,6 @@
// const typeof( ((type *)0)->member ) *__mptr = (ptr); // const typeof( ((type *)0)->member ) *__mptr = (ptr);
// (type *)( (char *)__mptr - offsetof(type,member) );}) // (type *)( (char *)__mptr - offsetof(type,member) );})
struct tlvdb {
struct tlv tag;
struct tlvdb *next;
struct tlvdb *parent;
struct tlvdb *children;
};
struct tlvdb_root {
struct tlvdb db;
size_t len;
unsigned char buf[0];
};
static tlv_tag_t tlv_parse_tag(const unsigned char **buf, size_t *len) { static tlv_tag_t tlv_parse_tag(const unsigned char **buf, size_t *len) {
tlv_tag_t tag; tlv_tag_t tag;
@ -212,6 +199,7 @@ struct tlvdb *tlvdb_parse(const unsigned char *buf, size_t len) {
err: err:
tlvdb_free(&root->db); tlvdb_free(&root->db);
free(root);
return NULL; return NULL;
} }
@ -248,9 +236,53 @@ struct tlvdb *tlvdb_parse_multi(const unsigned char *buf, size_t len) {
err: err:
tlvdb_free(&root->db); tlvdb_free(&root->db);
free(root);
return NULL; return NULL;
} }
bool tlvdb_parse_root(struct tlvdb_root *root) {
if (root == NULL || root->len == 0) {
return false;
}
const uint8_t *tmp;
size_t left;
tmp = root->buf;
left = root->len;
if (tlvdb_parse_one(&root->db, NULL, &tmp, &left) == true) {
if (left == 0) {
return true;
}
}
return false;
}
bool tlvdb_parse_root_multi(struct tlvdb_root *root) {
if (root == NULL || root->len == 0) {
return false;
}
const uint8_t *tmp;
size_t left;
tmp = root->buf;
left = root->len;
if (tlvdb_parse_one(&root->db, NULL, &tmp, &left) == true) {
while (left > 0) {
struct tlvdb *db = calloc(1, sizeof(*db));
if (tlvdb_parse_one(db, NULL, &tmp, &left) == true) {
tlvdb_add(&root->db, db);
} else {
free(db);
return false;
}
}
return true;
}
return false;
}
struct tlvdb *tlvdb_fixed(tlv_tag_t tag, size_t len, const unsigned char *value) { struct tlvdb *tlvdb_fixed(tlv_tag_t tag, size_t len, const unsigned char *value) {
struct tlvdb_root *root = calloc(1, sizeof(*root) + len); struct tlvdb_root *root = calloc(1, sizeof(*root) + len);
@ -291,6 +323,21 @@ void tlvdb_free(struct tlvdb *tlvdb) {
} }
} }
void tlvdb_root_free(struct tlvdb_root *root) {
if (root == NULL) {
return;
}
if (root->db.children) {
tlvdb_free(root->db.children);
root->db.children = NULL;
}
if (root->db.next) {
tlvdb_free(root->db.next);
root->db.next = NULL;
}
free(root);
}
struct tlvdb *tlvdb_find_next(struct tlvdb *tlvdb, tlv_tag_t tag) { struct tlvdb *tlvdb_find_next(struct tlvdb *tlvdb, tlv_tag_t tag) {
if (!tlvdb) if (!tlvdb)
return NULL; return NULL;

View file

@ -31,14 +31,31 @@ struct tlv {
const unsigned char *value; const unsigned char *value;
}; };
struct tlvdb; struct tlvdb {
struct tlv tag;
struct tlvdb *next;
struct tlvdb *parent;
struct tlvdb *children;
};
struct tlvdb_root {
struct tlvdb db;
size_t len;
unsigned char buf[0];
};
typedef void (*tlv_cb)(void *data, const struct tlv *tlv, int level, bool is_leaf); typedef void (*tlv_cb)(void *data, const struct tlv *tlv, int level, bool is_leaf);
struct tlvdb *tlvdb_fixed(tlv_tag_t tag, size_t len, const unsigned char *value); struct tlvdb *tlvdb_fixed(tlv_tag_t tag, size_t len, const unsigned char *value);
struct tlvdb *tlvdb_external(tlv_tag_t tag, size_t len, const unsigned char *value); struct tlvdb *tlvdb_external(tlv_tag_t tag, size_t len, const unsigned char *value);
struct tlvdb *tlvdb_parse(const unsigned char *buf, size_t len); struct tlvdb *tlvdb_parse(const unsigned char *buf, size_t len);
struct tlvdb *tlvdb_parse_multi(const unsigned char *buf, size_t len); struct tlvdb *tlvdb_parse_multi(const unsigned char *buf, size_t len);
bool tlvdb_parse_root(struct tlvdb_root *root);
bool tlvdb_parse_root_multi(struct tlvdb_root *root);
void tlvdb_free(struct tlvdb *tlvdb); void tlvdb_free(struct tlvdb *tlvdb);
void tlvdb_root_free(struct tlvdb_root *root);
struct tlvdb *tlvdb_elm_get_next(struct tlvdb *tlvdb); struct tlvdb *tlvdb_elm_get_next(struct tlvdb *tlvdb);
struct tlvdb *tlvdb_elm_get_children(struct tlvdb *tlvdb); struct tlvdb *tlvdb_elm_get_children(struct tlvdb *tlvdb);

View file

@ -214,18 +214,23 @@ bool create_path(const char *dirname) {
} }
*/ */
bool setDefaultPath(savePaths_t pathIndex, const char *Path) { bool setDefaultPath(savePaths_t pathIndex, const char *path) {
if (pathIndex < spItemCount) { if (pathIndex < spItemCount) {
if ((Path == NULL) && (g_session.defaultPaths[pathIndex] != NULL)) {
if ((path == NULL) && (g_session.defaultPaths[pathIndex] != NULL)) {
free(g_session.defaultPaths[pathIndex]); free(g_session.defaultPaths[pathIndex]);
g_session.defaultPaths[pathIndex] = NULL; g_session.defaultPaths[pathIndex] = NULL;
} }
if (Path != NULL) { if (path == NULL) {
g_session.defaultPaths[pathIndex] = (char *)realloc(g_session.defaultPaths[pathIndex], strlen(Path) + 1); return false;
strcpy(g_session.defaultPaths[pathIndex], Path);
} }
size_t len = strlen(path);
g_session.defaultPaths[pathIndex] = (char *)realloc(g_session.defaultPaths[pathIndex], len + 1);
strcpy(g_session.defaultPaths[pathIndex], path);
return true; return true;
} }
return false; return false;
@ -234,47 +239,70 @@ bool setDefaultPath(savePaths_t pathIndex, const char *Path) {
static char *filenamemcopy(const char *preferredName, const char *suffix) { static char *filenamemcopy(const char *preferredName, const char *suffix) {
if (preferredName == NULL) return NULL; if (preferredName == NULL) return NULL;
if (suffix == NULL) return NULL; if (suffix == NULL) return NULL;
char *fileName = (char *) calloc(strlen(preferredName) + strlen(suffix) + 1, sizeof(uint8_t)); char *fileName = (char *) calloc(strlen(preferredName) + strlen(suffix) + 1, sizeof(uint8_t));
if (fileName == NULL) if (fileName == NULL) {
return NULL; return NULL;
}
strcpy(fileName, preferredName); strcpy(fileName, preferredName);
if (str_endswith(fileName, suffix)) if (str_endswith(fileName, suffix)) {
return fileName; return fileName;
}
strcat(fileName, suffix); strcat(fileName, suffix);
return fileName; return fileName;
} }
static size_t path_size(savePaths_t a) {
if (a == spItemCount) {
return 0;
}
return strlen(g_session.defaultPaths[a]);
}
char *newfilenamemcopy(const char *preferredName, const char *suffix) { char *newfilenamemcopy(const char *preferredName, const char *suffix) {
if (preferredName == NULL) return NULL; if (preferredName == NULL || suffix == NULL) {
if (suffix == NULL) return NULL; return NULL;
}
uint16_t p_namelen = strlen(preferredName); uint16_t p_namelen = strlen(preferredName);
if (str_endswith(preferredName, suffix)) if (str_endswith(preferredName, suffix))
p_namelen -= strlen(suffix); p_namelen -= strlen(suffix);
const size_t fileNameLen = p_namelen + strlen(suffix) + 1 + 10; // 10: room for filenum to ensure new filename
const size_t fileNameSize = fileNameLen * sizeof(uint8_t); const size_t len = p_namelen + strlen(suffix) + 1 + 10;
char *fileName = (char *) calloc(fileNameLen, sizeof(uint8_t)); // 10: room for filenum to ensure new filename int foobar = path_size(spDefault);
(void) foobar;
char *fileName = (char *) calloc(len, sizeof(uint8_t));
if (fileName == NULL) { if (fileName == NULL) {
return NULL; return NULL;
} }
int num = 1; int num = 1;
snprintf(fileName, fileNameSize, "%.*s%s", p_namelen, preferredName, suffix);
snprintf(fileName, len, "%.*s%s", p_namelen, preferredName, suffix);
while (fileExists(fileName)) { while (fileExists(fileName)) {
snprintf(fileName, fileNameSize, "%.*s-%d%s", p_namelen, preferredName, num, suffix); snprintf(fileName, len, "%.*s-%d%s", p_namelen, preferredName, num, suffix);
num++; num++;
} }
PrintAndLogEx(INFO, "FILE PATH: %s", fileName);
return fileName; return fileName;
} }
int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) { int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) {
if (data == NULL) return PM3_EINVARG; if (data == NULL || datalen == 0) {
return PM3_EINVARG;
}
char *fileName = newfilenamemcopy(preferredName, suffix); char *fileName = newfilenamemcopy(preferredName, suffix);
if (fileName == NULL) return PM3_EMALLOC; if (fileName == NULL) {
return PM3_EMALLOC;
}
/* We should have a valid filename now, e.g. dumpdata-3.bin */ /* We should have a valid filename now, e.g. dumpdata-3.bin */
@ -295,9 +323,14 @@ int saveFile(const char *preferredName, const char *suffix, const void *data, si
int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t blocksize) { int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t blocksize) {
if (data == NULL) return PM3_EINVARG; if (data == NULL || datalen == 0) {
return PM3_EINVARG;
}
char *fileName = newfilenamemcopy(preferredName, ".eml"); char *fileName = newfilenamemcopy(preferredName, ".eml");
if (fileName == NULL) return PM3_EMALLOC; if (fileName == NULL) {
return PM3_EMALLOC;
}
int retval = PM3_SUCCESS; int retval = PM3_SUCCESS;
int blocks = datalen / blocksize; int blocks = datalen / blocksize;
@ -343,10 +376,14 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s
} }
int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)) { int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)) {
if (data == NULL) return PM3_EINVARG; if (data == NULL || datalen == 0) {
return PM3_EINVARG;
}
char *fileName = newfilenamemcopy(preferredName, ".json"); char *fileName = newfilenamemcopy(preferredName, ".json");
if (fileName == NULL) return PM3_EMALLOC; if (fileName == NULL) {
return PM3_EMALLOC;
}
int retval = PM3_SUCCESS; int retval = PM3_SUCCESS;
@ -704,9 +741,15 @@ int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool
int saveFileWAVE(const char *preferredName, const int *data, size_t datalen) { int saveFileWAVE(const char *preferredName, const int *data, size_t datalen) {
if (data == NULL) return PM3_EINVARG; if (data == NULL || datalen == 0) {
return PM3_EINVARG;
}
char *fileName = newfilenamemcopy(preferredName, ".wav"); char *fileName = newfilenamemcopy(preferredName, ".wav");
if (fileName == NULL) return PM3_EMALLOC; if (fileName == NULL) {
return PM3_EMALLOC;
}
int retval = PM3_SUCCESS; int retval = PM3_SUCCESS;
struct wave_info_t wave_info = { struct wave_info_t wave_info = {
@ -731,11 +774,14 @@ int saveFileWAVE(const char *preferredName, const int *data, size_t datalen) {
retval = PM3_EFILE; retval = PM3_EFILE;
goto out; goto out;
} }
fwrite(&wave_info, sizeof(wave_info), 1, wave_file); fwrite(&wave_info, sizeof(wave_info), 1, wave_file);
for (int i = 0; i < datalen; i++) { for (int i = 0; i < datalen; i++) {
uint8_t sample = data[i] + 128; uint8_t sample = data[i] + 128;
fwrite(&sample, 1, 1, wave_file); fwrite(&sample, 1, 1, wave_file);
} }
fclose(wave_file); fclose(wave_file);
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu") " bytes to wave file " _YELLOW_("'%s'"), 2 * datalen, fileName); PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu") " bytes to wave file " _YELLOW_("'%s'"), 2 * datalen, fileName);
@ -747,9 +793,14 @@ out:
int saveFilePM3(const char *preferredName, int *data, size_t datalen) { int saveFilePM3(const char *preferredName, int *data, size_t datalen) {
if (data == NULL) return PM3_EINVARG; if (data == NULL || datalen == 0) {
return PM3_EINVARG;
}
char *fileName = newfilenamemcopy(preferredName, ".pm3"); char *fileName = newfilenamemcopy(preferredName, ".pm3");
if (fileName == NULL) return PM3_EMALLOC; if (fileName == NULL) {
return PM3_EMALLOC;
}
int retval = PM3_SUCCESS; int retval = PM3_SUCCESS;
@ -760,8 +811,9 @@ int saveFilePM3(const char *preferredName, int *data, size_t datalen) {
goto out; goto out;
} }
for (uint32_t i = 0; i < datalen; i++) for (uint32_t i = 0; i < datalen; i++) {
fprintf(f, "%d\n", data[i]); fprintf(f, "%d\n", data[i]);
}
fflush(f); fflush(f);
fclose(f); fclose(f);
@ -1110,12 +1162,18 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
goto out; goto out;
} }
uint8_t *udata = (uint8_t *)data; typedef union UDATA {
void *v;
uint8_t *bytes;
mfu_dump_t *mfu;
topaz_tag_t *topaz;
} UDATA;
UDATA udata = (UDATA)data;
char ctype[100] = {0}; char ctype[100] = {0};
JsonLoadStr(root, "$.FileType", ctype); JsonLoadStr(root, "$.FileType", ctype);
if (!strcmp(ctype, "raw")) { if (!strcmp(ctype, "raw")) {
JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen); JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen);
} }
if (!strcmp(ctype, "mfcard")) { if (!strcmp(ctype, "mfcard")) {
@ -1135,7 +1193,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
goto out; goto out;
} }
memcpy(&udata[sptr], block, 16); memcpy(&udata.bytes[sptr], block, 16);
sptr += len; sptr += len;
} }
@ -1154,7 +1212,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
size_t len = 0; size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len); JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
if (!len) if (!len)
break; break;
@ -1166,18 +1224,16 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
if (!strcmp(ctype, "mfu")) { if (!strcmp(ctype, "mfu")) {
mfu_dump_t *mem = (mfu_dump_t *)udata; JsonLoadBufAsHex(root, "$.Card.Version", udata.mfu->version, sizeof(udata.mfu->version), datalen);
JsonLoadBufAsHex(root, "$.Card.TBO_0", udata.mfu->tbo, sizeof(udata.mfu->tbo), datalen);
JsonLoadBufAsHex(root, "$.Card.Version", mem->version, sizeof(mem->version), datalen); JsonLoadBufAsHex(root, "$.Card.TBO_1", udata.mfu->tbo1, sizeof(udata.mfu->tbo1), datalen);
JsonLoadBufAsHex(root, "$.Card.TBO_0", mem->tbo, sizeof(mem->tbo), datalen); JsonLoadBufAsHex(root, "$.Card.Signature", udata.mfu->signature, sizeof(udata.mfu->signature), datalen);
JsonLoadBufAsHex(root, "$.Card.TBO_1", mem->tbo1, sizeof(mem->tbo1), datalen); JsonLoadBufAsHex(root, "$.Card.Counter0", &udata.mfu->counter_tearing[0][0], 3, datalen);
JsonLoadBufAsHex(root, "$.Card.Signature", mem->signature, sizeof(mem->signature), datalen); JsonLoadBufAsHex(root, "$.Card.Tearing0", &udata.mfu->counter_tearing[0][3], 1, datalen);
JsonLoadBufAsHex(root, "$.Card.Counter0", &mem->counter_tearing[0][0], 3, datalen); JsonLoadBufAsHex(root, "$.Card.Counter1", &udata.mfu->counter_tearing[1][0], 3, datalen);
JsonLoadBufAsHex(root, "$.Card.Tearing0", &mem->counter_tearing[0][3], 1, datalen); JsonLoadBufAsHex(root, "$.Card.Tearing1", &udata.mfu->counter_tearing[1][3], 1, datalen);
JsonLoadBufAsHex(root, "$.Card.Counter1", &mem->counter_tearing[1][0], 3, datalen); JsonLoadBufAsHex(root, "$.Card.Counter2", &udata.mfu->counter_tearing[2][0], 3, datalen);
JsonLoadBufAsHex(root, "$.Card.Tearing1", &mem->counter_tearing[1][3], 1, datalen); JsonLoadBufAsHex(root, "$.Card.Tearing2", &udata.mfu->counter_tearing[2][3], 1, datalen);
JsonLoadBufAsHex(root, "$.Card.Counter2", &mem->counter_tearing[2][0], 3, datalen);
JsonLoadBufAsHex(root, "$.Card.Tearing2", &mem->counter_tearing[2][3], 1, datalen);
*datalen = MFU_DUMP_PREFIX_LENGTH; *datalen = MFU_DUMP_PREFIX_LENGTH;
size_t sptr = 0; size_t sptr = 0;
@ -1191,15 +1247,15 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
size_t len = 0; size_t len = 0;
JsonLoadBufAsHex(root, blocks, &mem->data[sptr], MFU_BLOCK_SIZE, &len); JsonLoadBufAsHex(root, blocks, &udata.mfu->data[sptr], MFU_BLOCK_SIZE, &len);
if (!len) if (!len)
break; break;
sptr += len; sptr += len;
mem->pages++; udata.mfu->pages++;
} }
// remove one, since pages indicates a index rather than number of available pages // remove one, since pages indicates a index rather than number of available pages
--mem->pages; --udata.mfu->pages;
*datalen += sptr; *datalen += sptr;
} }
@ -1216,7 +1272,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i); snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i);
size_t len = 0; size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len); JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
if (!len) if (!len)
break; break;
@ -1238,7 +1294,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i); snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i);
size_t len = 0; size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata[sptr], 8, &len); JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 8, &len);
if (!len) if (!len)
break; break;
@ -1259,7 +1315,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i); snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i);
size_t len = 0; size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len); JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
if (!len) if (!len)
break; break;
@ -1280,7 +1336,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i); snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i);
size_t len = 0; size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len); JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
if (!len) if (!len)
break; break;
@ -1290,19 +1346,18 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
} }
if (!strcmp(ctype, "15693")) { if (!strcmp(ctype, "15693")) {
JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen); JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen);
} }
if (!strcmp(ctype, "legic")) { if (!strcmp(ctype, "legic")) {
JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen); JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen);
} }
if (!strcmp(ctype, "topaz")) { if (!strcmp(ctype, "topaz")) {
topaz_tag_t *mem = (topaz_tag_t *)udata; JsonLoadBufAsHex(root, "$.Card.UID", udata.topaz->uid, sizeof(udata.topaz->uid), datalen);
JsonLoadBufAsHex(root, "$.Card.UID", mem->uid, sizeof(mem->uid), datalen); JsonLoadBufAsHex(root, "$.Card.HR01", udata.topaz->HR01, sizeof(udata.topaz->HR01), datalen);
JsonLoadBufAsHex(root, "$.Card.HR01", mem->HR01, sizeof(mem->HR01), datalen); JsonLoadBufAsHex(root, "$.Card.Size", (uint8_t *) & (udata.topaz->size), 2, datalen);
JsonLoadBufAsHex(root, "$.Card.Size", (uint8_t *) & (mem->size), 2, datalen);
size_t sptr = 0; size_t sptr = 0;
for (int i = 0; i < (TOPAZ_STATIC_MEMORY / 8); i++) { for (int i = 0; i < (TOPAZ_STATIC_MEMORY / 8); i++) {
@ -1316,7 +1371,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
size_t len = 0; size_t len = 0;
JsonLoadBufAsHex(root, blocks, &mem->data_blocks[sptr][0], TOPAZ_BLOCK_SIZE, &len); JsonLoadBufAsHex(root, blocks, &udata.topaz->data_blocks[sptr][0], TOPAZ_BLOCK_SIZE, &len);
if (!len) if (!len)
break; break;
@ -1862,14 +1917,18 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea
(strcmp(PYTHON_SCRIPTS_SUBDIR, pm3dir) == 0) || (strcmp(PYTHON_SCRIPTS_SUBDIR, pm3dir) == 0) ||
(strcmp(RESOURCES_SUBDIR, pm3dir) == 0))) { (strcmp(RESOURCES_SUBDIR, pm3dir) == 0))) {
char *path = calloc(strlen(exec_path) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char)); char *path = calloc(strlen(exec_path) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
if (path == NULL) if (path == NULL) {
goto out; goto out;
}
strcpy(path, exec_path); strcpy(path, exec_path);
strcat(path, pm3dir); strcat(path, pm3dir);
strcat(path, filename); strcat(path, filename);
if ((g_debugMode == 2) && (!silent)) { if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", path); PrintAndLogEx(INFO, "Searching %s", path);
} }
if (fileExists(path)) { if (fileExists(path)) {
free(filename); free(filename);
*foundpath = path; *foundpath = path;
@ -2007,7 +2066,8 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
} }
int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft, size_t blocksize) { int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft, size_t blocksize) {
if (n == 0) {
if (d == NULL || n == 0) {
PrintAndLogEx(INFO, "No data to save. Skipping..."); PrintAndLogEx(INFO, "No data to save. Skipping...");
return PM3_EINVARG; return PM3_EINVARG;
} }

View file

@ -60,7 +60,9 @@ typedef enum {
int fileExists(const char *filename); int fileExists(const char *filename);
//bool create_path(const char *dirname); //bool create_path(const char *dirname);
bool setDefaultPath(savePaths_t pathIndex, const char *Path); // set a path in the path list g_session.defaultPaths
// set a path in the path list g_session.defaultPaths
bool setDefaultPath(savePaths_t pathIndex, const char *path);
char *newfilenamemcopy(const char *preferredName, const char *suffix); char *newfilenamemcopy(const char *preferredName, const char *suffix);

View file

@ -489,7 +489,7 @@ static void flash_suggest_update_bootloader(void) {
PrintAndLogEx(ERR, "------------- " _CYAN_("Follow these steps") " -------------------"); PrintAndLogEx(ERR, "------------- " _CYAN_("Follow these steps") " -------------------");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(ERR, " 1) ./pm3-flash-bootrom"); PrintAndLogEx(ERR, " 1) ./pm3-flash-bootrom");
PrintAndLogEx(ERR, " 2) ./pm3-flash-all"); PrintAndLogEx(ERR, " 2) ./pm3-flash-fullimage");
PrintAndLogEx(ERR, " 3) ./pm3"); PrintAndLogEx(ERR, " 3) ./pm3");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "---------------------------------------------------"); PrintAndLogEx(INFO, "---------------------------------------------------");

View file

@ -440,7 +440,8 @@ int APDUDecode(uint8_t *data, int len, APDU_t *apdu) {
int APDUEncode(APDU_t *apdu, uint8_t *data, int *len) { int APDUEncode(APDU_t *apdu, uint8_t *data, int *len) {
if (len) if (len)
*len = 0; *len = 0;
if (apdu == NULL)
return 1;
if (apdu->le > 0x10000) if (apdu->le > 0x10000)
return 1; return 1;

View file

@ -17,9 +17,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "iso7816core.h" #include "iso7816core.h"
#include <string.h> #include <string.h>
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "comms.h" // DropField #include "comms.h" // DropField
#include "cmdparser.h" #include "cmdparser.h"
@ -29,6 +27,7 @@
#include "cmdhf14b.h" #include "cmdhf14b.h"
#include "iso14b.h" // iso14b_raw_cmd_t #include "iso14b.h" // iso14b_raw_cmd_t
#include "util_posix.h" #include "util_posix.h"
#include "protocols.h" // ISO7816 APDU return codes
//iceman: this logging setting, should be unified with client debug etc. //iceman: this logging setting, should be unified with client debug etc.
static bool APDULogging = false; static bool APDULogging = false;
@ -170,7 +169,7 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
*sw = isw; *sw = isw;
} }
if (isw != 0x9000) { if (isw != ISO7816_OK) {
if (APDULogging) { if (APDULogging) {
if (*sw >> 8 == 0x61) { if (*sw >> 8 == 0x61) {
PrintAndLogEx(ERR, "APDU chaining len %02x", *sw & 0xFF); PrintAndLogEx(ERR, "APDU chaining len %02x", *sw & 0xFF);

View file

@ -38,6 +38,7 @@
#include "util.h" #include "util.h"
#include "comms.h" // clearCommandBuffer #include "comms.h" // clearCommandBuffer
#include "commonutil.h" // ntohl (pm3 version) #include "commonutil.h" // ntohl (pm3 version)
#include "protocols.h" // ISO7816 APDU return codes
// Date type. This is the actual on-card format. // Date type. This is the actual on-card format.
typedef struct { typedef struct {
@ -98,7 +99,7 @@ typedef struct {
KEY_TYPE key, const char* defaultValue) { \ KEY_TYPE key, const char* defaultValue) { \
struct _ksx6924_enum_ ## KEY_TYPE *r = bsearch( \ struct _ksx6924_enum_ ## KEY_TYPE *r = bsearch( \
&key, KSX6924_ENUM_ ## NAME, \ &key, KSX6924_ENUM_ ## NAME, \
sizeof(KSX6924_ENUM_ ## NAME) / sizeof(KSX6924_ENUM_ ## NAME [0]), \ ARRAYLEN(KSX6924_ENUM_ ## NAME), \
sizeof(KSX6924_ENUM_ ## NAME [0]), \ sizeof(KSX6924_ENUM_ ## NAME [0]), \
_ksx6924_ ## KEY_TYPE ## _enum_compare); \ _ksx6924_ ## KEY_TYPE ## _enum_compare); \
if (r == NULL) { \ if (r == NULL) { \
@ -402,7 +403,7 @@ bool KSX6924TrySelect(void) {
return false; return false;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
if (sw) { if (sw) {
PrintAndLogEx(FAILED, PrintAndLogEx(FAILED,
"Not a KS X 6924 card! APDU response: %04x - %s", "Not a KS X 6924 card! APDU response: %04x - %s",
@ -444,7 +445,7 @@ bool KSX6924GetBalance(uint32_t *result) {
return false; return false;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
return false; return false;
} }
@ -476,7 +477,7 @@ bool KSX6924InitializeCard(uint8_t mpda1, uint8_t mpda2, uint8_t mpda3, uint8_t
return false; return false;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
return false; return false;
} }
@ -574,7 +575,7 @@ bool KSX6924ProprietaryGetRecord(uint8_t id, uint8_t *result, size_t result_len)
return false; return false;
} }
if (sw != 0x9000) { if (sw != ISO7816_OK) {
return false; return false;
} }

View file

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

View file

@ -32,9 +32,9 @@
#include "aes.h" #include "aes.h"
#include "ui.h" #include "ui.h"
#include "crc.h" #include "crc.h"
#include "crc16.h" // crc16 ccitt #include "crc16.h" // crc16 ccitt
#include "crc32.h" #include "crc32.h"
#include "protocols.h" #include "protocols.h" // ISO7816 APDU return codes
#include "cmdhf14a.h" #include "cmdhf14a.h"
#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes #include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
#include "iso7816/iso7816core.h" // APDU logging #include "iso7816/iso7816core.h" // APDU logging
@ -470,7 +470,7 @@ static int DESFIRESendApduEx(bool activate_field, sAPDU_t apdu, uint16_t le, uin
if (sw) if (sw)
*sw = isw; *sw = isw;
if (isw != 0x9000 && if (isw != ISO7816_OK &&
isw != DESFIRE_GET_ISO_STATUS(MFDES_S_OPERATION_OK) && isw != DESFIRE_GET_ISO_STATUS(MFDES_S_OPERATION_OK) &&
isw != DESFIRE_GET_ISO_STATUS(MFDES_S_SIGNATURE) && isw != DESFIRE_GET_ISO_STATUS(MFDES_S_SIGNATURE) &&
isw != DESFIRE_GET_ISO_STATUS(MFDES_S_ADDITIONAL_FRAME) && isw != DESFIRE_GET_ISO_STATUS(MFDES_S_ADDITIONAL_FRAME) &&
@ -1655,7 +1655,7 @@ static bool DesfireCheckISOAuthCmd(DesfireISOSelectWay way, uint32_t appID, char
uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keyNum; uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keyNum;
res = DesfireExchangeISO(false, &dctx, (sAPDU_t) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, rndlen * 2, piccrnd}, 0, resp, &resplen, &sw); res = DesfireExchangeISO(false, &dctx, (sAPDU_t) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, rndlen * 2, piccrnd}, 0, resp, &resplen, &sw);
DropField(); DropField();
return (sw == 0x9000 || sw == 0x6982); return (sw == ISO7816_OK || sw == ISO7816_SECURITY_STATUS_NOT_SATISFIED);
} }
void DesfireCheckAuthCommands(DesfireISOSelectWay way, uint32_t appID, char *dfname, uint8_t keyNum, AuthCommandsChk_t *authCmdCheck) { void DesfireCheckAuthCommands(DesfireISOSelectWay way, uint32_t appID, char *dfname, uint8_t keyNum, AuthCommandsChk_t *authCmdCheck) {
@ -2301,9 +2301,9 @@ static const char *GetDesfireKeyType(uint8_t keytype) {
} }
const char *GetDesfireAccessRightStr(uint8_t right) { const char *GetDesfireAccessRightStr(uint8_t right) {
static char int_access_str[200];
if (right <= 0x0d) { if (right <= 0x0d) {
static char int_access_str[200];
snprintf(int_access_str, sizeof(int_access_str), "key 0x%02x", right); snprintf(int_access_str, sizeof(int_access_str), "key 0x%02x", right);
return int_access_str; return int_access_str;
} }
@ -2859,7 +2859,7 @@ int DesfireISOSelectEx(DesfireContext_t *dctx, bool fieldon, DesfireISOSelectCon
size_t xresplen = 0; size_t xresplen = 0;
uint16_t sw = 0; uint16_t sw = 0;
int res = DesfireExchangeISO(fieldon, dctx, (sAPDU_t) {0x00, ISO7816_SELECT_FILE, cntr, ((resp == NULL) ? 0x0C : 0x00), datalen, data}, APDU_INCLUDE_LE_00, xresp, &xresplen, &sw); int res = DesfireExchangeISO(fieldon, dctx, (sAPDU_t) {0x00, ISO7816_SELECT_FILE, cntr, ((resp == NULL) ? 0x0C : 0x00), datalen, data}, APDU_INCLUDE_LE_00, xresp, &xresplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000) if (res == PM3_SUCCESS && sw != ISO7816_OK)
return PM3_ESOFT; return PM3_ESOFT;
if (resp != NULL && resplen != NULL) { if (resp != NULL && resplen != NULL) {
@ -2885,7 +2885,7 @@ int DesfireISOSelectDF(DesfireContext_t *dctx, char *dfname, uint8_t *resp, size
int DesfireISOGetChallenge(DesfireContext_t *dctx, DesfireCryptoAlgorithm keytype, uint8_t *resp, size_t *resplen) { int DesfireISOGetChallenge(DesfireContext_t *dctx, DesfireCryptoAlgorithm keytype, uint8_t *resp, size_t *resplen) {
uint16_t sw = 0; uint16_t sw = 0;
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_GET_CHALLENGE, 0x00, 0x00, 0x00, NULL}, DesfireGetRndLenForKey(keytype), resp, resplen, &sw); int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_GET_CHALLENGE, 0x00, 0x00, 0x00, NULL}, DesfireGetRndLenForKey(keytype), resp, resplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000) if (res == PM3_SUCCESS && sw != ISO7816_OK)
return PM3_ESOFT; return PM3_ESOFT;
return res; return res;
@ -2900,7 +2900,7 @@ int DesfireISOExternalAuth(DesfireContext_t *dctx, bool app_level, uint8_t keynu
uint16_t sw = 0; uint16_t sw = 0;
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, DesfireGetRndLenForKey(keytype) * 2, data}, 0, resp, &resplen, &sw); int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, DesfireGetRndLenForKey(keytype) * 2, data}, 0, resp, &resplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000) if (res == PM3_SUCCESS && sw != ISO7816_OK)
return PM3_ESOFT; return PM3_ESOFT;
return res; return res;
@ -2913,7 +2913,7 @@ int DesfireISOInternalAuth(DesfireContext_t *dctx, bool app_level, uint8_t keynu
uint16_t sw = 0; uint16_t sw = 0;
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_INTERNAL_AUTHENTICATION, p1, p2, keylen, data}, keylen * 2, resp, resplen, &sw); int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_INTERNAL_AUTHENTICATION, p1, p2, keylen, data}, keylen * 2, resp, resplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000) if (res == PM3_SUCCESS && sw != ISO7816_OK)
return PM3_ESOFT; return PM3_ESOFT;
return res; return res;
@ -2929,7 +2929,7 @@ int DesfireISOReadBinary(DesfireContext_t *dctx, bool use_file_id, uint8_t filei
uint16_t sw = 0; uint16_t sw = 0;
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_READ_BINARY, p1, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw); int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_READ_BINARY, p1, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000) if (res == PM3_SUCCESS && sw != ISO7816_OK)
return PM3_ESOFT; return PM3_ESOFT;
return res; return res;
@ -2948,7 +2948,7 @@ int DesfireISOUpdateBinary(DesfireContext_t *dctx, bool use_file_id, uint8_t fil
uint16_t sw = 0; uint16_t sw = 0;
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_UPDATE_BINARY, p1, p2, datalen, data}, 0, resp, &resplen, &sw); int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_UPDATE_BINARY, p1, p2, datalen, data}, 0, resp, &resplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000) if (res == PM3_SUCCESS && sw != ISO7816_OK)
return PM3_ESOFT; return PM3_ESOFT;
return res; return res;
@ -2959,7 +2959,7 @@ int DesfireISOReadRecords(DesfireContext_t *dctx, uint8_t recordnum, bool read_a
uint16_t sw = 0; uint16_t sw = 0;
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_READ_RECORDS, recordnum, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw); int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_READ_RECORDS, recordnum, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000) if (res == PM3_SUCCESS && sw != ISO7816_OK)
return PM3_ESOFT; return PM3_ESOFT;
return res; return res;
@ -2973,7 +2973,7 @@ int DesfireISOAppendRecord(DesfireContext_t *dctx, uint8_t fileid, uint8_t *data
uint16_t sw = 0; uint16_t sw = 0;
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_APPEND_RECORD, 0x00, p2, datalen, data}, 0, resp, &resplen, &sw); int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_APPEND_RECORD, 0x00, p2, datalen, data}, 0, resp, &resplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000) if (res == PM3_SUCCESS && sw != ISO7816_OK)
return PM3_ESOFT; return PM3_ESOFT;
return res; return res;

View file

@ -74,22 +74,37 @@ AccessConditions_t MFAccessConditionsTrailer[] = {
}; };
bool mfValidateAccessConditions(const uint8_t *data) { bool mfValidateAccessConditions(const uint8_t *data) {
uint8_t ndata1 = (data[0]) & 0x0f; uint8_t nd1 = NIBBLE_LOW(data[0]);
uint8_t ndata2 = (data[0] >> 4) & 0x0f; uint8_t nd2 = NIBBLE_HIGH(data[0]);
uint8_t ndata3 = (data[1]) & 0x0f; uint8_t nd3 = NIBBLE_LOW(data[1]);
uint8_t data1 = (data[1] >> 4) & 0x0f; uint8_t d1 = NIBBLE_HIGH(data[1]);
uint8_t data2 = (data[2]) & 0x0f; uint8_t d2 = NIBBLE_LOW(data[2]);
uint8_t data3 = (data[2] >> 4) & 0x0f; uint8_t d3 = NIBBLE_HIGH(data[2]);
return ((ndata1 == (data1 ^ 0xF)) && (ndata2 == (data2 ^ 0xF)) && (ndata3 == (data3 ^ 0xF))); return ((nd1 == (d1 ^ 0xF)) && (nd2 == (d2 ^ 0xF)) && (nd3 == (d3 ^ 0xF)));
}
bool mfReadOnlyAccessConditions(uint8_t blockn, const uint8_t *data) {
uint8_t d1 = NIBBLE_HIGH(data[1]) >> blockn;
uint8_t d2 = NIBBLE_LOW(data[2]) >> blockn;
uint8_t d3 = NIBBLE_HIGH(data[2]) >> blockn;
uint8_t cond = (d1 & 0x01) << 2 | (d2 & 0x01) << 1 | (d3 & 0x01);
if (blockn == 3) {
if ((cond == 0x02) || (cond == 0x06) || (cond == 0x07)) return true;
} else {
if ((cond == 0x02) || (cond == 0x05)) return true;
}
return false;
} }
const char *mfGetAccessConditionsDesc(uint8_t blockn, const uint8_t *data) {
uint8_t data1 = ((data[1] >> 4) & 0x0f) >> blockn;
uint8_t data2 = ((data[2]) & 0x0f) >> blockn;
uint8_t data3 = ((data[2] >> 4) & 0x0f) >> blockn;
uint8_t cond = (data1 & 0x01) << 2 | (data2 & 0x01) << 1 | (data3 & 0x01); const char *mfGetAccessConditionsDesc(uint8_t blockn, const uint8_t *data) {
uint8_t d1 = NIBBLE_HIGH(data[1]) >> blockn;
uint8_t d2 = NIBBLE_LOW(data[2]) >> blockn;
uint8_t d3 = NIBBLE_HIGH(data[2]) >> blockn;
uint8_t cond = (d1 & 0x01) << 2 | (d2 & 0x01) << 1 | (d3 & 0x01);
if (blockn == 3) { if (blockn == 3) {
for (int i = 0; i < ARRAYLEN(MFAccessConditionsTrailer); i++) for (int i = 0; i < ARRAYLEN(MFAccessConditionsTrailer); i++)

View file

@ -71,6 +71,7 @@ int MFPGetSignature(bool activateField, bool leaveSignalON, uint8_t *dataout, in
int MFPGetVersion(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); int MFPGetVersion(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
bool mfValidateAccessConditions(const uint8_t *data); bool mfValidateAccessConditions(const uint8_t *data);
bool mfReadOnlyAccessConditions(uint8_t blockn, const uint8_t *data);
const char *mfGetAccessConditionsDesc(uint8_t blockn, const uint8_t *data); const char *mfGetAccessConditionsDesc(uint8_t blockn, const uint8_t *data);
uint8_t mfNumBlocksPerSector(uint8_t sectorNo); uint8_t mfNumBlocksPerSector(uint8_t sectorNo);

View file

@ -1499,7 +1499,7 @@ static void reverse_array(const uint8_t *src, int src_len, uint8_t *dest) {
} }
}; };
int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) { int vigik_verify(mfc_vigik_t *d) {
// iso9796 // iso9796
// Exponent V = 2 // Exponent V = 2
@ -1507,16 +1507,16 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
if (g_debugMode == DEBUG) { if (g_debugMode == DEBUG) {
PrintAndLogEx(INFO, "Raw"); PrintAndLogEx(INFO, "Raw");
print_hex_noascii_break(uid, uidlen, MFBLOCK_SIZE * 2); print_hex_noascii_break((uint8_t *)d, sizeof(*d) - sizeof(d->rsa_signature), MFBLOCK_SIZE * 2);
PrintAndLogEx(INFO, "Raw signature"); PrintAndLogEx(INFO, "Raw signature");
print_hex_noascii_break(signature, signature_len, MFBLOCK_SIZE * 2); print_hex_noascii_break(d->rsa_signature, sizeof(d->rsa_signature), MFBLOCK_SIZE * 2);
} }
uint8_t rev_sig[128]; uint8_t rev_sig[128];
reverse_array(signature, signature_len, rev_sig); reverse_array(d->rsa_signature, sizeof(d->rsa_signature), rev_sig);
PrintAndLogEx(INFO, "Raw signature reverse"); PrintAndLogEx(INFO, "Raw signature reverse");
print_hex_noascii_break(rev_sig, signature_len, MFBLOCK_SIZE * 2); print_hex_noascii_break(rev_sig, sizeof(d->rsa_signature), MFBLOCK_SIZE * 2);
// t = 0xBC = Implicitly known // t = 0xBC = Implicitly known
// t = 0xCC = look at byte before to determine hash function // t = 0xCC = look at byte before to determine hash function
@ -1563,10 +1563,10 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
mbedtls_mpi_init(&sqr); mbedtls_mpi_init(&sqr);
mbedtls_mpi_init(&res); mbedtls_mpi_init(&res);
mbedtls_mpi_read_binary(&N, (const unsigned char*)n, PUBLIC_VIGIK_KEYLEN); mbedtls_mpi_read_binary(&N, (const unsigned char *)n, PUBLIC_VIGIK_KEYLEN);
//mbedtls_mpi_read_binary(&s, (const unsigned char*)signature, signature_len); //mbedtls_mpi_read_binary(&s, (const unsigned char*)signature, signature_len);
mbedtls_mpi_read_binary(&s, (const unsigned char*)rev_sig, signature_len); mbedtls_mpi_read_binary(&s, (const unsigned char *)rev_sig, sizeof(d->rsa_signature));
// check is sign < (N/2) // check is sign < (N/2)
@ -1574,7 +1574,7 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
mbedtls_mpi_init(&n_2); mbedtls_mpi_init(&n_2);
mbedtls_mpi_copy(&n_2, &N); mbedtls_mpi_copy(&n_2, &N);
mbedtls_mpi_shift_r(&n_2, 1); mbedtls_mpi_shift_r(&n_2, 1);
bool is_less = (mbedtls_mpi_cmp_mpi(&s, &n_2) > 0) ? false : true; bool is_less = (mbedtls_mpi_cmp_mpi(&s, &n_2) > 0) ? false : true;
PrintAndLogEx(DEBUG, "z < (N/2) ..... %s", (is_less) ? _GREEN_("YES") : _RED_("NO")); PrintAndLogEx(DEBUG, "z < (N/2) ..... %s", (is_less) ? _GREEN_("YES") : _RED_("NO"));
mbedtls_mpi_free(&n_2); mbedtls_mpi_free(&n_2);
@ -1644,10 +1644,10 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
PrintAndLogEx(DEBUG, "LSB............ " _GREEN_("%u"), lsb); PrintAndLogEx(DEBUG, "LSB............ " _GREEN_("%u"), lsb);
if (g_debugMode == DEBUG) { if (g_debugMode == DEBUG) {
mbedtls_mpi_write_file( "[=] N.............. ", &N, 16, NULL ); mbedtls_mpi_write_file("[=] N.............. ", &N, 16, NULL);
mbedtls_mpi_write_file( "[=] signature...... ", &s, 16, NULL ); mbedtls_mpi_write_file("[=] signature...... ", &s, 16, NULL);
mbedtls_mpi_write_file( "[=] square mod n... ", &sqr, 16, NULL ); mbedtls_mpi_write_file("[=] square mod n... ", &sqr, 16, NULL);
mbedtls_mpi_write_file( "[=] n-fs........... ", &res, 16, NULL ); mbedtls_mpi_write_file("[=] n-fs........... ", &res, 16, NULL);
} }
@ -1656,9 +1656,9 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
// xor 0xDC01 // xor 0xDC01
int count_zero = 0; int count_zero = 0;
for (int x = 0; x < sizeof(nfs); x +=2) { for (int x = 0; x < sizeof(nfs); x += 2) {
nfs[x] ^= 0xDC; nfs[x] ^= 0xDC;
nfs[x+1] ^= 0x01; nfs[x + 1] ^= 0x01;
if (nfs[x] == 0x00) if (nfs[x] == 0x00)
count_zero++; count_zero++;
@ -1725,7 +1725,7 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
if (is_valid == false || i == ARRAYLEN(vigik_rsa_pk)) { if (is_valid == false || i == ARRAYLEN(vigik_rsa_pk)) {
PrintAndLogEx(INFO, "Signature:"); PrintAndLogEx(INFO, "Signature:");
print_hex_noascii_break(signature, signature_len, MFBLOCK_SIZE * 2); print_hex_noascii_break(d->rsa_signature, sizeof(d->rsa_signature), MFBLOCK_SIZE * 2);
PrintAndLogEx(SUCCESS, "Signature verification: " _RED_("failed")); PrintAndLogEx(SUCCESS, "Signature verification: " _RED_("failed"));
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -1738,37 +1738,35 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
PrintAndLogEx(INFO, "%.64s", vigik_rsa_pk[i].n + 192); PrintAndLogEx(INFO, "%.64s", vigik_rsa_pk[i].n + 192);
PrintAndLogEx(INFO, "Signature:"); PrintAndLogEx(INFO, "Signature:");
print_hex_noascii_break(signature, signature_len, MFBLOCK_SIZE * 2); print_hex_noascii_break(d->rsa_signature, sizeof(d->rsa_signature), MFBLOCK_SIZE * 2);
PrintAndLogEx(SUCCESS, "Signature verification: " _GREEN_("successful")); PrintAndLogEx(SUCCESS, "Signature verification: " _GREEN_("successful"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int vigik_annotate(uint8_t *d) { int vigik_annotate(mfc_vigik_t *d) {
if (d == NULL) if (d == NULL)
return PM3_EINVARG; return PM3_EINVARG;
mfc_vigik_t *foo = (mfc_vigik_t*)d; PrintAndLogEx(INFO, "Manufacture......... %s", sprint_hex(d->b0, sizeof(d->b0)));
PrintAndLogEx(INFO, "MAD................. %s", sprint_hex(d->mad, sizeof(d->mad)));
PrintAndLogEx(INFO, "Manufacture......... %s", sprint_hex(foo->b0, sizeof(foo->b0))); PrintAndLogEx(INFO, "Counters............ %u", d->counters);
PrintAndLogEx(INFO, "MAD................. %s", sprint_hex(foo->mad, sizeof(foo->mad))); PrintAndLogEx(INFO, "rtf................. %s", sprint_hex(d->rtf, sizeof(d->rtf)));
PrintAndLogEx(INFO, "Counters............ %u", foo->counters); PrintAndLogEx(INFO, "Service code........ 0x%08x / %u - " _YELLOW_("%s"), d->service_code, d->service_code, vigik_get_service(d->service_code));
PrintAndLogEx(INFO, "rtf................. %s", sprint_hex(foo->rtf, sizeof(foo->rtf))); PrintAndLogEx(INFO, "Info flag........... %u -", d->info_flag); // , sprint_bin(d->info_flag, 1));
PrintAndLogEx(INFO, "Service code........ 0x%08x / %u - " _YELLOW_("%s"), foo->service_code, foo->service_code, vigik_get_service(foo->service_code)); PrintAndLogEx(INFO, "Key version......... %u", d->key_version);
PrintAndLogEx(INFO, "Info flag........... %u -", foo->info_flag); // , sprint_bin(foo->info_flag, 1)); PrintAndLogEx(INFO, "PTR Counter......... %u", d->ptr_counter);
PrintAndLogEx(INFO, "Key version......... %u", foo->key_version); PrintAndLogEx(INFO, "Counter num......... %u", d->counter_num);
PrintAndLogEx(INFO, "PTR Counter......... %u", foo->ptr_counter); PrintAndLogEx(INFO, "Slot access date.... %s", sprint_hex(d->slot_access_date, sizeof(d->slot_access_date)));
PrintAndLogEx(INFO, "Counter num......... %u", foo->counter_num); PrintAndLogEx(INFO, "Slot dst duration... %u", d->slot_dst_duration);
PrintAndLogEx(INFO, "Slot access date.... %s", sprint_hex(foo->slot_access_date, sizeof(foo->slot_access_date))); PrintAndLogEx(INFO, "Other Slots......... %s", sprint_hex(d->other_slots, sizeof(d->other_slots)));
PrintAndLogEx(INFO, "Slot dst duration... %u", foo->slot_dst_duration); PrintAndLogEx(INFO, "Services counter.... %u", d->services_counter);
PrintAndLogEx(INFO, "Other Slots......... %s", sprint_hex(foo->other_slots, sizeof(foo->other_slots))); PrintAndLogEx(INFO, "Loading date........ %s", sprint_hex(d->loading_date, sizeof(d->loading_date)));
PrintAndLogEx(INFO, "Services counter.... %u", foo->services_counter); PrintAndLogEx(INFO, "Reserved null....... %u", d->reserved_null);
PrintAndLogEx(INFO, "Loading date........ %s", sprint_hex(foo->loading_date, sizeof(foo->loading_date)));
PrintAndLogEx(INFO, "Reserved null....... %u", foo->reserved_null);
PrintAndLogEx(INFO, "----------------------------------------------------------------"); PrintAndLogEx(INFO, "----------------------------------------------------------------");
PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, "");
vigik_verify(d, 96, foo->rsa_signature, sizeof(foo->rsa_signature)); vigik_verify(d);
PrintAndLogEx(INFO, "----------------------------------------------------------------"); PrintAndLogEx(INFO, "----------------------------------------------------------------");
PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, "");
return PM3_SUCCESS; return PM3_SUCCESS;

View file

@ -23,6 +23,7 @@
#include "common.h" #include "common.h"
#include "util.h" // FILE_PATH_SIZE #include "util.h" // FILE_PATH_SIZE
#include "protocol_vigik.h"
#define MIFARE_SECTOR_RETRY 10 #define MIFARE_SECTOR_RETRY 10
@ -113,6 +114,6 @@ void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool i
// remove all sector trailers in a MFC dump // remove all sector trailers in a MFC dump
int convert_mfc_2_arr(uint8_t *in, uint16_t ilen, uint8_t *out, uint16_t *olen); int convert_mfc_2_arr(uint8_t *in, uint16_t ilen, uint8_t *out, uint16_t *olen);
const char *vigik_get_service(uint16_t service_code); const char *vigik_get_service(uint16_t service_code);
int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len); int vigik_verify(mfc_vigik_t *d);
int vigik_annotate(uint8_t *d); int vigik_annotate(mfc_vigik_t *d);
#endif #endif

View file

@ -349,6 +349,7 @@ const static vocabulory_t vocabulory[] = {
{ 0, "hf mf gen3freeze" }, { 0, "hf mf gen3freeze" },
{ 0, "hf mf ggetblk" }, { 0, "hf mf ggetblk" },
{ 0, "hf mf gload" }, { 0, "hf mf gload" },
{ 0, "hf mf gsave" },
{ 0, "hf mf gsetblk" }, { 0, "hf mf gsetblk" },
{ 0, "hf mf gview" }, { 0, "hf mf gview" },
{ 0, "hf mf ndefformat" }, { 0, "hf mf ndefformat" },
@ -437,6 +438,12 @@ const static vocabulory_t vocabulory[] = {
{ 0, "hf st25ta protect" }, { 0, "hf st25ta protect" },
{ 0, "hf st25ta pwd" }, { 0, "hf st25ta pwd" },
{ 0, "hf st25ta sim" }, { 0, "hf st25ta sim" },
{ 1, "hf tesla help" },
{ 0, "hf tesla info" },
{ 1, "hf tesla list" },
{ 1, "hf texkom help" },
{ 0, "hf texkom reader" },
{ 0, "hf texkom sim" },
{ 1, "hf thinfilm help" }, { 1, "hf thinfilm help" },
{ 0, "hf thinfilm info" }, { 0, "hf thinfilm info" },
{ 1, "hf thinfilm list" }, { 1, "hf thinfilm list" },
@ -452,9 +459,6 @@ const static vocabulory_t vocabulory[] = {
{ 0, "hf topaz rdbl" }, { 0, "hf topaz rdbl" },
{ 1, "hf topaz view" }, { 1, "hf topaz view" },
{ 0, "hf topaz wrbl" }, { 0, "hf topaz wrbl" },
{ 1, "hf texkom help" },
{ 0, "hf texkom reader" },
{ 0, "hf texkom sim" },
{ 1, "hf xerox help" }, { 1, "hf xerox help" },
{ 0, "hf xerox info" }, { 0, "hf xerox info" },
{ 0, "hf xerox reader" }, { 0, "hf xerox reader" },
@ -736,6 +740,12 @@ const static vocabulory_t vocabulory[] = {
{ 0, "nfc barcode read" }, { 0, "nfc barcode read" },
{ 0, "nfc barcode sim" }, { 0, "nfc barcode sim" },
{ 1, "nfc barcode help" }, { 1, "nfc barcode help" },
{ 1, "piv help" },
{ 0, "piv select" },
{ 0, "piv getdata" },
{ 0, "piv authsign" },
{ 0, "piv scan" },
{ 1, "piv list" },
{ 1, "smart help" }, { 1, "smart help" },
{ 1, "smart list" }, { 1, "smart list" },
{ 0, "smart info" }, { 0, "smart info" },

View file

@ -23,7 +23,6 @@
#endif #endif
#include "ui.h" #include "ui.h"
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include <stdio.h> // for Mingw readline #include <stdio.h> // for Mingw readline
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
@ -62,10 +61,18 @@ pthread_mutex_t g_print_lock = PTHREAD_MUTEX_INITIALIZER;
static void fPrintAndLog(FILE *stream, const char *fmt, ...); static void fPrintAndLog(FILE *stream, const char *fmt, ...);
#ifdef _WIN32
#define MKDIR_CHK _mkdir(path)
#else
#define MKDIR_CHK mkdir(path, 0700)
#endif
// needed by flasher, so let's put it here instead of fileutils.c // needed by flasher, so let's put it here instead of fileutils.c
int searchHomeFilePath(char **foundpath, const char *subdir, const char *filename, bool create_home) { int searchHomeFilePath(char **foundpath, const char *subdir, const char *filename, bool create_home) {
if (foundpath == NULL) if (foundpath == NULL) {
return PM3_EINVARG; return PM3_EINVARG;
}
const char *user_path = get_my_user_directory(); const char *user_path = get_my_user_directory();
if (user_path == NULL) { if (user_path == NULL) {
@ -75,20 +82,21 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
size_t pathlen = strlen(user_path) + strlen(PM3_USER_DIRECTORY) + 1; size_t pathlen = strlen(user_path) + strlen(PM3_USER_DIRECTORY) + 1;
char *path = calloc(pathlen, sizeof(char)); char *path = calloc(pathlen, sizeof(char));
if (path == NULL) if (path == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
}
strcpy(path, user_path); strcpy(path, user_path);
strcat(path, PM3_USER_DIRECTORY); strcat(path, PM3_USER_DIRECTORY);
int result; int result;
#ifdef _WIN32 #ifdef _WIN32
struct _stat st; struct _stat st;
// Mingw _stat fails if path ends with /, so let's use a stripped path // Mingw _stat fails if path ends with /, so let's use a stripped path
if (path[strlen(path) - 1] == '/') { if (str_endswith(path, PATHSEP)) {
path[strlen(path) - 1] = '\0'; memset(path + (strlen(path) - strlen(PATHSEP)), 0x00, strlen(PATHSEP));
result = _stat(path, &st); result = _stat(path, &st);
path[strlen(path)] = '/'; strcat(path, PATHSEP);
} else { } else {
result = _stat(path, &st); result = _stat(path, &st);
} }
@ -96,19 +104,16 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
struct stat st; struct stat st;
result = stat(path, &st); result = stat(path, &st);
#endif #endif
if ((result != 0) && create_home) { if ((result != 0) && create_home) {
#ifdef _WIN32 if (MKDIR_CHK) {
if (_mkdir(path))
#else
if (mkdir(path, 0700))
#endif
{
fprintf(stderr, "Could not create user directory %s\n", path); fprintf(stderr, "Could not create user directory %s\n", path);
free(path); free(path);
return PM3_EFILE; return PM3_EFILE;
} }
} }
if (subdir != NULL) { if (subdir != NULL) {
pathlen += strlen(subdir); pathlen += strlen(subdir);
char *tmp = realloc(path, pathlen * sizeof(char)); char *tmp = realloc(path, pathlen * sizeof(char));
@ -121,24 +126,20 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
#ifdef _WIN32 #ifdef _WIN32
// Mingw _stat fails if path ends with /, so let's use a stripped path // Mingw _stat fails if path ends with /, so let's use a stripped path
if (path[strlen(path) - 1] == '/') { if (str_endswith(path, PATHSEP)) {
path[strlen(path) - 1] = '\0'; memset(path + (strlen(path) - strlen(PATHSEP)), 0x00, strlen(PATHSEP));
result = _stat(path, &st); result = _stat(path, &st);
path[strlen(path)] = '/'; strcat(path, PATHSEP);
} else { } else {
result = _stat(path, &st); result = _stat(path, &st);
} }
#else #else
result = stat(path, &st); result = stat(path, &st);
#endif #endif
if ((result != 0) && create_home) { if ((result != 0) && create_home) {
#ifdef _WIN32 if (MKDIR_CHK) {
if (_mkdir(path))
#else
if (mkdir(path, 0700))
#endif
{
fprintf(stderr, "Could not create user directory %s\n", path); fprintf(stderr, "Could not create user directory %s\n", path);
free(path); free(path);
return PM3_EFILE; return PM3_EFILE;
@ -150,15 +151,18 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
*foundpath = path; *foundpath = path;
return PM3_SUCCESS; return PM3_SUCCESS;
} }
pathlen += strlen(filename); pathlen += strlen(filename);
char *tmp = realloc(path, pathlen * sizeof(char)); char *tmp = realloc(path, pathlen * sizeof(char));
if (tmp == NULL) { if (tmp == NULL) {
//free(path); //free(path);
return PM3_EMALLOC; return PM3_EMALLOC;
} }
path = tmp; path = tmp;
strcat(path, filename); strcat(path, filename);
*foundpath = path; *foundpath = path;
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -527,12 +531,11 @@ void memcpy_filter_emoji(void *dest, const void *src, size_t n, emojiMode_t mode
uint8_t emojified_token_length = 0; uint8_t emojified_token_length = 0;
char *current_token = NULL; char *current_token = NULL;
uint8_t current_token_length = 0; uint8_t current_token_length = 0;
char current_char;
char *rdest = (char *)dest; char *rdest = (char *)dest;
char *rsrc = (char *)src; char *rsrc = (char *)src;
uint16_t si = 0; uint16_t si = 0;
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
current_char = rsrc[i]; char current_char = rsrc[i];
if (current_token_length == 0) { if (current_token_length == 0) {
// starting a new token. // starting a new token.

View file

@ -35,7 +35,9 @@ typedef enum logLevel {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG, INPLA
typedef enum emojiMode {EMO_ALIAS, EMO_EMOJI, EMO_ALTTEXT, EMO_NONE} emojiMode_t; typedef enum emojiMode {EMO_ALIAS, EMO_EMOJI, EMO_ALTTEXT, EMO_NONE} emojiMode_t;
typedef enum clientdebugLevel {cdbOFF, cdbSIMPLE, cdbFULL} clientdebugLevel_t; typedef enum clientdebugLevel {cdbOFF, cdbSIMPLE, cdbFULL} clientdebugLevel_t;
// typedef enum devicedebugLevel {ddbOFF, ddbERROR, ddbINFO, ddbDEBUG, ddbEXTENDED} devicedebugLevel_t; // typedef enum devicedebugLevel {ddbOFF, ddbERROR, ddbINFO, ddbDEBUG, ddbEXTENDED} devicedebugLevel_t;
typedef enum savePaths {spDefault, spDump, spTrace, spItemCount} savePaths_t; // last item spItemCount used to auto map to number of files
// last item spItemCount used to auto map to number of files
typedef enum savePaths {spDefault, spDump, spTrace, spItemCount} savePaths_t;
typedef struct {int x; int y; int h; int w;} qtWindow_t; typedef struct {int x; int y; int h; int w;} qtWindow_t;
typedef struct { typedef struct {

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