This commit is contained in:
Adrian Teuscher 2023-01-27 19:45:06 +01:00
commit 5d17177498
184 changed files with 4180 additions and 2318 deletions

View file

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

View file

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

View file

@ -3,14 +3,29 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [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)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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[] = {

View file

@ -262,9 +262,9 @@ void CodeIso15693AsTag(const uint8_t *cmd, size_t len) {
}
// Transmit the command (to the tag) that was placed in cmd[].
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);

View file

@ -40,7 +40,7 @@ void CodeIso15693AsTag(const uint8_t *cmd, size_t len);
void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow);
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);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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") " ---------------------"},

View file

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

View file

@ -53,4 +53,7 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode);
int 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

View file

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

View file

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

View file

@ -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) {

View file

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

View file

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

View file

@ -285,7 +285,7 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
// get header from card
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));

View file

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

View file

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

View file

@ -318,6 +318,18 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i
snprintf(exp, size, "AUTH-B(%d)", cmd[1]);
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");
}

View file

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

View file

@ -306,7 +306,7 @@ static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) {
}
// ref: https://www.nxp.com/docs/en/application-note/AN12343.pdf p7
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];

View file

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

View file

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

View file

@ -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
View file

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

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

@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// High frequency ISO14443A / TESLA commands
//-----------------------------------------------------------------------------
#ifndef CMDHFTESLA_H__
#define CMDHFTESLA_H__
#include "common.h"
int CmdHFTESLA(const char *Cmd);
#endif

View file

@ -311,7 +311,7 @@ static bool TexcomTK15Decode(uint32_t *implengths, uint32_t implengthslen, char
bool prevbit = (implengths[implengthslen - 3] > implengths[implengthslen - 2]);
bool 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 {

View file

@ -292,7 +292,7 @@ static bool topaz_byte_is_locked(uint16_t byteno) {
}
}
static int topaz_set_cc_dynamic(uint8_t *data) {
static int topaz_set_cc_dynamic(const uint8_t *data) {
if (data[0] != 0xE1) {
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) {

View file

@ -660,7 +660,6 @@ static int start_drawing_1in54B(uint8_t model_nr, uint8_t *black, uint8_t *red)
}
static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
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);

View file

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

View file

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

View file

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

View file

@ -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, "---------------------------------------------------------------------------------------------------");

View file

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

View file

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

View file

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

View file

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

View file

@ -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
View file

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

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

@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// PIV commands
//-----------------------------------------------------------------------------
#ifndef CMDPIV_H__
#define CMDPIV_H__
#include "common.h"
int CmdPIV(const char *Cmd);
#endif

View file

@ -147,7 +147,7 @@ static int split(char *str, char **arr) {
return word_cnt;
}
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");
@ -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);

View file

@ -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) {

View file

@ -485,8 +485,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
uint32_t end_of_transmission_timestamp = 0;
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);

View file

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

View file

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

View file

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

View file

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

View file

@ -214,18 +214,23 @@ bool create_path(const char *dirname) {
}
*/
bool setDefaultPath(savePaths_t pathIndex, const char *Path) {
bool setDefaultPath(savePaths_t pathIndex, const char *path) {
if (pathIndex < spItemCount) {
if ((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;
}

View file

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

View file

@ -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, "---------------------------------------------------");

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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++)

View file

@ -71,6 +71,7 @@ int MFPGetSignature(bool activateField, bool leaveSignalON, uint8_t *dataout, in
int MFPGetVersion(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
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);

View file

@ -1499,7 +1499,7 @@ static void reverse_array(const uint8_t *src, int src_len, uint8_t *dest) {
}
};
int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) {
int vigik_verify(mfc_vigik_t *d) {
// iso9796
// 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
@ -1566,7 +1566,7 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
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)
@ -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;

View file

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

View file

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

View file

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

View file

@ -35,7 +35,9 @@ typedef enum logLevel {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG, INPLA
typedef enum emojiMode {EMO_ALIAS, EMO_EMOJI, EMO_ALTTEXT, EMO_NONE} emojiMode_t;
typedef enum 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 {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1442,6 +1442,7 @@ __attribute__((noinline))
#endif
void mpi_mul_hlp(size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b) {
mbedtls_mpi_uint c = 0, t = 0;
(void)t;
#if defined(MULADDC_HUIT)
for (; i >= 8; i -= 8) {

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