mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
Merge branch 'master' of https://github.com/adite/proxmark3
This commit is contained in:
commit
5d17177498
184 changed files with 4180 additions and 2318 deletions
21
.github/ISSUE_TEMPLATE/checklist-for-release.md
vendored
21
.github/ISSUE_TEMPLATE/checklist-for-release.md
vendored
|
@ -18,26 +18,11 @@ assignees: doegox, iceman1001
|
|||
- [ ] `tools/build_all_firmwares.sh` check that the script contains all standalone modes then compile all standalone modes (linux only)
|
||||
- [ ] `experimental_lib` compilation & tests
|
||||
- [ ] `experimental_client_with_swig` compilation & tests
|
||||
- [ ] Check Android `CMakeLists.txt` list of source file
|
||||
- [ ] GitHub Actions - green across the board ( MacOS, Ubuntu, Windows)
|
||||
|
||||
# OS compilation and tests
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
make clean && make -j PLATFORM=PM3GENERIC PLATFORM_EXTRAS= && tools/pm3_tests.sh --long || exit 1
|
||||
make clean && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS= || exit 1
|
||||
make clean && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON || exit 1
|
||||
make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && sudo make install PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && ( cd /tmp; proxmark3 -c 'data load -f lf_EM4x05.pm3;lf search -1'|grep 'Valid FDX-B ID found' ) && sudo make uninstall || exit 1
|
||||
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3GENERIC PLATFORM_EXTRAS= && cp -a ../*scripts ../*libs . && ../../tools/pm3_tests.sh --clientbin $(pwd)/proxmark3 client ) || exit 1
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS= ) || exit 1
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON ) || exit 1
|
||||
|
||||
# Hitag2crack, optionally with --long and --opencl ...
|
||||
make hitag2crack/clean && make hitag2crack && tools/pm3_tests.sh hitag2crack || exit 1
|
||||
```
|
||||
Run `tools/release_tests.sh` on:
|
||||
|
||||
- [ ] RPI Zero
|
||||
- [ ] Jetson Nano
|
||||
|
@ -47,9 +32,9 @@ make hitag2crack/clean && make hitag2crack && tools/pm3_tests.sh hitag2crack ||
|
|||
- [ ] Kali
|
||||
- [ ] Debian Stable
|
||||
- [ ] Debian Testing
|
||||
- [ ] Ubuntu21
|
||||
- [ ] Ubuntu 22
|
||||
- [ ] ParrotOS
|
||||
- [ ] Fedora
|
||||
- [ ] Fedora 37
|
||||
- [ ] OpenSuse Leap
|
||||
- [ ] OpenSuse Tumbleweed
|
||||
- [ ] OSX (MacPorts)
|
||||
|
|
3
.github/workflows/macos.yml
vendored
3
.github/workflows/macos.yml
vendored
|
@ -36,6 +36,7 @@ jobs:
|
|||
|
||||
- name: Install dependencies
|
||||
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
|
||||
continue-on-error: true
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
|
@ -77,6 +78,7 @@ jobs:
|
|||
|
||||
- name: Install dependencies
|
||||
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
|
||||
continue-on-error: true
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
|
@ -119,6 +121,7 @@ jobs:
|
|||
|
||||
- name: Install dependencies
|
||||
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
|
||||
continue-on-error: true
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
|
|
29
CHANGELOG.md
29
CHANGELOG.md
|
@ -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...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Fixed potential NULL array printing (@jmichel)
|
||||
- Added PIV aid to resource file (@jmichel)
|
||||
- Fixed failing compilation on Proxspace environment due to how python is initialized (@jmichel)
|
||||
- Fixed length check in sim module communications (@jmichel)
|
||||
- Added new magic gen4 cards command in docs (@McEloff)
|
||||
- Added `hf tesla info` - intital information command to read TESLA cards (@iceman1001)
|
||||
- Changed `hf emrtd info` - looking for lower case .bin extensions (@iceman1001)
|
||||
- Changed `hf emrtd dump` - looking for lower case .bin extensions (@iceman1001)
|
||||
- Changed `lf paradox clone` - it now accepts FC/CN (@mwalker33)
|
||||
- Added standalone mode for simulatin Nedap ID (@anon)
|
||||
- Changed `hf mfu info` - now also does a simple OTP fingerprinting (@iceman1001)
|
||||
- Changed `hf mf wrbl` - now checks for strict readonly ACL's in the data to write (@iceman1001)
|
||||
- Changed `hf mf view` - verbose printing if strict readonly ACL's exists in dump file (@iceman1001)
|
||||
- Add command `piv authsign` to get a buffer signed by the selected key (@jmichelp)
|
||||
- Add command `piv scan` which tries to read all known containers on PIV (@jmichelp)
|
||||
- Add support for PIV commands, over wired and contactless interfaces (@jmichelp)
|
||||
- Add `--shallow` option to `hf iclass` reader commands to do shallow (ASK) reader modulation instead of OOK (@nvx)
|
||||
- Improved NXP SLI/SLIX series tag identification (@nvx)
|
||||
- Fixed buffer overflow in "lf em 4x05 sniff" (@HeinrichsH)
|
||||
- Fixed potential NULL array printing (@jmichelp)
|
||||
- Added PIV aid to resource file (@jmichelp)
|
||||
- Fixed failing compilation on Proxspace environment due to how python is initialized (@jmichelp)
|
||||
- Fixed length check in sim module communications (@jmichelp)
|
||||
- Changed timings in i2c.c when communicating with sim module (@iceman1001)
|
||||
- Moved to non-deprecated API to initialize Python interpreter (@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)
|
||||
- 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 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)
|
||||
|
@ -1353,3 +1368,5 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
### Added
|
||||
- iClass functionality: full simulation of iclass tags, so tags can be simulated with data (not only CSN). Not yet support for write/update, but readers do not seem to enforce update. (@holiman).
|
||||
- iClass decryption. Proxmark can now decrypt data on an iclass tag, but requires you to have the HID decryption key locally on your computer, as this is not bundled with the sourcecode.
|
||||
- `hf 15 info` can detect NTAG 5 tags
|
||||
- `hf 15 info` include an EAS status check on more of the icode tags which support EAS (SLI, SLIX, SLIX-L, and SLIX-S)
|
8
Makefile
8
Makefile
|
@ -80,20 +80,20 @@ ifneq (,$(INSTALLSHARES))
|
|||
endif
|
||||
ifneq (,$(INSTALLDOCS))
|
||||
$(Q)$(INSTALLSUDO) $(RMDIR) $(foreach doc,$(INSTALLDOCS),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH)$(PATHSEP)$(notdir $(doc)))
|
||||
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH)
|
||||
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH)
|
||||
endif
|
||||
ifneq (,$(INSTALLTOOLS))
|
||||
$(Q)$(INSTALLSUDO) $(RM) $(foreach tool,$(INSTALLTOOLS),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)$(PATHSEP)$(notdir $(tool)))
|
||||
endif
|
||||
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)
|
||||
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)
|
||||
ifneq (,$(INSTALLSIMFW))
|
||||
$(Q)$(INSTALLSUDO) $(RM) $(foreach fw,$(INSTALLSIMFW),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(notdir $(fw)))
|
||||
endif
|
||||
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)
|
||||
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)
|
||||
ifeq ($(platform),Linux)
|
||||
$(Q)$(INSTALLSUDO) $(RM) $(DESTDIR)$(UDEV_PREFIX)/77-pm3-usb-device-blacklist.rules
|
||||
endif
|
||||
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)
|
||||
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)
|
||||
|
||||
# tests
|
||||
mfkey/check: FORCE
|
||||
|
|
|
@ -29,8 +29,8 @@ GZIP = gzip
|
|||
MKDIR = mkdir -p
|
||||
RM = rm -f
|
||||
RMDIR = rm -rf
|
||||
# rmdir only if dir is empty, tolerate failure
|
||||
RMDIR_SOFT = -rmdir
|
||||
# rmdir only if dir is empty, you must add "-" when using it to tolerate failure
|
||||
RMDIR_SOFT = rmdir
|
||||
MV = mv
|
||||
TOUCH = touch
|
||||
FALSE = false
|
||||
|
|
10
README.md
10
README.md
|
@ -83,7 +83,7 @@ We define generic Proxmark3 platforms as following devices.
|
|||
- **Note**: unknown pin assignments.
|
||||
- ⚠ Ryscorp Proxmark3 Pro
|
||||
- **Note**: device has different fpga and unknown pin assignments.
|
||||
- **Note**: Company have dissappared, leaving their customers in the dark.
|
||||
- **Note**: Company have disappeared, leaving their customers in the dark.
|
||||
- ⚠ iCopy-X
|
||||
- **Note**: experimental support, currently incompatible with iCopy-X GUI as Proxmark client commands are now using cliparser.
|
||||
- **Note**: see also [icopyx-community repos](https://github.com/iCopy-X-Community/) for upstream sources, reversed hw etc.
|
||||
|
@ -93,7 +93,13 @@ We define generic Proxmark3 platforms as following devices.
|
|||
- ⚠ VX
|
||||
- **Note**: unknown device hw
|
||||
- ⚠ Proxmark3 X
|
||||
- **Note**: unknown device hw.
|
||||
- **Note**: unknown device hw
|
||||
- ⚠ Proxmark3 Ultimate
|
||||
- **Note**: unknown device hw
|
||||
- ⚠ Proxmark3 SE
|
||||
- **Note**: unknown device hw
|
||||
|
||||
When it comes to these new unknown models we are depending on the community to report in if this repo works and what they did to make it work.
|
||||
|
||||
|
||||
**256kb flash memory size of generic Proxmark3 platforms**
|
||||
|
|
|
@ -185,7 +185,7 @@ showinfo:
|
|||
.DELETE_ON_ERROR:
|
||||
|
||||
# version_pm3.c should be remade on every time fullimage.stage1.elf should be remade
|
||||
version_pm3.c: default_version_pm3.c $(OBJDIR)/fpga_version_info.o $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ)
|
||||
version_pm3.c: default_version_pm3.c $(OBJDIR)/fpga_version_info.o $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ) .FORCE
|
||||
$(info [-] GEN $@)
|
||||
$(Q)$(SH) ../tools/mkversion.sh > $@ || $(CP) $< $@
|
||||
|
||||
|
@ -257,7 +257,7 @@ uninstall:
|
|||
$(info [@] Uninstalling fullimage from $(DESTDIR)$(PREFIX)...)
|
||||
$(Q)$(INSTALLSUDO) $(RM) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(INSTALLFWTAG)
|
||||
|
||||
.PHONY: all clean help install uninstall
|
||||
.PHONY: all clean help install uninstall .FORCE
|
||||
help:
|
||||
@echo Multi-OS Makefile, you are running on $(DETECTED_OS)
|
||||
@echo Possible targets:
|
||||
|
|
|
@ -50,12 +50,18 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
| LF_ICEHID | LF HID collector to flashmem |
|
||||
| (RDV4 only) | |
|
||||
+----------------------------------------------------------+
|
||||
| LF_NEDAP_SIM | LF Nedap ID simple simulator |
|
||||
| | |
|
||||
+----------------------------------------------------------+
|
||||
| LF_NEXID | LF Nexwatch collector to flashmem |
|
||||
| (RDV4 only) | |
|
||||
+----------------------------------------------------------+
|
||||
| LF_PROXBRUTE | HID ProxII bruteforce |
|
||||
| | - Brad Antoniewicz |
|
||||
+----------------------------------------------------------+
|
||||
| LF_PROX2BRUTE | HID ProxII bruteforce v2 |
|
||||
| | |
|
||||
+----------------------------------------------------------+
|
||||
| LF_SAMYRUN | HID26 read/clone/sim |
|
||||
| (default) | - Samy Kamkar |
|
||||
+----------------------------------------------------------+
|
||||
|
@ -118,11 +124,14 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
+----------------------------------------------------------+
|
||||
endef
|
||||
|
||||
STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN LF_THAREXDE LF_NEXID
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_TCPRST HF_TMUDFORD HF_YOUNG HF_REBLAY DANKARMULTI
|
||||
|
||||
STANDALONE_MODES := LF_SKELETON
|
||||
STANDALONE_MODES += LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_YOUNG
|
||||
STANDALONE_MODES += DANKARMULTI
|
||||
STANDALONE_MODES_REQ_BT := HF_REBLAY
|
||||
STANDALONE_MODES_REQ_SMARTCARD :=
|
||||
STANDALONE_MODES_REQ_FLASH := LF_HIDFCBRUTE LF_ICEHID LF_NEXID LF_THAREXDE HF_BOG HF_COLIN HF_ICECLASS HF_MFCSIM HF_LEGICSIM
|
||||
STANDALONE_MODES_REQ_FLASH := LF_HIDFCBRUTE LF_ICEHID LF_NEXID LF_THAREXDE HF_BOG HF_COLIN HF_ICECLASS HF_LEGICSIM HF_MFCSIM
|
||||
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),)
|
||||
STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE)
|
||||
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),)
|
||||
|
|
|
@ -21,13 +21,21 @@ SRC_STANDALONE = placeholder.c
|
|||
ifneq (,$(findstring WITH_STANDALONE_LF_SKELETON,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_skeleton.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_SAMYRUN
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_SAMYRUN,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_samyrun.c
|
||||
# WITH_STANDALONE_LF_EM4100EMUL
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100EMUL,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_em4100emul.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_PROXBRUTE
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_PROXBRUTE,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_proxbrute.c
|
||||
# WITH_STANDALONE_LF_EM4100RSWB
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RSWB,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_em4100rswb.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_EM4100RSWW
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RSWW,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_em4100rsww.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_EM4100RWC
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RWC,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_em4100rwc.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_HIDBRUTE
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_HIDBRUTE,$(APP_CFLAGS)))
|
||||
|
@ -37,21 +45,33 @@ endif
|
|||
ifneq (,$(findstring WITH_STANDALONE_LF_HIDFCBRUTE,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_hidfcbrute.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_YOUNG
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_YOUNG,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_young.c
|
||||
# WITH_STANDALONE_LF_ICEHID
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_icehid.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_MATTYRUN
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_MATTYRUN,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_mattyrun.c
|
||||
# WITH_STANDALONE_LF_NEDAP_SIM
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_NEDAP_SIM,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_nedap_sim.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_COLIN
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_COLIN,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = vtsend.c hf_colin.c frozen.c nprintf.c
|
||||
# WITH_STANDALONE_LF_NEXID
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_NEXID,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_nexid.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_BOG
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_BOG,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_bog.c
|
||||
# WITH_STANDALONE_LF_SAMYRUN
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_SAMYRUN,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_samyrun.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_PROXBRUTE
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_PROXBRUTE,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_proxbrute.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_PROX2BRUTE
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_PROX2BRUTE,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_prox2brute.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_THAREXDE
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_THAREXDE,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_tharexde.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_14ASNIFF
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_14ASNIFF,$(APP_CFLAGS)))
|
||||
|
@ -69,33 +89,21 @@ endif
|
|||
ifneq (,$(findstring WITH_STANDALONE_HF_AVEFUL,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_aveful.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_TCPRST
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_TCPRST,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_tcprst.c
|
||||
# WITH_STANDALONE_HF_BOG
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_BOG,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_bog.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_ICEHID
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_icehid.c
|
||||
# WITH_STANDALONE_HF_COLIN
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_COLIN,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = vtsend.c hf_colin.c frozen.c nprintf.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_NEXID
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_NEXID,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_nexid.c
|
||||
# WITH_STANDALONE_HF_CRAFTBYTE
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_CRAFTBYTE,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_craftbyte.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_EM4100EMUL
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100EMUL,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_em4100emul.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_EM4100RSWB
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RSWB,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_em4100rswb.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_EM4100RSWW
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RSWW,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_em4100rsww.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_EM4100RWC
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RWC,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_em4100rwc.c
|
||||
# WITH_STANDALONE_HF_ICECLASS
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_iceclass.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_LEGIC
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_LEGIC,$(APP_CFLAGS)))
|
||||
|
@ -105,33 +113,33 @@ endif
|
|||
ifneq (,$(findstring WITH_STANDALONE_HF_LEGICSIM,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_legicsim.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_MATTYRUN
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_MATTYRUN,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_mattyrun.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_MFCSIM
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_MFCSIM,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_mfcsim.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_MSDSAL
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_MSDSAL,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_msdsal.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_ICECLASS
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_iceclass.c
|
||||
# WITH_STANDALONE_HF_REBLAY
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_REBLAY,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_reblay.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_THAREXDE
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_THAREXDE,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_tharexde.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_CRAFTBYTE
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_CRAFTBYTE,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_craftbyte.c
|
||||
# WITH_STANDALONE_HF_TCPRST
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_TCPRST,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_tcprst.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_TMUDFORD
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_TMUDFORD,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_tmudford.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_REBLAY
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_REBLAY,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_reblay.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_MFCSIM
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_MFCSIM,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_mfcsim.c
|
||||
# WITH_STANDALONE_HF_YOUNG
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_YOUNG,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_young.c
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring WITH_STANDALONE_DANKARMULTI,$(APP_CFLAGS)))
|
||||
|
|
|
@ -322,6 +322,7 @@ static int reader_dump_mode(void) {
|
|||
.use_credit_key = false,
|
||||
.do_auth = true,
|
||||
.send_reply = false,
|
||||
.shallow_mod = false,
|
||||
};
|
||||
memcpy(auth.key, legacy_aa1_key, sizeof(auth.key));
|
||||
|
||||
|
@ -333,7 +334,7 @@ static int reader_dump_mode(void) {
|
|||
|
||||
// select tag.
|
||||
uint32_t eof_time = 0;
|
||||
bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time);
|
||||
bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time, false);
|
||||
if (res == false) {
|
||||
switch_off();
|
||||
continue;
|
||||
|
@ -382,7 +383,7 @@ static int reader_dump_mode(void) {
|
|||
|
||||
// main read loop
|
||||
for (uint16_t i = start_block; i <= app1_limit; i++) {
|
||||
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) {
|
||||
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time, false)) {
|
||||
dumped++;
|
||||
}
|
||||
}
|
||||
|
@ -394,7 +395,7 @@ static int reader_dump_mode(void) {
|
|||
auth.use_credit_key = true;
|
||||
memcpy(auth.key, aa2_key, sizeof(auth.key));
|
||||
|
||||
res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time);
|
||||
res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time, false);
|
||||
if (res) {
|
||||
|
||||
// sanity check of CSN.
|
||||
|
@ -408,7 +409,7 @@ static int reader_dump_mode(void) {
|
|||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
|
||||
for (uint16_t i = app1_limit + 1; i <= app2_limit; i++) {
|
||||
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) {
|
||||
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time, false)) {
|
||||
dumped++;
|
||||
}
|
||||
}
|
||||
|
@ -458,6 +459,7 @@ static int dump_sim_mode(void) {
|
|||
.use_credit_key = false,
|
||||
.do_auth = true,
|
||||
.send_reply = false,
|
||||
.shallow_mod = false,
|
||||
};
|
||||
memcpy(auth.key, legacy_aa1_key, sizeof(auth.key));
|
||||
|
||||
|
@ -469,7 +471,7 @@ static int dump_sim_mode(void) {
|
|||
|
||||
// select tag.
|
||||
uint32_t eof_time = 0;
|
||||
bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time);
|
||||
bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time, false);
|
||||
if (res == false) {
|
||||
switch_off();
|
||||
continue;
|
||||
|
@ -518,7 +520,7 @@ static int dump_sim_mode(void) {
|
|||
|
||||
// main read loop
|
||||
for (uint16_t i = start_block; i <= app1_limit; i++) {
|
||||
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) {
|
||||
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time, false)) {
|
||||
dumped++;
|
||||
}
|
||||
}
|
||||
|
@ -530,7 +532,7 @@ static int dump_sim_mode(void) {
|
|||
auth.use_credit_key = true;
|
||||
memcpy(auth.key, aa2_key, sizeof(auth.key));
|
||||
|
||||
res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time);
|
||||
res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time, false);
|
||||
if (res) {
|
||||
|
||||
// sanity check of CSN.
|
||||
|
@ -544,7 +546,7 @@ static int dump_sim_mode(void) {
|
|||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
|
||||
for (uint16_t i = app1_limit + 1; i <= app2_limit; i++) {
|
||||
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) {
|
||||
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time, false)) {
|
||||
dumped++;
|
||||
}
|
||||
}
|
||||
|
|
207
armsrc/Standalone/lf_nedap_sim.c
Normal file
207
armsrc/Standalone/lf_nedap_sim.c
Normal 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
|
||||
}
|
108
armsrc/Standalone/lf_prox2brute.c
Normal file
108
armsrc/Standalone/lf_prox2brute.c
Normal 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
|
||||
}
|
|
@ -100,6 +100,8 @@ STANDALONE_MODES_REQ_FLASH :=
|
|||
STANDALONE_MODES_REQ_BT :=
|
||||
```
|
||||
|
||||
Please respect alphabetic order!
|
||||
|
||||
## Update MAKEFILE.INC
|
||||
^[Top](#top)
|
||||
|
||||
|
@ -117,6 +119,8 @@ ifneq (,$(findstring WITH_STANDALONE_LF_FOO,$(APP_CFLAGS)))
|
|||
endif
|
||||
```
|
||||
|
||||
Please respect alphabetic order!
|
||||
|
||||
## Adding identification string of your mode
|
||||
^[Top](#top)
|
||||
|
||||
|
@ -174,9 +178,11 @@ Once you're ready to share your mode, please
|
|||
|
||||
* add a line in CHANGELOG.md
|
||||
* add your mode in the modes table in `doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md`
|
||||
* add your mode in `tools/build_all_firmwares.sh`
|
||||
* add your mode in `tools/build_all_firmwares.sh` such that it reflects `armsrc/Standalone/Makefile.hal` list of firmwares to build.
|
||||
|
||||
and submit your PR.
|
||||
Please respect alphabetic order of standalone modes everywhere!
|
||||
|
||||
Then submit your PR.
|
||||
|
||||
Once approved, add also your mode in https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode
|
||||
|
||||
|
|
|
@ -345,7 +345,7 @@ static void print_debug_level(void) {
|
|||
char dbglvlstr[20] = {0};
|
||||
switch (g_dbglevel) {
|
||||
case DBG_NONE:
|
||||
sprintf(dbglvlstr, "none");
|
||||
sprintf(dbglvlstr, "off");
|
||||
break;
|
||||
case DBG_ERROR:
|
||||
sprintf(dbglvlstr, "error");
|
||||
|
|
|
@ -298,7 +298,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
|||
// 8-byte IDm, number of blocks, blocks numbers
|
||||
// number of blocks limited to 4 for FelicaLite(S)
|
||||
static void BuildFliteRdblk(const uint8_t *idm, uint8_t blocknum, const uint16_t *blocks) {
|
||||
if (blocknum > 4 || blocknum <= 0)
|
||||
if (blocknum > 4 || blocknum == 0)
|
||||
Dbprintf("Invalid number of blocks, %d != 4", blocknum);
|
||||
|
||||
uint8_t c = 0, i = 0;
|
||||
|
|
|
@ -235,9 +235,10 @@ static int json_get_utf8_char_len(unsigned char ch) {
|
|||
|
||||
/* string = '"' { quoted_printable_chars } '"' */
|
||||
static int json_parse_string(struct frozen *f) {
|
||||
int n, ch = 0, len = 0;
|
||||
int ch = 0;
|
||||
TRY(json_test_and_skip(f, '"'));
|
||||
{
|
||||
int len = 0;
|
||||
SET_STATE(f, f->cur, "", 0);
|
||||
for (; f->cur < f->end; f->cur += len) {
|
||||
ch = *(unsigned char *) f->cur;
|
||||
|
@ -245,6 +246,7 @@ static int json_parse_string(struct frozen *f) {
|
|||
EXPECT(ch >= 32 && len > 0, JSON_STRING_INVALID); /* No control chars */
|
||||
EXPECT(len <= json_left(f), JSON_STRING_INCOMPLETE);
|
||||
if (ch == '\\') {
|
||||
int n;
|
||||
EXPECT((n = json_get_escape_len(f->cur + 1, json_left(f))) > 0, n);
|
||||
len += n;
|
||||
} else if (ch == '"') {
|
||||
|
@ -295,17 +297,17 @@ static int json_parse_number(struct frozen *f) {
|
|||
#if JSON_ENABLE_ARRAY
|
||||
/* array = '[' [ value { ',' value } ] ']' */
|
||||
static int json_parse_array(struct frozen *f) {
|
||||
int i = 0, current_path_len;
|
||||
char buf[20];
|
||||
CALL_BACK(f, JSON_TYPE_ARRAY_START, NULL, 0);
|
||||
TRY(json_test_and_skip(f, '['));
|
||||
{
|
||||
{
|
||||
int i = 0;
|
||||
SET_STATE(f, f->cur - 1, "", 0);
|
||||
while (json_cur(f) != ']') {
|
||||
char buf[20];
|
||||
snprintf(buf, sizeof(buf), "[%d]", i);
|
||||
i++;
|
||||
current_path_len = json_append_to_path(f, buf, strlen(buf));
|
||||
int current_path_len = json_append_to_path(f, buf, strlen(buf));
|
||||
f->cur_name =
|
||||
f->path + strlen(f->path) - strlen(buf) + 1 /*opening brace*/;
|
||||
f->cur_name_len = strlen(buf) - 2 /*braces*/;
|
||||
|
@ -1427,9 +1429,12 @@ static void json_next_cb(void *userdata, const char *name, size_t name_len,
|
|||
|
||||
static void *json_next(const char *s, int len, void *handle, const char *path,
|
||||
struct json_token *key, struct json_token *val, int *i) {
|
||||
struct json_token tmpval, *v = val == NULL ? &tmpval : val;
|
||||
struct json_token tmpkey, *k = key == NULL ? &tmpkey : key;
|
||||
int tmpidx, *pidx = i == NULL ? &tmpidx : i;
|
||||
struct json_token tmpval;
|
||||
struct json_token *v = val == NULL ? &tmpval : val;
|
||||
struct json_token tmpkey;
|
||||
struct json_token *k = key == NULL ? &tmpkey : key;
|
||||
int tmpidx;
|
||||
int *pidx = i == NULL ? &tmpidx : i;
|
||||
struct next_data data = {handle, path, (int) strlen(path), 0, k, v, pidx};
|
||||
json_walk(s, len, json_next_cb, &data);
|
||||
return data.found ? data.handle : NULL;
|
||||
|
|
|
@ -1268,7 +1268,6 @@ void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol) {
|
|||
uint8_t rx[HITAG_FRAME_LEN];
|
||||
size_t rxlen = 0;
|
||||
uint8_t tx[HITAG_FRAME_LEN];
|
||||
size_t txlen;
|
||||
int t_wait = HITAG_T_WAIT_MAX;
|
||||
|
||||
|
||||
|
@ -1284,7 +1283,7 @@ void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol) {
|
|||
WDT_HIT();
|
||||
|
||||
//send read request
|
||||
txlen = 0;
|
||||
size_t txlen = 0;
|
||||
uint8_t cmd = 0x0c;
|
||||
txlen = concatbits(tx, txlen, &cmd, 8 - 4, 4);
|
||||
uint8_t addr = pageNum;
|
||||
|
|
|
@ -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) {
|
||||
LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false);
|
||||
}
|
||||
|
|
|
@ -1245,29 +1245,28 @@ send:
|
|||
}
|
||||
|
||||
// THE READER CODE
|
||||
static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time) {
|
||||
static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time, bool shallow_mod) {
|
||||
CodeIso15693AsReader(frame, len);
|
||||
tosend_t *ts = get_tosend();
|
||||
TransmitTo15693Tag(ts->buf, ts->max, start_time);
|
||||
TransmitTo15693Tag(ts->buf, ts->max, start_time, shallow_mod);
|
||||
*end_time = *start_time + (32 * ((8 * ts->max) - 4)); // subtract the 4 padding bits after EOF
|
||||
LogTrace_ISO15693(frame, len, (*start_time * 4), (*end_time * 4), NULL, true);
|
||||
}
|
||||
|
||||
static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t *resp, size_t max_resp_size,
|
||||
uint8_t expected_size, uint8_t tries, uint32_t *start_time,
|
||||
uint16_t timeout, uint32_t *eof_time) {
|
||||
uint16_t timeout, uint32_t *eof_time, bool shallow_mod) {
|
||||
|
||||
uint16_t resp_len = 0;
|
||||
int res;
|
||||
while (tries-- > 0) {
|
||||
|
||||
iclass_send_as_reader(cmd, cmdsize, start_time, eof_time);
|
||||
iclass_send_as_reader(cmd, cmdsize, start_time, eof_time, shallow_mod);
|
||||
|
||||
if (resp == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
res = GetIso15693AnswerFromTag(resp, max_resp_size, timeout, eof_time, false, true, &resp_len);
|
||||
int res = GetIso15693AnswerFromTag(resp, max_resp_size, timeout, eof_time, false, true, &resp_len);
|
||||
if (res == PM3_SUCCESS && expected_size == resp_len) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1282,7 +1281,7 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t *
|
|||
* @return false = fail
|
||||
* true = Got all.
|
||||
*/
|
||||
static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, uint8_t *status) {
|
||||
static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, uint8_t *status, bool shallow_mod) {
|
||||
|
||||
static uint8_t act_all[] = { ICLASS_CMD_ACTALL };
|
||||
static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 };
|
||||
|
@ -1299,7 +1298,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
|
|||
|
||||
// wakeup
|
||||
uint32_t start_time = GetCountSspClk();
|
||||
iclass_send_as_reader(act_all, 1, &start_time, eof_time);
|
||||
iclass_send_as_reader(act_all, 1, &start_time, eof_time, shallow_mod);
|
||||
int res;
|
||||
uint16_t resp_len = 0;
|
||||
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time, false, true, &resp_len);
|
||||
|
@ -1308,7 +1307,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
|
|||
|
||||
// send Identify
|
||||
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
iclass_send_as_reader(identify, 1, &start_time, eof_time);
|
||||
iclass_send_as_reader(identify, 1, &start_time, eof_time, shallow_mod);
|
||||
|
||||
// expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC
|
||||
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len);
|
||||
|
@ -1320,7 +1319,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
|
|||
|
||||
// select the card
|
||||
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
iclass_send_as_reader(select, sizeof(select), &start_time, eof_time);
|
||||
iclass_send_as_reader(select, sizeof(select), &start_time, eof_time, shallow_mod);
|
||||
|
||||
// expect a 10-byte response here, 8 byte CSN and 2 byte CRC
|
||||
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len);
|
||||
|
@ -1332,7 +1331,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
|
|||
|
||||
// card selected, now read config (block1) (only 8 bytes no CRC)
|
||||
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time, eof_time);
|
||||
iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time, eof_time, shallow_mod);
|
||||
|
||||
// expect a 8-byte response here
|
||||
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len);
|
||||
|
@ -1350,7 +1349,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
|
|||
|
||||
// read App Issuer Area block 5
|
||||
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
iclass_send_as_reader(read_aia, sizeof(read_aia), &start_time, eof_time);
|
||||
iclass_send_as_reader(read_aia, sizeof(read_aia), &start_time, eof_time, shallow_mod);
|
||||
|
||||
// expect a 10-byte response here
|
||||
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len);
|
||||
|
@ -1364,7 +1363,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
|
|||
|
||||
// card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
|
||||
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, eof_time);
|
||||
iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, eof_time, shallow_mod);
|
||||
|
||||
// expect a 8-byte response here
|
||||
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len);
|
||||
|
@ -1386,7 +1385,7 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
|
|||
read_aia[3] = 0x10;
|
||||
|
||||
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
iclass_send_as_reader(read_aia, sizeof(read_aia), &start_time, eof_time);
|
||||
iclass_send_as_reader(read_aia, sizeof(read_aia), &start_time, eof_time, shallow_mod);
|
||||
|
||||
// expect a 10-byte response here
|
||||
res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len);
|
||||
|
@ -1402,9 +1401,9 @@ static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint3
|
|||
return true;
|
||||
}
|
||||
|
||||
bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time) {
|
||||
bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, bool shallow_mod) {
|
||||
uint8_t result = 0;
|
||||
return select_iclass_tag_ex(hdr, use_credit_key, eof_time, &result);
|
||||
return select_iclass_tag_ex(hdr, use_credit_key, eof_time, &result, shallow_mod);
|
||||
}
|
||||
|
||||
// Reader iClass Anticollission
|
||||
|
@ -1413,6 +1412,7 @@ void ReaderIClass(uint8_t flags) {
|
|||
|
||||
// flag to use credit key
|
||||
bool use_credit_key = ((flags & FLAG_ICLASS_READER_CREDITKEY) == FLAG_ICLASS_READER_CREDITKEY);
|
||||
bool shallow_mod = (flags & FLAG_ICLASS_READER_SHALLOW_MOD);
|
||||
|
||||
if ((flags & FLAG_ICLASS_READER_INIT) == FLAG_ICLASS_READER_INIT) {
|
||||
Iso15693InitReader();
|
||||
|
@ -1427,7 +1427,7 @@ void ReaderIClass(uint8_t flags) {
|
|||
uint32_t eof_time = 0;
|
||||
picopass_hdr_t hdr = {0};
|
||||
|
||||
if (select_iclass_tag_ex(&hdr, use_credit_key, &eof_time, &res) == false) {
|
||||
if (select_iclass_tag_ex(&hdr, use_credit_key, &eof_time, &res, shallow_mod) == false) {
|
||||
reply_ng(CMD_HF_ICLASS_READER, PM3_ERFTRANS, NULL, 0);
|
||||
goto out;
|
||||
}
|
||||
|
@ -1498,7 +1498,7 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, ui
|
|||
cmd_check[7] = pmac[2];
|
||||
cmd_check[8] = pmac[3];
|
||||
}
|
||||
return iclass_send_cmd_with_retries(cmd_check, sizeof(cmd_check), resp_auth, sizeof(resp_auth), 4, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time);
|
||||
return iclass_send_cmd_with_retries(cmd_check, sizeof(cmd_check), resp_auth, sizeof(resp_auth), 4, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time, payload->shallow_mod);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1516,6 +1516,8 @@ void iClass_Authentication_fast(iclass_chk_t *p) {
|
|||
return;
|
||||
}
|
||||
|
||||
bool shallow_mod = p->shallow_mod;
|
||||
|
||||
uint8_t check[9] = { ICLASS_CMD_CHECK };
|
||||
uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
|
||||
uint8_t readcheck_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 };
|
||||
|
@ -1537,7 +1539,7 @@ void iClass_Authentication_fast(iclass_chk_t *p) {
|
|||
bool isOK = false;
|
||||
|
||||
uint32_t start_time = 0, eof_time = 0;
|
||||
if (select_iclass_tag(&hdr, p->use_credit_key, &eof_time) == false)
|
||||
if (select_iclass_tag(&hdr, p->use_credit_key, &eof_time, shallow_mod) == false)
|
||||
goto out;
|
||||
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
|
@ -1566,14 +1568,14 @@ void iClass_Authentication_fast(iclass_chk_t *p) {
|
|||
check[8] = keys[i].mac[3];
|
||||
|
||||
// expect 4bytes, 3 retries times..
|
||||
isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 2, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time);
|
||||
isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 2, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, shallow_mod);
|
||||
if (isOK)
|
||||
goto out;
|
||||
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
// Auth Sequence MUST begin with reading e-purse. (block2)
|
||||
// Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
|
||||
iclass_send_as_reader(readcheck_cc, sizeof(readcheck_cc), &start_time, &eof_time);
|
||||
iclass_send_as_reader(readcheck_cc, sizeof(readcheck_cc), &start_time, &eof_time, shallow_mod);
|
||||
LED_B_OFF();
|
||||
}
|
||||
|
||||
|
@ -1586,11 +1588,11 @@ out:
|
|||
// Tries to read block.
|
||||
// retries 3times.
|
||||
// reply 8 bytes block
|
||||
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time) {
|
||||
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time, bool shallow_mod) {
|
||||
uint8_t resp[10];
|
||||
uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00};
|
||||
AddCrc(c + 1, 1);
|
||||
bool isOK = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time);
|
||||
bool isOK = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time, shallow_mod);
|
||||
if (isOK)
|
||||
memcpy(data, resp, 8);
|
||||
return isOK;
|
||||
|
@ -1602,6 +1604,7 @@ bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, ui
|
|||
void iClass_ReadBlock(uint8_t *msg) {
|
||||
|
||||
iclass_auth_req_t *payload = (iclass_auth_req_t *)msg;
|
||||
bool shallow_mod = payload->shallow_mod;
|
||||
|
||||
iclass_readblock_resp_t response = { .isOK = true };
|
||||
memset(response.data, 0, sizeof(response.data));
|
||||
|
@ -1614,7 +1617,7 @@ void iClass_ReadBlock(uint8_t *msg) {
|
|||
// select tag.
|
||||
uint32_t eof_time = 0;
|
||||
picopass_hdr_t hdr = {0};
|
||||
bool res = select_iclass_tag(&hdr, payload->use_credit_key, &eof_time);
|
||||
bool res = select_iclass_tag(&hdr, payload->use_credit_key, &eof_time, shallow_mod);
|
||||
if (res == false) {
|
||||
if (payload->send_reply) {
|
||||
response.isOK = res;
|
||||
|
@ -1642,7 +1645,7 @@ void iClass_ReadBlock(uint8_t *msg) {
|
|||
|
||||
// read data
|
||||
uint8_t resp[10];
|
||||
res = iclass_send_cmd_with_retries(cmd_read, sizeof(cmd_read), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time);
|
||||
res = iclass_send_cmd_with_retries(cmd_read, sizeof(cmd_read), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, shallow_mod);
|
||||
if (res) {
|
||||
memcpy(response.data, resp, sizeof(response.data));
|
||||
if (payload->send_reply) {
|
||||
|
@ -1670,6 +1673,7 @@ void iClass_Dump(uint8_t *msg) {
|
|||
|
||||
iclass_dump_req_t *cmd = (iclass_dump_req_t *)msg;
|
||||
iclass_auth_req_t *req = &cmd->req;
|
||||
bool shallow_mod = req->shallow_mod;
|
||||
|
||||
uint8_t *dataout = BigBuf_malloc(ICLASS_16KS_SIZE);
|
||||
if (dataout == NULL) {
|
||||
|
@ -1689,7 +1693,7 @@ void iClass_Dump(uint8_t *msg) {
|
|||
picopass_hdr_t hdr = {0};
|
||||
memset(&hdr, 0xff, sizeof(picopass_hdr_t));
|
||||
|
||||
bool res = select_iclass_tag(&hdr, req->use_credit_key, &eof_time);
|
||||
bool res = select_iclass_tag(&hdr, req->use_credit_key, &eof_time, shallow_mod);
|
||||
if (res == false) {
|
||||
if (req->send_reply) {
|
||||
reply_ng(CMD_HF_ICLASS_DUMP, PM3_ETIMEOUT, NULL, 0);
|
||||
|
@ -1724,7 +1728,7 @@ void iClass_Dump(uint8_t *msg) {
|
|||
uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, i, 0x00, 0x00};
|
||||
AddCrc(c + 1, 1);
|
||||
|
||||
res = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time);
|
||||
res = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, shallow_mod);
|
||||
if (res) {
|
||||
memcpy(dataout + (8 * i), resp, 8);
|
||||
} else {
|
||||
|
@ -1759,7 +1763,7 @@ void iClass_Dump(uint8_t *msg) {
|
|||
BigBuf_free();
|
||||
}
|
||||
|
||||
static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac, bool use_mac) {
|
||||
static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac, bool use_mac, bool shallow_mod) {
|
||||
|
||||
// write command: cmd, 1 blockno, 8 data, 4 mac
|
||||
uint8_t write[14] = { 0x80 | ICLASS_CMD_UPDATE, blockno };
|
||||
|
@ -1775,7 +1779,7 @@ static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac,
|
|||
|
||||
uint8_t resp[10] = {0};
|
||||
uint32_t eof_time = 0, start_time = 0;
|
||||
bool isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_UPDATE, &eof_time);
|
||||
bool isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_UPDATE, &eof_time, shallow_mod);
|
||||
if (isOK == false) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1807,6 +1811,7 @@ void iClass_WriteBlock(uint8_t *msg) {
|
|||
LED_A_ON();
|
||||
|
||||
iclass_writeblock_req_t *payload = (iclass_writeblock_req_t *)msg;
|
||||
bool shallow_mod = payload->req.shallow_mod;
|
||||
|
||||
uint8_t write[14] = { 0x80 | ICLASS_CMD_UPDATE, payload->req.blockno };
|
||||
uint8_t write_len = 14;
|
||||
|
@ -1816,7 +1821,7 @@ void iClass_WriteBlock(uint8_t *msg) {
|
|||
// select tag.
|
||||
uint32_t eof_time = 0;
|
||||
picopass_hdr_t hdr = {0};
|
||||
uint8_t res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time);
|
||||
uint8_t res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time, shallow_mod);
|
||||
if (res == false) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -1871,7 +1876,7 @@ void iClass_WriteBlock(uint8_t *msg) {
|
|||
uint8_t tries = 3;
|
||||
while (tries-- > 0) {
|
||||
|
||||
iclass_send_as_reader(write, write_len, &start_time, &eof_time);
|
||||
iclass_send_as_reader(write, write_len, &start_time, &eof_time, shallow_mod);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
res = false;
|
||||
|
@ -1939,6 +1944,8 @@ void iClass_Restore(iclass_restore_req_t *msg) {
|
|||
return;
|
||||
}
|
||||
|
||||
bool shallow_mod = msg->req.shallow_mod;
|
||||
|
||||
LED_A_ON();
|
||||
Iso15693InitReader();
|
||||
|
||||
|
@ -1947,7 +1954,7 @@ void iClass_Restore(iclass_restore_req_t *msg) {
|
|||
picopass_hdr_t hdr = {0};
|
||||
|
||||
// select
|
||||
bool res = select_iclass_tag(&hdr, msg->req.use_credit_key, &eof_time);
|
||||
bool res = select_iclass_tag(&hdr, msg->req.use_credit_key, &eof_time, shallow_mod);
|
||||
if (res == false) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -1988,7 +1995,7 @@ void iClass_Restore(iclass_restore_req_t *msg) {
|
|||
}
|
||||
|
||||
// data + mac
|
||||
if (iclass_writeblock_ext(item.blockno, item.data, mac, use_mac)) {
|
||||
if (iclass_writeblock_ext(item.blockno, item.data, mac, use_mac, shallow_mod)) {
|
||||
Dbprintf("Write block [%3d/0x%02X] " _GREEN_("successful"), item.blockno, item.blockno);
|
||||
written++;
|
||||
} else {
|
||||
|
|
|
@ -38,8 +38,8 @@ void iClass_Authentication_fast(iclass_chk_t *p);
|
|||
bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out);
|
||||
|
||||
void iClass_ReadBlock(uint8_t *msg);
|
||||
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time);
|
||||
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time, bool shallow_mod);
|
||||
|
||||
bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time);
|
||||
bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, bool shallow_mod);
|
||||
bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out);
|
||||
#endif
|
||||
|
|
|
@ -1229,6 +1229,17 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
|
|||
|
||||
AddCrc14A(rPPS, sizeof(rPPS) - 2);
|
||||
|
||||
if (tagType == 7) {
|
||||
uint8_t pwd[4];
|
||||
uint8_t gen_pwd[4];
|
||||
uint16_t start = (*pages - 1) * 4 + MFU_DUMP_PREFIX_LENGTH;
|
||||
emlGetMemBt(pwd, start, sizeof(pwd));
|
||||
Uint4byteToMemBe(gen_pwd, ul_ev1_pwdgenB(data));
|
||||
if (memcmp(pwd, gen_pwd, sizeof(pwd)) == 0) {
|
||||
rPACK[0] = 0x80;
|
||||
rPACK[1] = 0x80;
|
||||
}
|
||||
}
|
||||
AddCrc14A(rPACK, sizeof(rPACK) - 2);
|
||||
|
||||
static tag_response_info_t responses_init[] = {
|
||||
|
|
|
@ -262,9 +262,9 @@ void CodeIso15693AsTag(const uint8_t *cmd, size_t len) {
|
|||
}
|
||||
|
||||
// Transmit the command (to the tag) that was placed in cmd[].
|
||||
void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) {
|
||||
void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time, bool shallow_mod) {
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | (shallow_mod ? FPGA_HF_READER_MODE_SEND_SHALLOW_MOD : FPGA_HF_READER_MODE_SEND_FULL_MOD));
|
||||
|
||||
if (*start_time < DELAY_ARM_TO_TAG) {
|
||||
*start_time = DELAY_ARM_TO_TAG;
|
||||
|
@ -1585,7 +1585,7 @@ void AcquireRawAdcSamplesIso15693(void) {
|
|||
tosend_t *ts = get_tosend();
|
||||
|
||||
uint32_t start_time = 0;
|
||||
TransmitTo15693Tag(ts->buf, ts->max, &start_time);
|
||||
TransmitTo15693Tag(ts->buf, ts->max, &start_time, false);
|
||||
|
||||
// wait for last transfer to complete
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) ;
|
||||
|
@ -1899,7 +1899,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t
|
|||
}
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
TransmitTo15693Tag(ts->buf, ts->max, &start_time);
|
||||
TransmitTo15693Tag(ts->buf, ts->max, &start_time, false);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
*resp_len = 0;
|
||||
|
@ -1922,7 +1922,7 @@ int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, ui
|
|||
|
||||
CodeIso15693AsReaderEOF();
|
||||
tosend_t *ts = get_tosend();
|
||||
TransmitTo15693Tag(ts->buf, ts->max, &start_time);
|
||||
TransmitTo15693Tag(ts->buf, ts->max, &start_time, false);
|
||||
uint32_t end_time = start_time + 32 * (8 * ts->max - 4); // subtract the 4 padding bits after EOF
|
||||
LogTrace_ISO15693(NULL, 0, (start_time * 4), (end_time * 4), NULL, true);
|
||||
|
||||
|
|
|
@ -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);
|
||||
int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time);
|
||||
void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time);
|
||||
void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time, bool shallow_mod);
|
||||
int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time, bool fsk, bool recv_speed, uint16_t *resp_len);
|
||||
|
||||
//void RecordRawAdcSamplesIso15693(void);
|
||||
|
|
|
@ -461,7 +461,6 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
|
|||
uint16_t len = 0;
|
||||
uint32_t pos = 0;
|
||||
uint8_t par[3] = {0x00, 0x00, 0x00}; // enough for 18 Bytes to send
|
||||
uint8_t res = 0;
|
||||
|
||||
uint8_t d_block[18], d_block_enc[18];
|
||||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
|
||||
|
@ -495,7 +494,7 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
|
|||
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
|
||||
|
||||
if (len != 0) { // Something not right, len == 0 (no response is ok as its waiting for transfer
|
||||
res = 0;
|
||||
uint8_t res = 0;
|
||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0;
|
||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1;
|
||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2;
|
||||
|
|
|
@ -39,14 +39,14 @@
|
|||
|
||||
typedef struct {
|
||||
uint8_t *buffer;
|
||||
uint8_t numbits;
|
||||
uint8_t position;
|
||||
uint32_t numbits;
|
||||
uint32_t position;
|
||||
} BitstreamIn_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *buffer;
|
||||
uint8_t numbits;
|
||||
uint8_t position;
|
||||
uint32_t numbits;
|
||||
uint32_t position;
|
||||
} BitstreamOut_t;
|
||||
|
||||
bool headBit(BitstreamIn_t *stream);
|
||||
|
|
|
@ -48,7 +48,7 @@ INSTALLFW = $(OBJDIR)/bootrom.elf
|
|||
OBJS = $(OBJDIR)/bootrom.s19
|
||||
|
||||
# version_pm3.c should be remade on every compilation
|
||||
version_pm3.c: default_version_pm3.c
|
||||
version_pm3.c: default_version_pm3.c .FORCE
|
||||
$(info [=] GEN $@)
|
||||
$(Q)$(SH) ../tools/mkversion.sh > $@ || $(PERL) ../tools/mkversion.pl > $@ || $(CP) $< $@
|
||||
|
||||
|
@ -82,7 +82,7 @@ uninstall:
|
|||
$(info [@] Uninstalling bootrom from $(DESTDIR)$(PREFIX)...)
|
||||
$(Q)$(INSTALLSUDO) $(RM) $(foreach fw,$(INSTALLFW),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(notdir $(fw)))
|
||||
|
||||
.PHONY: all clean help install showinfo
|
||||
.PHONY: all clean help install showinfo .FORCE
|
||||
help:
|
||||
@echo Multi-OS Makefile, you are running on $(DETECTED_OS)
|
||||
@echo Possible targets:
|
||||
|
|
|
@ -293,9 +293,10 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/cmdhfseos.c
|
||||
${PM3_ROOT}/client/src/cmdhfst.c
|
||||
${PM3_ROOT}/client/src/cmdhfst25ta.c
|
||||
${PM3_ROOT}/client/src/cmdhftesla.c
|
||||
${PM3_ROOT}/client/src/cmdhftexkom.c
|
||||
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
||||
${PM3_ROOT}/client/src/cmdhftopaz.c
|
||||
${PM3_ROOT}/client/src/cmdhftexkom.c
|
||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||
${PM3_ROOT}/client/src/cmdhfxerox.c
|
||||
${PM3_ROOT}/client/src/cmdhw.c
|
||||
|
@ -336,6 +337,7 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/cmdmain.c
|
||||
${PM3_ROOT}/client/src/cmdnfc.c
|
||||
${PM3_ROOT}/client/src/cmdparser.c
|
||||
${PM3_ROOT}/client/src/cmdpiv.c
|
||||
${PM3_ROOT}/client/src/cmdscript.c
|
||||
${PM3_ROOT}/client/src/cmdsmartcard.c
|
||||
${PM3_ROOT}/client/src/cmdtrace.c
|
||||
|
|
|
@ -583,6 +583,7 @@ SRCS = mifare/aiddesfire.c \
|
|||
cmdhfseos.c \
|
||||
cmdhfst.c \
|
||||
cmdhfst25ta.c \
|
||||
cmdhftesla.c \
|
||||
cmdhfthinfilm.c \
|
||||
cmdhftopaz.c \
|
||||
cmdhftexkom.c \
|
||||
|
@ -626,6 +627,7 @@ SRCS = mifare/aiddesfire.c \
|
|||
cmdmain.c \
|
||||
cmdnfc.c \
|
||||
cmdparser.c \
|
||||
cmdpiv.c \
|
||||
cmdscript.c \
|
||||
cmdsmartcard.c \
|
||||
cmdtrace.c \
|
||||
|
|
|
@ -530,7 +530,6 @@ stop_tests:
|
|||
bucket_states_tested += bucket_size[block_idx];
|
||||
// prepare to set new states
|
||||
state_p = &states[KEYSTREAM_SIZE];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
|
|
@ -1909,3 +1909,79 @@ D144BD193063
|
|||
# Keys Swim
|
||||
8627C10A7014
|
||||
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
|
|
@ -276,6 +276,7 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/cmdhfepa.c
|
||||
${PM3_ROOT}/client/src/cmdhffelica.c
|
||||
${PM3_ROOT}/client/src/cmdhffido.c
|
||||
${PM3_ROOT}/client/src/cmdhffudan.c
|
||||
${PM3_ROOT}/client/src/cmdhfgallagher.c
|
||||
${PM3_ROOT}/client/src/cmdhfcipurse.c
|
||||
${PM3_ROOT}/client/src/cmdhficlass.c
|
||||
|
@ -293,9 +294,12 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/cmdhfseos.c
|
||||
${PM3_ROOT}/client/src/cmdhfst.c
|
||||
${PM3_ROOT}/client/src/cmdhfst25ta.c
|
||||
${PM3_ROOT}/client/src/cmdhftesla.c
|
||||
${PM3_ROOT}/client/src/cmdhftexkom.c
|
||||
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
||||
${PM3_ROOT}/client/src/cmdhftopaz.c
|
||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||
${PM3_ROOT}/client/src/cmdhfxerox.c
|
||||
${PM3_ROOT}/client/src/cmdhw.c
|
||||
${PM3_ROOT}/client/src/cmdlf.c
|
||||
${PM3_ROOT}/client/src/cmdlfawid.c
|
||||
|
@ -334,6 +338,7 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/cmdmain.c
|
||||
${PM3_ROOT}/client/src/cmdnfc.c
|
||||
${PM3_ROOT}/client/src/cmdparser.c
|
||||
${PM3_ROOT}/client/src/cmdpiv.c
|
||||
${PM3_ROOT}/client/src/cmdscript.c
|
||||
${PM3_ROOT}/client/src/cmdsmartcard.c
|
||||
${PM3_ROOT}/client/src/cmdtrace.c
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
-- This Lua script is designed to run with Iceman/RRG Proxmark3 fork
|
||||
-- Just copy hf_mf_dump-luxeo.lua to client/luascripts/
|
||||
-- and run "script run hf_mf_dump-luxeo"
|
||||
-- and run "script run hf_mf_dump_luxeo"
|
||||
|
||||
-- requirements
|
||||
local cmds = require('commands')
|
||||
|
@ -12,16 +12,16 @@ local ansicolors = require('ansicolors')
|
|||
|
||||
copyright = ''
|
||||
author = '0xdrrb'
|
||||
version = 'v0.1.2'
|
||||
version = 'v0.1.3'
|
||||
desc = [[
|
||||
This is a script that tries to dump and decrypt the data of a specific type of Mifare laundromat token.
|
||||
OBS! Tag must be on the antenna.
|
||||
]]
|
||||
example = [[
|
||||
script run hf_mf_dump-luxeo
|
||||
script run hf_mf_dump_luxeo
|
||||
]]
|
||||
usage = [[
|
||||
script run hf_mf_dump-luxeo
|
||||
script run hf_mf_dump_luxeo
|
||||
]]
|
||||
arguments = [[
|
||||
-h This help
|
|
@ -105,7 +105,7 @@ local function main(args)
|
|||
|
||||
-- chomp emu header
|
||||
if #hex == 1192 then
|
||||
hex = hex:sub(112)
|
||||
hex = hex:sub(113)
|
||||
end
|
||||
|
||||
local amiibo_offset = 0
|
||||
|
|
|
@ -139,14 +139,10 @@ local function main(args)
|
|||
-- force lock bytes, otherwise the Amiibo won't be recognized
|
||||
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)
|
||||
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))
|
||||
end
|
||||
if blocks[148] == nil or blocks[148] == '00000000' then
|
||||
blocks[148] = "80800000"
|
||||
end
|
||||
|
||||
err = LoadEmulator(uid, blocks)
|
||||
if err then return oops(err) end
|
||||
|
|
|
@ -6,20 +6,20 @@ local ansicolors = require('ansicolors')
|
|||
|
||||
copyright = ''
|
||||
author = "Iceman"
|
||||
version = 'v1.0.1'
|
||||
version = 'v1.0.2'
|
||||
desc = [[
|
||||
This script calculates mifare Ultralight-EV1 pwd based on uid diversification for an Italian ticketsystem
|
||||
Algo not found by me.
|
||||
]]
|
||||
example =[[
|
||||
-- if called without, it reads tag uid
|
||||
script run hf_mfu_uidkeycalc-italy
|
||||
script run hf_mfu_uidkeycalc_italy
|
||||
|
||||
--
|
||||
script run hf_mfu_uidkeycalc-italy -u 11223344556677
|
||||
script run hf_mfu_uidkeycalc_italy -u 11223344556677
|
||||
]]
|
||||
usage = [[
|
||||
script run hf_mfu_uidkeycalc-italy -h -u <uid> "
|
||||
script run hf_mfu_uidkeycalc_italy -h -u <uid> "
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
|
@ -6,7 +6,7 @@ local ac = require('ansicolors')
|
|||
|
||||
copyright = ''
|
||||
author = "Christian Herrmann"
|
||||
version = 'v1.0.0'
|
||||
version = 'v1.0.1'
|
||||
desc = [[
|
||||
This script loads a json format file, with the field "data" and a hexbyte array of data. Ie t55x7 dump,
|
||||
it tries to identify which system based on block1, and detect block0 settings.
|
||||
|
@ -16,7 +16,7 @@ example = [[
|
|||
script run lf_ident_json -i lf_t55xx.json
|
||||
]]
|
||||
usage = [[
|
||||
script run lf_en4100_bulk.lua [-h] [-c] [-p password] [-s <start cn>] [-v]
|
||||
script run lf_ident_json.lua [-h] [-c] [-p password] [-s <start cn>] [-v]
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#include "cipursecore.h"
|
||||
#include <string.h> // memcpy memset
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "comms.h" // DropField
|
||||
#include "util_posix.h" // msleep
|
||||
|
@ -28,6 +27,7 @@
|
|||
#include "../iso7816/apduinfo.h" // sAPDU_t
|
||||
#include "ui.h"
|
||||
#include "util.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
// context for secure channel
|
||||
CipurseContext_t cipurseContext;
|
||||
|
@ -112,7 +112,7 @@ static int CIPURSEExchangeEx(bool activate_field, bool leave_field_on, sAPDU_t a
|
|||
*sw = isw;
|
||||
}
|
||||
|
||||
if (isw != 0x9000) {
|
||||
if (isw != ISO7816_OK) {
|
||||
if (GetAPDULogging()) {
|
||||
if (*sw >> 8 == 0x61) {
|
||||
PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff);
|
||||
|
@ -255,7 +255,7 @@ bool CIPURSEChannelAuthenticate(uint8_t keyindex, uint8_t *key, bool verbose) {
|
|||
|
||||
// authenticate
|
||||
res = CIPURSEMutualAuthenticate(keyindex, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000 || len != 16) {
|
||||
if (res != 0 || sw != ISO7816_OK || len != 16) {
|
||||
if (sw == 0x6988) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(WARNING, "Authentication ( " _RED_("fail") " ). Wrong key");
|
||||
|
|
|
@ -1230,7 +1230,7 @@ int FSKrawDemod(uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow, bo
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, _YELLOW_("%s") " decoded bitstream", GetFSKType(fchigh, fclow, invert));
|
||||
PrintAndLogEx(INFO, "-----------------------");
|
||||
printDemodBuff(0, false, invert, false);
|
||||
printDemodBuff(0, false, false, false);
|
||||
}
|
||||
goto out;
|
||||
} else {
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "cmdhftexkom.h" // Texkom
|
||||
#include "cmdhfxerox.h" // Xerox
|
||||
#include "cmdhffudan.h" // Fudan cards
|
||||
#include "cmdhftesla.h" // Tesla
|
||||
#include "cmdtrace.h" // trace list
|
||||
#include "ui.h"
|
||||
#include "proxgui.h"
|
||||
|
@ -123,7 +124,7 @@ int CmdHFSearch(const char *Cmd) {
|
|||
PROMPT_CLEARLINE;
|
||||
PrintAndLogEx(INPLACE, " Searching for iCLASS / PicoPass tag...");
|
||||
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");
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
|
@ -493,9 +494,10 @@ static command_t CommandTable[] = {
|
|||
{"ntag424", CmdHF_ntag424, AlwaysAvailable, "{ NXP NTAG 4242 DNA RFIDs... }"},
|
||||
{"seos", CmdHFSeos, AlwaysAvailable, "{ SEOS RFIDs... }"},
|
||||
{"st25ta", CmdHFST25TA, AlwaysAvailable, "{ ST25TA RFIDs... }"},
|
||||
{"tesla", CmdHFTESLA, AlwaysAvailable, "{ TESLA Cards... }"},
|
||||
{"texkom", CmdHFTexkom, AlwaysAvailable, "{ Texkom RFIDs... }"},
|
||||
{"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
|
||||
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
|
||||
{"texkom", CmdHFTexkom, AlwaysAvailable, "{ Texkom RFIDs... }"},
|
||||
{"xerox", CmdHFXerox, AlwaysAvailable, "{ Fuji/Xerox cartridge RFIDs... }"},
|
||||
{"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"},
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"},
|
||||
|
|
|
@ -42,7 +42,13 @@
|
|||
#include "desfire.h" // desfire enums
|
||||
#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 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;
|
||||
|
||||
// 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))) {
|
||||
|
||||
int clen = 0;
|
||||
|
@ -1454,29 +1460,34 @@ static int CmdHF14AChaining(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14a chaining",
|
||||
"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");
|
||||
|
||||
void *argtable[] = {
|
||||
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
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
struct arg_str *str = arg_get_str(ctx, 1);
|
||||
int len = arg_get_str_len(ctx, 1);
|
||||
bool on = arg_get_lit(ctx, 1);
|
||||
bool off = arg_get_lit(ctx, 2);
|
||||
|
||||
if (len && (!strcmp(str->sval[0], "enable") || !strcmp(str->sval[0], "1")))
|
||||
APDUInFramingEnable = true;
|
||||
if ((on + off) > 1) {
|
||||
PrintAndLogEx(INFO, "Select only one option");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (len && (!strcmp(str->sval[0], "disable") || !strcmp(str->sval[0], "0")))
|
||||
APDUInFramingEnable = false;
|
||||
if (on)
|
||||
Set_apdu_in_framing(true);
|
||||
|
||||
if (off)
|
||||
Set_apdu_in_framing(false);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 == 0x9000) {
|
||||
if (sw == ISO7816_OK || sw == ISO7816_INVALID_DF || sw == ISO7816_FILE_TERMINATED) {
|
||||
if (sw == ISO7816_OK) {
|
||||
if (verbose) PrintAndLogEx(SUCCESS, "Application ( " _GREEN_("ok") " )");
|
||||
} else {
|
||||
if (verbose) PrintAndLogEx(WARNING, "Application ( " _RED_("blocked") " )");
|
||||
|
@ -2380,14 +2391,14 @@ int infoHF14A4Applications(bool verbose) {
|
|||
if (res)
|
||||
break;
|
||||
|
||||
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) {
|
||||
if (sw == ISO7816_OK || sw == ISO7816_INVALID_DF || sw == ISO7816_FILE_TERMINATED) {
|
||||
if (!found) {
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, "----------------- " _CYAN_("Short AID search") " -----------------");
|
||||
}
|
||||
found++;
|
||||
|
||||
if (sw == 0x9000) {
|
||||
if (sw == ISO7816_OK) {
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "Application " _CYAN_("%s") " ( " _GREEN_("ok") " )", hintAIDList[i].desc);
|
||||
cardFound[i] = true;
|
||||
|
@ -2574,7 +2585,7 @@ retry_ins:
|
|||
// Show response.
|
||||
if (sw_occurrences < error_limit) {
|
||||
logLevel_t log_level = INFO;
|
||||
if (sw == 0x9000) {
|
||||
if (sw == ISO7816_OK) {
|
||||
log_level = SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -2674,7 +2685,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
// Try NDEF Type 4 Tag v1.0
|
||||
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);
|
||||
|
@ -2688,7 +2699,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -2714,7 +2725,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -2729,7 +2740,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
|
|||
return res;
|
||||
}
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -2763,7 +2774,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -2780,7 +2791,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -2819,7 +2830,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
free(ndef_file);
|
||||
|
@ -2887,7 +2898,7 @@ int CmdHF14ANdefFormat(const char *Cmd) {
|
|||
|
||||
bool have_application = true;
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
have_application = false;
|
||||
PrintAndLogEx(INFO, "no NDEF application found");
|
||||
} else {
|
||||
|
|
|
@ -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 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
|
||||
|
|
|
@ -126,8 +126,8 @@ static void hf14b_aid_search(bool verbose) {
|
|||
}
|
||||
}
|
||||
|
||||
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) {
|
||||
if (sw == 0x9000) {
|
||||
if (sw == ISO7816_OK || sw == ISO7816_INVALID_DF || sw == ISO7816_FILE_TERMINATED) {
|
||||
if (sw == ISO7816_OK) {
|
||||
if (verbose) PrintAndLogEx(SUCCESS, "Application ( " _GREEN_("ok") " )");
|
||||
} else {
|
||||
if (verbose) PrintAndLogEx(WARNING, "Application ( " _RED_("blocked") " )");
|
||||
|
@ -2035,7 +2035,7 @@ int CmdHF14BNdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
res = PM3_ESOFT;
|
||||
goto out;
|
||||
|
@ -2055,7 +2055,7 @@ int CmdHF14BNdefRead(const char *Cmd) {
|
|||
goto out;
|
||||
|
||||
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));
|
||||
res = PM3_ESOFT;
|
||||
goto out;
|
||||
|
@ -2071,7 +2071,7 @@ int CmdHF14BNdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
res = PM3_ESOFT;
|
||||
goto out;
|
||||
|
@ -2090,7 +2090,7 @@ int CmdHF14BNdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
res = PM3_ESOFT;
|
||||
goto out;
|
||||
|
|
|
@ -67,7 +67,7 @@ typedef struct {
|
|||
// structure and database for uid -> tagtype lookups
|
||||
typedef struct {
|
||||
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;
|
||||
} productName_t;
|
||||
|
||||
|
@ -90,17 +90,23 @@ static const productName_t uidmapping[] = {
|
|||
// E0 04 xx
|
||||
// 04 = Manufacturer code (Philips/NXP)
|
||||
// XX = IC id (Chip ID Family)
|
||||
//I-Code SLI SL2 ICS20 [IC id = 01]
|
||||
//I-Code SLI-S [IC id = 02]
|
||||
//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 SLI SL2 ICS20 [IC id = 01 + bit35 set to 0 + bit36 set to 0]
|
||||
//I-Code SLIX [IC id = 01 + bit35 set to 0 + bit36 set to 1]
|
||||
//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 SLI-L [IC id = 03 + bit36 set to 0]
|
||||
//I-Code SLIX-L [IC id = 03 + bit36 set to 1]
|
||||
{ 0xE004000000000000LL, 16, "NXP Semiconductors Germany (Philips)" },
|
||||
{ 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)" },
|
||||
{ 0xE004030000000000LL, 24, "NXP(Philips); IC SL2 ICS50/ICS51(SLI-L) ICS5002/ICS5102(SLIX-L)" },
|
||||
{ 0xE004011800000000LL, 0xFFFFFF1800000000LL, "NXP(Philips); IC NTP53x2/NTP5210/NTA5332(NTAG 5)" },
|
||||
{ 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 .. .. ..
|
||||
// 05 = Manufacturer code (Infineon)
|
||||
|
@ -364,7 +370,11 @@ static const char *getTagInfo_15(uint8_t *uid) {
|
|||
int i = 0, best = -1;
|
||||
memcpy(&myuid, uid, sizeof(uint64_t));
|
||||
while (uidmapping[i].mask > 0) {
|
||||
if (uidmapping[i].mask > 64) {
|
||||
mask = uidmapping[i].mask;
|
||||
} else {
|
||||
mask = (~0ULL) << (64 - uidmapping[i].mask);
|
||||
}
|
||||
if ((myuid & mask) == uidmapping[i].uid) {
|
||||
if (best == -1) {
|
||||
best = i;
|
||||
|
@ -642,6 +652,94 @@ static int CmdHF15Samples(const char *Cmd) {
|
|||
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
|
||||
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"));
|
||||
|
||||
if (support_easmode) {
|
||||
reqlen = 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 {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
NxpTestEAS(uid);
|
||||
}
|
||||
|
||||
if (support_signature) {
|
||||
// Check if we can also read the signature
|
||||
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);
|
||||
NxpCheckSig(uid);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
|
@ -935,6 +967,12 @@ static int CmdHF15Info(const char *Cmd) {
|
|||
if (data[8] == 0x04 && data[7] == 0x01 && nxp_version == 0x08) {
|
||||
PrintAndLogEx(DEBUG, "SLIX2 Detected, getting NXP System Info");
|
||||
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, "");
|
||||
|
@ -1375,11 +1413,11 @@ static int CmdHF15WriteAfi(const char *Cmd) {
|
|||
// arg0 (datalen, cmd len? .arg0 == crc?)
|
||||
// arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 )
|
||||
// arg2 (recv == 1 == expect a response)
|
||||
uint8_t read_respone = 1;
|
||||
uint8_t read_response = 1;
|
||||
|
||||
PacketResponseNG resp;
|
||||
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) {
|
||||
PrintAndLogEx(ERR, "iso15693 timeout");
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "util.h"
|
||||
#include "fileutils.h" // laodFileJSONroot
|
||||
#include "crypto/libpcrypto.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
const uint8_t PxSE_AID[] = {0xA0, 0x00, 0x00, 0x05, 0x07, 0x01, 0x00};
|
||||
#define PxSE_AID_LENGTH 7
|
||||
|
@ -104,11 +105,11 @@ static int SelectAndPrintInfoFile(void) {
|
|||
uint16_t sw = 0;
|
||||
|
||||
int res = CIPURSESelectFile(0x2ff7, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
return PM3_EAPDU_FAIL;
|
||||
|
||||
res = CIPURSEReadBinary(0, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
return PM3_EAPDU_FAIL;
|
||||
|
||||
if (len > 0) {
|
||||
|
@ -151,7 +152,7 @@ static int CmdHFCipurseInfo(const char *Cmd) {
|
|||
bool mfExist = false;
|
||||
bool infoPrinted = false;
|
||||
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;
|
||||
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++) {
|
||||
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;
|
||||
PrintAndLogEx(INFO, _CYAN_("PxSE") " exist: %s", PxSE_AID_LIST[i].name);
|
||||
if (len > 0) {
|
||||
|
@ -179,7 +180,7 @@ static int CmdHFCipurseInfo(const char *Cmd) {
|
|||
}
|
||||
PrintAndLogEx(INFO, "Application `" _YELLOW_("AF F1") "` selected " _GREEN_("successfully"));
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
if (sw == 0x0000) {
|
||||
PrintAndLogEx(ERR, "APDU exchange error. Card returns 0x0000");
|
||||
} else {
|
||||
|
@ -362,7 +363,7 @@ static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, si
|
|||
if (useAID && aidLen > 0) {
|
||||
|
||||
res = CIPURSESelectAID(true, true, aid, aidLen, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (res != 0 || *sw != ISO7816_OK) {
|
||||
if (verbose) {
|
||||
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) {
|
||||
|
||||
res = CIPURSESelectFileEx(true, true, fileId, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (res != 0 || *sw != ISO7816_OK) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(ERR, "Cipurse select file 0x%04x ( %s )", fileId, _RED_("fail"));
|
||||
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) {
|
||||
|
||||
res = CIPURSESelectMFDefaultFileEx(true, true, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (res != 0 || *sw != ISO7816_OK) {
|
||||
if (verbose) {
|
||||
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 {
|
||||
|
||||
res = CIPURSESelect(true, true, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (res != 0 || *sw != ISO7816_OK) {
|
||||
if (verbose) {
|
||||
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);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (res != 0 || *sw != ISO7816_OK) {
|
||||
if (verbose) {
|
||||
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;
|
||||
uint16_t sw = 0;
|
||||
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();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -553,7 +554,7 @@ static int CmdHFCipurseAuth(const char *Cmd) {
|
|||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
|
||||
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();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -635,7 +636,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
|||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
|
||||
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);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -660,7 +661,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(ERR, "File select ( " _RED_("error") " ). Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
|
@ -671,7 +672,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Select file 0x%x ( %s )", fileId, _GREEN_("ok"));
|
||||
|
||||
res = CIPURSEReadBinary(offset, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
|
@ -758,7 +759,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
|||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
|
||||
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);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -789,7 +790,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
|
@ -800,7 +801,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Select file 0x%x ( %s )", fileId, _GREEN_("ok"));
|
||||
|
||||
res = CIPURSEUpdateBinary(offset, hdata, hdatalen, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(ERR, "File write " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
|
@ -812,7 +813,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
|||
if (needCommit) {
|
||||
sw = 0;
|
||||
res = CIPURSECommitTransaction(&sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
|
||||
|
||||
if (verbose)
|
||||
|
@ -883,7 +884,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
|||
uint16_t sw = 0;
|
||||
|
||||
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") " )");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -921,7 +922,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
|
@ -1020,7 +1021,7 @@ static int CmdHFCipurseWriteFileAttr(const char *Cmd) {
|
|||
uint16_t sw = 0;
|
||||
|
||||
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") " )");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1058,7 +1059,7 @@ static int CmdHFCipurseWriteFileAttr(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSEUpdateFileAttributes(hdata, hdatalen, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(ERR, "File attributes update " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
|
@ -1070,7 +1071,7 @@ static int CmdHFCipurseWriteFileAttr(const char *Cmd) {
|
|||
if (needCommit) {
|
||||
sw = 0;
|
||||
res = CIPURSECommitTransaction(&sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
|
||||
|
||||
if (verbose)
|
||||
|
@ -1125,7 +1126,7 @@ static int CmdHFCipurseFormatAll(const char *Cmd) {
|
|||
uint16_t sw = 0;
|
||||
|
||||
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);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1154,7 +1155,7 @@ static int CmdHFCipurseFormatAll(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSEFormatAll(&sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Format " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1239,14 +1240,14 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
|
|||
|
||||
if (useAID || useFID || selmfd) {
|
||||
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") " )");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1277,7 +1278,7 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
|
|||
}
|
||||
|
||||
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, "0x%04x - %s", sw,
|
||||
GetSpecificAPDUCodeDesc(SelectAPDUCodeDescriptions, ARRAYLEN(SelectAPDUCodeDescriptions), sw));
|
||||
|
@ -1289,7 +1290,7 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
|
|||
if (needCommit) {
|
||||
sw = 0;
|
||||
res = CIPURSECommitTransaction(&sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
|
||||
|
||||
if (verbose)
|
||||
|
@ -1376,14 +1377,14 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
|||
|
||||
if (useChildFID) {
|
||||
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);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1405,7 +1406,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
|||
|
||||
if (useChildFID) {
|
||||
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, "0x%04x - %s",
|
||||
sw,
|
||||
|
@ -1417,7 +1418,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Child file id " _CYAN_("%04x") " deleted " _GREEN_("succesfully"), childFileId);
|
||||
} else if (useFID) {
|
||||
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, "0x%04x - %s",
|
||||
sw,
|
||||
|
@ -1429,7 +1430,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "File id " _CYAN_("%04x") " deleted " _GREEN_("succesfully"), fileId);
|
||||
} else {
|
||||
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, "0x%04x - %s",
|
||||
sw,
|
||||
|
@ -1444,7 +1445,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
|||
if (needCommit) {
|
||||
sw = 0;
|
||||
res = CIPURSECommitTransaction(&sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
|
||||
|
||||
if (verbose)
|
||||
|
@ -1588,14 +1589,14 @@ static int CmdHFCipurseUpdateKey(const char *Cmd) {
|
|||
|
||||
if (useAID || useFID || selmfd) {
|
||||
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") " )");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
DropField();
|
||||
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);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Update key command " _RED_("ERROR"));
|
||||
PrintAndLogEx(ERR, "0x%04x - %s", sw,
|
||||
GetSpecificAPDUCodeDesc(UAPDpdateKeyCodeDescriptions, ARRAYLEN(UAPDpdateKeyCodeDescriptions), sw));
|
||||
|
@ -1638,7 +1639,7 @@ static int CmdHFCipurseUpdateKey(const char *Cmd) {
|
|||
if (needCommit) {
|
||||
sw = 0;
|
||||
res = CIPURSECommitTransaction(&sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
|
||||
|
||||
if (verbose)
|
||||
|
@ -1736,14 +1737,14 @@ static int CmdHFCipurseUpdateKeyAttr(const char *Cmd) {
|
|||
|
||||
if (useAID || useFID || selmfd) {
|
||||
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") " )");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1774,7 +1775,7 @@ static int CmdHFCipurseUpdateKeyAttr(const char *Cmd) {
|
|||
}
|
||||
|
||||
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, "0x%04x - %s", sw,
|
||||
GetSpecificAPDUCodeDesc(UAPDpdateKeyAttrCodeDescriptions, ARRAYLEN(UAPDpdateKeyAttrCodeDescriptions), sw));
|
||||
|
@ -1786,7 +1787,7 @@ static int CmdHFCipurseUpdateKeyAttr(const char *Cmd) {
|
|||
if (needCommit) {
|
||||
sw = 0;
|
||||
res = CIPURSECommitTransaction(&sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
|
||||
|
||||
if (verbose)
|
||||
|
@ -1803,7 +1804,7 @@ bool CheckCardCipurse(void) {
|
|||
uint16_t sw = 0;
|
||||
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) {
|
||||
|
|
|
@ -194,7 +194,7 @@ static bool emrtd_exchange_commands(sAPDU_t apdu, bool include_le, uint16_t le,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(DEBUG, "Command failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return false;
|
||||
}
|
||||
|
@ -1957,14 +1957,16 @@ int infoHF_EMRTD_offline(const char *path) {
|
|||
uint8_t *data;
|
||||
size_t datalen = 0;
|
||||
char *filepath = calloc(strlen(path) + 100, sizeof(char));
|
||||
if (filepath == NULL)
|
||||
if (filepath == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
strcpy(filepath, path);
|
||||
strncat(filepath, PATHSEP, 2);
|
||||
strcat(filepath, dg_table[EF_COM].filename);
|
||||
|
||||
if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to read EF_COM.");
|
||||
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)) {
|
||||
PrintAndLogEx(ERR, "Failed to read EF_COM");
|
||||
free(filepath);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -1996,19 +1998,21 @@ int infoHF_EMRTD_offline(const char *path) {
|
|||
strncat(filepath, PATHSEP, 2);
|
||||
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);
|
||||
free(data);
|
||||
} 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);
|
||||
strncat(filepath, PATHSEP, 2);
|
||||
strcat(filepath, dg_table[EF_SOD].filename);
|
||||
|
||||
if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to read EF_SOD.");
|
||||
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)) {
|
||||
PrintAndLogEx(ERR, "Failed to read EF_SOD");
|
||||
free(filepath);
|
||||
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);
|
||||
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);
|
||||
|
||||
|
@ -2035,10 +2039,12 @@ int infoHF_EMRTD_offline(const char *path) {
|
|||
strcpy(filepath, path);
|
||||
strncat(filepath, PATHSEP, 2);
|
||||
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
|
||||
if (dg->parser != NULL)
|
||||
if (dg->parser != NULL) {
|
||||
dg->parser(data, datalen);
|
||||
}
|
||||
|
||||
PrintAndLogEx(DEBUG, "EF_DG%i hash algo: %i", dg->dgnum, hash_algo);
|
||||
// Check file hash
|
||||
|
@ -2058,13 +2064,6 @@ int infoHF_EMRTD_offline(const char *path) {
|
|||
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) {
|
||||
// Date has to be 6 chars
|
||||
if (datalen != 6) {
|
||||
|
@ -2085,7 +2084,9 @@ static int CmdHFeMRTDDump(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf emrtd dump",
|
||||
"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[] = {
|
||||
|
@ -2094,7 +2095,7 @@ static int CmdHFeMRTDDump(const char *Cmd) {
|
|||
arg_str0("d", "dateofbirth", "<YYMMDD>", "date of birth 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(NULL, "path", "<dirpath>", "save dump to the given dirpath"),
|
||||
arg_str0(NULL, "dir", "<str>", "save dump to the given dirpath"),
|
||||
arg_param_end
|
||||
};
|
||||
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) {
|
||||
BAC = false;
|
||||
} else {
|
||||
text_to_upper(docnum, slen);
|
||||
strn_upper((char *)docnum, slen);
|
||||
if (slen != 9) {
|
||||
// Pad to 9 with <
|
||||
memset(docnum + slen, '<', 9 - slen);
|
||||
|
@ -2143,7 +2144,7 @@ static int CmdHFeMRTDDump(const char *Cmd) {
|
|||
error = true;
|
||||
} else {
|
||||
BAC = true;
|
||||
text_to_upper(mrz, slen);
|
||||
strn_upper((char *)mrz, slen);
|
||||
memcpy(docnum, &mrz[0], 9);
|
||||
memcpy(dob, &mrz[13], 6);
|
||||
memcpy(expiry, &mrz[21], 6);
|
||||
|
@ -2183,7 +2184,10 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf emrtd info",
|
||||
"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[] = {
|
||||
|
@ -2192,7 +2196,7 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
|
|||
arg_str0("d", "dateofbirth", "<YYMMDD>", "date of birth 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(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_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) {
|
||||
BAC = false;
|
||||
} else {
|
||||
text_to_upper(docnum, slen);
|
||||
strn_upper((char *)docnum, slen);
|
||||
if (slen != 9) {
|
||||
memset(docnum + slen, '<', 9 - slen);
|
||||
}
|
||||
|
@ -2241,7 +2245,7 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
|
|||
error = true;
|
||||
} else {
|
||||
BAC = true;
|
||||
text_to_upper(mrz, slen);
|
||||
strn_upper((char *)mrz, slen);
|
||||
memcpy(docnum, &mrz[0], 9);
|
||||
memcpy(dob, &mrz[13], 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 show_images = arg_get_lit(ctx, 6);
|
||||
CLIParserFree(ctx);
|
||||
if ((! IfPm3Iso14443()) && (! is_offline)) {
|
||||
if ((IfPm3Iso14443() == false) && (is_offline == false)) {
|
||||
PrintAndLogEx(WARNING, "Only offline mode is available");
|
||||
error = true;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "cmdtrace.h"
|
||||
#include "util.h"
|
||||
#include "fileutils.h" // laodFileJSONroot
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
#define DEF_FIDO_SIZE 2048
|
||||
#define DEF_FIDO_PARAM_FILE "hf_fido2_defparams.json"
|
||||
|
@ -84,7 +85,7 @@ static int CmdHFFidoInfo(const char *Cmd) {
|
|||
return res;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
if (sw)
|
||||
PrintAndLogEx(INFO, "Not a FIDO card! APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
else
|
||||
|
@ -111,7 +112,7 @@ static int CmdHFFidoInfo(const char *Cmd) {
|
|||
if (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));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -262,7 +263,7 @@ static int CmdHFFidoRegister(const char *cmd) {
|
|||
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));
|
||||
DropField();
|
||||
json_decref(root);
|
||||
|
@ -277,7 +278,7 @@ static int CmdHFFidoRegister(const char *cmd) {
|
|||
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));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -584,7 +585,7 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
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));
|
||||
DropField();
|
||||
json_decref(root);
|
||||
|
@ -599,7 +600,7 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
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));
|
||||
json_decref(root);
|
||||
return PM3_ESOFT;
|
||||
|
@ -724,7 +725,7 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
|||
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));
|
||||
DropField();
|
||||
json_decref(root);
|
||||
|
@ -752,7 +753,7 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
|||
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));
|
||||
json_decref(root);
|
||||
return PM3_EFILE;
|
||||
|
@ -843,7 +844,7 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
|
|||
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));
|
||||
DropField();
|
||||
json_decref(root);
|
||||
|
@ -871,7 +872,7 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
|
|||
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));
|
||||
json_decref(root);
|
||||
return PM3_ESOFT;
|
||||
|
|
|
@ -285,7 +285,7 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
|
|||
|
||||
// get header from 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) {
|
||||
cc = &iclass_last_known_card;
|
||||
// calc diversified key for selected card
|
||||
|
@ -905,19 +905,25 @@ static int CmdHFiClassInfo(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool shallow_mod = arg_get_lit(ctx, 1);
|
||||
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 = {
|
||||
.flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
|
||||
};
|
||||
|
||||
if (shallow_mod) {
|
||||
payload.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
|
||||
}
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
|
||||
do {
|
||||
|
@ -973,17 +979,19 @@ static int CmdHFiClassReader(const char *Cmd) {
|
|||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
bool shallow_mod = arg_get_lit(ctx, 2);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
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) {
|
||||
|
@ -1547,12 +1555,16 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
|
|||
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 = {
|
||||
.flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
|
||||
};
|
||||
|
||||
if (shallow_mod) {
|
||||
payload.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
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("z", "dense", "dense dump output style"),
|
||||
arg_lit0(NULL, "force", "force unsecure card read"),
|
||||
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -1693,6 +1706,7 @@ static int CmdHFiClassDump(const char *Cmd) {
|
|||
bool use_replay = arg_get_lit(ctx, 8);
|
||||
bool dense_output = g_session.dense_output || arg_get_lit(ctx, 9);
|
||||
bool force = arg_get_lit(ctx, 10);
|
||||
bool shallow_mod = arg_get_lit(ctx, 11);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
@ -1711,6 +1725,11 @@ static int CmdHFiClassDump(const char *Cmd) {
|
|||
iclass_card_select_t payload_rdr = {
|
||||
.flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
|
||||
};
|
||||
|
||||
if (shallow_mod) {
|
||||
payload_rdr.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
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.send_reply = true,
|
||||
.req.do_auth = auth,
|
||||
.req.shallow_mod = shallow_mod,
|
||||
.end_block = app_limit1,
|
||||
};
|
||||
memcpy(payload.req.key, key, 8);
|
||||
|
@ -1950,7 +1970,7 @@ write_dump:
|
|||
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 = {
|
||||
.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.send_reply = true,
|
||||
.req.do_auth = use_secure_pagemode,
|
||||
.req.shallow_mod = shallow_mod,
|
||||
};
|
||||
memcpy(payload.req.key, KEY, 8);
|
||||
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, "nr", "replay of NR/MAC"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -2072,6 +2094,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
|
|||
bool rawkey = arg_get_lit(ctx, 8);
|
||||
bool use_replay = arg_get_lit(ctx, 9);
|
||||
bool verbose = arg_get_lit(ctx, 10);
|
||||
bool shallow_mod = arg_get_lit(ctx, 11);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
@ -2080,7 +2103,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
|
|||
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) {
|
||||
case PM3_SUCCESS:
|
||||
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, "raw", "no computations applied to key"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -2165,6 +2189,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
|
|||
bool elite = arg_get_lit(ctx, 7);
|
||||
bool rawkey = arg_get_lit(ctx, 8);
|
||||
bool verbose = arg_get_lit(ctx, 9);
|
||||
bool shallow_mod = arg_get_lit(ctx, 10);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
@ -2215,6 +2240,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
|
|||
payload->req.blockno = startblock;
|
||||
payload->req.send_reply = true;
|
||||
payload->req.do_auth = true;
|
||||
payload->req.shallow_mod = shallow_mod;
|
||||
memcpy(payload->req.key, key, 8);
|
||||
|
||||
payload->item_cnt = (endblock - startblock + 1);
|
||||
|
@ -2268,7 +2294,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
|
|||
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 = {
|
||||
.use_raw = rawkey,
|
||||
|
@ -2278,6 +2304,7 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo
|
|||
.blockno = blockno,
|
||||
.send_reply = true,
|
||||
.do_auth = auth,
|
||||
.shallow_mod = shallow_mod,
|
||||
};
|
||||
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, "nr", "replay of NR/MAC"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -2381,6 +2409,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
|
|||
bool rawkey = arg_get_lit(ctx, 6);
|
||||
bool use_replay = arg_get_lit(ctx, 7);
|
||||
bool verbose = arg_get_lit(ctx, 8);
|
||||
bool shallow_mod = arg_get_lit(ctx, 9);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
@ -2400,7 +2429,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
|
|||
}
|
||||
|
||||
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)
|
||||
return res;
|
||||
|
||||
|
@ -2975,7 +3004,7 @@ static int CmdHFiClassCalcNewKey(const char *Cmd) {
|
|||
|
||||
if (givenCSN == false) {
|
||||
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();
|
||||
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, "elite", "elite computations applied to key"),
|
||||
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
|
||||
};
|
||||
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_elite = arg_get_lit(ctx, 3);
|
||||
bool use_raw = arg_get_lit(ctx, 4);
|
||||
bool shallow_mod = arg_get_lit(ctx, 5);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
@ -3213,7 +3244,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
|
|||
|
||||
bool got_csn = false;
|
||||
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)
|
||||
PrintAndLogEx(WARNING, "one more try");
|
||||
else
|
||||
|
@ -3295,6 +3326,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
|
|||
}
|
||||
packet->use_credit_key = use_credit_key;
|
||||
packet->count = curr_chunk_cnt;
|
||||
packet->shallow_mod = shallow_mod;
|
||||
// copy chunk of pre calculated macs to packet
|
||||
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, "cn", "<dec>", "card number"),
|
||||
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
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -3843,6 +3876,8 @@ static int CmdHFiClassEncode(const char *Cmd) {
|
|||
int format_len = 0;
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 9), (uint8_t *)format, sizeof(format), &format_len);
|
||||
|
||||
bool shallow_mod = arg_get_lit(ctx, 10);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if ((rawkey + elite) > 1) {
|
||||
|
@ -3964,7 +3999,7 @@ static int CmdHFiClassEncode(const char *Cmd) {
|
|||
int isok = PM3_SUCCESS;
|
||||
// write
|
||||
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) {
|
||||
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));
|
||||
|
@ -4135,11 +4170,16 @@ int CmdHFiClass(const char *Cmd) {
|
|||
// DESFIRE| | |
|
||||
//}
|
||||
|
||||
int info_iclass(void) {
|
||||
int info_iclass(bool shallow_mod) {
|
||||
|
||||
iclass_card_select_t payload = {
|
||||
.flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
|
||||
};
|
||||
|
||||
if (shallow_mod) {
|
||||
payload.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload, sizeof(iclass_card_select_t));
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
|
||||
int CmdHFiClass(const char *Cmd);
|
||||
|
||||
int info_iclass(void);
|
||||
int read_iclass_csn(bool loop, bool verbose);
|
||||
int info_iclass(bool shallow_mod);
|
||||
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 HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite);
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "emv/tlv.h"
|
||||
#include "iso7816/apduinfo.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -126,7 +127,7 @@ static int CmdHFKSX6924Info(const char *Cmd) {
|
|||
return res;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
if (sw) {
|
||||
PrintAndLogEx(INFO, "Not a KS X 6924 card! APDU response: %04x - %s",
|
||||
sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
|
|
|
@ -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]);
|
||||
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:
|
||||
snprintf(exp, size, "MAGIC WUPC1");
|
||||
break;
|
||||
|
@ -942,14 +954,14 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
|||
break;
|
||||
case MFDES_READ_DATA:
|
||||
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 {
|
||||
snprintf(exp, size, "READ DATA");
|
||||
}
|
||||
break;
|
||||
case MFDES_WRITE_DATA:
|
||||
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 {
|
||||
snprintf(exp, size, "WRITE DATA");
|
||||
}
|
||||
|
@ -984,14 +996,14 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
|||
break;
|
||||
case MFDES_WRITE_RECORD:
|
||||
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 {
|
||||
snprintf(exp, size, "WRITE RECORD");
|
||||
}
|
||||
break;
|
||||
case MFDES_READ_RECORDS:
|
||||
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 {
|
||||
snprintf(exp, size, "READ RECORDS");
|
||||
}
|
||||
|
@ -1086,21 +1098,21 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
|||
break;
|
||||
case MFDES_AUTHENTICATE:
|
||||
if (data_size >= 1) {
|
||||
snprintf(exp, size, "AUTH NATIVE (keyNo %d)", data[0]);
|
||||
snprintf(exp, size, "AUTH NATIVE (keyNo %u)", data[0]);
|
||||
} else {
|
||||
snprintf(exp, size, "AUTH NATIVE");
|
||||
}
|
||||
break; // AUTHENTICATE_NATIVE
|
||||
case MFDES_AUTHENTICATE_ISO:
|
||||
if (data_size >= 1) {
|
||||
snprintf(exp, size, "AUTH ISO (keyNo %d)", data[0]);
|
||||
snprintf(exp, size, "AUTH ISO (keyNo %u)", data[0]);
|
||||
} else {
|
||||
snprintf(exp, size, "AUTH ISO");
|
||||
}
|
||||
break; // AUTHENTICATE_STANDARD
|
||||
case MFDES_AUTHENTICATE_AES:
|
||||
if (data_size >= 1) {
|
||||
snprintf(exp, size, "AUTH AES (keyNo %d)", data[0]);
|
||||
snprintf(exp, size, "AUTH AES (keyNo %u)", data[0]);
|
||||
} else {
|
||||
snprintf(exp, size, "AUTH AES");
|
||||
}
|
||||
|
@ -1119,14 +1131,14 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
|||
break;
|
||||
case MFDES_CHANGE_KEY:
|
||||
if (data_size >= 1) {
|
||||
snprintf(exp, size, "CHANGE KEY (keyNo %d)", data[0]);
|
||||
snprintf(exp, size, "CHANGE KEY (keyNo %u)", data[0]);
|
||||
} else {
|
||||
snprintf(exp, size, "CHANGE KEY");
|
||||
}
|
||||
break;
|
||||
case MFDES_GET_KEY_VERSION:
|
||||
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 {
|
||||
snprintf(exp, size, "GET KEY VERSION");
|
||||
}
|
||||
|
|
|
@ -369,12 +369,37 @@ static bool mf_write_block(const uint8_t *key, uint8_t keytype, uint8_t blockno,
|
|||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
|
||||
PrintAndLogEx(FAILED, "Command execute timeout");
|
||||
return PM3_ETIMEOUT;
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mf acl",
|
||||
|
@ -482,7 +507,10 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
|
|||
"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"
|
||||
"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"
|
||||
);
|
||||
void *argtable[] = {
|
||||
|
@ -490,7 +518,7 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
|
|||
arg_int1(NULL, "blk", "<dec>", "block number"),
|
||||
arg_lit0("a", NULL, "input key type is key A (def)"),
|
||||
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("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
|
||||
|
||||
|
@ -528,6 +556,8 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
|
|||
if (b > 255) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// BLOCK 0 detection
|
||||
if (b == 0 && force == false) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
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;
|
||||
|
||||
// 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, "data: %s", sprint_hex(block, sizeof(block)));
|
||||
|
||||
|
@ -909,6 +971,11 @@ static int CmdHF14AMfDump(const char *Cmd) {
|
|||
for (blockNo = 0; blockNo < mfNumBlocksPerSector(sectorNo); blockNo++) {
|
||||
bool received = false;
|
||||
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++) {
|
||||
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));
|
||||
received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500);
|
||||
} 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
|
||||
|
||||
payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo;
|
||||
|
@ -930,10 +996,6 @@ static int CmdHF14AMfDump(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
|
||||
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
|
||||
|
||||
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);
|
||||
} else {
|
||||
PrintAndLogEx(FAILED, "could not read block %2d of sector %2d", blockNo, sectorNo);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
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"
|
||||
"\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"
|
||||
" 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 --1k --uid 04010203\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("k", "kfn", "<fn>", "key filename"),
|
||||
arg_lit0(NULL, "ka", "use specified keyfile to authenticate"),
|
||||
arg_lit0(NULL, "force", "override warnings"),
|
||||
arg_param_end
|
||||
};
|
||||
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);
|
||||
|
||||
bool use_keyfile_for_auth = arg_get_lit(ctx, 8);
|
||||
bool force = arg_get_lit(ctx, 9);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// validations
|
||||
|
@ -1172,7 +1237,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
|
|||
|
||||
PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", datafilename);
|
||||
|
||||
// main loop for restoreing.
|
||||
// main loop for restoring.
|
||||
// a bit more complicated than needed
|
||||
// this is because of two things.
|
||||
// 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++) {
|
||||
|
||||
uint8_t bldata[MFBLOCK_SIZE] = {0x00};
|
||||
|
||||
memcpy(bldata, dump, MFBLOCK_SIZE);
|
||||
|
||||
// if sector trailer
|
||||
|
@ -1206,9 +1270,22 @@ static int CmdHF14AMfRestore(const char *Cmd) {
|
|||
|
||||
// ensure access right isn't messed up.
|
||||
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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@ -3609,8 +3686,6 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
|||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
nonces_t data[1];
|
||||
|
||||
sector_t *k_sector = NULL;
|
||||
|
||||
//Validations
|
||||
|
@ -3701,7 +3776,7 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
|||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) continue;
|
||||
if (!(flags & FLAG_NR_AR_ATTACK)) break;
|
||||
if ((resp.oldarg[0] & 0xffff) != CMD_HF_MIFARE_SIMULATE) break;
|
||||
|
||||
nonces_t data[1];
|
||||
memcpy(data, resp.data.asBytes, sizeof(data));
|
||||
readerAttack(k_sector, k_sectorsCount, data[0], setEmulatorMem, verbose);
|
||||
}
|
||||
|
@ -6818,6 +6893,7 @@ static int CmdHF14AMfView(const char *Cmd) {
|
|||
|
||||
if (verbose) {
|
||||
mf_print_keys(block_cnt, dump);
|
||||
mf_analyse_acl(block_cnt, dump);
|
||||
}
|
||||
|
||||
int sector = DetectHID(dump, 0x4910);
|
||||
|
@ -6835,9 +6911,14 @@ static int CmdHF14AMfView(const char *Cmd) {
|
|||
return res;
|
||||
}
|
||||
|
||||
typedef union UDATA {
|
||||
uint8_t *bytes;
|
||||
mfc_vigik_t *vigik;
|
||||
} UDATA;
|
||||
// allocate memory
|
||||
uint8_t* d = calloc(bytes_read, sizeof(uint8_t));
|
||||
if (d == NULL) {
|
||||
UDATA d;
|
||||
d.bytes = calloc(bytes_read, sizeof(uint8_t));
|
||||
if (d.bytes == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
uint16_t dlen = 0;
|
||||
|
@ -6845,14 +6926,14 @@ static int CmdHF14AMfView(const char *Cmd) {
|
|||
// vigik struture sector 0
|
||||
uint8_t *pdump = dump;
|
||||
|
||||
memcpy(d + dlen, pdump, MFBLOCK_SIZE * 3);
|
||||
memcpy(d.bytes + dlen, pdump, MFBLOCK_SIZE * 3);
|
||||
dlen += MFBLOCK_SIZE * 3;
|
||||
pdump += (MFBLOCK_SIZE * 4); // skip sectortrailer
|
||||
|
||||
// extract memory from MAD sectors
|
||||
for (int i = 0; i <= madlen; 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;
|
||||
}
|
||||
|
||||
|
@ -6860,8 +6941,8 @@ static int CmdHF14AMfView(const char *Cmd) {
|
|||
}
|
||||
|
||||
// convert_mfc_2_arr(pdump, bytes_read, d, &dlen);
|
||||
vigik_annotate(d);
|
||||
free(d);
|
||||
vigik_annotate(d.vigik);
|
||||
free(d.bytes);
|
||||
}
|
||||
|
||||
free(dump);
|
||||
|
@ -7325,7 +7406,7 @@ static int CmdHF14AGen4Save(const char *Cmd) {
|
|||
char filename[FILE_PATH_SIZE];
|
||||
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);
|
||||
|
||||
// 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 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);
|
||||
uint8_t block[MFBLOCK_SIZE] = {0x00};
|
||||
int dlen = 0;
|
||||
uint8_t data[16] = {0};
|
||||
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
|
||||
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
|
||||
int optionsprovided = 0;
|
||||
|
@ -7597,11 +7676,12 @@ static int CmdHF14AMfValue(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (action < 3) {
|
||||
|
||||
uint8_t isok = true;
|
||||
if (g_session.pm3_present == false)
|
||||
return PM3_ENOTTY;
|
||||
|
||||
if (action <= 1) { // increment/decrement value
|
||||
uint8_t block[MFBLOCK_SIZE] = {0x00};
|
||||
memcpy(block, (uint8_t *)&value, 4);
|
||||
uint8_t cmddata[26];
|
||||
memcpy(cmddata, key, sizeof(key)); // Key == 6 data went to 10, so lets offset 9 for inc/dec
|
||||
|
|
|
@ -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
|
||||
static nxp_producttype_t getProductType(uint8_t *versionhw) {
|
||||
static nxp_producttype_t getProductType(const uint8_t *versionhw) {
|
||||
|
||||
uint8_t product = versionhw[2];
|
||||
|
||||
|
@ -323,7 +323,7 @@ static nxp_producttype_t getProductType(uint8_t *versionhw) {
|
|||
return DESFIRE_UNKNOWN_PROD;
|
||||
}
|
||||
|
||||
static const char *getProductTypeStr(uint8_t *versionhw) {
|
||||
static const char *getProductTypeStr(const uint8_t *versionhw) {
|
||||
|
||||
uint8_t product = versionhw[2];
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ static uint8_t default_3des_keys[][16] = {
|
|||
|
||||
static uint8_t default_pwd_pack[][4] = {
|
||||
{0xFF, 0xFF, 0xFF, 0xFF}, // PACK 0x00,0x00 -- factory default
|
||||
{0x4E, 0x45, 0x78, 0x54},
|
||||
{0x4E, 0x45, 0x78, 0x54}, // NExT
|
||||
};
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
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 {
|
||||
const char *desc;
|
||||
const char *version;
|
||||
|
@ -1184,7 +1224,7 @@ static mfu_identify_t mfu_ident_table[] = {
|
|||
"Snackworld", "0004040101000B03",
|
||||
9, 7, "483000E1100600",
|
||||
NULL, NULL,
|
||||
"hf mfu dump -k %08x"
|
||||
"hf mfu dump -k"
|
||||
},
|
||||
{
|
||||
"Amiibo", "0004040201001103",
|
||||
|
@ -1324,6 +1364,7 @@ static int mfu_fingerprint(TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authke
|
|||
if (item) {
|
||||
PrintAndLogEx(SUCCESS, "Found " _GREEN_("%s"), item->desc);
|
||||
|
||||
if (item->hint) {
|
||||
if (item->Pwd) {
|
||||
char s[40] = {0};
|
||||
snprintf(s, sizeof(s), item->hint, item->Pwd(uid));
|
||||
|
@ -1333,6 +1374,26 @@ static int mfu_fingerprint(TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authke
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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};
|
||||
snprintf(s, sizeof(s), item->hint, item->otp(uid));
|
||||
PrintAndLogEx(HINT, "Use `" _YELLOW_("%s") "`", s);
|
||||
} else {
|
||||
PrintAndLogEx(HINT, "Use `" _YELLOW_("%s") "`", item->hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
|
||||
|
||||
out:
|
||||
free(data);
|
||||
|
@ -3248,7 +3309,7 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "----------------------------------");
|
||||
PrintAndLogEx(INFO, " algo | pwd | pack");
|
||||
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, " 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));
|
||||
|
@ -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, "-----------------+----------+-----");
|
||||
PrintAndLogEx(INFO, " Vingcard algo");
|
||||
PrintAndLogEx(INFO, " Saflok algo");
|
||||
PrintAndLogEx(INFO, " SALTO algo");
|
||||
PrintAndLogEx(INFO, " Dorma Kaba algo");
|
||||
PrintAndLogEx(INFO, "----------------------------------");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "crypto/asn1utils.h" // ASN1 decode / print
|
||||
#include "commonutil.h" // get_sw
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -55,7 +56,7 @@ static int seos_select(void) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -75,7 +76,7 @@ static int seos_select(void) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
|
||||
#include "cmdnfc.h" // print_type4_cc_info
|
||||
#include "commonutil.h" // get_sw
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
#define TIMEOUT 2000
|
||||
|
||||
|
@ -136,7 +137,7 @@ static int infoHFST25TA(void) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -156,7 +157,7 @@ static int infoHFST25TA(void) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -172,7 +173,7 @@ static int infoHFST25TA(void) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -192,7 +193,7 @@ static int infoHFST25TA(void) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -210,7 +211,7 @@ static int infoHFST25TA(void) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -329,7 +330,7 @@ int CmdHFST25TANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -349,7 +350,7 @@ int CmdHFST25TANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -378,7 +379,7 @@ int CmdHFST25TANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -397,7 +398,7 @@ int CmdHFST25TANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -495,7 +496,7 @@ static int CmdHFST25TAProtect(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -515,7 +516,7 @@ static int CmdHFST25TAProtect(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -534,7 +535,7 @@ static int CmdHFST25TAProtect(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -553,7 +554,7 @@ static int CmdHFST25TAProtect(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -639,7 +640,7 @@ static int CmdHFST25TAPwd(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -659,7 +660,7 @@ static int CmdHFST25TAPwd(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -678,7 +679,7 @@ static int CmdHFST25TAPwd(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -699,7 +700,7 @@ static int CmdHFST25TAPwd(const char *Cmd) {
|
|||
}
|
||||
|
||||
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));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
|
262
client/src/cmdhftesla.c
Normal file
262
client/src/cmdhftesla.c
Normal 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
26
client/src/cmdhftesla.h
Normal 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
|
|
@ -311,7 +311,7 @@ static bool TexcomTK15Decode(uint32_t *implengths, uint32_t implengthslen, char
|
|||
bool prevbit = (implengths[implengthslen - 3] > 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(cbitstring, "1");
|
||||
} else {
|
||||
|
|
|
@ -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) {
|
||||
topaz_tag.size = TOPAZ_STATIC_MEMORY;
|
||||
|
@ -583,9 +583,7 @@ static void topaz_print_lifecycle_state(uint8_t *data) {
|
|||
// to be done
|
||||
}
|
||||
|
||||
static void printTopazDumpContents(uint8_t *dump, size_t size) {
|
||||
|
||||
topaz_tag_t *t = (topaz_tag_t *)dump;
|
||||
static void printTopazDumpContents(topaz_tag_t *dump) {
|
||||
|
||||
// uses a global var for all
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
@ -608,14 +606,14 @@ static void printTopazDumpContents(uint8_t *dump, size_t size) {
|
|||
PrintAndLogEx(SUCCESS, " %3u / 0x%02x | %s| %s | %s",
|
||||
i,
|
||||
i,
|
||||
sprint_hex(&t->data_blocks[i][0], 8),
|
||||
sprint_hex(&dump->data_blocks[i][0], 8),
|
||||
lockstr,
|
||||
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", 0x0E, 0x0E, sprint_hex(&t->data_blocks[0x0E][0], 8), topaz_ks[3]);
|
||||
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(&dump->data_blocks[0x0E][0], 8), topaz_ks[3]);
|
||||
PrintAndLogEx(SUCCESS, "------------+-------------------------+---+------------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
@ -797,7 +795,7 @@ static int CmdHFTopazDump(const char *Cmd) {
|
|||
if (status != PM3_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
printTopazDumpContents((uint8_t *)&topaz_tag, sizeof(topaz_tag_t));
|
||||
printTopazDumpContents(&topaz_tag);
|
||||
|
||||
bool set_dynamic = false;
|
||||
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);
|
||||
|
||||
// read dump file
|
||||
uint8_t *dump = NULL;
|
||||
topaz_tag_t *dump = NULL;
|
||||
size_t bytes_read = TOPAZ_MAX_SIZE;
|
||||
int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, sizeof(topaz_tag_t) + TOPAZ_MAX_SIZE);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
printTopazDumpContents(dump, bytes_read);
|
||||
if (bytes_read < sizeof(topaz_tag_t)) {
|
||||
free(dump);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
printTopazDumpContents(dump);
|
||||
|
||||
if (topaz_set_cc_dynamic(&topaz_tag.data_blocks[1][0]) == PM3_SUCCESS) {
|
||||
|
||||
|
|
|
@ -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) {
|
||||
uint8_t progress;
|
||||
uint8_t step0[2] = {0xcd, 0x0d};
|
||||
uint8_t step1[3] = {0xcd, 0x00, 10}; // select e-paper type and reset 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 step14[2]={0xcd,0x0c}; // The end of the transmission
|
||||
uint8_t rx[20];
|
||||
uint16_t actrxlen[20], i;
|
||||
uint16_t actrxlen[20];
|
||||
|
||||
clearCommandBuffer();
|
||||
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
|
||||
} else {
|
||||
uint8_t progress;
|
||||
PrintAndLogEx(DEBUG, "Step5: e-paper config2");
|
||||
ret = transceive_blocking(step5, 2, rx, 20, actrxlen, true); // cd 05
|
||||
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");
|
||||
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);
|
||||
ret = transceive_blocking(step8, 19, rx, 20, actrxlen, true); // cd 08
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
ret = transceive_blocking(step8, 19, rx, 20, actrxlen, true); // cd 08
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
ret = transceive_blocking(step8, 103, rx, 20, actrxlen, true); // cd 08
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
ret = transceive_blocking(step8, 123, rx, 20, actrxlen, true); // cd 08
|
||||
if (ret != PM3_SUCCESS) {
|
||||
|
@ -872,7 +872,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
msleep(6);
|
||||
}
|
||||
} 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);
|
||||
ret = transceive_blocking(step8, 109, rx, 20, actrxlen, false); // cd 08
|
||||
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
|
||||
|
||||
for (i = 0; i < 484; i++) {
|
||||
for (uint16_t i = 0; i < 484; i++) {
|
||||
read_black(i, step8, model_nr, black);
|
||||
//memset(&step8[3], 0xf0, 120);
|
||||
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;
|
||||
}
|
||||
} 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);
|
||||
memset(&step8[3], 0xFF, sizeof(step8) - 3);
|
||||
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");
|
||||
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);
|
||||
ret = transceive_blocking(step13, 124, rx, 20, actrxlen, true); //CD 19
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
//memset(&step13[3], 0xfE, 106);
|
||||
ret = transceive_blocking(step13, 109, rx, 20, actrxlen, false);
|
||||
|
|
|
@ -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) {
|
||||
int i, n;
|
||||
register RC2_INT *p0, *p1;
|
||||
register RC2_INT x0, x1, x2, x3, t;
|
||||
register RC2_INT x0, x1, x2, x3;
|
||||
unsigned long l;
|
||||
|
||||
l = d[0];
|
||||
|
@ -217,7 +217,7 @@ void RC2_encrypt(unsigned long *d, RC2_KEY *key) {
|
|||
|
||||
p0 = p1 = &(key->data[0]);
|
||||
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);
|
||||
t = (x1 + (x2 & ~x0) + (x3 & x0) + * (p0++)) & 0xffff;
|
||||
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) {
|
||||
int i, n;
|
||||
register RC2_INT *p0, *p1;
|
||||
register RC2_INT x0, x1, x2, x3, t;
|
||||
register RC2_INT x0, x1, x2, x3;
|
||||
unsigned long l;
|
||||
|
||||
l = d[0];
|
||||
|
@ -260,7 +260,7 @@ void RC2_decrypt(unsigned long *d, RC2_KEY *key) {
|
|||
p0 = &(key->data[63]);
|
||||
p1 = &(key->data[0]);
|
||||
for (;;) {
|
||||
t = ((x3 << 11) | (x3 >> 5)) & 0xffff;
|
||||
register RC2_INT t = ((x3 << 11) | (x3 >> 5)) & 0xffff;
|
||||
x3 = (t - (x0 & ~x2) - (x1 & x2) - * (p0--)) & 0xffff;
|
||||
t = ((x2 << 13) | (x2 >> 3)) & 0xffff;
|
||||
x2 = (t - (x3 & ~x1) - (x0 & x1) - * (p0--)) & 0xffff;
|
||||
|
|
|
@ -592,12 +592,12 @@ static int CmdLCD(const char *Cmd) {
|
|||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
int r_len = 0;
|
||||
uint8_t raw[1] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &r_len);
|
||||
int j = arg_get_int_def(ctx, 2, 1);
|
||||
CLIParserFree(ctx);
|
||||
if (j < 1) {
|
||||
PrintAndLogEx(WARNING, "Count must be larger than zero");
|
||||
return PM3_EINVARG;
|
||||
|
|
|
@ -229,6 +229,8 @@ void printEM410x(uint32_t hi, uint64_t id, bool verbose, int type) {
|
|||
uint8_t sebury2 = (id >> 16) & 0x7F;
|
||||
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, "VD / ID : %03" PRIu64 " / %010" PRIu64, (id >> 32LL) & 0xFFFF, (id & 0xFFFFFFFF));
|
||||
|
||||
PrintAndLogEx(INFO, "------------------------------------------------");
|
||||
}
|
||||
}
|
||||
|
@ -672,11 +674,6 @@ static int CmdEM410xClone(const char *Cmd) {
|
|||
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);
|
||||
|
||||
struct {
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "generator.h"
|
||||
#include "cliparser.h"
|
||||
#include "cmdhw.h"
|
||||
#include "util.h"
|
||||
|
||||
//////////////// 4205 / 4305 commands
|
||||
|
||||
|
@ -1996,8 +1997,7 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
const char *cmdText;
|
||||
char dataText[100];
|
||||
char blkAddr[4];
|
||||
char bits[80];
|
||||
int i, bitidx;
|
||||
int i;
|
||||
int ZeroWidth; // 32-42 "1" is 32
|
||||
int CycleWidth;
|
||||
size_t pulseSamples;
|
||||
|
@ -2018,13 +2018,15 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
PrintAndLogEx(SUCCESS, "offset | Command | Data | blk | raw");
|
||||
PrintAndLogEx(SUCCESS, "-------+-------------+----------+-----+------------------------------------------------------------");
|
||||
|
||||
smartbuf bits = { 0 };
|
||||
bits.ptr = malloc(EM4X05_BITS_BUFSIZE);
|
||||
bits.size = EM4X05_BITS_BUFSIZE;
|
||||
bits.idx = 0;
|
||||
size_t idx = 0;
|
||||
// loop though sample buffer
|
||||
while (idx < g_GraphTraceLen) {
|
||||
bool eop = false;
|
||||
bool haveData = false;
|
||||
bool pwd = false;
|
||||
uint32_t tmpValue;
|
||||
|
||||
idx = em4x05_Sniff_GetNextBitStart(idx, g_GraphTraceLen, g_GraphBuffer, &pulseSamples);
|
||||
size_t pktOffset = idx;
|
||||
|
@ -2037,9 +2039,10 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
|
||||
if (ZeroWidth <= 50) {
|
||||
pktOffset -= ZeroWidth;
|
||||
memset(bits, 0x00, sizeof(bits));
|
||||
bitidx = 0;
|
||||
memset(bits.ptr, 0, bits.size);
|
||||
bits.idx = 0;
|
||||
|
||||
bool eop = false;
|
||||
while ((idx < g_GraphTraceLen) && !eop) {
|
||||
CycleWidth = idx;
|
||||
idx = em4x05_Sniff_GetNextBitStart(idx, g_GraphTraceLen, g_GraphBuffer, &pulseSamples);
|
||||
|
@ -2047,7 +2050,7 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
CycleWidth = idx - CycleWidth;
|
||||
if ((CycleWidth > 300) || (CycleWidth < (ZeroWidth - 5))) { // to long or too short
|
||||
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 = "";
|
||||
|
||||
// EM4305 command lengths
|
||||
|
@ -2059,76 +2062,77 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
// -> disable 1010 11111111 0 11111111 0 11111111 0 11111111 0 00000000 0
|
||||
|
||||
// Check to see if we got the leading 0
|
||||
if (((strncmp(bits, "00011", 5) == 0) && (bitidx == 50)) ||
|
||||
((strncmp(bits, "00101", 5) == 0) && (bitidx == 57)) ||
|
||||
((strncmp(bits, "01001", 5) == 0) && (bitidx == 12)) ||
|
||||
((strncmp(bits, "01100", 5) == 0) && (bitidx == 50)) ||
|
||||
((strncmp(bits, "01010", 5) == 0) && (bitidx == 50))) {
|
||||
memmove(bits, &bits[1], bitidx - 1);
|
||||
bitidx--;
|
||||
if (((strncmp(bits.ptr, "00011", 5) == 0) && (bits.idx == 50)) ||
|
||||
((strncmp(bits.ptr, "00101", 5) == 0) && (bits.idx == 57)) ||
|
||||
((strncmp(bits.ptr, "01001", 5) == 0) && (bits.idx == 12)) ||
|
||||
((strncmp(bits.ptr, "01100", 5) == 0) && (bits.idx == 50)) ||
|
||||
((strncmp(bits.ptr, "01010", 5) == 0) && (bits.idx == 50))) {
|
||||
memmove(bits.ptr, &bits.ptr[1], bits.idx - 1);
|
||||
bits.idx--;
|
||||
PrintAndLogEx(INFO, "Trim leading 0");
|
||||
}
|
||||
bits[bitidx] = 0;
|
||||
sb_append_char(&bits, 0);
|
||||
bits.idx--;
|
||||
|
||||
// logon
|
||||
if ((strncmp(bits, "0011", 4) == 0) && (bitidx == 49)) {
|
||||
if ((strncmp(bits.ptr, "0011", 4) == 0) && (bits.idx == 49)) {
|
||||
haveData = true;
|
||||
pwd = true;
|
||||
cmdText = "Logon";
|
||||
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);
|
||||
}
|
||||
|
||||
// write
|
||||
if ((strncmp(bits, "0101", 4) == 0) && (bitidx == 56)) {
|
||||
if ((strncmp(bits.ptr, "0101", 4) == 0) && (bits.idx == 56)) {
|
||||
haveData = true;
|
||||
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);
|
||||
if (tmpValue == 2) {
|
||||
pwd = true;
|
||||
}
|
||||
tmpValue = em4x05_Sniff_GetBlock(&bits[11], fwd);
|
||||
tmpValue = em4x05_Sniff_GetBlock(&bits.ptr[11], fwd);
|
||||
snprintf(dataText, sizeof(dataText), "%08X", tmpValue);
|
||||
}
|
||||
|
||||
// read
|
||||
if ((strncmp(bits, "1001", 4) == 0) && (bitidx == 11)) {
|
||||
if ((strncmp(bits.ptr, "1001", 4) == 0) && (bits.idx == 11)) {
|
||||
haveData = true;
|
||||
pwd = false;
|
||||
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);
|
||||
strncpy(dataText, " ", sizeof(dataText));
|
||||
}
|
||||
|
||||
// protect
|
||||
if ((strncmp(bits, "1100", 4) == 0) && (bitidx == 49)) {
|
||||
if ((strncmp(bits.ptr, "1100", 4) == 0) && (bits.idx == 49)) {
|
||||
haveData = true;
|
||||
pwd = false;
|
||||
cmdText = "Protect";
|
||||
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);
|
||||
}
|
||||
|
||||
// disable
|
||||
if ((strncmp(bits, "1010", 4) == 0) && (bitidx == 49)) {
|
||||
if ((strncmp(bits.ptr, "1010", 4) == 0) && (bits.idx == 49)) {
|
||||
haveData = true;
|
||||
pwd = false;
|
||||
cmdText = "Disable";
|
||||
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);
|
||||
}
|
||||
|
||||
// bits[bitidx] = 0;
|
||||
} else {
|
||||
i = (CycleWidth - ZeroWidth) / 28;
|
||||
bits[bitidx++] = '0';
|
||||
sb_append_char(&bits, '0');
|
||||
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
|
||||
if (haveData) { //&& (minWidth > 1) && (maxWidth > minWidth)){
|
||||
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
|
||||
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
|
||||
PrintAndLogEx(SUCCESS, "---------------------------------------------------------------------------------------------------");
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#define EM4305_PROT2_BLOCK 15
|
||||
#define EM4469_PROT_BLOCK 3
|
||||
|
||||
#define EM4X05_BITS_BUFSIZE 128
|
||||
|
||||
// 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_BIPHASE | EM4x05_SET_NUM_BLOCKS(4) ) // ASK/BIPHASE , data rate 32, 4 data blocks
|
||||
|
|
|
@ -404,7 +404,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
|
|||
uint8_t data[MAX_GRAPH_TRACE_LEN] = {0};
|
||||
size_t datasize = getFromGraphBuf(data);
|
||||
|
||||
uint8_t rawbits[4096];
|
||||
uint8_t rawbits[4096] = {0};
|
||||
int rawbit = 0;
|
||||
int worst = 0, worstPos = 0;
|
||||
|
||||
|
|
|
@ -230,6 +230,7 @@ static int CmdParadoxClone(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf paradox clone",
|
||||
"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 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf paradox clone --raw 0f55555695596a6a9999a59a --em -> encode for EM4305/4469"
|
||||
|
@ -238,6 +239,8 @@ static int CmdParadoxClone(const char *Cmd) {
|
|||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
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, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
|
@ -249,8 +252,10 @@ static int CmdParadoxClone(const char *Cmd) {
|
|||
uint8_t raw[12] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
|
||||
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);
|
||||
|
||||
if (q5 && em) {
|
||||
|
@ -258,15 +263,57 @@ static int CmdParadoxClone(const char *Cmd) {
|
|||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t blocks[4] = {0};
|
||||
|
||||
if (raw_len != 0) {
|
||||
if (raw_len != 12) {
|
||||
PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t blocks[4];
|
||||
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
|
||||
blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 3 << T55x7_MAXBLOCK_SHIFT;
|
||||
|
|
|
@ -2362,7 +2362,7 @@ static int CmdT55xxRestore(const char *Cmd) {
|
|||
}
|
||||
|
||||
// read dump file
|
||||
uint8_t *dump = NULL;
|
||||
uint32_t *dump = NULL;
|
||||
size_t bytes_read = 0;
|
||||
res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (T55x7_BLOCK_COUNT * 4));
|
||||
if (res != PM3_SUCCESS) {
|
||||
|
@ -2387,11 +2387,10 @@ static int CmdT55xxRestore(const char *Cmd) {
|
|||
snprintf(pwdopt, sizeof(pwdopt), "-p %08X", password);
|
||||
}
|
||||
|
||||
uint32_t *data = (uint32_t *) dump;
|
||||
uint8_t idx;
|
||||
// Restore endien for writing to card
|
||||
for (idx = 0; idx < 12; idx++) {
|
||||
data[idx] = BSWAP_32(data[idx]);
|
||||
dump[idx] = BSWAP_32(dump[idx]);
|
||||
}
|
||||
|
||||
// Have data ready, lets write
|
||||
|
@ -2400,12 +2399,12 @@ static int CmdT55xxRestore(const char *Cmd) {
|
|||
// write blocks 1..3 page 1
|
||||
// update downlink mode (if needed) and write b 0
|
||||
downlink_mode = 0;
|
||||
if ((((data[11] >> 28) & 0xF) == 6) || (((data[11] >> 28) & 0xF) == 9))
|
||||
downlink_mode = (data[11] >> 10) & 3;
|
||||
if ((((dump[11] >> 28) & 0xF) == 6) || (((dump[11] >> 28) & 0xF) == 9))
|
||||
downlink_mode = (dump[11] >> 10) & 3;
|
||||
|
||||
// write out blocks 1-7 page 0
|
||||
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) {
|
||||
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 (usepwd) {
|
||||
snprintf(pwdopt, sizeof(pwdopt), "-p %08X", data[7]);
|
||||
snprintf(pwdopt, sizeof(pwdopt), "-p %08X", dump[7]);
|
||||
}
|
||||
|
||||
// write out blocks 1-3 page 1
|
||||
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) {
|
||||
PrintAndLogEx(WARNING, "Warning: error writing blk %d", idx);
|
||||
|
@ -2430,7 +2429,7 @@ static int CmdT55xxRestore(const char *Cmd) {
|
|||
config.downlink_mode = downlink_mode;
|
||||
|
||||
// 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) {
|
||||
PrintAndLogEx(WARNING, "Warning: error writing blk 0");
|
||||
}
|
||||
|
@ -4012,7 +4011,6 @@ static int CmdT55xxSniff(const char *Cmd) {
|
|||
size_t idx = 0;
|
||||
uint32_t usedPassword, blockData;
|
||||
int pulseSamples = 0, pulseIdx = 0;
|
||||
const char *modeText;
|
||||
char pwdText[100];
|
||||
char dataText[100];
|
||||
int pulseBuffer[80] = { 0 }; // max should be 73 +/- - Holds Pulse widths
|
||||
|
@ -4038,7 +4036,7 @@ static int CmdT55xxSniff(const char *Cmd) {
|
|||
int maxWidth = 0;
|
||||
data[0] = 0;
|
||||
bool have_data = false;
|
||||
modeText = "Default";
|
||||
const char *modeText = "Default";
|
||||
strncpy(pwdText, " ", sizeof(pwdText));
|
||||
strncpy(dataText, " ", sizeof(dataText));
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "cmdanalyse.h"
|
||||
#include "emv/cmdemv.h" // EMV
|
||||
#include "cmdflashmem.h" // rdv40 flashmem commands
|
||||
#include "cmdpiv.h"
|
||||
#include "cmdsmartcard.h" // rdv40 smart card ISO7816 commands
|
||||
#include "cmdusart.h" // rdv40 FPC USART commands
|
||||
#include "cmdwiegand.h" // wiegand commands
|
||||
|
@ -324,6 +325,7 @@ static command_t CommandTable[] = {
|
|||
{"lf", CmdLF, AlwaysAvailable, "{ Low frequency commands... }"},
|
||||
{"mem", CmdFlashMem, IfPm3Flash, "{ Flash memory manipulation... }"},
|
||||
{"nfc", CmdNFC, AlwaysAvailable, "{ NFC commands... }"},
|
||||
{"piv", CmdPIV, AlwaysAvailable, "{ PIV commands... }"},
|
||||
{"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software... }"},
|
||||
{"smart", CmdSmartcard, AlwaysAvailable, "{ Smart card ISO-7816 commands... }"},
|
||||
{"script", CmdScript, AlwaysAvailable, "{ Scripting commands... }"},
|
||||
|
|
988
client/src/cmdpiv.c
Normal file
988
client/src/cmdpiv.c
Normal 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
26
client/src/cmdpiv.h
Normal 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
|
|
@ -147,7 +147,7 @@ static int split(char *str, char **arr) {
|
|||
return word_cnt;
|
||||
}
|
||||
|
||||
static void set_python_path(char *path) {
|
||||
static void set_python_path(const char *path) {
|
||||
PyObject *syspath = PySys_GetObject("path");
|
||||
if (syspath == 0) {
|
||||
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];
|
||||
strcpy(scripts_path, exec_path);
|
||||
strcat(scripts_path, PYTHON_SCRIPTS_SUBDIR);
|
||||
// strcat(scripts_path, PYTHON_LIBRARIES_WILDCARD);
|
||||
// strcat(scripts_path, PYTHON_LIBRARIES_WILDCARD);
|
||||
set_python_path(scripts_path);
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,7 @@ static void set_python_paths(void) {
|
|||
strcpy(scripts_path, user_path);
|
||||
strcat(scripts_path, PM3_USER_DIRECTORY);
|
||||
strcat(scripts_path, PYTHON_SCRIPTS_SUBDIR);
|
||||
// strcat(scripts_path, PYTHON_LIBRARIES_WILDCARD);
|
||||
// strcat(scripts_path, PYTHON_LIBRARIES_WILDCARD);
|
||||
set_python_path(scripts_path);
|
||||
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ static void set_python_paths(void) {
|
|||
strcpy(scripts_path, exec_path);
|
||||
strcat(scripts_path, PM3_SHARE_RELPATH);
|
||||
strcat(scripts_path, PYTHON_SCRIPTS_SUBDIR);
|
||||
// strcat(scripts_path, PYTHON_LIBRARIES_WILDCARD);
|
||||
// strcat(scripts_path, PYTHON_LIBRARIES_WILDCARD);
|
||||
set_python_path(scripts_path);
|
||||
}
|
||||
}
|
||||
|
@ -407,12 +407,16 @@ static int CmdScriptRun(const char *Cmd) {
|
|||
Py_Initialize();
|
||||
#else
|
||||
PyConfig py_conf;
|
||||
PyConfig_InitIsolatedConfig(&py_conf);
|
||||
// Despite being isolated we probably want to allow users to use
|
||||
// the Python packages they installed on their user directory as well
|
||||
// as system ones. But it seems isolated mode still enforces them off.
|
||||
py_conf.use_environment = 1;
|
||||
// We need to use Python mode instead of isolated to avoid breaking stuff.
|
||||
PyConfig_InitPythonConfig(&py_conf);
|
||||
// Let's still make things bit safer by being as close as possible to isolated mode.
|
||||
py_conf.configure_c_stdio = -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.use_environment = 0;
|
||||
#endif
|
||||
|
||||
//int argc, char ** argv
|
||||
|
@ -429,8 +433,13 @@ static int CmdScriptRun(const char *Cmd) {
|
|||
#else
|
||||
// The following line will implicitly pre-initialize Python
|
||||
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
|
||||
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);
|
||||
|
||||
|
|
|
@ -719,7 +719,7 @@ static int CmdSmartInfo(const char *Cmd) {
|
|||
|
||||
// print header
|
||||
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.
|
||||
char *hexstr = calloc((card.atr_len << 1) + 1, sizeof(uint8_t));
|
||||
if (hexstr == NULL) {
|
||||
|
|
|
@ -485,8 +485,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
|||
uint32_t end_of_transmission_timestamp = 0;
|
||||
uint8_t topaz_reader_command[9];
|
||||
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 *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
|
||||
|
||||
//--- Draw the data column
|
||||
char line[18][140] = {{0}};
|
||||
char line[18][160] = {{0}};
|
||||
|
||||
if (data_len == 0) {
|
||||
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;
|
||||
if (markCRCBytes) {
|
||||
if (markCRCBytes && data_len > 2) {
|
||||
//CRC-command
|
||||
if (((protocol == PROTO_HITAG1) || (protocol == PROTO_HITAGS)) && (data_len > 1)) {
|
||||
// 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 {
|
||||
|
||||
if (crcStatus == 0 || crcStatus == 1) {
|
||||
|
||||
char *pos1 = line[(data_len - 2) / 18];
|
||||
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) {
|
||||
uint8_t mfData[32] = {0};
|
||||
size_t mfDataLen = 0;
|
||||
if (DecodeMifareData(frame, data_len, parityBytes, hdr->isResponse, mfData, &mfDataLen, mfDicKeys, mfDicKeysCount)) {
|
||||
memset(explanation, 0x00, sizeof(explanation));
|
||||
annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen, hdr->isResponse);
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdemv.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "comms.h" // DropField
|
||||
#include "cmdsmartcard.h" // smart_select
|
||||
#include "cmdtrace.h"
|
||||
|
@ -35,6 +33,7 @@
|
|||
#include "ui.h"
|
||||
#include "emv_tags.h"
|
||||
#include "fileutils.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -1564,7 +1563,7 @@ static int CmdEMVScan(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "PPSE");
|
||||
res = EMVSelectPSE(channel, true, true, 2, buf, sizeof(buf), &len, &sw);
|
||||
|
||||
if (!res && sw == 0x9000) {
|
||||
if (!res && sw == ISO7816_OK) {
|
||||
if (decodeTLV)
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "emvcore.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "comms.h" // DropField
|
||||
#include "cmdparser.h"
|
||||
|
@ -31,6 +29,7 @@
|
|||
#include "emv_tags.h"
|
||||
#include "emvjson.h"
|
||||
#include "util_posix.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
// Got from here. Thanks!
|
||||
// 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) {
|
||||
uint8_t data[APDU_RES_LEN] = {0};
|
||||
size_t datalen = 0;
|
||||
uint8_t sfidata[0x11][APDU_RES_LEN];
|
||||
size_t sfidatalen[0x11] = {0};
|
||||
uint16_t sw = 0;
|
||||
int res;
|
||||
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);
|
||||
|
||||
if (!res) {
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(FAILED, "Select PSE error. APDU error: %04x.", sw);
|
||||
return 1;
|
||||
}
|
||||
|
@ -403,6 +400,8 @@ int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFi
|
|||
// PSE/PPSE with SFI
|
||||
struct tlvdb *tsfi = tlvdb_find_path(t, (tlv_tag_t[]) {0x6f, 0xa5, 0x88, 0x00});
|
||||
if (tsfi) {
|
||||
uint8_t sfidata[0x11][APDU_RES_LEN];
|
||||
size_t sfidatalen[0x11] = {0};
|
||||
uint8_t sfin = 0;
|
||||
tlv_get_uint8(tlvdb_get_tlv(tsfi), &sfin);
|
||||
PrintAndLogEx(INFO, "* PPSE get SFI: 0x%02x.", sfin);
|
||||
|
@ -419,7 +418,7 @@ int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFi
|
|||
}
|
||||
|
||||
// error catch!
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
sfidatalen[ui] = 0;
|
||||
PrintAndLogEx(FAILED, "PPSE get Error. APDU error: %04x.", sw);
|
||||
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 };
|
||||
|
||||
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);
|
||||
if (!pk) {
|
||||
PrintAndLogEx(ERR, "Error: Key not found, exiting");
|
||||
|
@ -768,6 +763,9 @@ int trDDA(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
tlvdb_free(atc_db);
|
||||
|
||||
} 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);
|
||||
if (dac_db) {
|
||||
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
||||
|
|
|
@ -44,19 +44,6 @@
|
|||
// const typeof( ((type *)0)->member ) *__mptr = (ptr);
|
||||
// (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) {
|
||||
tlv_tag_t tag;
|
||||
|
||||
|
@ -212,6 +199,7 @@ struct tlvdb *tlvdb_parse(const unsigned char *buf, size_t len) {
|
|||
err:
|
||||
tlvdb_free(&root->db);
|
||||
|
||||
free(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -248,9 +236,53 @@ struct tlvdb *tlvdb_parse_multi(const unsigned char *buf, size_t len) {
|
|||
err:
|
||||
tlvdb_free(&root->db);
|
||||
|
||||
free(root);
|
||||
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_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) {
|
||||
if (!tlvdb)
|
||||
return NULL;
|
||||
|
|
|
@ -31,14 +31,31 @@ struct tlv {
|
|||
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);
|
||||
|
||||
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_parse(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_root_free(struct tlvdb_root *root);
|
||||
|
||||
struct tlvdb *tlvdb_elm_get_next(struct tlvdb *tlvdb);
|
||||
struct tlvdb *tlvdb_elm_get_children(struct tlvdb *tlvdb);
|
||||
|
|
|
@ -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 ((Path == NULL) && (g_session.defaultPaths[pathIndex] != NULL)) {
|
||||
|
||||
if ((path == NULL) && (g_session.defaultPaths[pathIndex] != NULL)) {
|
||||
free(g_session.defaultPaths[pathIndex]);
|
||||
g_session.defaultPaths[pathIndex] = NULL;
|
||||
}
|
||||
|
||||
if (Path != NULL) {
|
||||
g_session.defaultPaths[pathIndex] = (char *)realloc(g_session.defaultPaths[pathIndex], strlen(Path) + 1);
|
||||
strcpy(g_session.defaultPaths[pathIndex], Path);
|
||||
if (path == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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 false;
|
||||
|
@ -234,47 +239,70 @@ bool setDefaultPath(savePaths_t pathIndex, const char *Path) {
|
|||
static char *filenamemcopy(const char *preferredName, const char *suffix) {
|
||||
if (preferredName == NULL) return NULL;
|
||||
if (suffix == NULL) return NULL;
|
||||
|
||||
char *fileName = (char *) calloc(strlen(preferredName) + strlen(suffix) + 1, sizeof(uint8_t));
|
||||
if (fileName == NULL)
|
||||
if (fileName == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(fileName, preferredName);
|
||||
if (str_endswith(fileName, suffix))
|
||||
if (str_endswith(fileName, suffix)) {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
strcat(fileName, suffix);
|
||||
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) {
|
||||
if (preferredName == NULL) return NULL;
|
||||
if (suffix == NULL) return NULL;
|
||||
if (preferredName == NULL || suffix == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint16_t p_namelen = strlen(preferredName);
|
||||
if (str_endswith(preferredName, suffix))
|
||||
p_namelen -= strlen(suffix);
|
||||
|
||||
const size_t fileNameLen = p_namelen + strlen(suffix) + 1 + 10;
|
||||
const size_t fileNameSize = fileNameLen * sizeof(uint8_t);
|
||||
// 10: room for filenum to ensure new filename
|
||||
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) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int num = 1;
|
||||
snprintf(fileName, fileNameSize, "%.*s%s", p_namelen, preferredName, suffix);
|
||||
|
||||
snprintf(fileName, len, "%.*s%s", p_namelen, preferredName, suffix);
|
||||
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++;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "FILE PATH: %s", fileName);
|
||||
return fileName;
|
||||
}
|
||||
|
||||
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);
|
||||
if (fileName == NULL) return PM3_EMALLOC;
|
||||
if (fileName == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
|
||||
if (data == NULL) return PM3_EINVARG;
|
||||
if (data == NULL || datalen == 0) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
char *fileName = newfilenamemcopy(preferredName, ".eml");
|
||||
if (fileName == NULL) return PM3_EMALLOC;
|
||||
if (fileName == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
int retval = PM3_SUCCESS;
|
||||
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 *)) {
|
||||
|
||||
if (data == NULL) return PM3_EINVARG;
|
||||
if (data == NULL || datalen == 0) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
char *fileName = newfilenamemcopy(preferredName, ".json");
|
||||
if (fileName == NULL) return PM3_EMALLOC;
|
||||
if (fileName == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
if (data == NULL) return PM3_EINVARG;
|
||||
if (data == NULL || datalen == 0) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
char *fileName = newfilenamemcopy(preferredName, ".wav");
|
||||
if (fileName == NULL) return PM3_EMALLOC;
|
||||
if (fileName == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
int retval = PM3_SUCCESS;
|
||||
|
||||
struct wave_info_t wave_info = {
|
||||
|
@ -731,11 +774,14 @@ int saveFileWAVE(const char *preferredName, const int *data, size_t datalen) {
|
|||
retval = PM3_EFILE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fwrite(&wave_info, sizeof(wave_info), 1, wave_file);
|
||||
|
||||
for (int i = 0; i < datalen; i++) {
|
||||
uint8_t sample = data[i] + 128;
|
||||
fwrite(&sample, 1, 1, wave_file);
|
||||
}
|
||||
|
||||
fclose(wave_file);
|
||||
|
||||
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) {
|
||||
|
||||
if (data == NULL) return PM3_EINVARG;
|
||||
if (data == NULL || datalen == 0) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
char *fileName = newfilenamemcopy(preferredName, ".pm3");
|
||||
if (fileName == NULL) return PM3_EMALLOC;
|
||||
if (fileName == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
int retval = PM3_SUCCESS;
|
||||
|
||||
|
@ -760,8 +811,9 @@ int saveFilePM3(const char *preferredName, int *data, size_t datalen) {
|
|||
goto out;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < datalen; i++)
|
||||
for (uint32_t i = 0; i < datalen; i++) {
|
||||
fprintf(f, "%d\n", data[i]);
|
||||
}
|
||||
|
||||
fflush(f);
|
||||
fclose(f);
|
||||
|
@ -1110,12 +1162,18 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
|||
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};
|
||||
JsonLoadStr(root, "$.FileType", ctype);
|
||||
|
||||
if (!strcmp(ctype, "raw")) {
|
||||
JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen);
|
||||
JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen);
|
||||
}
|
||||
|
||||
if (!strcmp(ctype, "mfcard")) {
|
||||
|
@ -1135,7 +1193,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
|||
goto out;
|
||||
}
|
||||
|
||||
memcpy(&udata[sptr], block, 16);
|
||||
memcpy(&udata.bytes[sptr], block, 16);
|
||||
sptr += len;
|
||||
}
|
||||
|
||||
|
@ -1154,7 +1212,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
|||
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
|
||||
|
||||
size_t len = 0;
|
||||
JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len);
|
||||
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
|
||||
if (!len)
|
||||
break;
|
||||
|
||||
|
@ -1166,18 +1224,16 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
|||
|
||||
if (!strcmp(ctype, "mfu")) {
|
||||
|
||||
mfu_dump_t *mem = (mfu_dump_t *)udata;
|
||||
|
||||
JsonLoadBufAsHex(root, "$.Card.Version", mem->version, sizeof(mem->version), datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.TBO_0", mem->tbo, sizeof(mem->tbo), datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.TBO_1", mem->tbo1, sizeof(mem->tbo1), datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Signature", mem->signature, sizeof(mem->signature), datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Counter0", &mem->counter_tearing[0][0], 3, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Tearing0", &mem->counter_tearing[0][3], 1, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Counter1", &mem->counter_tearing[1][0], 3, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Tearing1", &mem->counter_tearing[1][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);
|
||||
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.TBO_1", udata.mfu->tbo1, sizeof(udata.mfu->tbo1), datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Signature", udata.mfu->signature, sizeof(udata.mfu->signature), datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Counter0", &udata.mfu->counter_tearing[0][0], 3, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Tearing0", &udata.mfu->counter_tearing[0][3], 1, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Counter1", &udata.mfu->counter_tearing[1][0], 3, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Tearing1", &udata.mfu->counter_tearing[1][3], 1, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Counter2", &udata.mfu->counter_tearing[2][0], 3, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Tearing2", &udata.mfu->counter_tearing[2][3], 1, datalen);
|
||||
*datalen = MFU_DUMP_PREFIX_LENGTH;
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
break;
|
||||
|
||||
sptr += len;
|
||||
mem->pages++;
|
||||
udata.mfu->pages++;
|
||||
}
|
||||
// remove one, since pages indicates a index rather than number of available pages
|
||||
--mem->pages;
|
||||
--udata.mfu->pages;
|
||||
|
||||
*datalen += sptr;
|
||||
}
|
||||
|
@ -1216,7 +1272,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
|||
snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i);
|
||||
|
||||
size_t len = 0;
|
||||
JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len);
|
||||
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
|
||||
if (!len)
|
||||
break;
|
||||
|
||||
|
@ -1238,7 +1294,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
|||
snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i);
|
||||
|
||||
size_t len = 0;
|
||||
JsonLoadBufAsHex(root, blocks, &udata[sptr], 8, &len);
|
||||
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 8, &len);
|
||||
if (!len)
|
||||
break;
|
||||
|
||||
|
@ -1259,7 +1315,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
|||
snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i);
|
||||
|
||||
size_t len = 0;
|
||||
JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len);
|
||||
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
|
||||
if (!len)
|
||||
break;
|
||||
|
||||
|
@ -1280,7 +1336,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
|||
snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i);
|
||||
|
||||
size_t len = 0;
|
||||
JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len);
|
||||
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
|
||||
if (!len)
|
||||
break;
|
||||
|
||||
|
@ -1290,19 +1346,18 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
|||
}
|
||||
|
||||
if (!strcmp(ctype, "15693")) {
|
||||
JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen);
|
||||
JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen);
|
||||
}
|
||||
|
||||
if (!strcmp(ctype, "legic")) {
|
||||
JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen);
|
||||
JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen);
|
||||
}
|
||||
|
||||
if (!strcmp(ctype, "topaz")) {
|
||||
|
||||
topaz_tag_t *mem = (topaz_tag_t *)udata;
|
||||
JsonLoadBufAsHex(root, "$.Card.UID", mem->uid, sizeof(mem->uid), datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.HR01", mem->HR01, sizeof(mem->HR01), datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Size", (uint8_t *) & (mem->size), 2, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.UID", udata.topaz->uid, sizeof(udata.topaz->uid), datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.HR01", udata.topaz->HR01, sizeof(udata.topaz->HR01), datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.Size", (uint8_t *) & (udata.topaz->size), 2, datalen);
|
||||
|
||||
size_t sptr = 0;
|
||||
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);
|
||||
|
||||
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)
|
||||
break;
|
||||
|
||||
|
@ -1862,14 +1917,18 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea
|
|||
(strcmp(PYTHON_SCRIPTS_SUBDIR, pm3dir) == 0) ||
|
||||
(strcmp(RESOURCES_SUBDIR, pm3dir) == 0))) {
|
||||
char *path = calloc(strlen(exec_path) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
|
||||
if (path == NULL)
|
||||
if (path == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
strcpy(path, exec_path);
|
||||
strcat(path, pm3dir);
|
||||
strcat(path, filename);
|
||||
|
||||
if ((g_debugMode == 2) && (!silent)) {
|
||||
PrintAndLogEx(INFO, "Searching %s", path);
|
||||
}
|
||||
|
||||
if (fileExists(path)) {
|
||||
free(filename);
|
||||
*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) {
|
||||
if (n == 0) {
|
||||
|
||||
if (d == NULL || n == 0) {
|
||||
PrintAndLogEx(INFO, "No data to save. Skipping...");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,9 @@ typedef enum {
|
|||
|
||||
int fileExists(const char *filename);
|
||||
//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);
|
||||
|
||||
|
|
|
@ -489,7 +489,7 @@ static void flash_suggest_update_bootloader(void) {
|
|||
PrintAndLogEx(ERR, "------------- " _CYAN_("Follow these steps") " -------------------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(ERR, " 1) ./pm3-flash-bootrom");
|
||||
PrintAndLogEx(ERR, " 2) ./pm3-flash-all");
|
||||
PrintAndLogEx(ERR, " 2) ./pm3-flash-fullimage");
|
||||
PrintAndLogEx(ERR, " 3) ./pm3");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "---------------------------------------------------");
|
||||
|
|
|
@ -440,7 +440,8 @@ int APDUDecode(uint8_t *data, int len, APDU_t *apdu) {
|
|||
int APDUEncode(APDU_t *apdu, uint8_t *data, int *len) {
|
||||
if (len)
|
||||
*len = 0;
|
||||
|
||||
if (apdu == NULL)
|
||||
return 1;
|
||||
if (apdu->le > 0x10000)
|
||||
return 1;
|
||||
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "iso7816core.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "comms.h" // DropField
|
||||
#include "cmdparser.h"
|
||||
|
@ -29,6 +27,7 @@
|
|||
#include "cmdhf14b.h"
|
||||
#include "iso14b.h" // iso14b_raw_cmd_t
|
||||
#include "util_posix.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
//iceman: this logging setting, should be unified with client debug etc.
|
||||
static bool APDULogging = false;
|
||||
|
@ -170,7 +169,7 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
*sw = isw;
|
||||
}
|
||||
|
||||
if (isw != 0x9000) {
|
||||
if (isw != ISO7816_OK) {
|
||||
if (APDULogging) {
|
||||
if (*sw >> 8 == 0x61) {
|
||||
PrintAndLogEx(ERR, "APDU chaining len %02x", *sw & 0xFF);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "util.h"
|
||||
#include "comms.h" // clearCommandBuffer
|
||||
#include "commonutil.h" // ntohl (pm3 version)
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
// Date type. This is the actual on-card format.
|
||||
typedef struct {
|
||||
|
@ -98,7 +99,7 @@ typedef struct {
|
|||
KEY_TYPE key, const char* defaultValue) { \
|
||||
struct _ksx6924_enum_ ## KEY_TYPE *r = bsearch( \
|
||||
&key, KSX6924_ENUM_ ## NAME, \
|
||||
sizeof(KSX6924_ENUM_ ## NAME) / sizeof(KSX6924_ENUM_ ## NAME [0]), \
|
||||
ARRAYLEN(KSX6924_ENUM_ ## NAME), \
|
||||
sizeof(KSX6924_ENUM_ ## NAME [0]), \
|
||||
_ksx6924_ ## KEY_TYPE ## _enum_compare); \
|
||||
if (r == NULL) { \
|
||||
|
@ -402,7 +403,7 @@ bool KSX6924TrySelect(void) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
if (sw) {
|
||||
PrintAndLogEx(FAILED,
|
||||
"Not a KS X 6924 card! APDU response: %04x - %s",
|
||||
|
@ -444,7 +445,7 @@ bool KSX6924GetBalance(uint32_t *result) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -476,7 +477,7 @@ bool KSX6924InitializeCard(uint8_t mpda1, uint8_t mpda2, uint8_t mpda3, uint8_t
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -574,7 +575,7 @@ bool KSX6924ProprietaryGetRecord(uint8_t id, uint8_t *result, size_t result_len)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,14 +42,14 @@
|
|||
|
||||
typedef struct {
|
||||
uint8_t *buffer;
|
||||
uint8_t numbits;
|
||||
uint8_t position;
|
||||
uint32_t numbits;
|
||||
uint32_t position;
|
||||
} BitstreamIn_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *buffer;
|
||||
uint8_t numbits;
|
||||
uint8_t position;
|
||||
uint32_t numbits;
|
||||
uint32_t position;
|
||||
} BitstreamOut_t;
|
||||
|
||||
bool headBit(BitstreamIn_t *stream);
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include "crc.h"
|
||||
#include "crc16.h" // crc16 ccitt
|
||||
#include "crc32.h"
|
||||
#include "protocols.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
#include "cmdhf14a.h"
|
||||
#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
|
||||
#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)
|
||||
*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_SIGNATURE) &&
|
||||
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;
|
||||
res = DesfireExchangeISO(false, &dctx, (sAPDU_t) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, rndlen * 2, piccrnd}, 0, resp, &resplen, &sw);
|
||||
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) {
|
||||
|
@ -2301,9 +2301,9 @@ static const char *GetDesfireKeyType(uint8_t keytype) {
|
|||
}
|
||||
|
||||
const char *GetDesfireAccessRightStr(uint8_t right) {
|
||||
static char int_access_str[200];
|
||||
|
||||
if (right <= 0x0d) {
|
||||
static char int_access_str[200];
|
||||
snprintf(int_access_str, sizeof(int_access_str), "key 0x%02x", right);
|
||||
return int_access_str;
|
||||
}
|
||||
|
@ -2859,7 +2859,7 @@ int DesfireISOSelectEx(DesfireContext_t *dctx, bool fieldon, DesfireISOSelectCon
|
|||
size_t xresplen = 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);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
if (res == PM3_SUCCESS && sw != ISO7816_OK)
|
||||
return PM3_ESOFT;
|
||||
|
||||
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) {
|
||||
uint16_t sw = 0;
|
||||
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 res;
|
||||
|
@ -2900,7 +2900,7 @@ int DesfireISOExternalAuth(DesfireContext_t *dctx, bool app_level, uint8_t keynu
|
|||
|
||||
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);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
if (res == PM3_SUCCESS && sw != ISO7816_OK)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
|
@ -2913,7 +2913,7 @@ int DesfireISOInternalAuth(DesfireContext_t *dctx, bool app_level, uint8_t keynu
|
|||
|
||||
uint16_t sw = 0;
|
||||
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 res;
|
||||
|
@ -2929,7 +2929,7 @@ int DesfireISOReadBinary(DesfireContext_t *dctx, bool use_file_id, uint8_t filei
|
|||
|
||||
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);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
if (res == PM3_SUCCESS && sw != ISO7816_OK)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
|
@ -2948,7 +2948,7 @@ int DesfireISOUpdateBinary(DesfireContext_t *dctx, bool use_file_id, uint8_t fil
|
|||
|
||||
uint16_t sw = 0;
|
||||
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 res;
|
||||
|
@ -2959,7 +2959,7 @@ int DesfireISOReadRecords(DesfireContext_t *dctx, uint8_t recordnum, bool read_a
|
|||
|
||||
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);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
if (res == PM3_SUCCESS && sw != ISO7816_OK)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
|
@ -2973,7 +2973,7 @@ int DesfireISOAppendRecord(DesfireContext_t *dctx, uint8_t fileid, uint8_t *data
|
|||
|
||||
uint16_t sw = 0;
|
||||
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 res;
|
||||
|
|
|
@ -74,22 +74,37 @@ AccessConditions_t MFAccessConditionsTrailer[] = {
|
|||
};
|
||||
|
||||
bool mfValidateAccessConditions(const uint8_t *data) {
|
||||
uint8_t ndata1 = (data[0]) & 0x0f;
|
||||
uint8_t ndata2 = (data[0] >> 4) & 0x0f;
|
||||
uint8_t ndata3 = (data[1]) & 0x0f;
|
||||
uint8_t data1 = (data[1] >> 4) & 0x0f;
|
||||
uint8_t data2 = (data[2]) & 0x0f;
|
||||
uint8_t data3 = (data[2] >> 4) & 0x0f;
|
||||
uint8_t nd1 = NIBBLE_LOW(data[0]);
|
||||
uint8_t nd2 = NIBBLE_HIGH(data[0]);
|
||||
uint8_t nd3 = NIBBLE_LOW(data[1]);
|
||||
uint8_t d1 = NIBBLE_HIGH(data[1]);
|
||||
uint8_t d2 = NIBBLE_LOW(data[2]);
|
||||
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) {
|
||||
for (int i = 0; i < ARRAYLEN(MFAccessConditionsTrailer); i++)
|
||||
|
|
|
@ -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);
|
||||
|
||||
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);
|
||||
|
||||
uint8_t mfNumBlocksPerSector(uint8_t sectorNo);
|
||||
|
|
|
@ -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
|
||||
// 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) {
|
||||
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");
|
||||
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];
|
||||
reverse_array(signature, signature_len, rev_sig);
|
||||
reverse_array(d->rsa_signature, sizeof(d->rsa_signature), rev_sig);
|
||||
|
||||
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 = 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(&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*)rev_sig, signature_len);
|
||||
mbedtls_mpi_read_binary(&s, (const unsigned char *)rev_sig, sizeof(d->rsa_signature));
|
||||
|
||||
// check is sign < (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);
|
||||
if (g_debugMode == DEBUG) {
|
||||
mbedtls_mpi_write_file( "[=] N.............. ", &N, 16, NULL );
|
||||
mbedtls_mpi_write_file( "[=] signature...... ", &s, 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.............. ", &N, 16, NULL);
|
||||
mbedtls_mpi_write_file("[=] signature...... ", &s, 16, NULL);
|
||||
mbedtls_mpi_write_file("[=] square mod n... ", &sqr, 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
|
||||
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+1] ^= 0x01;
|
||||
nfs[x + 1] ^= 0x01;
|
||||
|
||||
if (nfs[x] == 0x00)
|
||||
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)) {
|
||||
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"));
|
||||
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, "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"));
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int vigik_annotate(uint8_t *d) {
|
||||
int vigik_annotate(mfc_vigik_t *d) {
|
||||
if (d == NULL)
|
||||
return PM3_EINVARG;
|
||||
|
||||
mfc_vigik_t *foo = (mfc_vigik_t*)d;
|
||||
|
||||
PrintAndLogEx(INFO, "Manufacture......... %s", sprint_hex(foo->b0, sizeof(foo->b0)));
|
||||
PrintAndLogEx(INFO, "MAD................. %s", sprint_hex(foo->mad, sizeof(foo->mad)));
|
||||
PrintAndLogEx(INFO, "Counters............ %u", foo->counters);
|
||||
PrintAndLogEx(INFO, "rtf................. %s", sprint_hex(foo->rtf, sizeof(foo->rtf)));
|
||||
PrintAndLogEx(INFO, "Service code........ 0x%08x / %u - " _YELLOW_("%s"), foo->service_code, foo->service_code, vigik_get_service(foo->service_code));
|
||||
PrintAndLogEx(INFO, "Info flag........... %u -", foo->info_flag); // , sprint_bin(foo->info_flag, 1));
|
||||
PrintAndLogEx(INFO, "Key version......... %u", foo->key_version);
|
||||
PrintAndLogEx(INFO, "PTR Counter......... %u", foo->ptr_counter);
|
||||
PrintAndLogEx(INFO, "Counter num......... %u", foo->counter_num);
|
||||
PrintAndLogEx(INFO, "Slot access date.... %s", sprint_hex(foo->slot_access_date, sizeof(foo->slot_access_date)));
|
||||
PrintAndLogEx(INFO, "Slot dst duration... %u", foo->slot_dst_duration);
|
||||
PrintAndLogEx(INFO, "Other Slots......... %s", sprint_hex(foo->other_slots, sizeof(foo->other_slots)));
|
||||
PrintAndLogEx(INFO, "Services counter.... %u", foo->services_counter);
|
||||
PrintAndLogEx(INFO, "Loading date........ %s", sprint_hex(foo->loading_date, sizeof(foo->loading_date)));
|
||||
PrintAndLogEx(INFO, "Reserved null....... %u", foo->reserved_null);
|
||||
PrintAndLogEx(INFO, "Manufacture......... %s", sprint_hex(d->b0, sizeof(d->b0)));
|
||||
PrintAndLogEx(INFO, "MAD................. %s", sprint_hex(d->mad, sizeof(d->mad)));
|
||||
PrintAndLogEx(INFO, "Counters............ %u", d->counters);
|
||||
PrintAndLogEx(INFO, "rtf................. %s", sprint_hex(d->rtf, sizeof(d->rtf)));
|
||||
PrintAndLogEx(INFO, "Service code........ 0x%08x / %u - " _YELLOW_("%s"), d->service_code, d->service_code, vigik_get_service(d->service_code));
|
||||
PrintAndLogEx(INFO, "Info flag........... %u -", d->info_flag); // , sprint_bin(d->info_flag, 1));
|
||||
PrintAndLogEx(INFO, "Key version......... %u", d->key_version);
|
||||
PrintAndLogEx(INFO, "PTR Counter......... %u", d->ptr_counter);
|
||||
PrintAndLogEx(INFO, "Counter num......... %u", d->counter_num);
|
||||
PrintAndLogEx(INFO, "Slot access date.... %s", sprint_hex(d->slot_access_date, sizeof(d->slot_access_date)));
|
||||
PrintAndLogEx(INFO, "Slot dst duration... %u", d->slot_dst_duration);
|
||||
PrintAndLogEx(INFO, "Other Slots......... %s", sprint_hex(d->other_slots, sizeof(d->other_slots)));
|
||||
PrintAndLogEx(INFO, "Services counter.... %u", d->services_counter);
|
||||
PrintAndLogEx(INFO, "Loading date........ %s", sprint_hex(d->loading_date, sizeof(d->loading_date)));
|
||||
PrintAndLogEx(INFO, "Reserved null....... %u", d->reserved_null);
|
||||
PrintAndLogEx(INFO, "----------------------------------------------------------------");
|
||||
PrintAndLogEx(INFO, "");
|
||||
vigik_verify(d, 96, foo->rsa_signature, sizeof(foo->rsa_signature));
|
||||
vigik_verify(d);
|
||||
PrintAndLogEx(INFO, "----------------------------------------------------------------");
|
||||
PrintAndLogEx(INFO, "");
|
||||
return PM3_SUCCESS;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "common.h"
|
||||
|
||||
#include "util.h" // FILE_PATH_SIZE
|
||||
#include "protocol_vigik.h"
|
||||
|
||||
#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
|
||||
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);
|
||||
int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len);
|
||||
int vigik_annotate(uint8_t *d);
|
||||
int vigik_verify(mfc_vigik_t *d);
|
||||
int vigik_annotate(mfc_vigik_t *d);
|
||||
#endif
|
||||
|
|
|
@ -349,6 +349,7 @@ const static vocabulory_t vocabulory[] = {
|
|||
{ 0, "hf mf gen3freeze" },
|
||||
{ 0, "hf mf ggetblk" },
|
||||
{ 0, "hf mf gload" },
|
||||
{ 0, "hf mf gsave" },
|
||||
{ 0, "hf mf gsetblk" },
|
||||
{ 0, "hf mf gview" },
|
||||
{ 0, "hf mf ndefformat" },
|
||||
|
@ -437,6 +438,12 @@ const static vocabulory_t vocabulory[] = {
|
|||
{ 0, "hf st25ta protect" },
|
||||
{ 0, "hf st25ta pwd" },
|
||||
{ 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" },
|
||||
{ 0, "hf thinfilm info" },
|
||||
{ 1, "hf thinfilm list" },
|
||||
|
@ -452,9 +459,6 @@ const static vocabulory_t vocabulory[] = {
|
|||
{ 0, "hf topaz rdbl" },
|
||||
{ 1, "hf topaz view" },
|
||||
{ 0, "hf topaz wrbl" },
|
||||
{ 1, "hf texkom help" },
|
||||
{ 0, "hf texkom reader" },
|
||||
{ 0, "hf texkom sim" },
|
||||
{ 1, "hf xerox help" },
|
||||
{ 0, "hf xerox info" },
|
||||
{ 0, "hf xerox reader" },
|
||||
|
@ -736,6 +740,12 @@ const static vocabulory_t vocabulory[] = {
|
|||
{ 0, "nfc barcode read" },
|
||||
{ 0, "nfc barcode sim" },
|
||||
{ 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 list" },
|
||||
{ 0, "smart info" },
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#endif
|
||||
#include "ui.h"
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
|
||||
#include <stdio.h> // for Mingw readline
|
||||
#include <stdarg.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, ...);
|
||||
|
||||
#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
|
||||
int searchHomeFilePath(char **foundpath, const char *subdir, const char *filename, bool create_home) {
|
||||
if (foundpath == NULL)
|
||||
if (foundpath == NULL) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
const char *user_path = get_my_user_directory();
|
||||
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;
|
||||
char *path = calloc(pathlen, sizeof(char));
|
||||
if (path == NULL)
|
||||
if (path == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
strcpy(path, user_path);
|
||||
strcat(path, PM3_USER_DIRECTORY);
|
||||
|
||||
int result;
|
||||
|
||||
#ifdef _WIN32
|
||||
struct _stat st;
|
||||
// Mingw _stat fails if path ends with /, so let's use a stripped path
|
||||
if (path[strlen(path) - 1] == '/') {
|
||||
path[strlen(path) - 1] = '\0';
|
||||
if (str_endswith(path, PATHSEP)) {
|
||||
memset(path + (strlen(path) - strlen(PATHSEP)), 0x00, strlen(PATHSEP));
|
||||
result = _stat(path, &st);
|
||||
path[strlen(path)] = '/';
|
||||
strcat(path, PATHSEP);
|
||||
} else {
|
||||
result = _stat(path, &st);
|
||||
}
|
||||
|
@ -96,19 +104,16 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
|
|||
struct stat st;
|
||||
result = stat(path, &st);
|
||||
#endif
|
||||
|
||||
if ((result != 0) && create_home) {
|
||||
|
||||
#ifdef _WIN32
|
||||
if (_mkdir(path))
|
||||
#else
|
||||
if (mkdir(path, 0700))
|
||||
#endif
|
||||
{
|
||||
if (MKDIR_CHK) {
|
||||
fprintf(stderr, "Could not create user directory %s\n", path);
|
||||
free(path);
|
||||
return PM3_EFILE;
|
||||
}
|
||||
}
|
||||
|
||||
if (subdir != NULL) {
|
||||
pathlen += strlen(subdir);
|
||||
char *tmp = realloc(path, pathlen * sizeof(char));
|
||||
|
@ -121,24 +126,20 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
|
|||
|
||||
#ifdef _WIN32
|
||||
// Mingw _stat fails if path ends with /, so let's use a stripped path
|
||||
if (path[strlen(path) - 1] == '/') {
|
||||
path[strlen(path) - 1] = '\0';
|
||||
if (str_endswith(path, PATHSEP)) {
|
||||
memset(path + (strlen(path) - strlen(PATHSEP)), 0x00, strlen(PATHSEP));
|
||||
result = _stat(path, &st);
|
||||
path[strlen(path)] = '/';
|
||||
strcat(path, PATHSEP);
|
||||
} else {
|
||||
result = _stat(path, &st);
|
||||
}
|
||||
#else
|
||||
result = stat(path, &st);
|
||||
#endif
|
||||
|
||||
if ((result != 0) && create_home) {
|
||||
|
||||
#ifdef _WIN32
|
||||
if (_mkdir(path))
|
||||
#else
|
||||
if (mkdir(path, 0700))
|
||||
#endif
|
||||
{
|
||||
if (MKDIR_CHK) {
|
||||
fprintf(stderr, "Could not create user directory %s\n", path);
|
||||
free(path);
|
||||
return PM3_EFILE;
|
||||
|
@ -150,15 +151,18 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
|
|||
*foundpath = path;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
pathlen += strlen(filename);
|
||||
char *tmp = realloc(path, pathlen * sizeof(char));
|
||||
if (tmp == NULL) {
|
||||
//free(path);
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
path = tmp;
|
||||
strcat(path, filename);
|
||||
*foundpath = path;
|
||||
|
||||
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;
|
||||
char *current_token = NULL;
|
||||
uint8_t current_token_length = 0;
|
||||
char current_char;
|
||||
char *rdest = (char *)dest;
|
||||
char *rsrc = (char *)src;
|
||||
uint16_t si = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
current_char = rsrc[i];
|
||||
char current_char = rsrc[i];
|
||||
|
||||
if (current_token_length == 0) {
|
||||
// starting a new token.
|
||||
|
|
|
@ -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 clientdebugLevel {cdbOFF, cdbSIMPLE, cdbFULL} clientdebugLevel_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 {
|
||||
|
|
|
@ -266,7 +266,7 @@ void print_hex_break(const uint8_t *data, const size_t len, uint8_t breaks) {
|
|||
uint8_t mod = len % breaks;
|
||||
|
||||
if (mod) {
|
||||
char buf[UTIL_BUFFER_SIZE_SPRINT + 3];
|
||||
char buf[UTIL_BUFFER_SIZE_SPRINT + 3] = {0};
|
||||
hex_to_buffer((uint8_t *)buf, data + i, mod, (sizeof(buf) - 1), 0, 1, true);
|
||||
|
||||
// add the spaces...
|
||||
|
@ -291,7 +291,7 @@ void print_hex_noascii_break(const uint8_t *data, const size_t len, uint8_t brea
|
|||
uint8_t mod = len % breaks;
|
||||
|
||||
if (mod) {
|
||||
char buf[UTIL_BUFFER_SIZE_SPRINT + 3];
|
||||
char buf[UTIL_BUFFER_SIZE_SPRINT + 3] = {0};
|
||||
hex_to_buffer((uint8_t *)buf, data + i, mod, (sizeof(buf) - 1), 0, 0, true);
|
||||
|
||||
// add the spaces...
|
||||
|
@ -307,7 +307,7 @@ static void print_buffer_ex(const uint8_t *data, const size_t len, int level, ui
|
|||
if ((data == NULL) || (len < 1))
|
||||
return;
|
||||
|
||||
char buf[UTIL_BUFFER_SIZE_SPRINT + 3];
|
||||
char buf[UTIL_BUFFER_SIZE_SPRINT + 3] = {0};
|
||||
int i;
|
||||
for (i = 0; i < len; i += breaks) {
|
||||
|
||||
|
@ -614,7 +614,7 @@ void bytes_to_bytebits(const void *src, const size_t srclen, void *dest) {
|
|||
// hh,gg,ff,ee,dd,cc,bb,aa, pp,oo,nn,mm,ll,kk,jj,ii
|
||||
// up to 64 bytes or 512 bits
|
||||
uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize) {
|
||||
static uint8_t buf[64];
|
||||
static uint8_t buf[64] = {0};
|
||||
memset(buf, 0x00, 64);
|
||||
uint8_t *tmp = buf;
|
||||
for (uint8_t block = 0; block < (uint8_t)(len / blockSize); block++) {
|
||||
|
@ -1088,6 +1088,14 @@ void str_lower(char *s) {
|
|||
s[i] = tolower(s[i]);
|
||||
}
|
||||
|
||||
void str_upper(char *s) {
|
||||
strn_upper(s, strlen(s));
|
||||
}
|
||||
|
||||
void strn_upper(char *s, size_t n) {
|
||||
for (size_t i = 0; i < n; i++)
|
||||
s[i] = toupper(s[i]);
|
||||
}
|
||||
// check for prefix in string
|
||||
bool str_startswith(const char *s, const char *pre) {
|
||||
return strncmp(pre, s, strlen(pre)) == 0;
|
||||
|
@ -1239,7 +1247,7 @@ inline uint64_t leadingzeros64(uint64_t a) {
|
|||
}
|
||||
|
||||
|
||||
int byte_strstr(uint8_t *src, size_t srclen, uint8_t *pattern, size_t plen) {
|
||||
int byte_strstr(const uint8_t *src, size_t srclen, const uint8_t *pattern, size_t plen) {
|
||||
|
||||
size_t max = srclen - plen + 1;
|
||||
|
||||
|
@ -1261,3 +1269,12 @@ int byte_strstr(uint8_t *src, size_t srclen, uint8_t *pattern, size_t plen) {
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void sb_append_char(smartbuf *sb, unsigned char c) {
|
||||
if (sb->idx >= sb->size) {
|
||||
sb->size *= 2;
|
||||
sb->ptr = realloc(sb->ptr, sb->size);
|
||||
}
|
||||
sb->ptr[sb->idx] = c;
|
||||
sb->idx++;
|
||||
}
|
||||
|
|
|
@ -129,6 +129,9 @@ uint64_t HornerScheme(uint64_t num, uint64_t divider, uint64_t factor);
|
|||
int num_CPUs(void); // number of logical CPUs
|
||||
|
||||
void str_lower(char *s); // converts string to lower case
|
||||
void str_upper(char *s); // converts string to UPPER case
|
||||
void strn_upper(char *s, size_t n);
|
||||
|
||||
bool str_startswith(const char *s, const char *pre); // check for prefix in string
|
||||
bool str_endswith(const char *s, const char *suffix); // check for suffix in string
|
||||
void clean_ascii(unsigned char *buf, size_t len);
|
||||
|
@ -145,5 +148,12 @@ uint64_t bitcount64(uint64_t a);
|
|||
uint32_t leadingzeros32(uint32_t a);
|
||||
uint64_t leadingzeros64(uint64_t a);
|
||||
|
||||
int byte_strstr(uint8_t *src, size_t srclen, uint8_t *pattern, size_t plen);
|
||||
int byte_strstr(const uint8_t *src, size_t srclen, const uint8_t *pattern, size_t plen);
|
||||
|
||||
struct smartbuf {
|
||||
char *ptr;
|
||||
size_t size;
|
||||
size_t idx;
|
||||
} typedef smartbuf;
|
||||
void sb_append_char(smartbuf *sb, unsigned char c);
|
||||
#endif
|
||||
|
|
|
@ -262,10 +262,10 @@ uint32_t rotr(uint32_t a, uint8_t n) {
|
|||
return (a >> n) | (a << (32 - n));
|
||||
}
|
||||
|
||||
uint16_t get_sw(const uint8_t *d, uint8_t n) {
|
||||
uint16_t get_sw(const uint8_t *d, uint16_t n) {
|
||||
if (n < 2)
|
||||
return 0;
|
||||
|
||||
n -= 2;
|
||||
return d[n] * 0x0100 + d[n + 1];
|
||||
return (d[n] << 8 | d[n + 1]);
|
||||
}
|
||||
|
|
|
@ -85,5 +85,5 @@ void htole24(uint32_t val, uint8_t data[3]);
|
|||
uint32_t rotl(uint32_t a, uint8_t n);
|
||||
uint32_t rotr(uint32_t a, uint8_t n);
|
||||
|
||||
uint16_t get_sw(const uint8_t *d, uint8_t n);
|
||||
uint16_t get_sw(const uint8_t *d, uint16_t n);
|
||||
#endif
|
||||
|
|
|
@ -280,7 +280,6 @@ void cm_auth(const uint8_t *Gc, const uint8_t *Ci, const uint8_t *Q, uint8_t *Ch
|
|||
|
||||
static void cm_crypt(const CryptoAction ca, const uint8_t offset, const uint8_t len, const uint8_t *in, uint8_t *out, crypto_state s) {
|
||||
size_t pos;
|
||||
uint8_t bt;
|
||||
|
||||
next_n(true, 5, 0, s);
|
||||
next(true, offset, s);
|
||||
|
@ -288,7 +287,7 @@ static void cm_crypt(const CryptoAction ca, const uint8_t offset, const uint8_t
|
|||
next(true, len, s);
|
||||
for (pos = 0; pos < len; pos++) {
|
||||
// Perform the crypto operation
|
||||
bt = in[pos] ^ cm_byte(s);
|
||||
uint8_t bt = in[pos] ^ cm_byte(s);
|
||||
|
||||
// Generate output
|
||||
if (out) out[pos] = bt;
|
||||
|
|
|
@ -240,6 +240,12 @@ uint16_t ul_ev1_packgen_def(const uint8_t *uid) {
|
|||
return 0x0000;
|
||||
}
|
||||
|
||||
// MIFARE ULTRALIGHT OTP generators
|
||||
uint32_t ul_c_otpgenA(const uint8_t *uid) {
|
||||
return 0x534C544F;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------
|
||||
// MFC key generation stuff
|
||||
// Each algo implementation should offer two key generation functions.
|
||||
|
|
|
@ -36,6 +36,8 @@ uint16_t ul_ev1_packgenC(const uint8_t *uid);
|
|||
uint16_t ul_ev1_packgenD(const uint8_t *uid);
|
||||
uint16_t ul_ev1_packgenE(const uint8_t *uid);
|
||||
|
||||
uint32_t ul_c_otpgenA(const uint8_t *uid);
|
||||
|
||||
int mfc_algo_ving_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key);
|
||||
int mfc_algo_ving_all(uint8_t *uid, uint8_t *keys);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue