mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-22 14:23:50 -07:00
Merge branch 'master' into master
Signed-off-by: lnv42 <34003959+lnv42@users.noreply.github.com>
This commit is contained in:
commit
13106d4888
156 changed files with 3005 additions and 1167 deletions
21
.github/ISSUE_TEMPLATE/checklist-for-release.md
vendored
21
.github/ISSUE_TEMPLATE/checklist-for-release.md
vendored
|
@ -18,26 +18,11 @@ assignees: doegox, iceman1001
|
|||
- [ ] `tools/build_all_firmwares.sh` check that the script contains all standalone modes then compile all standalone modes (linux only)
|
||||
- [ ] `experimental_lib` compilation & tests
|
||||
- [ ] `experimental_client_with_swig` compilation & tests
|
||||
- [ ] Check Android `CMakeLists.txt` list of source file
|
||||
- [ ] GitHub Actions - green across the board ( MacOS, Ubuntu, Windows)
|
||||
|
||||
# OS compilation and tests
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
make clean && make -j PLATFORM=PM3GENERIC PLATFORM_EXTRAS= && tools/pm3_tests.sh --long || exit 1
|
||||
make clean && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS= || exit 1
|
||||
make clean && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON || exit 1
|
||||
make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && sudo make install PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && ( cd /tmp; proxmark3 -c 'data load -f lf_EM4x05.pm3;lf search -1'|grep 'Valid FDX-B ID found' ) && sudo make uninstall || exit 1
|
||||
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3GENERIC PLATFORM_EXTRAS= && cp -a ../*scripts ../*libs . && ../../tools/pm3_tests.sh --clientbin $(pwd)/proxmark3 client ) || exit 1
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS= ) || exit 1
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON ) || exit 1
|
||||
|
||||
# Hitag2crack, optionally with --long and --opencl ...
|
||||
make hitag2crack/clean && make hitag2crack && tools/pm3_tests.sh hitag2crack || exit 1
|
||||
```
|
||||
Run `tools/release_tests.sh` on:
|
||||
|
||||
- [ ] RPI Zero
|
||||
- [ ] Jetson Nano
|
||||
|
@ -47,9 +32,9 @@ make hitag2crack/clean && make hitag2crack && tools/pm3_tests.sh hitag2crack ||
|
|||
- [ ] Kali
|
||||
- [ ] Debian Stable
|
||||
- [ ] Debian Testing
|
||||
- [ ] Ubuntu21
|
||||
- [ ] Ubuntu 22
|
||||
- [ ] ParrotOS
|
||||
- [ ] Fedora
|
||||
- [ ] Fedora 37
|
||||
- [ ] OpenSuse Leap
|
||||
- [ ] OpenSuse Tumbleweed
|
||||
- [ ] OSX (MacPorts)
|
||||
|
|
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -3,17 +3,27 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Changed `hf 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 (@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)
|
||||
- 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)
|
||||
|
|
8
Makefile
8
Makefile
|
@ -80,20 +80,20 @@ ifneq (,$(INSTALLSHARES))
|
|||
endif
|
||||
ifneq (,$(INSTALLDOCS))
|
||||
$(Q)$(INSTALLSUDO) $(RMDIR) $(foreach doc,$(INSTALLDOCS),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH)$(PATHSEP)$(notdir $(doc)))
|
||||
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH)
|
||||
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH)
|
||||
endif
|
||||
ifneq (,$(INSTALLTOOLS))
|
||||
$(Q)$(INSTALLSUDO) $(RM) $(foreach tool,$(INSTALLTOOLS),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)$(PATHSEP)$(notdir $(tool)))
|
||||
endif
|
||||
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)
|
||||
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)
|
||||
ifneq (,$(INSTALLSIMFW))
|
||||
$(Q)$(INSTALLSUDO) $(RM) $(foreach fw,$(INSTALLSIMFW),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(notdir $(fw)))
|
||||
endif
|
||||
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)
|
||||
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)
|
||||
ifeq ($(platform),Linux)
|
||||
$(Q)$(INSTALLSUDO) $(RM) $(DESTDIR)$(UDEV_PREFIX)/77-pm3-usb-device-blacklist.rules
|
||||
endif
|
||||
$(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)
|
||||
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)
|
||||
|
||||
# tests
|
||||
mfkey/check: FORCE
|
||||
|
|
|
@ -29,8 +29,8 @@ GZIP = gzip
|
|||
MKDIR = mkdir -p
|
||||
RM = rm -f
|
||||
RMDIR = rm -rf
|
||||
# rmdir only if dir is empty, tolerate failure
|
||||
RMDIR_SOFT = -rmdir
|
||||
# rmdir only if dir is empty, you must add "-" when using it to tolerate failure
|
||||
RMDIR_SOFT = rmdir
|
||||
MV = mv
|
||||
TOUCH = touch
|
||||
FALSE = false
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -53,6 +53,9 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
| LF_NEXID | LF Nexwatch collector to flashmem |
|
||||
| (RDV4 only) | |
|
||||
+----------------------------------------------------------+
|
||||
| LF_NEDAP_SIM | LF Nedap ID simple simulator |
|
||||
| | |
|
||||
+----------------------------------------------------------+
|
||||
| LF_PROXBRUTE | HID ProxII bruteforce |
|
||||
| | - Brad Antoniewicz |
|
||||
+----------------------------------------------------------+
|
||||
|
@ -121,11 +124,12 @@ 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_PROX2BRUTE LF_SAMYRUN LF_THAREXDE LF_NEXID
|
||||
|
||||
STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE LF_NEXID LF_NEDAP_SIM
|
||||
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_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)),)
|
||||
|
|
|
@ -137,6 +137,10 @@ endif
|
|||
ifneq (,$(findstring WITH_STANDALONE_HF_MFCSIM,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_mfcsim.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_NEDAP_SIM
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_NEDAP_SIM,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_nedap_sim.c
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring WITH_STANDALONE_DANKARMULTI,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = dankarmulti.c
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// then from shell:
|
||||
// hexdump lf.bin -e '5/1 "%02X" /0 "\n"'
|
||||
//
|
||||
// To recall only LAST stored ID from flash use lf-last instead of lf file.
|
||||
// To recall only LAST stored ID from flash use lf-last instead of lf file.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// Modes of operation:
|
||||
|
|
207
armsrc/Standalone/lf_nedap_sim.c
Normal file
207
armsrc/Standalone/lf_nedap_sim.c
Normal file
|
@ -0,0 +1,207 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// This simple mode encode, then emulate a Nedap identificator until button pressed
|
||||
// lots of code from client side, cmdlfnedap, util, etc.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "standalone.h" // standalone definitions
|
||||
#include "proxmark3_arm.h"
|
||||
#include "appmain.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "lfops.h"
|
||||
#include "util.h"
|
||||
#include "dbprint.h"
|
||||
#include "string.h"
|
||||
#include "BigBuf.h"
|
||||
#include "crc16.h"
|
||||
|
||||
#define MODULE_LONG_NAME "LF Nedap simple simulator"
|
||||
|
||||
typedef struct _NEDAP_TAG {
|
||||
uint8_t subType;
|
||||
uint16_t customerCode;
|
||||
uint32_t id;
|
||||
|
||||
uint8_t bIsLong;
|
||||
} NEDAP_TAG, *PNEDAP_TAG;
|
||||
|
||||
const NEDAP_TAG Tag = {.subType = 0x5, .customerCode = 0x123, .id = 42424, .bIsLong = 1};
|
||||
|
||||
static int NedapPrepareBigBuffer(const NEDAP_TAG *pTag);
|
||||
static void biphaseSimBitInverted(uint8_t c, int *n, uint8_t *phase);
|
||||
static void NedapGen(uint8_t subType, uint16_t customerCode, uint32_t id, bool isLong, uint8_t *data);
|
||||
static uint8_t isEven_64_63(const uint8_t *data);
|
||||
static inline uint32_t bitcount32(uint32_t a);
|
||||
static void bytes_to_bytebits(const void *src, const size_t srclen, void *dest);
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" " MODULE_LONG_NAME);
|
||||
}
|
||||
|
||||
void RunMod(void) {
|
||||
int n;
|
||||
|
||||
StandAloneMode();
|
||||
|
||||
Dbprintf("[=] " MODULE_LONG_NAME " -- started");
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
Dbprintf("[=] NEDAP (%s) - ID: " _GREEN_("%05u") " subtype: " _GREEN_("%1u") " customer code: " _GREEN_("%u / 0x%03X"), Tag.bIsLong ? "128b" : "64b", Tag.id, Tag.subType, Tag.customerCode, Tag.customerCode);
|
||||
|
||||
n = NedapPrepareBigBuffer(&Tag);
|
||||
do {
|
||||
WDT_HIT();
|
||||
|
||||
if (data_available())
|
||||
break;
|
||||
|
||||
SimulateTagLowFrequency(n, 0, true);
|
||||
|
||||
} while (BUTTON_HELD(1000) == BUTTON_NO_CLICK);
|
||||
|
||||
Dbprintf("[=] " MODULE_LONG_NAME " -- exiting");
|
||||
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
static int NedapPrepareBigBuffer(const NEDAP_TAG *pTag) {
|
||||
int ret = 0;
|
||||
uint8_t data[16], bitStream[sizeof(data) * 8], phase = 0;
|
||||
uint16_t i, size = pTag->bIsLong ? sizeof(data) : (sizeof(data) / 2);
|
||||
|
||||
NedapGen(pTag->subType, pTag->customerCode, pTag->id, pTag->bIsLong, data);
|
||||
bytes_to_bytebits(data, size, bitStream);
|
||||
size <<= 3;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
biphaseSimBitInverted(!bitStream[i], &ret, &phase);
|
||||
}
|
||||
if (phase == 1) { //run a second set inverted to keep phase in check
|
||||
for (i = 0; i < size; i++) {
|
||||
biphaseSimBitInverted(!bitStream[i], &ret, &phase);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void biphaseSimBitInverted(uint8_t c, int *n, uint8_t *phase) {
|
||||
uint8_t *dest = BigBuf_get_addr();
|
||||
|
||||
if (c) {
|
||||
memset(dest + (*n), c ^ 1 ^ *phase, 32);
|
||||
memset(dest + (*n) + 32, c ^ *phase, 32);
|
||||
} else {
|
||||
memset(dest + (*n), c ^ *phase, 64);
|
||||
*phase ^= 1;
|
||||
}
|
||||
*n += 64;
|
||||
}
|
||||
|
||||
#define FIXED_71 0x71
|
||||
#define FIXED_40 0x40
|
||||
#define UNKNOWN_A 0x00
|
||||
#define UNKNOWN_B 0x00
|
||||
static const uint8_t translateTable[10] = {8, 2, 1, 12, 4, 5, 10, 13, 0, 9};
|
||||
static void NedapGen(uint8_t subType, uint16_t customerCode, uint32_t id, bool isLong, uint8_t *data) { // 8 or 16
|
||||
uint8_t buffer[7];
|
||||
|
||||
uint8_t r1 = (uint8_t)(id / 10000);
|
||||
uint8_t r2 = (uint8_t)((id % 10000) / 1000);
|
||||
uint8_t r3 = (uint8_t)((id % 1000) / 100);
|
||||
uint8_t r4 = (uint8_t)((id % 100) / 10);
|
||||
uint8_t r5 = (uint8_t)(id % 10);
|
||||
|
||||
// first part
|
||||
uint8_t idxC1 = r1;
|
||||
uint8_t idxC2 = (idxC1 + 1 + r2) % 10;
|
||||
uint8_t idxC3 = (idxC2 + 1 + r3) % 10;
|
||||
uint8_t idxC4 = (idxC3 + 1 + r4) % 10;
|
||||
uint8_t idxC5 = (idxC4 + 1 + r5) % 10;
|
||||
|
||||
buffer[0] = 0xc0 | (subType & 0x0F);
|
||||
buffer[1] = (customerCode & 0x0FF0) >> 4;
|
||||
buffer[2] = ((customerCode & 0x000F) << 4) | translateTable[idxC1];
|
||||
buffer[3] = (translateTable[idxC2] << 4) | translateTable[idxC3];
|
||||
buffer[4] = (translateTable[idxC4] << 4) | translateTable[idxC5];
|
||||
|
||||
// checksum
|
||||
init_table(CRC_XMODEM);
|
||||
uint16_t checksum = crc16_xmodem(buffer, 5);
|
||||
|
||||
buffer[6] = ((checksum & 0x000F) << 4) | (buffer[4] & 0x0F);
|
||||
buffer[5] = (checksum & 0x00F0) | ((buffer[4] & 0xF0) >> 4);
|
||||
buffer[4] = ((checksum & 0x0F00) >> 4) | (buffer[3] & 0x0F);
|
||||
buffer[3] = ((checksum & 0xF000) >> 8) | ((buffer[3] & 0xF0) >> 4);
|
||||
|
||||
// carry calc
|
||||
uint8_t carry = 0;
|
||||
for (uint8_t i = 0; i < sizeof(buffer); i++) {
|
||||
uint8_t tmp = buffer[sizeof(buffer) - 1 - i];
|
||||
data[7 - i] = ((tmp & 0x7F) << 1) | carry;
|
||||
carry = (tmp & 0x80) >> 7;
|
||||
}
|
||||
data[0] = 0xFE | carry;
|
||||
data[7] |= isEven_64_63(data);
|
||||
|
||||
// second part
|
||||
if (isLong) {
|
||||
uint8_t id0 = r1;
|
||||
uint8_t id1 = (r2 << 4) | r3;
|
||||
uint8_t id2 = (r4 << 4) | r5;
|
||||
|
||||
data[8] = (id2 >> 1);
|
||||
data[9] = ((id2 & 0x01) << 7) | (id1 >> 2);
|
||||
data[10] = ((id1 & 0x03) << 6) | (id0 >> 3);
|
||||
data[11] = ((id0 & 0x07) << 5) | (FIXED_71 >> 4);
|
||||
data[12] = ((FIXED_71 & 0x0F) << 4) | (FIXED_40 >> 5);
|
||||
data[13] = ((FIXED_40 & 0x1F) << 3) | (UNKNOWN_A >> 6);
|
||||
data[14] = ((UNKNOWN_A & 0x3F) << 2) | (UNKNOWN_B >> 7);
|
||||
data[15] = ((UNKNOWN_B & 0x7F) << 1);
|
||||
data[15] |= isEven_64_63(data + 8);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t isEven_64_63(const uint8_t *data) { // 8
|
||||
uint32_t tmp[2];
|
||||
memcpy(tmp, data, 8);
|
||||
return (bitcount32(tmp[0]) + (bitcount32(tmp[1] & 0xfeffffff))) & 1;
|
||||
}
|
||||
|
||||
static void bytes_to_bytebits(const void *src, const size_t srclen, void *dest) {
|
||||
uint8_t *s = (uint8_t *)src, *d = (uint8_t *)dest;
|
||||
size_t i = srclen * 8, j = srclen;
|
||||
|
||||
while (j--) {
|
||||
uint8_t b = s[j];
|
||||
d[--i] = (b >> 0) & 1;
|
||||
d[--i] = (b >> 1) & 1;
|
||||
d[--i] = (b >> 2) & 1;
|
||||
d[--i] = (b >> 3) & 1;
|
||||
d[--i] = (b >> 4) & 1;
|
||||
d[--i] = (b >> 5) & 1;
|
||||
d[--i] = (b >> 6) & 1;
|
||||
d[--i] = (b >> 7) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t bitcount32(uint32_t a) {
|
||||
#if defined __GNUC__
|
||||
return __builtin_popcountl(a);
|
||||
#else
|
||||
a = a - ((a >> 1) & 0x55555555);
|
||||
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
|
||||
return (((a + (a >> 4)) & 0x0f0f0f0f) * 0x01010101) >> 24;
|
||||
#endif
|
||||
}
|
|
@ -345,7 +345,7 @@ static void print_debug_level(void) {
|
|||
char dbglvlstr[20] = {0};
|
||||
switch (g_dbglevel) {
|
||||
case DBG_NONE:
|
||||
sprintf(dbglvlstr, "none");
|
||||
sprintf(dbglvlstr, "off");
|
||||
break;
|
||||
case DBG_ERROR:
|
||||
sprintf(dbglvlstr, "error");
|
||||
|
|
|
@ -298,7 +298,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
|||
// 8-byte IDm, number of blocks, blocks numbers
|
||||
// number of blocks limited to 4 for FelicaLite(S)
|
||||
static void BuildFliteRdblk(const uint8_t *idm, uint8_t blocknum, const uint16_t *blocks) {
|
||||
if (blocknum > 4 || blocknum <= 0)
|
||||
if (blocknum > 4 || blocknum == 0)
|
||||
Dbprintf("Invalid number of blocks, %d != 4", blocknum);
|
||||
|
||||
uint8_t c = 0, i = 0;
|
||||
|
|
|
@ -235,9 +235,10 @@ static int json_get_utf8_char_len(unsigned char ch) {
|
|||
|
||||
/* string = '"' { quoted_printable_chars } '"' */
|
||||
static int json_parse_string(struct frozen *f) {
|
||||
int n, ch = 0, len = 0;
|
||||
int ch = 0;
|
||||
TRY(json_test_and_skip(f, '"'));
|
||||
{
|
||||
int len = 0;
|
||||
SET_STATE(f, f->cur, "", 0);
|
||||
for (; f->cur < f->end; f->cur += len) {
|
||||
ch = *(unsigned char *) f->cur;
|
||||
|
@ -245,6 +246,7 @@ static int json_parse_string(struct frozen *f) {
|
|||
EXPECT(ch >= 32 && len > 0, JSON_STRING_INVALID); /* No control chars */
|
||||
EXPECT(len <= json_left(f), JSON_STRING_INCOMPLETE);
|
||||
if (ch == '\\') {
|
||||
int n;
|
||||
EXPECT((n = json_get_escape_len(f->cur + 1, json_left(f))) > 0, n);
|
||||
len += n;
|
||||
} else if (ch == '"') {
|
||||
|
@ -295,17 +297,17 @@ static int json_parse_number(struct frozen *f) {
|
|||
#if JSON_ENABLE_ARRAY
|
||||
/* array = '[' [ value { ',' value } ] ']' */
|
||||
static int json_parse_array(struct frozen *f) {
|
||||
int i = 0, current_path_len;
|
||||
char buf[20];
|
||||
CALL_BACK(f, JSON_TYPE_ARRAY_START, NULL, 0);
|
||||
TRY(json_test_and_skip(f, '['));
|
||||
{
|
||||
{
|
||||
int i = 0;
|
||||
SET_STATE(f, f->cur - 1, "", 0);
|
||||
while (json_cur(f) != ']') {
|
||||
char buf[20];
|
||||
snprintf(buf, sizeof(buf), "[%d]", i);
|
||||
i++;
|
||||
current_path_len = json_append_to_path(f, buf, strlen(buf));
|
||||
int current_path_len = json_append_to_path(f, buf, strlen(buf));
|
||||
f->cur_name =
|
||||
f->path + strlen(f->path) - strlen(buf) + 1 /*opening brace*/;
|
||||
f->cur_name_len = strlen(buf) - 2 /*braces*/;
|
||||
|
@ -1427,9 +1429,12 @@ static void json_next_cb(void *userdata, const char *name, size_t name_len,
|
|||
|
||||
static void *json_next(const char *s, int len, void *handle, const char *path,
|
||||
struct json_token *key, struct json_token *val, int *i) {
|
||||
struct json_token tmpval, *v = val == NULL ? &tmpval : val;
|
||||
struct json_token tmpkey, *k = key == NULL ? &tmpkey : key;
|
||||
int tmpidx, *pidx = i == NULL ? &tmpidx : i;
|
||||
struct json_token tmpval;
|
||||
struct json_token *v = val == NULL ? &tmpval : val;
|
||||
struct json_token tmpkey;
|
||||
struct json_token *k = key == NULL ? &tmpkey : key;
|
||||
int tmpidx;
|
||||
int *pidx = i == NULL ? &tmpidx : i;
|
||||
struct next_data data = {handle, path, (int) strlen(path), 0, k, v, pidx};
|
||||
json_walk(s, len, json_next_cb, &data);
|
||||
return data.found ? data.handle : NULL;
|
||||
|
|
|
@ -1268,7 +1268,6 @@ void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol) {
|
|||
uint8_t rx[HITAG_FRAME_LEN];
|
||||
size_t rxlen = 0;
|
||||
uint8_t tx[HITAG_FRAME_LEN];
|
||||
size_t txlen;
|
||||
int t_wait = HITAG_T_WAIT_MAX;
|
||||
|
||||
|
||||
|
@ -1284,7 +1283,7 @@ void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol) {
|
|||
WDT_HIT();
|
||||
|
||||
//send read request
|
||||
txlen = 0;
|
||||
size_t txlen = 0;
|
||||
uint8_t cmd = 0x0c;
|
||||
txlen = concatbits(tx, txlen, &cmd, 8 - 4, 4);
|
||||
uint8_t addr = pageNum;
|
||||
|
|
|
@ -749,7 +749,7 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
|
|||
}
|
||||
}
|
||||
|
||||
card_ptr->atr_len = (uint8_t) (len & 0xff);
|
||||
card_ptr->atr_len = (uint8_t)(len & 0xff);
|
||||
if (verbose) {
|
||||
LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false);
|
||||
}
|
||||
|
|
|
@ -1258,7 +1258,6 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t *
|
|||
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, shallow_mod);
|
||||
|
@ -1267,7 +1266,7 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t *
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -1814,17 +1814,17 @@ int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
static const uint8_t x_wup2[] = { 0x5D, 0x37, 0x21, 0x71, 0x71 };
|
||||
uint8_t slot_mark[1];
|
||||
|
||||
uint8_t x_atqb[24] = {0x0}; // ATQB len = 18
|
||||
uint8_t x_atqb[24] = {0x0}; // ATQB len = 18
|
||||
|
||||
uint32_t start_time = 0;
|
||||
uint32_t eof_time = 0;
|
||||
|
||||
iso14b_set_timeout(24); // wait for carrier
|
||||
iso14b_set_timeout(24); // wait for carrier
|
||||
|
||||
// wup1
|
||||
CodeAndTransmit14443bAsReader(x_wup1, sizeof(x_wup1), &start_time, &eof_time, true);
|
||||
|
||||
start_time = eof_time + US_TO_SSP(9000); // 9ms before next cmd
|
||||
start_time = eof_time + US_TO_SSP(9000); // 9ms before next cmd
|
||||
|
||||
// wup2
|
||||
CodeAndTransmit14443bAsReader(x_wup2, sizeof(x_wup2), &start_time, &eof_time, true);
|
||||
|
@ -1836,7 +1836,7 @@ int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
int slot;
|
||||
|
||||
for (slot = 0; slot < 4; slot++) {
|
||||
start_time = eof_time + ETU_TO_SSP(30); //(24); // next slot after 24 ETU
|
||||
start_time = eof_time + ETU_TO_SSP(30); //(24); // next slot after 24 ETU
|
||||
|
||||
retlen = Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time);
|
||||
|
||||
|
@ -1850,14 +1850,14 @@ int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
|
||||
// tx unframed slot-marker
|
||||
|
||||
if (Demod.posCount) { // no rx, but subcarrier burst detected
|
||||
if (Demod.posCount) { // no rx, but subcarrier burst detected
|
||||
uid |= (uint64_t)slot << uid_pos;
|
||||
|
||||
slot_mark[0] = 0xB1 + (slot << 1); // ack slot
|
||||
slot_mark[0] = 0xB1 + (slot << 1); // ack slot
|
||||
CodeAndTransmit14443bAsReader(slot_mark, sizeof(slot_mark), &start_time, &eof_time, false);
|
||||
break;
|
||||
} else { // no subcarrier burst
|
||||
slot_mark[0] = 0xA1 + (slot << 1); // nak slot
|
||||
} else { // no subcarrier burst
|
||||
slot_mark[0] = 0xA1 + (slot << 1); // nak slot
|
||||
CodeAndTransmit14443bAsReader(slot_mark, sizeof(slot_mark), &start_time, &eof_time, false);
|
||||
}
|
||||
}
|
||||
|
@ -1884,7 +1884,7 @@ int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
}
|
||||
|
||||
// VALIDATE CRC
|
||||
if (check_crc(CRC_14443_B, x_atqb, 18) == false) { // use fixed len because unstable EOF catch
|
||||
if (check_crc(CRC_14443_B, x_atqb, 18) == false) { // use fixed len because unstable EOF catch
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
|
|
@ -2356,7 +2356,7 @@ void MifareCIdent(bool is_mfc) {
|
|||
uint8_t rats[4] = { ISO14443A_CMD_RATS, 0x80, 0x31, 0x73 };
|
||||
uint8_t rdblf0[4] = { ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f};
|
||||
uint8_t rdbl00[4] = { ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa8};
|
||||
uint8_t gen4GetConf[8] = { GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_GETCNF, 0, 0};
|
||||
uint8_t gen4GetConf[8] = { GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_GETCNF, 0, 0};
|
||||
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -48,7 +48,7 @@ INSTALLFW = $(OBJDIR)/bootrom.elf
|
|||
OBJS = $(OBJDIR)/bootrom.s19
|
||||
|
||||
# version_pm3.c should be remade on every compilation
|
||||
version_pm3.c: default_version_pm3.c
|
||||
version_pm3.c: default_version_pm3.c .FORCE
|
||||
$(info [=] GEN $@)
|
||||
$(Q)$(SH) ../tools/mkversion.sh > $@ || $(PERL) ../tools/mkversion.pl > $@ || $(CP) $< $@
|
||||
|
||||
|
@ -82,7 +82,7 @@ uninstall:
|
|||
$(info [@] Uninstalling bootrom from $(DESTDIR)$(PREFIX)...)
|
||||
$(Q)$(INSTALLSUDO) $(RM) $(foreach fw,$(INSTALLFW),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(notdir $(fw)))
|
||||
|
||||
.PHONY: all clean help install showinfo
|
||||
.PHONY: all clean help install showinfo .FORCE
|
||||
help:
|
||||
@echo Multi-OS Makefile, you are running on $(DETECTED_OS)
|
||||
@echo Possible targets:
|
||||
|
|
|
@ -293,9 +293,9 @@ 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/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 +336,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
|
||||
|
|
|
@ -626,6 +626,7 @@ SRCS = mifare/aiddesfire.c \
|
|||
cmdmain.c \
|
||||
cmdnfc.c \
|
||||
cmdparser.c \
|
||||
cmdpiv.c \
|
||||
cmdscript.c \
|
||||
cmdsmartcard.c \
|
||||
cmdtrace.c \
|
||||
|
|
|
@ -530,7 +530,6 @@ stop_tests:
|
|||
bucket_states_tested += bucket_size[block_idx];
|
||||
// prepare to set new states
|
||||
state_p = &states[KEYSTREAM_SIZE];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
|
|
@ -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,11 @@ 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/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 +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
|
||||
|
|
|
@ -62,7 +62,7 @@ function main(args)
|
|||
|
||||
local i
|
||||
local cmds = {}
|
||||
--check for params
|
||||
--check for params
|
||||
for o, a in getopt.getopt(args, 'h') do
|
||||
if o == 'h' then return help() end
|
||||
end
|
||||
|
|
|
@ -23,7 +23,7 @@ author = 'Shain Lakin'
|
|||
version = 'v1.0.0'
|
||||
desc =[[
|
||||
|
||||
This script can be used to read blocks, write blocks, dump sectors,
|
||||
This script can be used to read blocks, write blocks, dump sectors,
|
||||
or write a files hex bytes to sector 0 or 1 on the NTAG I2C PLUS 2K tag.
|
||||
|
||||
]]
|
||||
|
@ -32,7 +32,7 @@ example =[[
|
|||
|
||||
Read block 04 from sector 1:
|
||||
script run hf_i2c_plus_2k_utils -m r -s 1 -b 04
|
||||
|
||||
|
||||
Write FFFFFFFF to block A0 sector 1:
|
||||
script run hf_i2c_plus_2k_utils -m w -s 1 -b A0 -d FFFFFFFF
|
||||
|
||||
|
@ -45,15 +45,15 @@ example =[[
|
|||
]]
|
||||
usage = [[
|
||||
|
||||
Read mode:
|
||||
Read mode:
|
||||
script run hf_i2c_plus_2k_utils -m r -s <sector> -b <block (hex)>
|
||||
|
||||
Write mode:
|
||||
|
||||
Write mode:
|
||||
script run hf_i2c_plus_2k_utils -m w -s <sector> -b <block (hex)> -d <data (hex)>
|
||||
|
||||
|
||||
Dump mode:
|
||||
script run hf_i2c_plus_2k_utils -m d -s <sector>
|
||||
|
||||
|
||||
File mode:
|
||||
script run hf_i2c_plus_2k_utils -m f -s <sector> -f <file>
|
||||
|
||||
|
@ -124,7 +124,7 @@ end
|
|||
---
|
||||
|
||||
|
||||
--- Function to connect
|
||||
--- Function to connect
|
||||
local function connect()
|
||||
core.clearCommandBuffer()
|
||||
|
||||
|
@ -189,7 +189,7 @@ local function filewriter(file,sector)
|
|||
end_char = 8
|
||||
block_counter = 4
|
||||
-- NTAG_I2C_PLUS_2K:SECTOR_0:225,SECTOR_1:255
|
||||
end_block = 225
|
||||
end_block = 225
|
||||
connect()
|
||||
select_sector(sector)
|
||||
for count = 1, len do
|
||||
|
@ -296,7 +296,7 @@ local function main(args)
|
|||
elseif mode == 'd' then
|
||||
dump(sector,uid)
|
||||
end
|
||||
|
||||
|
||||
else
|
||||
return print(usage)
|
||||
end
|
||||
|
|
|
@ -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
|
|
@ -63,8 +63,8 @@ local function card_format(key_a,key_b,ab,user,s70)
|
|||
core.console(cmd)
|
||||
print(cmd)
|
||||
core.clearCommandBuffer()
|
||||
if s70 == false and k > 15 then
|
||||
return
|
||||
if s70 == false and k > 15 then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -109,8 +109,8 @@ local function main(args)
|
|||
command = 'hf 14a sim -t 1 -u ' .. uid_format
|
||||
msg('Bruteforcing Mifare Classic card numbers')
|
||||
elseif mftype == 'mfc4' then
|
||||
command = 'hf 14a sim -t 8 -u ' .. uid_format
|
||||
msg('Bruteforcing Mifare Classic 4K card numbers')
|
||||
command = 'hf 14a sim -t 8 -u ' .. uid_format
|
||||
msg('Bruteforcing Mifare Classic 4K card numbers')
|
||||
elseif mftype == 'mfu' then
|
||||
command = 'hf 14a sim -t 2 -u ' .. uid_format
|
||||
msg('Bruteforcing Mifare Ultralight card numbers')
|
||||
|
|
|
@ -50,17 +50,17 @@ arguments = [[
|
|||
-c read magic configuration
|
||||
-u UID (8-14 hexsymbols), set UID on tag
|
||||
-t tag type to impersonate
|
||||
1 = Mifare Mini S20 4-byte 12 = NTAG 210
|
||||
2 = Mifare Mini S20 7-byte 13 = NTAG 212
|
||||
3 = Mifare 1k S50 4-byte 14 = NTAG 213
|
||||
4 = Mifare 1k S50 7-byte 15 = NTAG 215
|
||||
5 = Mifare 4k S70 4-byte 16 = NTAG 216
|
||||
6 = Mifare 4k S70 7-byte 17 = NTAG I2C 1K
|
||||
*** 7 = UL - NOT WORKING FULLY 18 = NTAG I2C 2K
|
||||
*** 8 = UL-C - NOT WORKING FULLY 19 = NTAG I2C 1K PLUS
|
||||
9 = UL EV1 48b 20 = NTAG I2C 2K PLUS
|
||||
10 = UL EV1 128b 21 = NTAG 213F
|
||||
*** 11 = UL Plus - NOT WORKING YET 22 = NTAG 216F
|
||||
1 = Mifare Mini S20 4-byte 12 = NTAG 210
|
||||
2 = Mifare Mini S20 7-byte 13 = NTAG 212
|
||||
3 = Mifare 1k S50 4-byte 14 = NTAG 213
|
||||
4 = Mifare 1k S50 7-byte 15 = NTAG 215
|
||||
5 = Mifare 4k S70 4-byte 16 = NTAG 216
|
||||
6 = Mifare 4k S70 7-byte 17 = NTAG I2C 1K
|
||||
*** 7 = UL - NOT WORKING FULLY 18 = NTAG I2C 2K
|
||||
*** 8 = UL-C - NOT WORKING FULLY 19 = NTAG I2C 1K PLUS
|
||||
9 = UL EV1 48b 20 = NTAG I2C 2K PLUS
|
||||
10 = UL EV1 128b 21 = NTAG 213F
|
||||
*** 11 = UL Plus - NOT WORKING YET 22 = NTAG 216F
|
||||
|
||||
-p NTAG password (8 hexsymbols), set NTAG password on tag.
|
||||
-a NTAG pack ( 4 hexsymbols), set NTAG pack on tag.
|
||||
|
@ -178,7 +178,7 @@ local function read_config()
|
|||
if not info then return false, "Can't select card" end
|
||||
-- read Ultimate Magic Card CONFIG
|
||||
if magicconfig == nil then
|
||||
magicconfig = send("CF".._key.."C6")
|
||||
magicconfig = send("CF".._key.."C6")
|
||||
else print('No Config')
|
||||
end
|
||||
-- extract data from CONFIG - based on CONFIG in https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md#gen-4-gtu
|
||||
|
@ -196,92 +196,92 @@ local function read_config()
|
|||
else atsstr = (string.sub(ats, 3))
|
||||
end
|
||||
if ulprotocol == '00' then
|
||||
cardprotocol = 'MIFARE Classic Protocol'
|
||||
ultype = 'Disabled'
|
||||
if uidlength == '00' then
|
||||
uid = send("CF".._key.."CE00"):sub(1,8)
|
||||
if atqaf == '00 04' and sak == '09' then cardtype = 'MIFARE Mini S20 4-byte UID'
|
||||
elseif atqaf == '00 04' and sak == '08' then cardtype = 'MIFARE 1k S50 4-byte UID'
|
||||
elseif atqaf == '00 02' and sak == '18' then cardtype = 'MIFARE 4k S70 4-byte UID'
|
||||
end
|
||||
elseif uidlength == '01' then
|
||||
uid = send("CF".._key.."CE00"):sub(1,14)
|
||||
if atqaf == '00 44' and sak == '09' then cardtype = 'MIFARE Mini S20 7-byte UID'
|
||||
elseif atqaf == '00 44' and sak == '08' then cardtype = 'MIFARE 1k S50 7-byte UID'
|
||||
elseif atqaf == '00 42' and sak == '18' then cardtype = 'MIFARE 4k S70 7-byte UID'
|
||||
end
|
||||
end
|
||||
cardprotocol = 'MIFARE Classic Protocol'
|
||||
ultype = 'Disabled'
|
||||
if uidlength == '00' then
|
||||
uid = send("CF".._key.."CE00"):sub(1,8)
|
||||
if atqaf == '00 04' and sak == '09' then cardtype = 'MIFARE Mini S20 4-byte UID'
|
||||
elseif atqaf == '00 04' and sak == '08' then cardtype = 'MIFARE 1k S50 4-byte UID'
|
||||
elseif atqaf == '00 02' and sak == '18' then cardtype = 'MIFARE 4k S70 4-byte UID'
|
||||
end
|
||||
elseif uidlength == '01' then
|
||||
uid = send("CF".._key.."CE00"):sub(1,14)
|
||||
if atqaf == '00 44' and sak == '09' then cardtype = 'MIFARE Mini S20 7-byte UID'
|
||||
elseif atqaf == '00 44' and sak == '08' then cardtype = 'MIFARE 1k S50 7-byte UID'
|
||||
elseif atqaf == '00 42' and sak == '18' then cardtype = 'MIFARE 4k S70 7-byte UID'
|
||||
end
|
||||
end
|
||||
elseif ulprotocol == '01' then
|
||||
-- Read Ultralight config only if UL protocol is enabled
|
||||
cardprotocol = 'MIFARE Ultralight/NTAG'
|
||||
block0 = send("3000")
|
||||
uid0 = block0:sub(1,6)
|
||||
uid = uid0..block0:sub(9,16)
|
||||
if ulmode == '00' then ultype = 'Ultralight EV1'
|
||||
elseif ulmode == '01' then ultype = 'NTAG21x'
|
||||
elseif ulmode == '02' then ultype = 'Ultralight-C'
|
||||
elseif ulmode == '03' then ultype = 'Ultralight'
|
||||
end
|
||||
-- read VERSION
|
||||
cversion = send('30FA'):sub(1,16)
|
||||
-- pwdblock must be set since the 30F1 and 30F2 special commands don't work on the ntag21x part of the UMC
|
||||
if ulmode == '03' then versionstr = 'Ultralight'
|
||||
elseif ulmode == '02' then versionstr = 'Ultralight-C'
|
||||
elseif cversion == '0004030101000B03' then versionstr = 'UL EV1 48b'
|
||||
elseif cversion == '0004030101000E03' then versionstr = 'UL EV1 128b'
|
||||
elseif cversion == '0004040101000B03' then versionstr = 'NTAG 210'
|
||||
elseif cversion == '0004040101000E03' then versionstr = 'NTAG 212'
|
||||
elseif cversion == '0004040201000F03' then versionstr = 'NTAG 213'
|
||||
elseif cversion == '0004040201001103' then versionstr = 'NTAG 215'
|
||||
elseif cversion == '0004040201001303' then versionstr = 'NTAG 216'
|
||||
elseif cversion == '0004040502011303' then versionstr = 'NTAG I2C 1K'
|
||||
elseif cversion == '0004040502011503' then versionstr = 'NTAG I2C 2K'
|
||||
elseif cversion == '0004040502021303' then versionstr = 'NTAG I2C 1K PLUS'
|
||||
elseif cversion == '0004040502021503' then versionstr = 'NTAG I2C 2K PLUS'
|
||||
elseif cversion == '0004040401000F03' then versionstr = 'NTAG 213F'
|
||||
elseif cversion == '0004040401001303' then versionstr = 'NTAG 216F'
|
||||
end
|
||||
-- read PWD
|
||||
cpwd = send("30F0"):sub(1,8)
|
||||
pwd = send("30E5"):sub(1,8)
|
||||
-- 04 response indicates that blocks has been locked down.
|
||||
if pwd == '04' then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end
|
||||
-- read PACK
|
||||
cpack = send("30F1"):sub(1,4)
|
||||
pack = send("30E6"):sub(1,4)
|
||||
-- read SIGNATURE
|
||||
signature1 = send('30F2'):sub(1,32)
|
||||
signature2 = send('30F6'):sub(1,32)
|
||||
lib14a.disconnect()
|
||||
-- Read Ultralight config only if UL protocol is enabled
|
||||
cardprotocol = 'MIFARE Ultralight/NTAG'
|
||||
block0 = send("3000")
|
||||
uid0 = block0:sub(1,6)
|
||||
uid = uid0..block0:sub(9,16)
|
||||
if ulmode == '00' then ultype = 'Ultralight EV1'
|
||||
elseif ulmode == '01' then ultype = 'NTAG21x'
|
||||
elseif ulmode == '02' then ultype = 'Ultralight-C'
|
||||
elseif ulmode == '03' then ultype = 'Ultralight'
|
||||
end
|
||||
-- read VERSION
|
||||
cversion = send('30FA'):sub(1,16)
|
||||
-- pwdblock must be set since the 30F1 and 30F2 special commands don't work on the ntag21x part of the UMC
|
||||
if ulmode == '03' then versionstr = 'Ultralight'
|
||||
elseif ulmode == '02' then versionstr = 'Ultralight-C'
|
||||
elseif cversion == '0004030101000B03' then versionstr = 'UL EV1 48b'
|
||||
elseif cversion == '0004030101000E03' then versionstr = 'UL EV1 128b'
|
||||
elseif cversion == '0004040101000B03' then versionstr = 'NTAG 210'
|
||||
elseif cversion == '0004040101000E03' then versionstr = 'NTAG 212'
|
||||
elseif cversion == '0004040201000F03' then versionstr = 'NTAG 213'
|
||||
elseif cversion == '0004040201001103' then versionstr = 'NTAG 215'
|
||||
elseif cversion == '0004040201001303' then versionstr = 'NTAG 216'
|
||||
elseif cversion == '0004040502011303' then versionstr = 'NTAG I2C 1K'
|
||||
elseif cversion == '0004040502011503' then versionstr = 'NTAG I2C 2K'
|
||||
elseif cversion == '0004040502021303' then versionstr = 'NTAG I2C 1K PLUS'
|
||||
elseif cversion == '0004040502021503' then versionstr = 'NTAG I2C 2K PLUS'
|
||||
elseif cversion == '0004040401000F03' then versionstr = 'NTAG 213F'
|
||||
elseif cversion == '0004040401001303' then versionstr = 'NTAG 216F'
|
||||
end
|
||||
-- read PWD
|
||||
cpwd = send("30F0"):sub(1,8)
|
||||
pwd = send("30E5"):sub(1,8)
|
||||
-- 04 response indicates that blocks has been locked down.
|
||||
if pwd == '04' then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end
|
||||
-- read PACK
|
||||
cpack = send("30F1"):sub(1,4)
|
||||
pack = send("30E6"):sub(1,4)
|
||||
-- read SIGNATURE
|
||||
signature1 = send('30F2'):sub(1,32)
|
||||
signature2 = send('30F6'):sub(1,32)
|
||||
lib14a.disconnect()
|
||||
end
|
||||
if _print < 1 then
|
||||
print(string.rep('=', 88))
|
||||
print('\t\t\tUltimate Magic Card Configuration')
|
||||
print(string.rep('=', 88))
|
||||
print(' - Raw Config ', string.sub(magicconfig, 1, -9))
|
||||
print(' - Card Protocol ', cardprotocol)
|
||||
print(' - Ultralight Mode ', ultype)
|
||||
print(' - ULM Backdoor Key ', readpass)
|
||||
print(' - GTU Mode ', gtustr)
|
||||
if ulprotocol == '01' then
|
||||
print(' - Card Type ', versionstr)
|
||||
else
|
||||
print(' - Card Type ', cardtype)
|
||||
end
|
||||
print(' - UID ', uid)
|
||||
print(' - ATQA ', atqaf)
|
||||
print(' - SAK ', sak)
|
||||
if ulprotocol == '01' then
|
||||
print('')
|
||||
print(string.rep('=', 88))
|
||||
print('\t\t\tMagic UL/NTAG 21* Configuration')
|
||||
print(string.rep('=', 88))
|
||||
print(' - ATS ', atsstr)
|
||||
print(' - Password ', '[0xE5] '..pwd, '[0xF0] '..cpwd)
|
||||
print(' - Pack ', '[0xE6] '..pack, '[0xF1] '..cpack)
|
||||
print(' - Version ', cversion)
|
||||
print(' - Signature ', signature1..signature2)
|
||||
end
|
||||
print(string.rep('=', 88))
|
||||
print('\t\t\tUltimate Magic Card Configuration')
|
||||
print(string.rep('=', 88))
|
||||
print(' - Raw Config ', string.sub(magicconfig, 1, -9))
|
||||
print(' - Card Protocol ', cardprotocol)
|
||||
print(' - Ultralight Mode ', ultype)
|
||||
print(' - ULM Backdoor Key ', readpass)
|
||||
print(' - GTU Mode ', gtustr)
|
||||
if ulprotocol == '01' then
|
||||
print(' - Card Type ', versionstr)
|
||||
else
|
||||
print(' - Card Type ', cardtype)
|
||||
end
|
||||
print(' - UID ', uid)
|
||||
print(' - ATQA ', atqaf)
|
||||
print(' - SAK ', sak)
|
||||
if ulprotocol == '01' then
|
||||
print('')
|
||||
print(string.rep('=', 88))
|
||||
print('\t\t\tMagic UL/NTAG 21* Configuration')
|
||||
print(string.rep('=', 88))
|
||||
print(' - ATS ', atsstr)
|
||||
print(' - Password ', '[0xE5] '..pwd, '[0xF0] '..cpwd)
|
||||
print(' - Pack ', '[0xE6] '..pack, '[0xF1] '..cpack)
|
||||
print(' - Version ', cversion)
|
||||
print(' - Signature ', signature1..signature2)
|
||||
end
|
||||
end
|
||||
lib14a.disconnect()
|
||||
return true, 'Ok'
|
||||
|
@ -291,41 +291,41 @@ end
|
|||
local function write_uid(useruid)
|
||||
-- read CONFIG
|
||||
if not magicconfig then
|
||||
_print = 1
|
||||
read_config()
|
||||
_print = 1
|
||||
read_config()
|
||||
end
|
||||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
-- Writes a MFC UID with GEN4 magic commands.
|
||||
if ulprotocol == '00' then
|
||||
-- uid string checks
|
||||
if useruid == nil then return nil, 'empty uid string' end
|
||||
if #useruid == 0 then return nil, 'empty uid string' end
|
||||
if (#useruid ~= 8) and (#useruid ~= 14) then return nil, 'UID wrong length. Should be 4 or 7 hex bytes' end
|
||||
print('Writing new UID ', useruid)
|
||||
local uidbytes = utils.ConvertHexToBytes(useruid)
|
||||
local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), uidbytes[4])
|
||||
local block0 = string.format('%02X%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], uidbytes[4], bcc1)
|
||||
local resp = send('CF'.._key..'CD00'..block0)
|
||||
-- uid string checks
|
||||
if useruid == nil then return nil, 'empty uid string' end
|
||||
if #useruid == 0 then return nil, 'empty uid string' end
|
||||
if (#useruid ~= 8) and (#useruid ~= 14) then return nil, 'UID wrong length. Should be 4 or 7 hex bytes' end
|
||||
print('Writing new UID ', useruid)
|
||||
local uidbytes = utils.ConvertHexToBytes(useruid)
|
||||
local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), uidbytes[4])
|
||||
local block0 = string.format('%02X%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], uidbytes[4], bcc1)
|
||||
local resp = send('CF'.._key..'CD00'..block0)
|
||||
-- Writes a MFUL UID with bcc1, bcc2 using NTAG21xx commands.
|
||||
elseif ulprotocol == '01' then
|
||||
-- uid string checks
|
||||
if useruid == nil then return nil, 'empty uid string' end
|
||||
if #useruid == 0 then return nil, 'empty uid string' end
|
||||
if #useruid ~= 14 then return nil, 'uid wrong length. Should be 7 hex bytes' end
|
||||
print('Writing new UID ', useruid)
|
||||
local uidbytes = utils.ConvertHexToBytes(useruid)
|
||||
local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), 0x88)
|
||||
local bcc2 = bxor(bxor(bxor(uidbytes[4], uidbytes[5]), uidbytes[6]), uidbytes[7])
|
||||
local block0 = string.format('%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], bcc1)
|
||||
local block1 = string.format('%02X%02X%02X%02X', uidbytes[4], uidbytes[5], uidbytes[6], uidbytes[7])
|
||||
local block2 = string.format('%02X%02X%02X%02X', bcc2, 0x48, 0x00, 0x00)
|
||||
local resp
|
||||
resp = send('A200'..block0)
|
||||
resp = send('A201'..block1)
|
||||
resp = send('A202'..block2)
|
||||
-- uid string checks
|
||||
if useruid == nil then return nil, 'empty uid string' end
|
||||
if #useruid == 0 then return nil, 'empty uid string' end
|
||||
if #useruid ~= 14 then return nil, 'uid wrong length. Should be 7 hex bytes' end
|
||||
print('Writing new UID ', useruid)
|
||||
local uidbytes = utils.ConvertHexToBytes(useruid)
|
||||
local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), 0x88)
|
||||
local bcc2 = bxor(bxor(bxor(uidbytes[4], uidbytes[5]), uidbytes[6]), uidbytes[7])
|
||||
local block0 = string.format('%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], bcc1)
|
||||
local block1 = string.format('%02X%02X%02X%02X', uidbytes[4], uidbytes[5], uidbytes[6], uidbytes[7])
|
||||
local block2 = string.format('%02X%02X%02X%02X', bcc2, 0x48, 0x00, 0x00)
|
||||
local resp
|
||||
resp = send('A200'..block0)
|
||||
resp = send('A201'..block1)
|
||||
resp = send('A202'..block2)
|
||||
else
|
||||
print('Incorrect ul')
|
||||
print('Incorrect ul')
|
||||
end
|
||||
lib14a.disconnect()
|
||||
if resp ~= nil then
|
||||
|
@ -339,8 +339,8 @@ end
|
|||
local function write_atqasak(atqasak)
|
||||
-- read CONFIG
|
||||
if not magicconfig then
|
||||
_print = 1
|
||||
read_config()
|
||||
_print = 1
|
||||
read_config()
|
||||
end
|
||||
if atqasak == nil then return nil, 'Empty ATQA/SAK string' end
|
||||
if #atqasak == 0 then return nil, 'Empty ATQA/SAK string' end
|
||||
|
@ -350,25 +350,25 @@ end
|
|||
local atqauserf = atqauser2..atqauser1
|
||||
local sakuser = atqasak:sub(5,6)
|
||||
if sakuser == '04' then
|
||||
print('Never set SAK bit 3 (e.g. SAK=04), it indicates an extra cascade level is required')
|
||||
return nil
|
||||
print('Never set SAK bit 3 (e.g. SAK=04), it indicates an extra cascade level is required')
|
||||
return nil
|
||||
elseif (sakuser == '20' or sakuser == '28') and atslen == '00' then
|
||||
print('When SAK equals 20 or 28, ATS must be turned on')
|
||||
return nil
|
||||
print('When SAK equals 20 or 28, ATS must be turned on')
|
||||
return nil
|
||||
elseif atqauser2 == '40' then
|
||||
print('ATQA of [00 40] will cause the card to not answer.')
|
||||
return nil
|
||||
print('ATQA of [00 40] will cause the card to not answer.')
|
||||
return nil
|
||||
else
|
||||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
print('New ATQA: '..atqauser1..' '..atqauser2..' New SAK: '..sakuser)
|
||||
local resp = send("CF".._key.."35"..atqauserf..sakuser)
|
||||
lib14a.disconnect()
|
||||
if resp == nil then
|
||||
return nil, oops('Failed to write ATQA/SAK')
|
||||
else
|
||||
return true, 'Ok'
|
||||
end
|
||||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
print('New ATQA: '..atqauser1..' '..atqauser2..' New SAK: '..sakuser)
|
||||
local resp = send("CF".._key.."35"..atqauserf..sakuser)
|
||||
lib14a.disconnect()
|
||||
if resp == nil then
|
||||
return nil, oops('Failed to write ATQA/SAK')
|
||||
else
|
||||
return true, 'Ok'
|
||||
end
|
||||
end
|
||||
end
|
||||
---
|
||||
|
@ -376,8 +376,8 @@ end
|
|||
local function write_ntagpwd(ntagpwd)
|
||||
-- read CONFIG
|
||||
if not magicconfig then
|
||||
_print = 1
|
||||
read_config()
|
||||
_print = 1
|
||||
read_config()
|
||||
end
|
||||
if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end
|
||||
-- PWD string checks
|
||||
|
@ -401,8 +401,8 @@ end
|
|||
local function write_pack(userpack)
|
||||
-- read CONFIG
|
||||
if not magicconfig then
|
||||
_print = 1
|
||||
read_config()
|
||||
_print = 1
|
||||
read_config()
|
||||
end
|
||||
if ulprotocol == 0 then return nil, 'Magic Card is not using the Ultralight Protocol' end
|
||||
-- PACK string checks
|
||||
|
@ -426,8 +426,8 @@ local function write_otp(block3)
|
|||
if #block3 ~= 8 then return nil, 'OTP wrong length. Should be 4 hex bytes' end
|
||||
-- read CONFIG
|
||||
if not magicconfig then
|
||||
_print = 1
|
||||
read_config()
|
||||
_print = 1
|
||||
read_config()
|
||||
end
|
||||
if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end
|
||||
local info = connect()
|
||||
|
@ -450,8 +450,8 @@ local function write_version(data)
|
|||
if #data ~= 16 then return nil, 'version wrong length. Should be 8 hex bytes' end
|
||||
-- read CONFIG
|
||||
if not magicconfig then
|
||||
_print = 1
|
||||
read_config()
|
||||
_print = 1
|
||||
read_config()
|
||||
end
|
||||
if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end
|
||||
print('Writing new version', data)
|
||||
|
@ -478,8 +478,8 @@ local function write_signature(data)
|
|||
if #data ~= 64 then return nil, 'data wrong length. Should be 32 hex bytes' end
|
||||
-- read CONFIG
|
||||
if not magicconfig then
|
||||
_print = 1
|
||||
read_config()
|
||||
_print = 1
|
||||
read_config()
|
||||
end
|
||||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
|
@ -508,19 +508,19 @@ local function write_gtu(gtu)
|
|||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
if gtu == '00' then
|
||||
print('Enabling GTU Pre-Write')
|
||||
send('CF'.._key..'32'..gtu)
|
||||
print('Enabling GTU Pre-Write')
|
||||
send('CF'.._key..'32'..gtu)
|
||||
elseif gtu == '01' then
|
||||
print('Enabling GTU Restore Mode')
|
||||
send('CF'.._key..'32'..gtu)
|
||||
print('Enabling GTU Restore Mode')
|
||||
send('CF'.._key..'32'..gtu)
|
||||
elseif gtu == '02' then
|
||||
print('Disabled GTU')
|
||||
send('CF'.._key..'32'..gtu)
|
||||
print('Disabled GTU')
|
||||
send('CF'.._key..'32'..gtu)
|
||||
elseif gtu == '03' then
|
||||
print('Disabled GTU, high speed R/W mode for Ultralight')
|
||||
send('CF'.._key..'32'..gtu)
|
||||
print('Disabled GTU, high speed R/W mode for Ultralight')
|
||||
send('CF'.._key..'32'..gtu)
|
||||
else
|
||||
print('Failed to set GTU mode')
|
||||
print('Failed to set GTU mode')
|
||||
end
|
||||
lib14a.disconnect()
|
||||
return true, 'Ok'
|
||||
|
@ -536,13 +536,13 @@ local function write_ats(atsuser)
|
|||
local atscardlendecimal = tonumber(atscardlen, 16)
|
||||
local atsf = string.sub(atsuser, 3)
|
||||
if (#atsf / 2) ~= atscardlendecimal then
|
||||
oops('Given length of ATS ('..atscardlendecimal..') does not match the ATS_length ('..(#atsf / 2)..')')
|
||||
return true, 'Ok'
|
||||
oops('Given length of ATS ('..atscardlendecimal..') does not match the ATS_length ('..(#atsf / 2)..')')
|
||||
return true, 'Ok'
|
||||
else
|
||||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
print('Writing '..atscardlendecimal..' ATS bytes of '..atsf)
|
||||
send("CF".._key.."34"..atsuser)
|
||||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
print('Writing '..atscardlendecimal..' ATS bytes of '..atsf)
|
||||
send("CF".._key.."34"..atsuser)
|
||||
end
|
||||
lib14a.disconnect()
|
||||
return true, 'Ok'
|
||||
|
@ -556,11 +556,11 @@ local function write_ulp(ulp)
|
|||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
if ulp == '00' then
|
||||
print('Changing card to Mifare Classic Protocol')
|
||||
send("CF".._key.."69"..ulp)
|
||||
print('Changing card to Mifare Classic Protocol')
|
||||
send("CF".._key.."69"..ulp)
|
||||
elseif ulp == '01' then
|
||||
print('Changing card to Ultralight Protocol')
|
||||
send("CF".._key.."69"..ulp)
|
||||
print('Changing card to Ultralight Protocol')
|
||||
send("CF".._key.."69"..ulp)
|
||||
else
|
||||
oops('Protocol needs to be either 00 or 01')
|
||||
end
|
||||
|
@ -576,17 +576,17 @@ local function write_ulm(ulm)
|
|||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
if ulm == '00' then
|
||||
print('Changing card UL mode to Ultralight EV1')
|
||||
send("CF".._key.."6A"..ulm)
|
||||
print('Changing card UL mode to Ultralight EV1')
|
||||
send("CF".._key.."6A"..ulm)
|
||||
elseif ulm == '01' then
|
||||
print('Changing card UL mode to NTAG')
|
||||
send("CF".._key.."6A"..ulm)
|
||||
print('Changing card UL mode to NTAG')
|
||||
send("CF".._key.."6A"..ulm)
|
||||
elseif ulm == '02' then
|
||||
print('Changing card UL mode to Ultralight-C')
|
||||
send("CF".._key.."6A"..ulm)
|
||||
print('Changing card UL mode to Ultralight-C')
|
||||
send("CF".._key.."6A"..ulm)
|
||||
elseif ulm == '03' then
|
||||
print('Changing card UL mode to Ultralight')
|
||||
send("CF".._key.."6A"..ulm)
|
||||
print('Changing card UL mode to Ultralight')
|
||||
send("CF".._key.."6A"..ulm)
|
||||
else
|
||||
oops('UL mode needs to be either 00, 01, 02, 03')
|
||||
end
|
||||
|
@ -603,50 +603,50 @@ local function set_type(tagtype)
|
|||
if tagtype == 1 then
|
||||
print('Setting: Ultimate Magic card to Mifare mini S20 4-byte')
|
||||
connect()
|
||||
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000900")
|
||||
lib14a.disconnect()
|
||||
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000900")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233')
|
||||
-- Setting Mifare mini S20 7-byte
|
||||
elseif tagtype == 2 then
|
||||
print('Setting: Ultimate Magic card to Mifare mini S20 7-byte')
|
||||
connect()
|
||||
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000900")
|
||||
lib14a.disconnect()
|
||||
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000900")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
-- Setting Mifare 1k S50 4--byte
|
||||
elseif tagtype == 3 then
|
||||
print('Setting: Ultimate Magic card to Mifare 1k S50 4-byte')
|
||||
connect()
|
||||
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800")
|
||||
lib14a.disconnect()
|
||||
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233')
|
||||
-- Setting Mifare 1k S50 7-byte
|
||||
elseif tagtype == 4 then
|
||||
print('Setting: Ultimate Magic card to Mifare 1k S50 7-byte')
|
||||
connect()
|
||||
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000800")
|
||||
lib14a.disconnect()
|
||||
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000800")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
-- Setting Mifare 4k S70 4-byte
|
||||
elseif tagtype == 5 then
|
||||
print('Setting: Ultimate Magic card to Mifare 4k S70 4-byte')
|
||||
connect()
|
||||
send("CF".._key.."F000000000000002000978009102DABC19101011121314151602001800")
|
||||
lib14a.disconnect()
|
||||
send("CF".._key.."F000000000000002000978009102DABC19101011121314151602001800")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233')
|
||||
-- Setting Mifare 4k S70 7-byte
|
||||
elseif tagtype == 6 then
|
||||
print('Setting: Ultimate Magic card to Mifare 4k S70 7-byte')
|
||||
connect()
|
||||
send("CF".._key.."F000010000000002000978009102DABC19101011121314151642001800")
|
||||
lib14a.disconnect()
|
||||
send("CF".._key.."F000010000000002000978009102DABC19101011121314151642001800")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
-- Setting UL
|
||||
elseif tagtype == 7 then
|
||||
print('Setting: Ultimate Magic card to UL')
|
||||
connect()
|
||||
send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000003")
|
||||
lib14a.disconnect()
|
||||
send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000003")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_otp('00000000') -- Setting OTP to default 00 00 00 00
|
||||
write_version('0000000000000000') -- UL-C does not have a version
|
||||
|
@ -654,48 +654,48 @@ local function set_type(tagtype)
|
|||
elseif tagtype == 8 then
|
||||
print('Setting: Ultimate Magic card to UL-C')
|
||||
connect()
|
||||
send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000002")
|
||||
print('Setting default permissions and 3des key')
|
||||
send('A22A30000000') -- Auth0 page 48/0x30 and above need authentication
|
||||
send('A22B80000000') -- Auth1 read and write access restricted
|
||||
send('A22C42524541') -- Default 3des key
|
||||
send('A22D4B4D4549')
|
||||
send('A22E46594F55')
|
||||
send('A22F43414E21')
|
||||
lib14a.disconnect()
|
||||
send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000002")
|
||||
print('Setting default permissions and 3des key')
|
||||
send('A22A30000000') -- Auth0 page 48/0x30 and above need authentication
|
||||
send('A22B80000000') -- Auth1 read and write access restricted
|
||||
send('A22C42524541') -- Default 3des key
|
||||
send('A22D4B4D4549')
|
||||
send('A22E46594F55')
|
||||
send('A22F43414E21')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_otp('00000000') -- Setting OTP to default 00 00 00 00
|
||||
write_version('0000000000000000') -- UL-C does not have a version
|
||||
elseif tagtype == 9 then
|
||||
print('Setting: Ultimate Magic card to UL-EV1 48')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000")
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000")
|
||||
-- Setting UL-Ev1 default config bl 16,17
|
||||
send('a2E5FFFFFFFF') -- A2F0 block does not align correctly to actual pwd block
|
||||
send('a2E6FFFFFFFF') -- A2F1 block does not align correctly to actual pack block
|
||||
send('a2E5FFFFFFFF') -- A2F0 block does not align correctly to actual pwd block
|
||||
send('a2E6FFFFFFFF') -- A2F1 block does not align correctly to actual pack block
|
||||
send('a210000000FF')
|
||||
send('a21100050000')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_otp('00000000') -- Setting OTP to default 00 00 00 00
|
||||
write_version('0004030101000b03') -- UL-EV1 (48) 00 04 03 01 01 00 0b 03
|
||||
elseif tagtype == 10 then
|
||||
print('Setting: Ultimate Magic card to UL-EV1 128')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000")
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000")
|
||||
-- Setting UL-Ev1 default config bl 37,38
|
||||
send('a2E5FFFFFFFF') -- A2F0 block does not align correctly to actual pwd block
|
||||
send('a2E6FFFFFFFF') -- A2F1 block does not align correctly to actual pack block
|
||||
send('a2E5FFFFFFFF') -- A2F0 block does not align correctly to actual pwd block
|
||||
send('a2E6FFFFFFFF') -- A2F1 block does not align correctly to actual pack block
|
||||
send('a225000000FF')
|
||||
send('a22600050000')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_otp('00000000') -- Setting OTP to default 00 00 00 00
|
||||
write_version('0004030101000e03') -- UL-EV1 (128) 00 04 03 01 01 00 0e 03
|
||||
elseif tagtype == 12 then
|
||||
print('Setting: Ultimate Magic card to NTAG 210')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
-- Setting NTAG210 default CC block456
|
||||
send('a203e1100600')
|
||||
send('a2040300fe00')
|
||||
|
@ -703,13 +703,13 @@ local function set_type(tagtype)
|
|||
-- Setting cfg1/cfg2
|
||||
send('a210000000FF')
|
||||
send('a21100050000')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_version('0004040101000b03') -- NTAG210 00 04 04 01 01 00 0b 03
|
||||
elseif tagtype == 13 then
|
||||
print('Setting: Ultimate Magic card to NTAG 212')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
-- Setting NTAG212 default CC block456
|
||||
send('a203e1101000')
|
||||
send('a2040103900a')
|
||||
|
@ -717,13 +717,13 @@ local function set_type(tagtype)
|
|||
-- Setting cfg1/cfg2
|
||||
send('a225000000FF')
|
||||
send('a22600050000')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_version('0004040101000E03') -- NTAG212 00 04 04 01 01 00 0E 03
|
||||
elseif tagtype == 14 then
|
||||
print('Setting: Ultimate Magic card to NTAG 213')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
-- Setting NTAG213 default CC block456
|
||||
send('a203e1101200')
|
||||
send('a2040103a00c')
|
||||
|
@ -731,13 +731,13 @@ local function set_type(tagtype)
|
|||
-- setting cfg1/cfg2
|
||||
send('a229000000ff')
|
||||
send('a22a00050000')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_version('0004040201000F03') -- NTAG213 00 04 04 02 01 00 0f 03
|
||||
elseif tagtype == 15 then
|
||||
print('Setting: Ultimate Magic card to NTAG 215')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
-- Setting NTAG215 default CC block456
|
||||
send('a203e1103e00')
|
||||
send('a2040300fe00')
|
||||
|
@ -745,13 +745,13 @@ local function set_type(tagtype)
|
|||
-- setting cfg1/cfg2
|
||||
send('a283000000ff')
|
||||
send('a28400050000')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_version('0004040201001103') -- NTAG215 00 04 04 02 01 00 11 03
|
||||
elseif tagtype == 16 then
|
||||
print('Setting: Ultimate Magic card to NTAG 216')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
-- Setting NTAG216 default CC block456
|
||||
send('a203e1106d00')
|
||||
send('a2040300fe00')
|
||||
|
@ -759,56 +759,56 @@ local function set_type(tagtype)
|
|||
-- setting cfg1/cfg2
|
||||
send('a2e3000000ff')
|
||||
send('a2e400050000')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_version('0004040201001303') -- NTAG216 00 04 04 02 01 00 13 03
|
||||
elseif tagtype == 17 then
|
||||
print('Setting: Ultimate Magic card to NTAG I2C 1K')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
-- Setting NTAG I2C 1K default CC block456
|
||||
send('a203e1106D00')
|
||||
send('a2040300fe00')
|
||||
send('a20500000000')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_version('0004040502011303') -- NTAG_I2C_1K 00 04 04 05 02 01 13 03
|
||||
elseif tagtype == 18 then
|
||||
print('Setting: Ultimate Magic card to NTAG I2C 2K')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
-- Setting NTAG I2C 2K default CC block456
|
||||
send('a203e110EA00')
|
||||
send('a2040300fe00')
|
||||
send('a20500000000')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_version('0004040502011503') -- NTAG_I2C_2K 00 04 04 05 02 01 15 03
|
||||
elseif tagtype == 19 then
|
||||
print('Setting: Ultimate Magic card to NTAG I2C plus 1K')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
-- Setting NTAG I2C 1K default CC block456
|
||||
send('a203e1106D00')
|
||||
send('a2040300fe00')
|
||||
send('a20500000000')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_version('0004040502021303') -- NTAG_I2C_1K 00 04 04 05 02 02 13 03
|
||||
elseif tagtype == 20 then
|
||||
print('Setting: Ultimate Magic card to NTAG I2C plus 2K')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
-- Setting NTAG I2C 2K default CC block456
|
||||
send('a203e1106D00')
|
||||
send('a2040300fe00')
|
||||
send('a20500000000')
|
||||
write_uid('04112233445566')
|
||||
write_uid('04112233445566')
|
||||
write_version('0004040502021503') -- NTAG_I2C_2K 00 04 04 05 02 02 15 03
|
||||
elseif tagtype == 21 then
|
||||
print('Setting: Ultimate Magic card to NTAG 213F')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
-- Setting NTAG213 default CC block456
|
||||
send('a203e1101200')
|
||||
send('a2040103a00c')
|
||||
|
@ -816,13 +816,13 @@ local function set_type(tagtype)
|
|||
-- setting cfg1/cfg2
|
||||
send('a229000000ff')
|
||||
send('a22a00050000')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_version('0004040401000F03') -- NTAG213F 00 04 04 04 01 00 0f 03
|
||||
elseif tagtype == 22 then
|
||||
print('Setting: Ultimate Magic card to NTAG 216F')
|
||||
connect()
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
-- Setting NTAG216 default CC block456
|
||||
send('a203e1106d00')
|
||||
send('a2040300fe00')
|
||||
|
@ -830,11 +830,11 @@ local function set_type(tagtype)
|
|||
-- setting cfg1/cfg2
|
||||
send('a2e3000000ff')
|
||||
send('a2e400050000')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_version('0004040401001303') -- NTAG216F 00 04 04 04 01 00 13 03
|
||||
else
|
||||
oops('No matching tag types')
|
||||
oops('No matching tag types')
|
||||
end
|
||||
lib14a.disconnect()
|
||||
if resp == '04' then
|
||||
|
@ -847,13 +847,13 @@ end
|
|||
-- returns true if b is the index of a sector trailer
|
||||
local function mfIsSectorTrailer(b)
|
||||
n=b+1
|
||||
if (n < 32*4 ) then
|
||||
if (n % 4 == 0) then return true
|
||||
if (n < 32*4 ) then
|
||||
if (n % 4 == 0) then return true
|
||||
else return false
|
||||
end
|
||||
end
|
||||
|
||||
if (n % 16 == 0) then return true
|
||||
if (n % 16 == 0) then return true
|
||||
end
|
||||
|
||||
return false
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -6,20 +6,20 @@ local ansicolors = require('ansicolors')
|
|||
|
||||
copyright = ''
|
||||
author = "Iceman"
|
||||
version = 'v1.0.1'
|
||||
version = 'v1.0.2'
|
||||
desc = [[
|
||||
This script calculates mifare Ultralight-EV1 pwd based on uid diversification for an Italian ticketsystem
|
||||
Algo not found by me.
|
||||
]]
|
||||
example =[[
|
||||
-- if called without, it reads tag uid
|
||||
script run hf_mfu_uidkeycalc-italy
|
||||
script run hf_mfu_uidkeycalc_italy
|
||||
|
||||
--
|
||||
script run hf_mfu_uidkeycalc-italy -u 11223344556677
|
||||
script run hf_mfu_uidkeycalc_italy -u 11223344556677
|
||||
]]
|
||||
usage = [[
|
||||
script run hf_mfu_uidkeycalc-italy -h -u <uid> "
|
||||
script run hf_mfu_uidkeycalc_italy -h -u <uid> "
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
|
@ -6,7 +6,7 @@ local ac = require('ansicolors')
|
|||
|
||||
copyright = ''
|
||||
author = "Christian Herrmann"
|
||||
version = 'v1.0.0'
|
||||
version = 'v1.0.1'
|
||||
desc = [[
|
||||
This script loads a json format file, with the field "data" and a hexbyte array of data. Ie t55x7 dump,
|
||||
it tries to identify which system based on block1, and detect block0 settings.
|
||||
|
@ -16,7 +16,7 @@ example = [[
|
|||
script run lf_ident_json -i lf_t55xx.json
|
||||
]]
|
||||
usage = [[
|
||||
script run lf_en4100_bulk.lua [-h] [-c] [-p password] [-s <start cn>] [-v]
|
||||
script run lf_ident_json.lua [-h] [-c] [-p password] [-s <start cn>] [-v]
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
||||
|
|
|
@ -17,17 +17,17 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cipursecore.h"
|
||||
#include <string.h> // memcpy memset
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "comms.h" // DropField
|
||||
#include "util_posix.h" // msleep
|
||||
#include <string.h> // memcpy memset
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "comms.h" // DropField
|
||||
#include "util_posix.h" // msleep
|
||||
#include "cmdhf14a.h"
|
||||
#include "../emv/emvcore.h"
|
||||
#include "../emv/emvjson.h"
|
||||
#include "../iso7816/apduinfo.h" // sAPDU_t
|
||||
#include "../iso7816/apduinfo.h" // sAPDU_t
|
||||
#include "ui.h"
|
||||
#include "util.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
// context for secure channel
|
||||
CipurseContext_t cipurseContext;
|
||||
|
@ -112,7 +112,7 @@ static int CIPURSEExchangeEx(bool activate_field, bool leave_field_on, sAPDU_t a
|
|||
*sw = isw;
|
||||
}
|
||||
|
||||
if (isw != 0x9000) {
|
||||
if (isw != ISO7816_OK) {
|
||||
if (GetAPDULogging()) {
|
||||
if (*sw >> 8 == 0x61) {
|
||||
PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff);
|
||||
|
@ -255,7 +255,7 @@ bool CIPURSEChannelAuthenticate(uint8_t keyindex, uint8_t *key, bool verbose) {
|
|||
|
||||
// authenticate
|
||||
res = CIPURSEMutualAuthenticate(keyindex, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000 || len != 16) {
|
||||
if (res != 0 || sw != ISO7816_OK || len != 16) {
|
||||
if (sw == 0x6988) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(WARNING, "Authentication ( " _RED_("fail") " ). Wrong key");
|
||||
|
|
|
@ -2242,8 +2242,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 +2380,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 +2574,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 +2674,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 +2688,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 +2714,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 +2729,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 +2763,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 +2780,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 +2819,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 +2887,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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1384,11 +1384,11 @@ static int CmdHF15WriteAfi(const char *Cmd) {
|
|||
// arg0 (datalen, cmd len? .arg0 == crc?)
|
||||
// arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 )
|
||||
// arg2 (recv == 1 == expect a response)
|
||||
uint8_t read_respone = 1;
|
||||
uint8_t read_response = 1;
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_respone, req, reqlen);
|
||||
SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_response, req, reqlen);
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) {
|
||||
PrintAndLogEx(ERR, "iso15693 timeout");
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "util.h"
|
||||
#include "fileutils.h" // laodFileJSONroot
|
||||
#include "crypto/libpcrypto.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
const uint8_t PxSE_AID[] = {0xA0, 0x00, 0x00, 0x05, 0x07, 0x01, 0x00};
|
||||
#define PxSE_AID_LENGTH 7
|
||||
|
@ -104,11 +105,11 @@ static int SelectAndPrintInfoFile(void) {
|
|||
uint16_t sw = 0;
|
||||
|
||||
int res = CIPURSESelectFile(0x2ff7, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
return PM3_EAPDU_FAIL;
|
||||
|
||||
res = CIPURSEReadBinary(0, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
return PM3_EAPDU_FAIL;
|
||||
|
||||
if (len > 0) {
|
||||
|
@ -151,7 +152,7 @@ static int CmdHFCipurseInfo(const char *Cmd) {
|
|||
bool mfExist = false;
|
||||
bool infoPrinted = false;
|
||||
int res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
|
||||
if (res == PM3_SUCCESS && sw == 0x9000) {
|
||||
if (res == PM3_SUCCESS && sw == ISO7816_OK) {
|
||||
mfExist = true;
|
||||
PrintAndLogEx(INFO, _YELLOW_("MasterFile") " exist and can be selected.");
|
||||
|
||||
|
@ -161,7 +162,7 @@ static int CmdHFCipurseInfo(const char *Cmd) {
|
|||
|
||||
for (int i = 0; i < ARRAYLEN(PxSE_AID_LIST); i++) {
|
||||
res = CIPURSESelectAID(false, true, (uint8_t *)PxSE_AID_LIST[i].aid, PxSE_AID_LENGTH, buf, sizeof(buf), &len, &sw);
|
||||
if (res == PM3_SUCCESS && sw == 0x9000) {
|
||||
if (res == PM3_SUCCESS && sw == ISO7816_OK) {
|
||||
mfExist = true;
|
||||
PrintAndLogEx(INFO, _CYAN_("PxSE") " exist: %s", PxSE_AID_LIST[i].name);
|
||||
if (len > 0) {
|
||||
|
@ -179,7 +180,7 @@ static int CmdHFCipurseInfo(const char *Cmd) {
|
|||
}
|
||||
PrintAndLogEx(INFO, "Application `" _YELLOW_("AF F1") "` selected " _GREEN_("successfully"));
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
if (sw == 0x0000) {
|
||||
PrintAndLogEx(ERR, "APDU exchange error. Card returns 0x0000");
|
||||
} else {
|
||||
|
@ -362,7 +363,7 @@ static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, si
|
|||
if (useAID && aidLen > 0) {
|
||||
|
||||
res = CIPURSESelectAID(true, true, aid, aidLen, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (res != 0 || *sw != ISO7816_OK) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(ERR, "Cipurse select application " _GREEN_("%s ") _RED_("error") ". Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), *sw);
|
||||
}
|
||||
|
@ -375,7 +376,7 @@ static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, si
|
|||
} else if (useFID) {
|
||||
|
||||
res = CIPURSESelectFileEx(true, true, fileId, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (res != 0 || *sw != ISO7816_OK) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(ERR, "Cipurse select file 0x%04x ( %s )", fileId, _RED_("fail"));
|
||||
PrintAndLogEx(ERR, "Card returns 0x%04x", *sw);
|
||||
|
@ -389,7 +390,7 @@ static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, si
|
|||
} else if (selectDefaultFile) {
|
||||
|
||||
res = CIPURSESelectMFDefaultFileEx(true, true, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (res != 0 || *sw != ISO7816_OK) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(ERR, "Cipurse select default file " _RED_("error") ". Card returns 0x%04x", *sw);
|
||||
}
|
||||
|
@ -402,7 +403,7 @@ static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, si
|
|||
} else {
|
||||
|
||||
res = CIPURSESelect(true, true, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (res != 0 || *sw != ISO7816_OK) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(ERR, "Cipurse select default application " _RED_("error") ". Card returns 0x%04x", *sw);
|
||||
}
|
||||
|
@ -419,7 +420,7 @@ static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, si
|
|||
}
|
||||
|
||||
res = CIPURSESelectFileEx(false, true, childFileId, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (res != 0 || *sw != ISO7816_OK) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(ERR, "Select child file 0x%04x " _RED_("error") ". Card returns 0x%04x", childFileId, *sw);
|
||||
}
|
||||
|
@ -487,7 +488,7 @@ static int CmdHFCipurseSelect(const char *Cmd) {
|
|||
size_t len = 0;
|
||||
uint16_t sw = 0;
|
||||
res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, true, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -553,7 +554,7 @@ static int CmdHFCipurseAuth(const char *Cmd) {
|
|||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
|
||||
res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, true, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -635,7 +636,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
|||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
|
||||
res = CIPURSESelectAID(true, true, aid, aidLen, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Cipurse select application " _CYAN_("%s") " ( " _RED_("error") " ). Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), sw);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -660,7 +661,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(ERR, "File select ( " _RED_("error") " ). Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
|
@ -671,7 +672,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Select file 0x%x ( %s )", fileId, _GREEN_("ok"));
|
||||
|
||||
res = CIPURSEReadBinary(offset, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
|
@ -758,7 +759,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
|||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
|
||||
res = CIPURSESelectAID(true, true, aid, aidLen, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Cipurse select application " _CYAN_("%s") " ( " _RED_("error") " ). Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), sw);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -789,7 +790,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
|
@ -800,7 +801,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Select file 0x%x ( %s )", fileId, _GREEN_("ok"));
|
||||
|
||||
res = CIPURSEUpdateBinary(offset, hdata, hdatalen, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(ERR, "File write " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
|
@ -812,7 +813,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
|||
if (needCommit) {
|
||||
sw = 0;
|
||||
res = CIPURSECommitTransaction(&sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
|
||||
|
||||
if (verbose)
|
||||
|
@ -883,7 +884,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
|||
uint16_t sw = 0;
|
||||
|
||||
res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, verbose, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -921,7 +922,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
|
@ -1020,7 +1021,7 @@ static int CmdHFCipurseWriteFileAttr(const char *Cmd) {
|
|||
uint16_t sw = 0;
|
||||
|
||||
res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, verbose, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1058,7 +1059,7 @@ static int CmdHFCipurseWriteFileAttr(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSEUpdateFileAttributes(hdata, hdatalen, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(ERR, "File attributes update " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
|
@ -1070,7 +1071,7 @@ static int CmdHFCipurseWriteFileAttr(const char *Cmd) {
|
|||
if (needCommit) {
|
||||
sw = 0;
|
||||
res = CIPURSECommitTransaction(&sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
|
||||
|
||||
if (verbose)
|
||||
|
@ -1125,7 +1126,7 @@ static int CmdHFCipurseFormatAll(const char *Cmd) {
|
|||
uint16_t sw = 0;
|
||||
|
||||
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1154,7 +1155,7 @@ static int CmdHFCipurseFormatAll(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSEFormatAll(&sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Format " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1239,14 +1240,14 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
|
|||
|
||||
if (useAID || useFID || selmfd) {
|
||||
res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1277,7 +1278,7 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSECreateFile(hdata, hdatalen, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Create file command " _RED_("ERROR"));
|
||||
PrintAndLogEx(ERR, "0x%04x - %s", sw,
|
||||
GetSpecificAPDUCodeDesc(SelectAPDUCodeDescriptions, ARRAYLEN(SelectAPDUCodeDescriptions), sw));
|
||||
|
@ -1289,7 +1290,7 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
|
|||
if (needCommit) {
|
||||
sw = 0;
|
||||
res = CIPURSECommitTransaction(&sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
|
||||
|
||||
if (verbose)
|
||||
|
@ -1376,14 +1377,14 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
|||
|
||||
if (useChildFID) {
|
||||
res = SelectCommand(false, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Top level select " _RED_("error") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1405,7 +1406,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
|||
|
||||
if (useChildFID) {
|
||||
res = CIPURSEDeleteFile(childFileId, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Delete child file " _CYAN_("%04x ") " %s", childFileId, _RED_("ERROR"));
|
||||
PrintAndLogEx(ERR, "0x%04x - %s",
|
||||
sw,
|
||||
|
@ -1417,7 +1418,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Child file id " _CYAN_("%04x") " deleted " _GREEN_("succesfully"), childFileId);
|
||||
} else if (useFID) {
|
||||
res = CIPURSEDeleteFile(fileId, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Delete file " _CYAN_("%04x ") " %s", fileId, _RED_("ERROR"));
|
||||
PrintAndLogEx(ERR, "0x%04x - %s",
|
||||
sw,
|
||||
|
@ -1429,7 +1430,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "File id " _CYAN_("%04x") " deleted " _GREEN_("succesfully"), fileId);
|
||||
} else {
|
||||
res = CIPURSEDeleteFileAID(aid, aidLen, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Delete application " _CYAN_("%s ") " %s", sprint_hex_inrow(aid, aidLen), _RED_("ERROR"));
|
||||
PrintAndLogEx(ERR, "0x%04x - %s",
|
||||
sw,
|
||||
|
@ -1444,7 +1445,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
|||
if (needCommit) {
|
||||
sw = 0;
|
||||
res = CIPURSECommitTransaction(&sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
|
||||
|
||||
if (verbose)
|
||||
|
@ -1588,14 +1589,14 @@ static int CmdHFCipurseUpdateKey(const char *Cmd) {
|
|||
|
||||
if (useAID || useFID || selmfd) {
|
||||
res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1626,7 +1627,7 @@ static int CmdHFCipurseUpdateKey(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSEUpdateKey(encKeyId, newKeyId, keydata, sizeof(keydata), buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Update key command " _RED_("ERROR"));
|
||||
PrintAndLogEx(ERR, "0x%04x - %s", sw,
|
||||
GetSpecificAPDUCodeDesc(UAPDpdateKeyCodeDescriptions, ARRAYLEN(UAPDpdateKeyCodeDescriptions), sw));
|
||||
|
@ -1638,7 +1639,7 @@ static int CmdHFCipurseUpdateKey(const char *Cmd) {
|
|||
if (needCommit) {
|
||||
sw = 0;
|
||||
res = CIPURSECommitTransaction(&sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
|
||||
|
||||
if (verbose)
|
||||
|
@ -1736,14 +1737,14 @@ static int CmdHFCipurseUpdateKeyAttr(const char *Cmd) {
|
|||
|
||||
if (useAID || useFID || selmfd) {
|
||||
res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1774,7 +1775,7 @@ static int CmdHFCipurseUpdateKeyAttr(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = CIPURSEUpdateKeyAttrib(trgKeyId, hdata[0], buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (res != 0 || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Update key attributes command " _RED_("ERROR"));
|
||||
PrintAndLogEx(ERR, "0x%04x - %s", sw,
|
||||
GetSpecificAPDUCodeDesc(UAPDpdateKeyAttrCodeDescriptions, ARRAYLEN(UAPDpdateKeyAttrCodeDescriptions), sw));
|
||||
|
@ -1786,7 +1787,7 @@ static int CmdHFCipurseUpdateKeyAttr(const char *Cmd) {
|
|||
if (needCommit) {
|
||||
sw = 0;
|
||||
res = CIPURSECommitTransaction(&sw);
|
||||
if (res != 0 || sw != 0x9000)
|
||||
if (res != 0 || sw != ISO7816_OK)
|
||||
PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
|
||||
|
||||
if (verbose)
|
||||
|
@ -1803,7 +1804,7 @@ bool CheckCardCipurse(void) {
|
|||
uint16_t sw = 0;
|
||||
int res = CIPURSESelect(true, false, buf, sizeof(buf), &len, &sw);
|
||||
|
||||
return (res == 0 && sw == 0x9000);
|
||||
return (res == 0 && sw == ISO7816_OK);
|
||||
}
|
||||
|
||||
static int CmdHFCipurseTest(const char *Cmd) {
|
||||
|
|
|
@ -194,7 +194,7 @@ static bool emrtd_exchange_commands(sAPDU_t apdu, bool include_le, uint16_t le,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(DEBUG, "Command failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return false;
|
||||
}
|
||||
|
@ -1957,14 +1957,16 @@ int infoHF_EMRTD_offline(const char *path) {
|
|||
uint8_t *data;
|
||||
size_t datalen = 0;
|
||||
char *filepath = calloc(strlen(path) + 100, sizeof(char));
|
||||
if (filepath == NULL)
|
||||
if (filepath == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
strcpy(filepath, path);
|
||||
strncat(filepath, PATHSEP, 2);
|
||||
strcat(filepath, dg_table[EF_COM].filename);
|
||||
|
||||
if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to read EF_COM.");
|
||||
if ((loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) &&
|
||||
(loadFile_safeEx(filepath, ".bin", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS)) {
|
||||
PrintAndLogEx(ERR, "Failed to read EF_COM");
|
||||
free(filepath);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -1996,19 +1998,21 @@ int infoHF_EMRTD_offline(const char *path) {
|
|||
strncat(filepath, PATHSEP, 2);
|
||||
strcat(filepath, dg_table[EF_CardAccess].filename);
|
||||
|
||||
if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) {
|
||||
if ((loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) ||
|
||||
(loadFile_safeEx(filepath, ".bin", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS)) {
|
||||
emrtd_print_ef_cardaccess_info(data, datalen);
|
||||
free(data);
|
||||
} else {
|
||||
PrintAndLogEx(HINT, "The error above this is normal. It just means that your eMRTD lacks PACE.");
|
||||
PrintAndLogEx(HINT, "The error above this is normal. It just means that your eMRTD lacks PACE");
|
||||
}
|
||||
|
||||
strcpy(filepath, path);
|
||||
strncat(filepath, PATHSEP, 2);
|
||||
strcat(filepath, dg_table[EF_SOD].filename);
|
||||
|
||||
if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to read EF_SOD.");
|
||||
if ((loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) &&
|
||||
(loadFile_safeEx(filepath, ".bin", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS)) {
|
||||
PrintAndLogEx(ERR, "Failed to read EF_SOD");
|
||||
free(filepath);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -2020,7 +2024,7 @@ int infoHF_EMRTD_offline(const char *path) {
|
|||
|
||||
res = emrtd_parse_ef_sod_hashes(data, datalen, *dg_hashes_sod, &hash_algo);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD. Hash checks will fail.");
|
||||
PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD. Hash checks will fail");
|
||||
}
|
||||
free(data);
|
||||
|
||||
|
@ -2035,10 +2039,12 @@ int infoHF_EMRTD_offline(const char *path) {
|
|||
strcpy(filepath, path);
|
||||
strncat(filepath, PATHSEP, 2);
|
||||
strcat(filepath, dg->filename);
|
||||
if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) {
|
||||
if ((loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) ||
|
||||
(loadFile_safeEx(filepath, ".bin", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS)) {
|
||||
// we won't halt on parsing errors
|
||||
if (dg->parser != NULL)
|
||||
if (dg->parser != NULL) {
|
||||
dg->parser(data, datalen);
|
||||
}
|
||||
|
||||
PrintAndLogEx(DEBUG, "EF_DG%i hash algo: %i", dg->dgnum, hash_algo);
|
||||
// Check file hash
|
||||
|
@ -2058,13 +2064,6 @@ int infoHF_EMRTD_offline(const char *path) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void text_to_upper(uint8_t *data, int datalen) {
|
||||
// Loop over text to make lowercase text uppercase
|
||||
for (int i = 0; i < datalen; i++) {
|
||||
data[i] = toupper(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static bool validate_date(uint8_t *data, int datalen) {
|
||||
// Date has to be 6 chars
|
||||
if (datalen != 6) {
|
||||
|
@ -2085,7 +2084,9 @@ static int CmdHFeMRTDDump(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf emrtd dump",
|
||||
"Dump all files on an eMRTD",
|
||||
"hf emrtd dump"
|
||||
"hf emrtd dump\n"
|
||||
"hf emrtd dump --dir ../dump\n"
|
||||
"hf emrtd dump -n 123456789 -d 19890101 -e 20250401"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -2094,7 +2095,7 @@ static int CmdHFeMRTDDump(const char *Cmd) {
|
|||
arg_str0("d", "dateofbirth", "<YYMMDD>", "date of birth in YYMMDD format"),
|
||||
arg_str0("e", "expiry", "<YYMMDD>", "expiry in YYMMDD format"),
|
||||
arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars"),
|
||||
arg_str0(NULL, "path", "<dirpath>", "save dump to the given dirpath"),
|
||||
arg_str0(NULL, "dir", "<str>", "save dump to the given dirpath"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -2110,7 +2111,7 @@ static int CmdHFeMRTDDump(const char *Cmd) {
|
|||
if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) {
|
||||
BAC = false;
|
||||
} else {
|
||||
text_to_upper(docnum, slen);
|
||||
strn_upper((char *)docnum, slen);
|
||||
if (slen != 9) {
|
||||
// Pad to 9 with <
|
||||
memset(docnum + slen, '<', 9 - slen);
|
||||
|
@ -2143,7 +2144,7 @@ static int CmdHFeMRTDDump(const char *Cmd) {
|
|||
error = true;
|
||||
} else {
|
||||
BAC = true;
|
||||
text_to_upper(mrz, slen);
|
||||
strn_upper((char *)mrz, slen);
|
||||
memcpy(docnum, &mrz[0], 9);
|
||||
memcpy(dob, &mrz[13], 6);
|
||||
memcpy(expiry, &mrz[21], 6);
|
||||
|
@ -2183,7 +2184,10 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf emrtd info",
|
||||
"Display info about an eMRTD",
|
||||
"hf emrtd info"
|
||||
"hf emrtd info\n"
|
||||
"hf emrtd info --dir ../dumps\n"
|
||||
"hf emrtd info -n 123456789 -d 19890101 -e 20250401\n"
|
||||
"hf emrtd info -n 123456789 -d 19890101 -e 20250401 -i"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -2192,7 +2196,7 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
|
|||
arg_str0("d", "dateofbirth", "<YYMMDD>", "date of birth in YYMMDD format"),
|
||||
arg_str0("e", "expiry", "<YYMMDD>", "expiry in YYMMDD format"),
|
||||
arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars (passports only)"),
|
||||
arg_str0(NULL, "path", "<dirpath>", "display info from offline dump stored in dirpath"),
|
||||
arg_str0(NULL, "dir", "<str>", "display info from offline dump stored in dirpath"),
|
||||
arg_lit0("i", "images", "show images"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -2209,7 +2213,7 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
|
|||
if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) {
|
||||
BAC = false;
|
||||
} else {
|
||||
text_to_upper(docnum, slen);
|
||||
strn_upper((char *)docnum, slen);
|
||||
if (slen != 9) {
|
||||
memset(docnum + slen, '<', 9 - slen);
|
||||
}
|
||||
|
@ -2241,7 +2245,7 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
|
|||
error = true;
|
||||
} else {
|
||||
BAC = true;
|
||||
text_to_upper(mrz, slen);
|
||||
strn_upper((char *)mrz, slen);
|
||||
memcpy(docnum, &mrz[0], 9);
|
||||
memcpy(dob, &mrz[13], 6);
|
||||
memcpy(expiry, &mrz[21], 6);
|
||||
|
@ -2262,7 +2266,7 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
|
|||
bool is_offline = CLIParamStrToBuf(arg_get_str(ctx, 5), path, sizeof(path), &slen) == 0 && slen > 0;
|
||||
bool show_images = arg_get_lit(ctx, 6);
|
||||
CLIParserFree(ctx);
|
||||
if ((! IfPm3Iso14443()) && (! is_offline)) {
|
||||
if ((IfPm3Iso14443() == false) && (is_offline == false)) {
|
||||
PrintAndLogEx(WARNING, "Only offline mode is available");
|
||||
error = true;
|
||||
}
|
||||
|
|
|
@ -228,7 +228,7 @@ static int CmdHFEPAPACESimulate(const char *Cmd) {
|
|||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
// bool use_pc = arg_get_lit(ctx, 1);
|
||||
// uint8_t pwd_type = 0;
|
||||
// uint8_t pwd_type = 0;
|
||||
|
||||
int plen = 0;
|
||||
uint8_t pwd[6] = {0};
|
||||
|
@ -273,7 +273,7 @@ static command_t CommandTable[] = {
|
|||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"cnonces", CmdHFEPACollectPACENonces, IfPm3Iso14443, "Acquire encrypted PACE nonces of specific size"},
|
||||
{"replay", CmdHFEPAPACEReplay, IfPm3Iso14443, "Perform PACE protocol by replaying given APDUs"},
|
||||
{"sim", CmdHFEPAPACESimulate, IfPm3Iso14443, "Simulate PACE protocol"},
|
||||
{"sim", CmdHFEPAPACESimulate, IfPm3Iso14443, "Simulate PACE protocol"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -3968,7 +3968,7 @@ static int CmdHFiClassEncode(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// iceman: only for formats w length smaller than 37.
|
||||
// iceman: only for formats w length smaller than 37.
|
||||
// Needs a check.
|
||||
|
||||
// increase length to allow setting bit just above real data
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "emv/tlv.h"
|
||||
#include "iso7816/apduinfo.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -126,7 +127,7 @@ static int CmdHFKSX6924Info(const char *Cmd) {
|
|||
return res;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
if (sw) {
|
||||
PrintAndLogEx(INFO, "Not a KS X 6924 card! APDU response: %04x - %s",
|
||||
sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
|
|
|
@ -318,6 +318,18 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i
|
|||
snprintf(exp, size, "AUTH-B(%d)", cmd[1]);
|
||||
break;
|
||||
}
|
||||
case MIFARE_MAGIC_GDM_AUTH_KEYA:{
|
||||
if (cmdsize > 3) {
|
||||
snprintf(exp, size, "MAGIC AUTH-A(%d)", cmd[1]);
|
||||
MifareAuthState = masNt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MIFARE_MAGIC_GDM_AUTH_KEYB: {
|
||||
MifareAuthState = masNt;
|
||||
snprintf(exp, size, "MAGIC AUTH-B(%d)", cmd[1]);
|
||||
break;
|
||||
}
|
||||
case MIFARE_MAGICWUPC1:
|
||||
snprintf(exp, size, "MAGIC WUPC1");
|
||||
break;
|
||||
|
@ -942,14 +954,14 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
|||
break;
|
||||
case MFDES_READ_DATA:
|
||||
if (data_size >= 7) {
|
||||
snprintf(exp, size, "READ DATA (fileId %02x, offset %d, len %d)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4));
|
||||
snprintf(exp, size, "READ DATA (fileId %02x, offset %u, len %u)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4));
|
||||
} else {
|
||||
snprintf(exp, size, "READ DATA");
|
||||
}
|
||||
break;
|
||||
case MFDES_WRITE_DATA:
|
||||
if (data_size >= 7) {
|
||||
snprintf(exp, size, "WRITE DATA (fileId %02x, offset %d, len %d)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4));
|
||||
snprintf(exp, size, "WRITE DATA (fileId %02x, offset %u, len %u)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4));
|
||||
} else {
|
||||
snprintf(exp, size, "WRITE DATA");
|
||||
}
|
||||
|
@ -984,14 +996,14 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
|||
break;
|
||||
case MFDES_WRITE_RECORD:
|
||||
if (data_size >= 7) {
|
||||
snprintf(exp, size, "WRITE RECORD (fileId %02x, offset %d, len %d)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4));
|
||||
snprintf(exp, size, "WRITE RECORD (fileId %02x, offset %u, len %u)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4));
|
||||
} else {
|
||||
snprintf(exp, size, "WRITE RECORD");
|
||||
}
|
||||
break;
|
||||
case MFDES_READ_RECORDS:
|
||||
if (data_size >= 7) {
|
||||
snprintf(exp, size, "READ RECORDS (fileId %02x, offset %d, len %d)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4));
|
||||
snprintf(exp, size, "READ RECORDS (fileId %02x, offset %u, len %u)", data[0], MemLeToUint3byte(data + 1), MemLeToUint3byte(data + 4));
|
||||
} else {
|
||||
snprintf(exp, size, "READ RECORDS");
|
||||
}
|
||||
|
@ -1086,21 +1098,21 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
|||
break;
|
||||
case MFDES_AUTHENTICATE:
|
||||
if (data_size >= 1) {
|
||||
snprintf(exp, size, "AUTH NATIVE (keyNo %d)", data[0]);
|
||||
snprintf(exp, size, "AUTH NATIVE (keyNo %u)", data[0]);
|
||||
} else {
|
||||
snprintf(exp, size, "AUTH NATIVE");
|
||||
}
|
||||
break; // AUTHENTICATE_NATIVE
|
||||
case MFDES_AUTHENTICATE_ISO:
|
||||
if (data_size >= 1) {
|
||||
snprintf(exp, size, "AUTH ISO (keyNo %d)", data[0]);
|
||||
snprintf(exp, size, "AUTH ISO (keyNo %u)", data[0]);
|
||||
} else {
|
||||
snprintf(exp, size, "AUTH ISO");
|
||||
}
|
||||
break; // AUTHENTICATE_STANDARD
|
||||
case MFDES_AUTHENTICATE_AES:
|
||||
if (data_size >= 1) {
|
||||
snprintf(exp, size, "AUTH AES (keyNo %d)", data[0]);
|
||||
snprintf(exp, size, "AUTH AES (keyNo %u)", data[0]);
|
||||
} else {
|
||||
snprintf(exp, size, "AUTH AES");
|
||||
}
|
||||
|
@ -1119,14 +1131,14 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
|||
break;
|
||||
case MFDES_CHANGE_KEY:
|
||||
if (data_size >= 1) {
|
||||
snprintf(exp, size, "CHANGE KEY (keyNo %d)", data[0]);
|
||||
snprintf(exp, size, "CHANGE KEY (keyNo %u)", data[0]);
|
||||
} else {
|
||||
snprintf(exp, size, "CHANGE KEY");
|
||||
}
|
||||
break;
|
||||
case MFDES_GET_KEY_VERSION:
|
||||
if (data_size >= 1) {
|
||||
snprintf(exp, size, "GET KEY VERSION (keyNo %d)", data[0]);
|
||||
snprintf(exp, size, "GET KEY VERSION (keyNo %u)", data[0]);
|
||||
} else {
|
||||
snprintf(exp, size, "GET KEY VERSION");
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ static bool mfc_value(const uint8_t *d, int32_t *val) {
|
|||
}
|
||||
|
||||
static void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose) {
|
||||
if (blockno == 0) {
|
||||
if (blockno == 0) {
|
||||
PrintAndLogEx(INFO, "%3d | " _RED_("%s"), blockno, sprint_hex_ascii(d, MFBLOCK_SIZE));
|
||||
} else if (mfIsSectorTrailer(blockno)) {
|
||||
PrintAndLogEx(INFO, "%3d | " _YELLOW_("%s"), blockno, sprint_hex_ascii(d, MFBLOCK_SIZE));
|
||||
|
@ -369,12 +369,37 @@ static bool mf_write_block(const uint8_t *key, uint8_t keytype, uint8_t blockno,
|
|||
PacketResponseNG resp;
|
||||
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)));
|
||||
|
||||
|
@ -1028,9 +1090,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 +1111,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 +1134,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 +1239,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 +1249,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 +1272,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 +3688,6 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
|||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
nonces_t data[1];
|
||||
|
||||
sector_t *k_sector = NULL;
|
||||
|
||||
//Validations
|
||||
|
@ -3701,7 +3778,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 +6895,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 +6913,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 +6928,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 +6943,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);
|
||||
|
@ -7324,8 +7407,8 @@ static int CmdHF14AGen4Save(const char *Cmd) {
|
|||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE];
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
|
||||
bool fill_emulator = arg_get_lit(ctx,7);
|
||||
|
||||
bool fill_emulator = arg_get_lit(ctx, 7);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// validations
|
||||
|
@ -7420,12 +7503,12 @@ static int CmdHF14AGen4Save(const char *Cmd) {
|
|||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
|
||||
if (fill_emulator) {
|
||||
PrintAndLogEx(INFO, "uploading to emulator memory" NOLF);
|
||||
// fast push mode
|
||||
g_conn.block_after_ACK = true;
|
||||
|
||||
|
||||
size_t offset = 0;
|
||||
int cnt = 0;
|
||||
uint16_t bytes_left = bytes ;
|
||||
|
@ -7454,7 +7537,7 @@ static int CmdHF14AGen4Save(const char *Cmd) {
|
|||
offset += MFBLOCK_SIZE;
|
||||
bytes_left -= MFBLOCK_SIZE;
|
||||
}
|
||||
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "uploaded " _YELLOW_("%d") " bytes to emulator memory", bytes);
|
||||
}
|
||||
|
@ -7533,7 +7616,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 +7623,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 +7678,12 @@ static int CmdHF14AMfValue(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (action < 3) {
|
||||
|
||||
uint8_t isok = true;
|
||||
if (g_session.pm3_present == false)
|
||||
return PM3_ENOTTY;
|
||||
|
||||
if (action <= 1) { // increment/decrement value
|
||||
uint8_t block[MFBLOCK_SIZE] = {0x00};
|
||||
memcpy(block, (uint8_t *)&value, 4);
|
||||
uint8_t cmddata[26];
|
||||
memcpy(cmddata, key, sizeof(key)); // Key == 6 data went to 10, so lets offset 9 for inc/dec
|
||||
|
|
|
@ -306,7 +306,7 @@ static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) {
|
|||
}
|
||||
|
||||
// ref: https://www.nxp.com/docs/en/application-note/AN12343.pdf p7
|
||||
static nxp_producttype_t getProductType(uint8_t *versionhw) {
|
||||
static nxp_producttype_t getProductType(const uint8_t *versionhw) {
|
||||
|
||||
uint8_t product = versionhw[2];
|
||||
|
||||
|
@ -323,7 +323,7 @@ static nxp_producttype_t getProductType(uint8_t *versionhw) {
|
|||
return DESFIRE_UNKNOWN_PROD;
|
||||
}
|
||||
|
||||
static const char *getProductTypeStr(uint8_t *versionhw) {
|
||||
static const char *getProductTypeStr(const uint8_t *versionhw) {
|
||||
|
||||
uint8_t product = versionhw[2];
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ static uint8_t default_3des_keys[][16] = {
|
|||
|
||||
static uint8_t default_pwd_pack[][4] = {
|
||||
{0xFF, 0xFF, 0xFF, 0xFF}, // PACK 0x00,0x00 -- factory default
|
||||
{0x4E, 0x45, 0x78, 0x54},
|
||||
{0x4E, 0x45, 0x78, 0x54}, // NExT
|
||||
};
|
||||
|
||||
static uint32_t UL_TYPES_ARRAY[] = {
|
||||
|
@ -1144,6 +1144,46 @@ Lego Dimensions,
|
|||
E1 10 12 00 01 03 A0 0C 34 03 13 D1 01 0F 54 02 65 6E
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
const char *desc;
|
||||
uint8_t mpos;
|
||||
uint8_t mlen;
|
||||
const char *match;
|
||||
uint32_t (*otp)(const uint8_t *uid);
|
||||
const char *hint;
|
||||
} mfu_otp_identify_t;
|
||||
|
||||
static mfu_otp_identify_t mfu_otp_ident_table[] = {
|
||||
{ "SALTO", 12, 4, "534C544F", ul_c_otpgenA, NULL },
|
||||
// { "SAFLOK", 12, 4, NULL, ul_c_otpgenB, NULL },
|
||||
// { "VINGCARD", 12, 4, NULL, ul_c_otpgenC, NULL },
|
||||
// { "DORMA KABA", 12, 4, NULL, ul_c_otpgenD, NULL },
|
||||
{ NULL, 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static mfu_otp_identify_t *mfu_match_otp_fingerprint(uint8_t *data) {
|
||||
uint8_t i = 0;
|
||||
do {
|
||||
int ml = 0;
|
||||
uint8_t mtmp[40] = {0};
|
||||
|
||||
// static or dynamic created OTP to fingerprint.
|
||||
if (mfu_otp_ident_table[i].match) {
|
||||
param_gethex_to_eol(mfu_otp_ident_table[i].match, 0, mtmp, sizeof(mtmp), &ml);
|
||||
} else {
|
||||
uint32_t otp = mfu_otp_ident_table[i].otp(data);
|
||||
num_to_bytes(otp, 4, mtmp);
|
||||
}
|
||||
|
||||
bool m2 = (memcmp(mtmp, data + mfu_otp_ident_table[i].mpos, mfu_otp_ident_table[i].mlen) == 0);
|
||||
if (m2) {
|
||||
PrintAndLogEx(DEBUG, "(fingerprint) found %s", mfu_otp_ident_table[i].desc);
|
||||
return &mfu_otp_ident_table[i];
|
||||
}
|
||||
} while (mfu_otp_ident_table[++i].desc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *desc;
|
||||
const char *version;
|
||||
|
@ -1184,7 +1224,7 @@ static mfu_identify_t mfu_ident_table[] = {
|
|||
"Snackworld", "0004040101000B03",
|
||||
9, 7, "483000E1100600",
|
||||
NULL, NULL,
|
||||
"hf mfu dump -k %08x"
|
||||
"hf mfu dump -k"
|
||||
},
|
||||
{
|
||||
"Amiibo", "0004040201001103",
|
||||
|
@ -1324,15 +1364,36 @@ static int mfu_fingerprint(TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authke
|
|||
if (item) {
|
||||
PrintAndLogEx(SUCCESS, "Found " _GREEN_("%s"), item->desc);
|
||||
|
||||
if (item->Pwd) {
|
||||
if (item->hint) {
|
||||
if (item->Pwd) {
|
||||
char s[40] = {0};
|
||||
snprintf(s, sizeof(s), item->hint, item->Pwd(uid));
|
||||
PrintAndLogEx(HINT, "Use `" _YELLOW_("%s") "`", s);
|
||||
} else {
|
||||
PrintAndLogEx(HINT, "Use `" _YELLOW_("%s") "`", item->hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OTP checks
|
||||
mfu_otp_identify_t *item = mfu_match_otp_fingerprint(data);
|
||||
if (item) {
|
||||
PrintAndLogEx(SUCCESS, "Found " _GREEN_("%s"), item->desc);
|
||||
|
||||
if (item->hint) {
|
||||
if (item->otp) {
|
||||
char s[40] = {0};
|
||||
snprintf(s, sizeof(s), item->hint, item->Pwd(uid));
|
||||
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;
|
||||
}
|
||||
|
@ -4154,7 +4218,7 @@ static int CmdHF14AMfuEView(const char *Cmd) {
|
|||
|
||||
if (override_end) {
|
||||
++end ;
|
||||
} else {
|
||||
} else {
|
||||
end = dump->pages ;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "crypto/asn1utils.h" // ASN1 decode / print
|
||||
#include "commonutil.h" // get_sw
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -55,7 +56,7 @@ static int seos_select(void) {
|
|||
}
|
||||
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Selecting SEOS applet aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -75,7 +76,7 @@ static int seos_select(void) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Selecting ADF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
|
||||
#include "cmdnfc.h" // print_type4_cc_info
|
||||
#include "commonutil.h" // get_sw
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
#define TIMEOUT 2000
|
||||
|
||||
|
@ -136,7 +137,7 @@ static int infoHFST25TA(void) {
|
|||
}
|
||||
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -156,7 +157,7 @@ static int infoHFST25TA(void) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -172,7 +173,7 @@ static int infoHFST25TA(void) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -192,7 +193,7 @@ static int infoHFST25TA(void) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Selecting system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -210,7 +211,7 @@ static int infoHFST25TA(void) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "reading system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -329,7 +330,7 @@ int CmdHFST25TANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -349,7 +350,7 @@ int CmdHFST25TANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -378,7 +379,7 @@ int CmdHFST25TANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -397,7 +398,7 @@ int CmdHFST25TANdefRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -495,7 +496,7 @@ static int CmdHFST25TAProtect(const char *Cmd) {
|
|||
}
|
||||
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -515,7 +516,7 @@ static int CmdHFST25TAProtect(const char *Cmd) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -534,7 +535,7 @@ static int CmdHFST25TAProtect(const char *Cmd) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -553,7 +554,7 @@ static int CmdHFST25TAProtect(const char *Cmd) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -639,7 +640,7 @@ static int CmdHFST25TAPwd(const char *Cmd) {
|
|||
}
|
||||
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -659,7 +660,7 @@ static int CmdHFST25TAPwd(const char *Cmd) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -678,7 +679,7 @@ static int CmdHFST25TAPwd(const char *Cmd) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -699,7 +700,7 @@ static int CmdHFST25TAPwd(const char *Cmd) {
|
|||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(ERR, "password change failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
|
|
@ -311,7 +311,7 @@ static bool TexcomTK15Decode(uint32_t *implengths, uint32_t implengthslen, char
|
|||
bool prevbit = (implengths[implengthslen - 3] > implengths[implengthslen - 2]);
|
||||
bool thesamebit = (abs(lastimplen - (int)implengths[implengthslen - 3]) < abs(lastimplen - (int)implengths[implengthslen - 2]));
|
||||
|
||||
if (prevbit ^ !thesamebit) {
|
||||
if (prevbit ^ (!thesamebit)) {
|
||||
strcat(bitstring, "10");
|
||||
strcat(cbitstring, "1");
|
||||
} else {
|
||||
|
|
|
@ -292,7 +292,7 @@ static bool topaz_byte_is_locked(uint16_t byteno) {
|
|||
}
|
||||
}
|
||||
|
||||
static int topaz_set_cc_dynamic(uint8_t *data) {
|
||||
static int topaz_set_cc_dynamic(const uint8_t *data) {
|
||||
|
||||
if (data[0] != 0xE1) {
|
||||
topaz_tag.size = TOPAZ_STATIC_MEMORY;
|
||||
|
@ -583,9 +583,7 @@ static void topaz_print_lifecycle_state(uint8_t *data) {
|
|||
// to be done
|
||||
}
|
||||
|
||||
static void printTopazDumpContents(uint8_t *dump, size_t size) {
|
||||
|
||||
topaz_tag_t *t = (topaz_tag_t *)dump;
|
||||
static void printTopazDumpContents(topaz_tag_t *dump) {
|
||||
|
||||
// uses a global var for all
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
@ -608,14 +606,14 @@ static void printTopazDumpContents(uint8_t *dump, size_t size) {
|
|||
PrintAndLogEx(SUCCESS, " %3u / 0x%02x | %s| %s | %s",
|
||||
i,
|
||||
i,
|
||||
sprint_hex(&t->data_blocks[i][0], 8),
|
||||
sprint_hex(&dump->data_blocks[i][0], 8),
|
||||
lockstr,
|
||||
block_info
|
||||
);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, " %3u / 0x%02x | %s| | %s", 0x0D, 0x0D, sprint_hex(&t->data_blocks[0x0D][0], 8), topaz_ks[2]);
|
||||
PrintAndLogEx(SUCCESS, " %3u / 0x%02x | %s| | %s", 0x0E, 0x0E, sprint_hex(&t->data_blocks[0x0E][0], 8), topaz_ks[3]);
|
||||
PrintAndLogEx(SUCCESS, " %3u / 0x%02x | %s| | %s", 0x0D, 0x0D, sprint_hex(&dump->data_blocks[0x0D][0], 8), topaz_ks[2]);
|
||||
PrintAndLogEx(SUCCESS, " %3u / 0x%02x | %s| | %s", 0x0E, 0x0E, sprint_hex(&dump->data_blocks[0x0E][0], 8), topaz_ks[3]);
|
||||
PrintAndLogEx(SUCCESS, "------------+-------------------------+---+------------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
@ -797,7 +795,7 @@ static int CmdHFTopazDump(const char *Cmd) {
|
|||
if (status != PM3_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
printTopazDumpContents((uint8_t *)&topaz_tag, sizeof(topaz_tag_t));
|
||||
printTopazDumpContents(&topaz_tag);
|
||||
|
||||
bool set_dynamic = false;
|
||||
if (topaz_set_cc_dynamic(&topaz_tag.data_blocks[1][0]) == PM3_SUCCESS) {
|
||||
|
@ -853,14 +851,17 @@ static int CmdHFTopazView(const char *Cmd) {
|
|||
CLIParserFree(ctx);
|
||||
|
||||
// read dump file
|
||||
uint8_t *dump = NULL;
|
||||
topaz_tag_t *dump = NULL;
|
||||
size_t bytes_read = TOPAZ_MAX_SIZE;
|
||||
int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, sizeof(topaz_tag_t) + TOPAZ_MAX_SIZE);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
printTopazDumpContents(dump, bytes_read);
|
||||
if (bytes_read < sizeof(topaz_tag_t)) {
|
||||
free(dump);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
printTopazDumpContents(dump);
|
||||
|
||||
if (topaz_set_cc_dynamic(&topaz_tag.data_blocks[1][0]) == PM3_SUCCESS) {
|
||||
|
||||
|
|
|
@ -660,7 +660,6 @@ static int start_drawing_1in54B(uint8_t model_nr, uint8_t *black, uint8_t *red)
|
|||
}
|
||||
|
||||
static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
||||
uint8_t progress;
|
||||
uint8_t step0[2] = {0xcd, 0x0d};
|
||||
uint8_t step1[3] = {0xcd, 0x00, 10}; // select e-paper type and reset e-paper
|
||||
// 4 :2.13inch e-Paper
|
||||
|
@ -687,7 +686,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
// uint8_t step13[2]={0xcd,0x0b}; // Judge whether the power supply is turned off successfully
|
||||
// uint8_t step14[2]={0xcd,0x0c}; // The end of the transmission
|
||||
uint8_t rx[20];
|
||||
uint16_t actrxlen[20], i;
|
||||
uint16_t actrxlen[20];
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
@ -812,6 +811,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
}
|
||||
// 1.54B Data transfer is complete and wait for refresh
|
||||
} else {
|
||||
uint8_t progress;
|
||||
PrintAndLogEx(DEBUG, "Step5: e-paper config2");
|
||||
ret = transceive_blocking(step5, 2, rx, 20, actrxlen, true); // cd 05
|
||||
if (ret != PM3_SUCCESS) {
|
||||
|
@ -831,7 +831,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
}
|
||||
PrintAndLogEx(DEBUG, "Step8: Start data transfer");
|
||||
if (model_nr == M2in13) { // 2.13inch
|
||||
for (i = 0; i < 250; i++) {
|
||||
for (uint16_t i = 0; i < 250; i++) {
|
||||
read_black(i, step8, model_nr, black);
|
||||
ret = transceive_blocking(step8, 19, rx, 20, actrxlen, true); // cd 08
|
||||
if (ret != PM3_SUCCESS) {
|
||||
|
@ -841,7 +841,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
PrintAndLogEx(INPLACE, "Progress: %d %%", progress);
|
||||
}
|
||||
} else if (model_nr == M2in9) {
|
||||
for (i = 0; i < 296; i++) {
|
||||
for (uint16_t i = 0; i < 296; i++) {
|
||||
read_black(i, step8, model_nr, black);
|
||||
ret = transceive_blocking(step8, 19, rx, 20, actrxlen, true); // cd 08
|
||||
if (ret != PM3_SUCCESS) {
|
||||
|
@ -851,7 +851,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
PrintAndLogEx(INPLACE, "Progress: %d %%", progress);
|
||||
}
|
||||
} else if (model_nr == M4in2) { //4.2inch
|
||||
for (i = 0; i < 150; i++) {
|
||||
for (uint16_t i = 0; i < 150; i++) {
|
||||
read_black(i, step8, model_nr, black);
|
||||
ret = transceive_blocking(step8, 103, rx, 20, actrxlen, true); // cd 08
|
||||
if (ret != PM3_SUCCESS) {
|
||||
|
@ -861,7 +861,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
PrintAndLogEx(INPLACE, "Progress: %d %%", progress);
|
||||
}
|
||||
} else if (model_nr == M7in5) { //7.5inch
|
||||
for (i = 0; i < 400; i++) {
|
||||
for (uint16_t i = 0; i < 400; i++) {
|
||||
read_black(i, step8, model_nr, black);
|
||||
ret = transceive_blocking(step8, 123, rx, 20, actrxlen, true); // cd 08
|
||||
if (ret != PM3_SUCCESS) {
|
||||
|
@ -872,7 +872,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
msleep(6);
|
||||
}
|
||||
} else if (model_nr == M2in13B) { //2.13inch B
|
||||
for (i = 0; i < 26; i++) {
|
||||
for (uint16_t i = 0; i < 26; i++) {
|
||||
read_black(i, step8, model_nr, black);
|
||||
ret = transceive_blocking(step8, 109, rx, 20, actrxlen, false); // cd 08
|
||||
if (ret != PM3_SUCCESS) {
|
||||
|
@ -883,7 +883,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
}
|
||||
} else if (model_nr == M7in5HD) { //7.5HD
|
||||
|
||||
for (i = 0; i < 484; i++) {
|
||||
for (uint16_t i = 0; i < 484; i++) {
|
||||
read_black(i, step8, model_nr, black);
|
||||
//memset(&step8[3], 0xf0, 120);
|
||||
ret = transceive_blocking(step8, 123, rx, 20, actrxlen, true); // cd 08
|
||||
|
@ -899,7 +899,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
return ret;
|
||||
}
|
||||
} else if (model_nr == M2in7) { //2.7inch
|
||||
for (i = 0; i < 48; i++) {
|
||||
for (uint16_t i = 0; i < 48; i++) {
|
||||
//read_black(i,step8, model_nr, black);
|
||||
memset(&step8[3], 0xFF, sizeof(step8) - 3);
|
||||
ret = transceive_blocking(step8, 124, rx, 20, actrxlen, true); // cd 08
|
||||
|
@ -925,7 +925,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
}
|
||||
PrintAndLogEx(DEBUG, "Step9b");
|
||||
if (model_nr == M2in7) {
|
||||
for (i = 0; i < 48; i++) {
|
||||
for (uint16_t i = 0; i < 48; i++) {
|
||||
read_black(i, step13, model_nr, black);
|
||||
ret = transceive_blocking(step13, 124, rx, 20, actrxlen, true); //CD 19
|
||||
if (ret != PM3_SUCCESS) {
|
||||
|
@ -935,7 +935,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
PrintAndLogEx(INPLACE, "Progress: %d %%", progress);
|
||||
}
|
||||
} else if (model_nr == M2in13B) {
|
||||
for (i = 0; i < 26; i++) {
|
||||
for (uint16_t i = 0; i < 26; i++) {
|
||||
read_red(i, step13, model_nr, red);
|
||||
//memset(&step13[3], 0xfE, 106);
|
||||
ret = transceive_blocking(step13, 109, rx, 20, actrxlen, false);
|
||||
|
|
|
@ -15,77 +15,77 @@
|
|||
#define TIMEOUT 2000
|
||||
|
||||
|
||||
#define c2l(c,l) (l = ((unsigned long)(*((c)++))), \
|
||||
l |= ((unsigned long)(*((c)++))) << 8L, \
|
||||
l |= ((unsigned long)(*((c)++))) << 16L, \
|
||||
l |= ((unsigned long)(*((c)++))) << 24L)
|
||||
#define c2l(c,l) (l = ((unsigned long)(*((c)++))), \
|
||||
l |= ((unsigned long)(*((c)++))) << 8L, \
|
||||
l |= ((unsigned long)(*((c)++))) << 16L, \
|
||||
l |= ((unsigned long)(*((c)++))) << 24L)
|
||||
|
||||
/* NOTE - c is not incremented as per c2l */
|
||||
#define c2ln(c,l1,l2,n) { \
|
||||
c += n; \
|
||||
l1 = l2 = 0; \
|
||||
switch (n) { \
|
||||
case 8: l2 = ((unsigned long)(*(--(c)))) << 24L; \
|
||||
case 7: l2 |= ((unsigned long)(*(--(c)))) << 16L; \
|
||||
case 6: l2 |= ((unsigned long)(*(--(c)))) << 8L; \
|
||||
case 5: l2 |= ((unsigned long)(*(--(c)))); \
|
||||
case 4: l1 = ((unsigned long)(*(--(c)))) << 24L; \
|
||||
case 3: l1 |= ((unsigned long)(*(--(c)))) << 16L; \
|
||||
case 2: l1 |= ((unsigned long)(*(--(c)))) << 8L; \
|
||||
case 1: l1 |= ((unsigned long)(*(--(c)))); \
|
||||
} \
|
||||
}
|
||||
#define c2ln(c,l1,l2,n) { \
|
||||
c += n; \
|
||||
l1 = l2 = 0; \
|
||||
switch (n) { \
|
||||
case 8: l2 = ((unsigned long)(*(--(c)))) << 24L; \
|
||||
case 7: l2 |= ((unsigned long)(*(--(c)))) << 16L; \
|
||||
case 6: l2 |= ((unsigned long)(*(--(c)))) << 8L; \
|
||||
case 5: l2 |= ((unsigned long)(*(--(c)))); \
|
||||
case 4: l1 = ((unsigned long)(*(--(c)))) << 24L; \
|
||||
case 3: l1 |= ((unsigned long)(*(--(c)))) << 16L; \
|
||||
case 2: l1 |= ((unsigned long)(*(--(c)))) << 8L; \
|
||||
case 1: l1 |= ((unsigned long)(*(--(c)))); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define l2c(l,c) (*((c)++) = (uint8_t)(((l)) & 0xff), \
|
||||
*((c)++) = (uint8_t)(((l) >> 8L) & 0xff), \
|
||||
*((c)++) = (uint8_t)(((l) >> 16L) & 0xff), \
|
||||
*((c)++) = (uint8_t)(((l) >> 24L) & 0xff))
|
||||
#define l2c(l,c) (*((c)++) = (uint8_t)(((l)) & 0xff), \
|
||||
*((c)++) = (uint8_t)(((l) >> 8L) & 0xff), \
|
||||
*((c)++) = (uint8_t)(((l) >> 16L) & 0xff), \
|
||||
*((c)++) = (uint8_t)(((l) >> 24L) & 0xff))
|
||||
|
||||
/* NOTE - c is not incremented as per l2c */
|
||||
#define l2cn(l1,l2,c,n) { \
|
||||
c += n; \
|
||||
switch (n) { \
|
||||
case 8: *(--(c)) = (uint8_t)(((l2) >> 24L) & 0xff); \
|
||||
case 7: *(--(c)) = (uint8_t)(((l2) >> 16L) & 0xff); \
|
||||
case 6: *(--(c)) = (uint8_t)(((l2) >> 8L) & 0xff); \
|
||||
case 5: *(--(c)) = (uint8_t)(((l2)) & 0xff); \
|
||||
case 4: *(--(c)) = (uint8_t)(((l1) >> 24L) & 0xff); \
|
||||
case 3: *(--(c)) = (uint8_t)(((l1) >> 16L) & 0xff); \
|
||||
case 2: *(--(c)) = (uint8_t)(((l1) >> 8L) & 0xff); \
|
||||
case 1: *(--(c)) = (uint8_t)(((l1)) & 0xff); \
|
||||
} \
|
||||
}
|
||||
#define l2cn(l1,l2,c,n) { \
|
||||
c += n; \
|
||||
switch (n) { \
|
||||
case 8: *(--(c)) = (uint8_t)(((l2) >> 24L) & 0xff); \
|
||||
case 7: *(--(c)) = (uint8_t)(((l2) >> 16L) & 0xff); \
|
||||
case 6: *(--(c)) = (uint8_t)(((l2) >> 8L) & 0xff); \
|
||||
case 5: *(--(c)) = (uint8_t)(((l2)) & 0xff); \
|
||||
case 4: *(--(c)) = (uint8_t)(((l1) >> 24L) & 0xff); \
|
||||
case 3: *(--(c)) = (uint8_t)(((l1) >> 16L) & 0xff); \
|
||||
case 2: *(--(c)) = (uint8_t)(((l1) >> 8L) & 0xff); \
|
||||
case 1: *(--(c)) = (uint8_t)(((l1)) & 0xff); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* NOTE - c is not incremented as per n2l */
|
||||
#define n2ln(c,l1,l2,n) { \
|
||||
c += n; \
|
||||
l1 = l2 = 0; \
|
||||
switch (n) { \
|
||||
case 8: l2 = ((unsigned long)(*(--(c)))); \
|
||||
case 7: l2 |= ((unsigned long)(*(--(c)))) << 8; \
|
||||
case 6: l2 |= ((unsigned long)(*(--(c)))) << 16; \
|
||||
case 5: l2 |= ((unsigned long)(*(--(c)))) << 24; \
|
||||
case 4: l1 = ((unsigned long)(*(--(c)))); \
|
||||
case 3: l1 |= ((unsigned long)(*(--(c)))) << 8; \
|
||||
case 2: l1 |= ((unsigned long)(*(--(c)))) << 16; \
|
||||
case 1: l1 |= ((unsigned long)(*(--(c)))) << 24; \
|
||||
} \
|
||||
}
|
||||
#define n2ln(c,l1,l2,n) { \
|
||||
c += n; \
|
||||
l1 = l2 = 0; \
|
||||
switch (n) { \
|
||||
case 8: l2 = ((unsigned long)(*(--(c)))); \
|
||||
case 7: l2 |= ((unsigned long)(*(--(c)))) << 8; \
|
||||
case 6: l2 |= ((unsigned long)(*(--(c)))) << 16; \
|
||||
case 5: l2 |= ((unsigned long)(*(--(c)))) << 24; \
|
||||
case 4: l1 = ((unsigned long)(*(--(c)))); \
|
||||
case 3: l1 |= ((unsigned long)(*(--(c)))) << 8; \
|
||||
case 2: l1 |= ((unsigned long)(*(--(c)))) << 16; \
|
||||
case 1: l1 |= ((unsigned long)(*(--(c)))) << 24; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* NOTE - c is not incremented as per l2n */
|
||||
#define l2nn(l1,l2,c,n) { \
|
||||
c+=n; \
|
||||
switch (n) { \
|
||||
case 8: *(--(c)) = (uint8_t)(((l2)) & 0xff); \
|
||||
case 7: *(--(c)) = (uint8_t)(((l2) >> 8) & 0xff); \
|
||||
case 6: *(--(c)) = (uint8_t)(((l2) >> 16) & 0xff); \
|
||||
case 5: *(--(c)) = (uint8_t)(((l2) >> 24) & 0xff); \
|
||||
case 4: *(--(c)) = (uint8_t)(((l1)) & 0xff); \
|
||||
case 3: *(--(c)) = (uint8_t)(((l1) >> 8) & 0xff); \
|
||||
case 2: *(--(c)) = (uint8_t)(((l1) >> 16) & 0xff); \
|
||||
case 1: *(--(c)) = (uint8_t)(((l1) >> 24) & 0xff); \
|
||||
} \
|
||||
}
|
||||
#define l2nn(l1,l2,c,n) { \
|
||||
c+=n; \
|
||||
switch (n) { \
|
||||
case 8: *(--(c)) = (uint8_t)(((l2)) & 0xff); \
|
||||
case 7: *(--(c)) = (uint8_t)(((l2) >> 8) & 0xff); \
|
||||
case 6: *(--(c)) = (uint8_t)(((l2) >> 16) & 0xff); \
|
||||
case 5: *(--(c)) = (uint8_t)(((l2) >> 24) & 0xff); \
|
||||
case 4: *(--(c)) = (uint8_t)(((l1)) & 0xff); \
|
||||
case 3: *(--(c)) = (uint8_t)(((l1) >> 8) & 0xff); \
|
||||
case 2: *(--(c)) = (uint8_t)(((l1) >> 16) & 0xff); \
|
||||
case 1: *(--(c)) = (uint8_t)(((l1) >> 24) & 0xff); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define n2l(c,l) (l = ((unsigned long)(*((c)++))) << 24L, \
|
||||
l |= ((unsigned long)(*((c)++))) << 16L, \
|
||||
|
@ -98,17 +98,17 @@
|
|||
*((c)++) = (uint8_t)(((l)) & 0xff))
|
||||
|
||||
#define C_RC2(n) \
|
||||
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); \
|
||||
t = (x2 + (x3 & ~x1) + (x0 & x1) + *(p0++)) & 0xffff; \
|
||||
x2 = (t << 3) | (t >> 13); \
|
||||
t = (x3 + (x0 & ~x2) + (x1 & x2) + *(p0++)) & 0xffff; \
|
||||
x3 = (t << 5) | (t >> 11);
|
||||
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); \
|
||||
t = (x2 + (x3 & ~x1) + (x0 & x1) + *(p0++)) & 0xffff; \
|
||||
x2 = (t << 3) | (t >> 13); \
|
||||
t = (x3 + (x0 & ~x2) + (x1 & x2) + *(p0++)) & 0xffff; \
|
||||
x3 = (t << 5) | (t >> 11);
|
||||
|
||||
#define RC2_ENCRYPT 1
|
||||
#define RC2_DECRYPT 0
|
||||
#define RC2_ENCRYPT 1
|
||||
#define RC2_DECRYPT 0
|
||||
|
||||
typedef unsigned int RC2_INT;
|
||||
|
||||
|
@ -202,7 +202,7 @@ void RC2_set_key(RC2_KEY *key, int len, const unsigned char *data, int bits) {
|
|||
void RC2_encrypt(unsigned long *d, RC2_KEY *key) {
|
||||
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;
|
||||
|
@ -533,8 +533,8 @@ static int CmdHFXeroxInfo(const char *Cmd) {
|
|||
packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW);
|
||||
packet->rawlen = 11;
|
||||
packet->raw[0] = 0x02;
|
||||
packet->raw[1] = 0x20; // set command: read mem
|
||||
memcpy(packet->raw + 2, card.uid, 8); // store uid
|
||||
packet->raw[1] = 0x20; // set command: read mem
|
||||
memcpy(packet->raw + 2, card.uid, 8); // store uid
|
||||
|
||||
for (int retry = 0; (retry < 5 && blocknum < sizeof(info_blocks)); retry++) {
|
||||
|
||||
|
@ -623,7 +623,7 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
}
|
||||
|
||||
iso14b_card_select_t card;
|
||||
int status = findXerox(&card, false); // remain RF on
|
||||
int status = findXerox(&card, false); // remain RF on
|
||||
if (status != PM3_SUCCESS) {
|
||||
free(packet);
|
||||
switch_off_field();
|
||||
|
@ -632,20 +632,20 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
|
||||
PrintAndLogEx(INFO, "Reading memory from tag UID " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
|
||||
|
||||
int blocknum = 1; // block 0 all zeros
|
||||
int blocknum = 1; // block 0 all zeros
|
||||
uint8_t data[256 * 4] = {0};
|
||||
|
||||
// set up the read command
|
||||
packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW);
|
||||
packet->rawlen = 11;
|
||||
packet->raw[0] = 0x02;
|
||||
memcpy(packet->raw + 2, card.uid, 8); // store uid
|
||||
memcpy(packet->raw + 2, card.uid, 8); // store uid
|
||||
|
||||
PrintAndLogEx(INFO, "." NOLF);
|
||||
|
||||
for (int retry = 0; (retry < 5 && blocknum < 0x100); retry++) {
|
||||
|
||||
packet->raw[1] = (blocknum < 12) ? 0x30 : 0x20; // set command: read ext mem or read mem
|
||||
packet->raw[1] = (blocknum < 12) ? 0x30 : 0x20; // set command: read ext mem or read mem
|
||||
packet->raw[10] = blocknum & 0xFF;
|
||||
|
||||
PacketResponseNG resp;
|
||||
|
@ -657,7 +657,7 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
resp.cmd, resp.length, resp.magic, resp.status, resp.crc, resp.oldarg[0], resp.oldarg[1], resp.oldarg[2],
|
||||
resp.data.asBytes[0], resp.data.asBytes[1], resp.data.asBytes[2], resp.ng ? 't' : 'f');
|
||||
*/
|
||||
if (/*resp.status != 0 ||*/ resp.length < 7) { // 14b raw command send data_len instead of status
|
||||
if (/*resp.status != 0 ||*/ resp.length < 7) { // 14b raw command send data_len instead of status
|
||||
PrintAndLogEx(FAILED, "retrying one more time");
|
||||
continue;
|
||||
}
|
||||
|
@ -722,8 +722,8 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
memcpy(k1, k2, sizeof(k1));
|
||||
|
||||
k1[2] = k2[3] ^ data[0x22 * 4 + 0];
|
||||
k1[3] = k2[4] ^ data[0x22 * 4 + 1]; // first_key[7];
|
||||
k1[5] = k2[1] ^ 0x01; // 01 = crypto method? rfid[23][2]
|
||||
k1[3] = k2[4] ^ data[0x22 * 4 + 1]; // first_key[7];
|
||||
k1[5] = k2[1] ^ 0x01; // 01 = crypto method? rfid[23][2]
|
||||
|
||||
RC2_set_key(&exp_key, 8, k1, 64);
|
||||
|
||||
|
@ -747,7 +747,7 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
uint16_t cs, csd;
|
||||
|
||||
// calc checksum
|
||||
for (b = 0, cs = 0; b < sizeof(decr) - 2; b += 2) cs += decr[b] | (decr[b + 1] << 8);
|
||||
for (b = 0, cs = 0; b < sizeof(decr) - 2; b += 2) cs += decr[b] | (decr[b + 1] << 8);
|
||||
cs = ~cs;
|
||||
csd = (decr[7] << 8) | decr[6];
|
||||
|
||||
|
@ -772,7 +772,7 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "---------+--------------+----------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
if (0 == filename[0]) { // generate filename from uid
|
||||
if (0 == filename[0]) { // generate filename from uid
|
||||
/*
|
||||
PrintAndLogEx(INFO, "Using UID as filename");
|
||||
|
||||
|
|
|
@ -592,12 +592,12 @@ static int CmdLCD(const char *Cmd) {
|
|||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
int r_len = 0;
|
||||
uint8_t raw[1] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &r_len);
|
||||
int j = arg_get_int_def(ctx, 2, 1);
|
||||
CLIParserFree(ctx);
|
||||
if (j < 1) {
|
||||
PrintAndLogEx(WARNING, "Count must be larger than zero");
|
||||
return PM3_EINVARG;
|
||||
|
|
|
@ -229,6 +229,8 @@ void printEM410x(uint32_t hi, uint64_t id, bool verbose, int type) {
|
|||
uint8_t sebury2 = (id >> 16) & 0x7F;
|
||||
uint32_t sebury3 = id & 0x7FFFFF;
|
||||
PrintAndLogEx(SUCCESS, "Pattern Sebury : %d %d %d [0x%X 0x%X 0x%X]", sebury1, sebury2, sebury3, sebury1, sebury2, sebury3);
|
||||
PrintAndLogEx(SUCCESS, "VD / ID : %03" PRIu64 " / %010" PRIu64, (id >> 32LL) & 0xFFFF, (id & 0xFFFFFFFF));
|
||||
|
||||
PrintAndLogEx(INFO, "------------------------------------------------");
|
||||
}
|
||||
}
|
||||
|
@ -672,11 +674,6 @@ static int CmdEM410xClone(const char *Cmd) {
|
|||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
if (q5) {
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Preparing to clone EM4102 to " _YELLOW_("%s") " tag with EM Tag ID " _GREEN_("%010" PRIX64) " (RF/%d)", q5 ? "Q5/T5555" : (em ? "EM4305/4469" : "T55x7"), id, clk);
|
||||
|
||||
struct {
|
||||
|
|
|
@ -2025,10 +2025,8 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
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;
|
||||
|
@ -2044,6 +2042,7 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
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);
|
||||
|
@ -2081,7 +2080,7 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
pwd = true;
|
||||
cmdText = "Logon";
|
||||
strncpy(blkAddr, " ", sizeof(blkAddr));
|
||||
tmpValue = em4x05_Sniff_GetBlock(&bits.ptr[4], fwd);
|
||||
uint32_t tmpValue = em4x05_Sniff_GetBlock(&bits.ptr[4], fwd);
|
||||
snprintf(dataText, sizeof(dataText), "%08X", tmpValue);
|
||||
}
|
||||
|
||||
|
@ -2089,7 +2088,7 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
if ((strncmp(bits.ptr, "0101", 4) == 0) && (bits.idx == 56)) {
|
||||
haveData = true;
|
||||
cmdText = "Write";
|
||||
tmpValue = (bits.ptr[4] - '0') + ((bits.ptr[5] - '0') << 1) + ((bits.ptr[6] - '0') << 2) + ((bits.ptr[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;
|
||||
|
@ -2103,7 +2102,7 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
haveData = true;
|
||||
pwd = false;
|
||||
cmdText = "Read";
|
||||
tmpValue = (bits.ptr[4] - '0') + ((bits.ptr[5] - '0') << 1) + ((bits.ptr[6] - '0') << 2) + ((bits.ptr[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));
|
||||
}
|
||||
|
@ -2114,7 +2113,7 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
pwd = false;
|
||||
cmdText = "Protect";
|
||||
strncpy(blkAddr, " ", sizeof(blkAddr));
|
||||
tmpValue = em4x05_Sniff_GetBlock(&bits.ptr[11], fwd);
|
||||
uint32_t tmpValue = em4x05_Sniff_GetBlock(&bits.ptr[11], fwd);
|
||||
snprintf(dataText, sizeof(dataText), "%08X", tmpValue);
|
||||
}
|
||||
|
||||
|
@ -2124,7 +2123,7 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
pwd = false;
|
||||
cmdText = "Disable";
|
||||
strncpy(blkAddr, " ", sizeof(blkAddr));
|
||||
tmpValue = em4x05_Sniff_GetBlock(&bits.ptr[11], fwd);
|
||||
uint32_t tmpValue = em4x05_Sniff_GetBlock(&bits.ptr[11], fwd);
|
||||
snprintf(dataText, sizeof(dataText), "%08X", tmpValue);
|
||||
}
|
||||
|
||||
|
|
|
@ -857,12 +857,12 @@ static int CmdLFHitag2Dump(const char *Cmd) {
|
|||
memcpy(htd.pwd.password, key, sizeof(htd.pwd.password));
|
||||
PrintAndLogEx(INFO, "Authenticating in password mode");
|
||||
}
|
||||
|
||||
|
||||
uint16_t cmd = CMD_LF_HITAG_READER;
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(cmd, htf, 0, 0, &htd, sizeof(htd));
|
||||
PacketResponseNG resp;
|
||||
|
||||
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
|
|
|
@ -404,7 +404,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
|
|||
uint8_t data[MAX_GRAPH_TRACE_LEN] = {0};
|
||||
size_t datasize = getFromGraphBuf(data);
|
||||
|
||||
uint8_t rawbits[4096];
|
||||
uint8_t rawbits[4096] = {0};
|
||||
int rawbit = 0;
|
||||
int worst = 0, worstPos = 0;
|
||||
|
||||
|
|
|
@ -230,6 +230,7 @@ static int CmdParadoxClone(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf paradox clone",
|
||||
"clone a paradox tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf paradox clone --fc 96 --cn 40426 -> encode for T55x7 tag with fc and cn\n"
|
||||
"lf paradox clone --raw 0f55555695596a6a9999a59a -> encode for T55x7 tag\n"
|
||||
"lf paradox clone --raw 0f55555695596a6a9999a59a --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf paradox clone --raw 0f55555695596a6a9999a59a --em -> encode for EM4305/4469"
|
||||
|
@ -238,6 +239,8 @@ static int CmdParadoxClone(const char *Cmd) {
|
|||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
|
||||
arg_u64_0(NULL, "fc", "<dec>", "facility code"),
|
||||
arg_u64_0(NULL, "cn", "<dec>", "card number"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
|
@ -249,8 +252,10 @@ static int CmdParadoxClone(const char *Cmd) {
|
|||
uint8_t raw[12] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
|
||||
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
|
||||
bool q5 = arg_get_lit(ctx, 4);
|
||||
bool em = arg_get_lit(ctx, 5);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
|
@ -258,14 +263,56 @@ static int CmdParadoxClone(const char *Cmd) {
|
|||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (raw_len != 12) {
|
||||
PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
uint32_t blocks[4] = {0};
|
||||
|
||||
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));
|
||||
if (raw_len != 0) {
|
||||
if (raw_len != 12) {
|
||||
PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
} else {
|
||||
uint8_t manchester[13] = { 0x00 }; // check size needed
|
||||
uint32_t t1;
|
||||
|
||||
manchester[0] = 0x0F; // preamble
|
||||
manchester[1] = 0x05; // Leading zeros - Note: from this byte on, is part of the CRC calculation
|
||||
manchester[2] = 0x55; // Leading zeros its 4 bits out for the CRC, so we need too move
|
||||
manchester[3] = 0x55; // Leading zeros back 4 bits once we have the crc (done below)
|
||||
|
||||
// add FC
|
||||
t1 = manchesterEncode2Bytes(fc);
|
||||
manchester[4] = (t1 >> 8) & 0xFF;
|
||||
manchester[5] = t1 & 0xFF;
|
||||
|
||||
// add cn
|
||||
t1 = manchesterEncode2Bytes(cn);
|
||||
manchester[6] = (t1 >> 24) & 0xFF;
|
||||
manchester[7] = (t1 >> 16) & 0xFF;
|
||||
manchester[8] = (t1 >> 8) & 0xFF;
|
||||
manchester[9] = t1 & 0xFF;
|
||||
|
||||
uint8_t crc = (CRC8Maxim(manchester + 1, 9) ^ 0x6) & 0xFF;
|
||||
|
||||
// add crc
|
||||
t1 = manchesterEncode2Bytes(crc);
|
||||
manchester[10] = (t1 >> 8) & 0xFF;
|
||||
manchester[11] = t1 & 0xFF;
|
||||
|
||||
// move left 4 bits left 4 bits - Now that we have the CRC we need to re-align the data.
|
||||
for (int i = 1; i < 12; i++)
|
||||
manchester[i] = (manchester[i] << 4) + (manchester[i + 1] >> 4);
|
||||
|
||||
// Add trailing 1010 (11)
|
||||
manchester[11] |= (1 << 3);
|
||||
manchester[11] |= (1 << 1);
|
||||
|
||||
// move into tag blocks
|
||||
for (int i = 0; i < 12; i++)
|
||||
blocks[1 + (i / 4)] += (manchester[i] << (8 * (3 - i % 4)));
|
||||
}
|
||||
|
||||
// Paradox - FSK2a, data rate 50, 3 data blocks
|
||||
|
|
|
@ -2362,7 +2362,7 @@ static int CmdT55xxRestore(const char *Cmd) {
|
|||
}
|
||||
|
||||
// read dump file
|
||||
uint8_t *dump = NULL;
|
||||
uint32_t *dump = NULL;
|
||||
size_t bytes_read = 0;
|
||||
res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (T55x7_BLOCK_COUNT * 4));
|
||||
if (res != PM3_SUCCESS) {
|
||||
|
@ -2387,11 +2387,10 @@ static int CmdT55xxRestore(const char *Cmd) {
|
|||
snprintf(pwdopt, sizeof(pwdopt), "-p %08X", password);
|
||||
}
|
||||
|
||||
uint32_t *data = (uint32_t *) dump;
|
||||
uint8_t idx;
|
||||
// Restore endien for writing to card
|
||||
for (idx = 0; idx < 12; idx++) {
|
||||
data[idx] = BSWAP_32(data[idx]);
|
||||
dump[idx] = BSWAP_32(dump[idx]);
|
||||
}
|
||||
|
||||
// Have data ready, lets write
|
||||
|
@ -2400,12 +2399,12 @@ static int CmdT55xxRestore(const char *Cmd) {
|
|||
// write blocks 1..3 page 1
|
||||
// update downlink mode (if needed) and write b 0
|
||||
downlink_mode = 0;
|
||||
if ((((data[11] >> 28) & 0xF) == 6) || (((data[11] >> 28) & 0xF) == 9))
|
||||
downlink_mode = (data[11] >> 10) & 3;
|
||||
if ((((dump[11] >> 28) & 0xF) == 6) || (((dump[11] >> 28) & 0xF) == 9))
|
||||
downlink_mode = (dump[11] >> 10) & 3;
|
||||
|
||||
// write out blocks 1-7 page 0
|
||||
for (idx = 1; idx <= 7; idx++) {
|
||||
snprintf(wcmd, sizeof(wcmd), "-b %d -d %08X %s", idx, data[idx], pwdopt);
|
||||
snprintf(wcmd, sizeof(wcmd), "-b %d -d %08X %s", idx, dump[idx], pwdopt);
|
||||
|
||||
if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "Warning: error writing blk %d", idx);
|
||||
|
@ -2414,12 +2413,12 @@ static int CmdT55xxRestore(const char *Cmd) {
|
|||
|
||||
// if password was set on the "blank" update as we may have just changed it
|
||||
if (usepwd) {
|
||||
snprintf(pwdopt, sizeof(pwdopt), "-p %08X", data[7]);
|
||||
snprintf(pwdopt, sizeof(pwdopt), "-p %08X", dump[7]);
|
||||
}
|
||||
|
||||
// write out blocks 1-3 page 1
|
||||
for (idx = 9; idx <= 11; idx++) {
|
||||
snprintf(wcmd, sizeof(wcmd), "-b %d --pg1 -d %08X %s", idx - 8, data[idx], pwdopt);
|
||||
snprintf(wcmd, sizeof(wcmd), "-b %d --pg1 -d %08X %s", idx - 8, dump[idx], pwdopt);
|
||||
|
||||
if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "Warning: error writing blk %d", idx);
|
||||
|
@ -2430,7 +2429,7 @@ static int CmdT55xxRestore(const char *Cmd) {
|
|||
config.downlink_mode = downlink_mode;
|
||||
|
||||
// Write the page 0 config
|
||||
snprintf(wcmd, sizeof(wcmd), "-b 0 -d %08X %s", data[0], pwdopt);
|
||||
snprintf(wcmd, sizeof(wcmd), "-b 0 -d %08X %s", dump[0], pwdopt);
|
||||
if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "Warning: error writing blk 0");
|
||||
}
|
||||
|
@ -4012,7 +4011,6 @@ static int CmdT55xxSniff(const char *Cmd) {
|
|||
size_t idx = 0;
|
||||
uint32_t usedPassword, blockData;
|
||||
int pulseSamples = 0, pulseIdx = 0;
|
||||
const char *modeText;
|
||||
char pwdText[100];
|
||||
char dataText[100];
|
||||
int pulseBuffer[80] = { 0 }; // max should be 73 +/- - Holds Pulse widths
|
||||
|
@ -4038,7 +4036,7 @@ static int CmdT55xxSniff(const char *Cmd) {
|
|||
int maxWidth = 0;
|
||||
data[0] = 0;
|
||||
bool have_data = false;
|
||||
modeText = "Default";
|
||||
const char *modeText = "Default";
|
||||
strncpy(pwdText, " ", sizeof(pwdText));
|
||||
strncpy(dataText, " ", sizeof(dataText));
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "cmdanalyse.h"
|
||||
#include "emv/cmdemv.h" // EMV
|
||||
#include "cmdflashmem.h" // rdv40 flashmem commands
|
||||
#include "cmdpiv.h"
|
||||
#include "cmdsmartcard.h" // rdv40 smart card ISO7816 commands
|
||||
#include "cmdusart.h" // rdv40 FPC USART commands
|
||||
#include "cmdwiegand.h" // wiegand commands
|
||||
|
@ -324,6 +325,7 @@ static command_t CommandTable[] = {
|
|||
{"lf", CmdLF, AlwaysAvailable, "{ Low frequency commands... }"},
|
||||
{"mem", CmdFlashMem, IfPm3Flash, "{ Flash memory manipulation... }"},
|
||||
{"nfc", CmdNFC, AlwaysAvailable, "{ NFC commands... }"},
|
||||
{"piv", CmdPIV, AlwaysAvailable, "{ PIV commands... }"},
|
||||
{"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software... }"},
|
||||
{"smart", CmdSmartcard, AlwaysAvailable, "{ Smart card ISO-7816 commands... }"},
|
||||
{"script", CmdScript, AlwaysAvailable, "{ Scripting commands... }"},
|
||||
|
|
988
client/src/cmdpiv.c
Normal file
988
client/src/cmdpiv.c
Normal file
|
@ -0,0 +1,988 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// PIV commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdpiv.h"
|
||||
|
||||
#include "comms.h" // DropField
|
||||
#include "cmdsmartcard.h" // smart_select
|
||||
#include "cmdtrace.h"
|
||||
#include "cliparser.h"
|
||||
#include "cmdparser.h"
|
||||
#include "commonutil.h" // Mem[LB]eToUintXByte
|
||||
#include "emv/tlv.h"
|
||||
#include "proxmark3.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "fileutils.h"
|
||||
#include "crypto/asn1utils.h"
|
||||
#include "protocols.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static uint8_t PIV_APPLET[9] = "\xA0\x00\x00\x03\x08\x00\x00\x10\x00";
|
||||
|
||||
enum piv_condition_t {
|
||||
PIV_MANDATORY,
|
||||
PIV_CONDITIONAL,
|
||||
PIV_OPTIONAL,
|
||||
PIV_INVALID = 0xff,
|
||||
};
|
||||
|
||||
struct piv_container {
|
||||
uint32_t id;
|
||||
const uint8_t *tlv_tag; // tag is between 1 and 3 bytes.
|
||||
size_t len; // length of the hex-form if the tag (i.e. twice the byte size) for pretty printing
|
||||
enum piv_condition_t cond;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#define PIV_TAG_ID(x) ((const uint8_t *)(x))
|
||||
#define PIV_CONTAINER_FINISH { (~0), NULL, 0, PIV_INVALID, NULL }
|
||||
|
||||
// Source: SP800-73-4, Annex A
|
||||
// https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-73-4.pdf
|
||||
static const struct piv_container PIV_CONTAINERS[] = {
|
||||
{0xDB00, PIV_TAG_ID("\x5F\xC1\x07"), 3, PIV_MANDATORY, "Card Capability Container"},
|
||||
{0x3000, PIV_TAG_ID("\x5F\xC1\x02"), 3, PIV_MANDATORY, "Card Holder Unique Identifier"},
|
||||
{0x0101, PIV_TAG_ID("\x5F\xC1\x05"), 3, PIV_MANDATORY, "X.509 Certificate for PIV Authentication (key ref 9A)"},
|
||||
{0x6010, PIV_TAG_ID("\x5F\xC1\x03"), 3, PIV_MANDATORY, "Cardholder Fingerprints"},
|
||||
{0x9000, PIV_TAG_ID("\x5F\xC1\x06"), 3, PIV_MANDATORY, "Security Object"},
|
||||
{0x6030, PIV_TAG_ID("\x5F\xC1\x08"), 3, PIV_MANDATORY, "Cardholder Facial Image"},
|
||||
{0x0500, PIV_TAG_ID("\x5F\xC1\x01"), 3, PIV_MANDATORY, "X.509 Certificate for Card Authentication (key ref 9E)"},
|
||||
{0x0100, PIV_TAG_ID("\x5F\xC1\x0A"), 3, PIV_CONDITIONAL, "X.509 Certificate for Digital Signature (key ref 9C)"},
|
||||
{0x0102, PIV_TAG_ID("\x5F\xC1\x0B"), 3, PIV_CONDITIONAL, "X.509 Certificate for Key Management (key ref 9D)"},
|
||||
{0x3001, PIV_TAG_ID("\x5F\xC1\x09"), 3, PIV_OPTIONAL, "Printed Information"},
|
||||
{0x6050, PIV_TAG_ID("\x7E"), 1, PIV_OPTIONAL, "Discovery Object"},
|
||||
{0x6060, PIV_TAG_ID("\x5F\xC1\x0C"), 3, PIV_OPTIONAL, "Key History Object"},
|
||||
{0x1001, PIV_TAG_ID("\x5F\xC1\x0D"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 1 (key ref 82)"},
|
||||
{0x1002, PIV_TAG_ID("\x5F\xC1\x0E"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 2 (key ref 83)"},
|
||||
{0x1003, PIV_TAG_ID("\x5F\xC1\x0F"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 3 (key ref 84)"},
|
||||
{0x1004, PIV_TAG_ID("\x5F\xC1\x10"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 4 (key ref 85)"},
|
||||
{0x1005, PIV_TAG_ID("\x5F\xC1\x11"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 5 (key ref 86)"},
|
||||
{0x1006, PIV_TAG_ID("\x5F\xC1\x12"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 6 (key ref 87)"},
|
||||
{0x1007, PIV_TAG_ID("\x5F\xC1\x13"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 7 (key ref 88)"},
|
||||
{0x1008, PIV_TAG_ID("\x5F\xC1\x14"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 8 (key ref 89)"},
|
||||
{0x1009, PIV_TAG_ID("\x5F\xC1\x15"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 9 (key ref 8A)"},
|
||||
{0x100A, PIV_TAG_ID("\x5F\xC1\x16"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 10 (key ref 8B)"},
|
||||
{0x100B, PIV_TAG_ID("\x5F\xC1\x17"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 11 (key ref 8C)"},
|
||||
{0x100C, PIV_TAG_ID("\x5F\xC1\x18"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 12 (key ref 8D)"},
|
||||
{0x100D, PIV_TAG_ID("\x5F\xC1\x19"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 13 (key ref 8E)"},
|
||||
{0x100E, PIV_TAG_ID("\x5F\xC1\x1A"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 14 (key ref 8F)"},
|
||||
{0x100F, PIV_TAG_ID("\x5F\xC1\x1B"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 15 (key ref 90)"},
|
||||
{0x1010, PIV_TAG_ID("\x5F\xC1\x1C"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 16 (key ref 91)"},
|
||||
{0x1011, PIV_TAG_ID("\x5F\xC1\x1D"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 17 (key ref 92)"},
|
||||
{0x1012, PIV_TAG_ID("\x5F\xC1\x1E"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 18 (key ref 93)"},
|
||||
{0x1013, PIV_TAG_ID("\x5F\xC1\x1F"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 19 (key ref 94)"},
|
||||
{0x1014, PIV_TAG_ID("\x5F\xC1\x20"), 3, PIV_OPTIONAL, "Retired X.509 Certificate for Key Management 20 (key ref 95)"},
|
||||
{0x1015, PIV_TAG_ID("\x5F\xC1\x21"), 3, PIV_OPTIONAL, "Cardholder Iris Images"},
|
||||
{0x1016, PIV_TAG_ID("\x7F\x61"), 2, PIV_OPTIONAL, "Biometric Information Templates Group Template"},
|
||||
{0x1017, PIV_TAG_ID("\x5F\xC1\x22"), 3, PIV_OPTIONAL, "Secure Messaging Certificate Signer"},
|
||||
{0x1018, PIV_TAG_ID("\x5F\xC1\x23"), 3, PIV_OPTIONAL, "Pairing Code Reference Data Container"},
|
||||
PIV_CONTAINER_FINISH,
|
||||
};
|
||||
|
||||
enum piv_tag_t {
|
||||
PIV_TAG_GENERIC,
|
||||
PIV_TAG_HEXDUMP,
|
||||
PIV_TAG_STRING,
|
||||
PIV_TAG_PRINTSTR,
|
||||
PIV_TAG_NUMERIC,
|
||||
PIV_TAG_YYYYMMDD,
|
||||
PIV_TAG_ENUM,
|
||||
PIV_TAG_TLV,
|
||||
PIV_TAG_GUID,
|
||||
PIV_TAG_CERT,
|
||||
PIV_TAG_FASCN,
|
||||
};
|
||||
|
||||
struct piv_tag {
|
||||
tlv_tag_t tag;
|
||||
const char *name;
|
||||
enum piv_tag_t type;
|
||||
const void *data;
|
||||
};
|
||||
|
||||
struct piv_tag_enum {
|
||||
unsigned long value;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#define PIV_ENUM_FINISH { (~0), NULL }
|
||||
|
||||
// From table 6-2 in SP800-78 specification
|
||||
static const struct piv_tag_enum PIV_CRYPTO_ALG[] = {
|
||||
{0x00, "3 Key 3DES - ECB"},
|
||||
{0x03, "3 Key 3DES - ECB"}, // Not a typo, 2 identifiers for the same algorithm
|
||||
{0x06, "RSA 1024 bit"},
|
||||
{0x07, "RSA 2048 bit"},
|
||||
{0x08, "AES-128 ECB"},
|
||||
{0x0A, "AES-192 ECB"},
|
||||
{0x0C, "AES-256 ECB"},
|
||||
{0x11, "ECC P-256"},
|
||||
{0x14, "ECC P-384"},
|
||||
{0x27, "Cipher Suite 2"},
|
||||
{0x2E, "Cipher Suite 7"},
|
||||
PIV_ENUM_FINISH,
|
||||
};
|
||||
|
||||
static const struct piv_tag_enum PIV_CERT_INFO[] = {
|
||||
{0x00, "Uncompressed"},
|
||||
{0x01, "GZIP Compressed"},
|
||||
PIV_ENUM_FINISH,
|
||||
};
|
||||
|
||||
static const struct piv_tag piv_tags[] = {
|
||||
{ 0x00, "Unknown ???", PIV_TAG_HEXDUMP, NULL },
|
||||
{ 0x01, "Name", PIV_TAG_PRINTSTR, NULL },
|
||||
{ 0x02, "Employee Affiliation", PIV_TAG_PRINTSTR, NULL },
|
||||
{ 0x04, "Expiry Date", PIV_TAG_PRINTSTR, NULL },
|
||||
{ 0x05, "Agency Card Serial Number", PIV_TAG_PRINTSTR, NULL },
|
||||
{ 0x06, "Issuer identification", PIV_TAG_PRINTSTR, NULL },
|
||||
{ 0x07, "Organization Affiliation (Line 1)", PIV_TAG_PRINTSTR, NULL },
|
||||
{ 0x08, "Organization Affiliation (Line 2)", PIV_TAG_PRINTSTR, NULL },
|
||||
|
||||
{ 0x30, "FASC-N", PIV_TAG_FASCN, NULL },
|
||||
{ 0x32, "Organizational Identifier [deprecated]", PIV_TAG_HEXDUMP, NULL },
|
||||
{ 0x33, "DUNS [deprecated]", PIV_TAG_HEXDUMP, NULL },
|
||||
{ 0x34, "GUID", PIV_TAG_GUID, NULL },
|
||||
{ 0x35, "Expiry Date", PIV_TAG_YYYYMMDD, NULL },
|
||||
{ 0x36, "Cardholder UUID", PIV_TAG_GUID, NULL },
|
||||
{ 0x3d, "Authentication Key Map", PIV_TAG_HEXDUMP, NULL },
|
||||
{ 0x3e, "Issuer Asymmetric Signature", PIV_TAG_CERT, NULL },
|
||||
|
||||
{ 0x4f, "Application Identifier (AID)", PIV_TAG_STRING, NULL },
|
||||
|
||||
{ 0x50, "Application Label", PIV_TAG_PRINTSTR, NULL },
|
||||
{ 0x53, "Discretionary data (or template)", PIV_TAG_TLV, NULL },
|
||||
{ 0x5f2f, "PIN Usage Policy", PIV_TAG_HEXDUMP, NULL },
|
||||
{ 0x5f50, "Issuer URL", PIV_TAG_PRINTSTR, NULL },
|
||||
|
||||
{ 0x61, "Application Property Template", PIV_TAG_GENERIC, NULL },
|
||||
|
||||
{ 0x70, "Certificate", PIV_TAG_CERT, NULL },
|
||||
{ 0x71, "CertInfo", PIV_TAG_ENUM, PIV_CERT_INFO },
|
||||
{ 0x72, "MSCUID [deprecated]", PIV_TAG_HEXDUMP, NULL },
|
||||
{ 0x79, "Coexistent tag allocation authority", PIV_TAG_HEXDUMP, NULL },
|
||||
{ 0x7f21, "Intermediate CVC", PIV_TAG_HEXDUMP, NULL },
|
||||
{ 0x7f60, "Biometric Information Template", PIV_TAG_GENERIC, NULL },
|
||||
|
||||
{ 0x80, "Cryptographic algorithm identifier", PIV_TAG_ENUM, PIV_CRYPTO_ALG },
|
||||
|
||||
{ 0x99, "Pairing Code", PIV_TAG_PRINTSTR, NULL },
|
||||
|
||||
{ 0xac, "Cryptographic algorithms supported", PIV_TAG_GENERIC, NULL },
|
||||
|
||||
{ 0xb4, "Security Object Buffer (deprecated)", PIV_TAG_GENERIC, NULL },
|
||||
{ 0xba, "Mapping of DG to Container ID", PIV_TAG_HEXDUMP, NULL },
|
||||
{ 0xbb, "Security Object", PIV_TAG_CERT, NULL },
|
||||
{ 0xbc, "Fingerprint I & II or Image for Visual Verification", PIV_TAG_GENERIC, NULL },
|
||||
|
||||
{ 0xc1, "keysWithOnCardCerts", PIV_TAG_NUMERIC, NULL },
|
||||
{ 0xc2, "keysWithOffCardCerts", PIV_TAG_NUMERIC, NULL },
|
||||
|
||||
{ 0xe3, "Extended Application CardURL [deprecated]", PIV_TAG_GENERIC, NULL },
|
||||
{ 0xee, "Buffer Length [deprecated]", PIV_TAG_NUMERIC, NULL },
|
||||
|
||||
{ 0xf0, "Card Identifier", PIV_TAG_STRING, NULL },
|
||||
{ 0xf1, "Capability Container version number", PIV_TAG_NUMERIC, NULL },
|
||||
{ 0xf2, "Capability Grammar version number", PIV_TAG_NUMERIC, NULL },
|
||||
{ 0xf3, "Application Card URL", PIV_TAG_PRINTSTR, NULL },
|
||||
{ 0xf4, "PKCS#15", PIV_TAG_NUMERIC, NULL },
|
||||
{ 0xf5, "Registered Data Model Number", PIV_TAG_NUMERIC, NULL },
|
||||
{ 0xf6, "Access Control Rule Table", PIV_TAG_HEXDUMP, NULL },
|
||||
{ 0xf7, "Card APDUs", PIV_TAG_GENERIC, NULL },
|
||||
{ 0xfa, "Redirection Tag", PIV_TAG_GENERIC, NULL },
|
||||
{ 0xfb, "Capability Tuples (CT)", PIV_TAG_GENERIC, NULL },
|
||||
{ 0xfc, "Status Tuples (ST)", PIV_TAG_GENERIC, NULL },
|
||||
{ 0xfd, "Next CCC", PIV_TAG_GENERIC, NULL },
|
||||
{ 0xfe, "Error Detection Code", PIV_TAG_GENERIC, NULL },
|
||||
};
|
||||
|
||||
struct guid {
|
||||
uint32_t part1;
|
||||
uint16_t part2;
|
||||
uint16_t part3;
|
||||
uint8_t data[8];
|
||||
};
|
||||
|
||||
static void parse_guid(const uint8_t *data, struct guid *guid) {
|
||||
if (guid == NULL) {
|
||||
return;
|
||||
}
|
||||
size_t ofs = 0;
|
||||
guid->part1 = MemBeToUint4byte(&data[ofs]);
|
||||
ofs += sizeof(uint32_t);
|
||||
guid->part2 = MemBeToUint2byte(&data[ofs]);
|
||||
ofs += sizeof(uint16_t);
|
||||
guid->part3 = MemBeToUint2byte(&data[ofs]);
|
||||
ofs += sizeof(uint16_t);
|
||||
for (size_t i = 0; i < sizeof(guid->data); i++) {
|
||||
guid->data[i] = data[ofs + i];
|
||||
}
|
||||
}
|
||||
|
||||
static void piv_print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf);
|
||||
static bool piv_tag_dump(const struct tlv *tlv, int level);
|
||||
|
||||
static void PrintChannel(Iso7816CommandChannel channel) {
|
||||
switch (channel) {
|
||||
case CC_CONTACTLESS:
|
||||
PrintAndLogEx(INFO, "Selected channel... " _GREEN_("CONTACTLESS (T=CL)"));
|
||||
break;
|
||||
case CC_CONTACT:
|
||||
PrintAndLogEx(INFO, "Selected channel... " _GREEN_("CONTACT"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int piv_sort_tag(tlv_tag_t tag) {
|
||||
return (int)(tag >= 0x100 ? tag : tag << 8);
|
||||
}
|
||||
|
||||
static int piv_tlv_compare(const void *a, const void *b) {
|
||||
const struct tlv *tlv = a;
|
||||
const struct piv_tag *tag = b;
|
||||
|
||||
return piv_sort_tag(tlv->tag) - (piv_sort_tag(tag->tag));
|
||||
}
|
||||
|
||||
static const struct piv_tag *piv_get_tag(const struct tlv *tlv) {
|
||||
const struct piv_tag *tag = bsearch(tlv, piv_tags, ARRAYLEN(piv_tags),
|
||||
sizeof(piv_tags[0]), piv_tlv_compare);
|
||||
return tag != NULL ? tag : &piv_tags[0];
|
||||
}
|
||||
|
||||
static unsigned long piv_value_numeric(const struct tlv *tlv, unsigned start, unsigned end) {
|
||||
unsigned long ret = 0;
|
||||
int i;
|
||||
|
||||
if (end > tlv->len * 2)
|
||||
return ret;
|
||||
if (start >= end)
|
||||
return ret;
|
||||
|
||||
if (start & 1) {
|
||||
ret += tlv->value[start / 2] & 0xf;
|
||||
i = start + 1;
|
||||
} else
|
||||
i = start;
|
||||
|
||||
for (; i < end - 1; i += 2) {
|
||||
ret *= 10;
|
||||
ret += tlv->value[i / 2] >> 4;
|
||||
ret *= 10;
|
||||
ret += tlv->value[i / 2] & 0xf;
|
||||
}
|
||||
|
||||
if (end & 1) {
|
||||
ret *= 10;
|
||||
ret += tlv->value[end / 2] >> 4;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void piv_tag_dump_yyyymmdd(const struct tlv *tlv, const struct piv_tag *tag, int level) {
|
||||
bool is_printable = true;
|
||||
for (size_t i = 0; i < tlv->len; i++) {
|
||||
if ((tlv->value[i] < 0x30) || (tlv->value[i] > 0x39)) {
|
||||
is_printable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_printable) {
|
||||
PrintAndLogEx(NORMAL, " " _YELLOW_("%c%c%c%c.%c%c.%c%c"),
|
||||
tlv->value[0], tlv->value[1], tlv->value[2], tlv->value[3],
|
||||
tlv->value[4], tlv->value[5],
|
||||
tlv->value[6], tlv->value[7]
|
||||
);
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " " _YELLOW_("%04lu.%02lu.%02lu"),
|
||||
piv_value_numeric(tlv, 0, 4),
|
||||
piv_value_numeric(tlv, 4, 6),
|
||||
piv_value_numeric(tlv, 6, 8)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void piv_tag_dump_enum(const struct tlv *tlv, const struct piv_tag *tag, int level) {
|
||||
const struct piv_tag_enum *values = tag->data;
|
||||
for (size_t i = 0; values[i].name != NULL; i++) {
|
||||
if (values[i].value == tlv->value[0]) {
|
||||
PrintAndLogEx(NORMAL, " %u - '" _YELLOW_("%s")"'",
|
||||
tlv->value[0], values[i].name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, " %u - " _RED_("Unknown??"), tlv->value[0]);
|
||||
}
|
||||
|
||||
static void piv_tag_dump_tlv(const struct tlv *tlv, const struct piv_tag *tag, int level) {
|
||||
// We don't use parsing methods because we need to discard constructed tags
|
||||
const unsigned char *buf = tlv->value;
|
||||
size_t left = tlv->len;
|
||||
|
||||
while (left) {
|
||||
struct tlv sub_tlv;
|
||||
//const struct piv_tag *sub_tag;
|
||||
|
||||
if (!tlv_parse_tl(&buf, &left, &sub_tlv)) {
|
||||
PrintAndLogEx(INFO, "%*sInvalid Tag-Len", (level * 4), " ");
|
||||
continue;
|
||||
}
|
||||
sub_tlv.value = buf;
|
||||
piv_tag_dump(&sub_tlv, level + 1);
|
||||
buf += sub_tlv.len;
|
||||
left -= sub_tlv.len;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void piv_print_cert(const uint8_t *buf, const size_t len, int level) {
|
||||
char prefix[256] = {0};
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
snprintf(prefix, sizeof(prefix), "%*s", 4 * level, " ");
|
||||
// TODO: when mbedTLS has a new release with the PCKS7 parser, we can replace the generic ASN.1 print
|
||||
// The pull request has been merged end of Nov 2022.
|
||||
asn1_print((uint8_t *) buf, len, prefix);
|
||||
}
|
||||
|
||||
static void piv_print_fascn(const uint8_t *buf, const size_t len, int level) {
|
||||
const char *encoded[32] = {
|
||||
_RED_("?"), // 0b00000
|
||||
"0", // 0b00001
|
||||
"8", // 0b00010
|
||||
_RED_("?"), // 0b00011
|
||||
"4", // 0b00100
|
||||
_RED_("?"), // 0b00101
|
||||
_RED_("?"), // 0b00110
|
||||
_RED_("?"), // 0b00111
|
||||
"2", // 0b01000
|
||||
_RED_("?"), // 0b01001
|
||||
_RED_("?"), // 0b01010
|
||||
_RED_("?"), // 0b01011
|
||||
_RED_("?"), // 0b01100
|
||||
"6", // 0b01101
|
||||
_RED_("?"), // 0b01110
|
||||
_RED_("?"), // 0b01111
|
||||
"1", // 0b10000
|
||||
_RED_("?"), // 0b10001
|
||||
_RED_("?"), // 0b10010
|
||||
"9", // 0b10011
|
||||
_RED_("?"), // 0b10100
|
||||
"5", // 0b10101
|
||||
_GREEN_(" FS "), // 0b10110
|
||||
_RED_("?"), // 0b10111
|
||||
_RED_("?"), // 0b11000
|
||||
"3", // 0b11001
|
||||
_YELLOW_("SS "), // 0b11010
|
||||
_RED_("?"), // 0b11011
|
||||
"7", // 0b11100
|
||||
_RED_("?"), // 0b11101
|
||||
_RED_("?"), // 0b11110
|
||||
_YELLOW_(" ES"), // 0b11111
|
||||
};
|
||||
const uint8_t cycle[8] = {5, 2, 7, 4, 1, 6, 3, 8};
|
||||
|
||||
PrintAndLogEx(INFO, "%*s" NOLF, 4 * level, " ");
|
||||
// Buffer is 40 bytes but last byte is LRC that we process separately
|
||||
for (int i = 0; i < 39; i++) {
|
||||
uint8_t tmp = buf[(5 * i) >> 3];
|
||||
uint8_t rot = cycle[i & 7];
|
||||
// rotate left to get the bits in place
|
||||
tmp = (tmp << rot) | (tmp >> (8 - rot));
|
||||
// append bits from next byte if needed
|
||||
if (rot < 5) {
|
||||
uint8_t tmp2 = buf[(5 * (i + 1)) >> 3];
|
||||
tmp2 = (tmp2 << rot) | (tmp2 >> (8 - rot));
|
||||
tmp &= 0x1f << rot;
|
||||
tmp |= tmp2 & ((1 << rot) - 1);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "%s" NOLF, encoded[tmp & 0x1f]);
|
||||
}
|
||||
uint8_t lrc = buf[24] & 0x1f;
|
||||
PrintAndLogEx(NORMAL, " LRC=[" _YELLOW_("%02x") "]", lrc);
|
||||
}
|
||||
|
||||
static bool piv_tag_dump(const struct tlv *tlv, int level) {
|
||||
if (tlv == NULL) {
|
||||
PrintAndLogEx(FAILED, "NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct piv_tag *tag = piv_get_tag(tlv);
|
||||
|
||||
PrintAndLogEx(INFO, "%*s--%2x[%02zx] '%s':" NOLF, (level * 4), " ", tlv->tag, tlv->len, tag->name);
|
||||
|
||||
switch (tag->type) {
|
||||
case PIV_TAG_GENERIC:
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
break;
|
||||
case PIV_TAG_HEXDUMP:
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
print_buffer(tlv->value, tlv->len, level + 1);
|
||||
break;
|
||||
case PIV_TAG_STRING:
|
||||
PrintAndLogEx(NORMAL, " '" _YELLOW_("%s")"'", sprint_hex_inrow(tlv->value, tlv->len));
|
||||
break;
|
||||
case PIV_TAG_NUMERIC:
|
||||
PrintAndLogEx(NORMAL, " " _YELLOW_("%lu"), piv_value_numeric(tlv, 0, tlv->len * 2));
|
||||
break;
|
||||
case PIV_TAG_YYYYMMDD:
|
||||
piv_tag_dump_yyyymmdd(tlv, tag, level);
|
||||
break;
|
||||
case PIV_TAG_ENUM:
|
||||
piv_tag_dump_enum(tlv, tag, level + 1);
|
||||
break;
|
||||
case PIV_TAG_TLV:
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
piv_tag_dump_tlv(tlv, tag, level);
|
||||
break;
|
||||
case PIV_TAG_PRINTSTR:
|
||||
PrintAndLogEx(NORMAL, " '" NOLF);
|
||||
for (size_t i = 0; i < tlv->len; i++) {
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("%c") NOLF, tlv->value[i]);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "'");
|
||||
break;
|
||||
case PIV_TAG_GUID:
|
||||
if (tlv->len != 16) {
|
||||
PrintAndLogEx(NORMAL, _RED_("<Invalid>"));
|
||||
} else {
|
||||
struct guid guid = {0};
|
||||
parse_guid(tlv->value, &guid);
|
||||
PrintAndLogEx(NORMAL, " " _YELLOW_("{%08x-%04x-%04x-") NOLF, guid.part1, guid.part2, guid.part3);
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("%02x") NOLF, guid.data[i]);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("}"));
|
||||
}
|
||||
break;
|
||||
case PIV_TAG_CERT:
|
||||
piv_print_cert(tlv->value, tlv->len, level + 2);
|
||||
break;
|
||||
case PIV_TAG_FASCN:
|
||||
PrintAndLogEx(NORMAL, " '" _YELLOW_("%s")"'", sprint_hex_inrow(tlv->value, tlv->len));
|
||||
if (tlv->len == 25) {
|
||||
piv_print_fascn(tlv->value, tlv->len, level + 2);
|
||||
}
|
||||
break;
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void piv_print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf) {
|
||||
piv_tag_dump(tlv, level);
|
||||
if (is_leaf) {
|
||||
print_buffer(tlv->value, tlv->len, level);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintTLV(const struct tlvdb *tlvdb) {
|
||||
if (tlvdb) {
|
||||
tlvdb_visit(tlvdb, piv_print_cb, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintTLVFromBuffer(const uint8_t *buf, size_t len) {
|
||||
if (buf == NULL || len == 0) {
|
||||
return;
|
||||
}
|
||||
struct tlvdb_root *root = calloc(1, sizeof(*root) + len);
|
||||
if (root == NULL) {
|
||||
return;
|
||||
}
|
||||
root->len = len;
|
||||
memcpy(root->buf, buf, len);
|
||||
if (tlvdb_parse_root_multi(root) == true) {
|
||||
PrintTLV(&(root->db));
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "TLV ERROR: Can't parse buffer as TLV tree.");
|
||||
}
|
||||
tlvdb_root_free(root);
|
||||
}
|
||||
|
||||
static int PivGetData(Iso7816CommandChannel channel, const uint8_t tag[], size_t tag_len, bool verbose, struct tlvdb_root **result, uint16_t *sw) {
|
||||
uint8_t apdu_data[5] = {0x5c, 0x00};
|
||||
|
||||
*result = NULL;
|
||||
*sw = 0;
|
||||
|
||||
if (tag_len < 1 || tag_len > 3) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
apdu_data[1] = tag_len;
|
||||
memcpy(&apdu_data[2], tag, tag_len);
|
||||
|
||||
sAPDU_t apdu = {
|
||||
.CLA = 0x00,
|
||||
.INS = 0xCB,
|
||||
.P1 = 0x3F,
|
||||
.P2 = 0xFF,
|
||||
.Lc = tag_len + 2,
|
||||
.data = apdu_data
|
||||
};
|
||||
|
||||
// Answer can be chained. Let's use a dynamically allocated buffer.
|
||||
size_t capacity = PM3_CMD_DATA_SIZE;
|
||||
struct tlvdb_root *root = calloc(1, sizeof(*root) + capacity);
|
||||
|
||||
if (root == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
root->len = 0;
|
||||
|
||||
size_t more_data = 0;
|
||||
do {
|
||||
size_t received = 0;
|
||||
int res = Iso7816ExchangeEx(channel, false, true, apdu, (more_data != 0), more_data, &(root->buf[root->len]), capacity - root->len, &received, sw);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "Sending APDU failed with code %d", res);
|
||||
free(root);
|
||||
return res;
|
||||
}
|
||||
root->len += received;
|
||||
if (((*sw) & 0xff00) == 0x6100) {
|
||||
// More data
|
||||
more_data = (*sw) & 0xff;
|
||||
if (more_data == 0x00 || more_data > MAX_APDU_SIZE) {
|
||||
more_data = MAX_APDU_SIZE;
|
||||
}
|
||||
apdu.CLA = 0x00;
|
||||
apdu.INS = 0xC0;
|
||||
apdu.P1 = 0x00;
|
||||
apdu.P2 = 0x00;
|
||||
apdu.Lc = 0;
|
||||
apdu.data = NULL;
|
||||
if ((capacity - root->len) < PM3_CMD_DATA_SIZE) {
|
||||
PrintAndLogEx(DEBUG, "Adding more capacity to buffer...");
|
||||
capacity += PM3_CMD_DATA_SIZE;
|
||||
struct tlvdb_root *new_root = realloc(root, sizeof(*root) + capacity);
|
||||
if (new_root == NULL) {
|
||||
PrintAndLogEx(FAILED, "Running out of memory while re-allocating buffer");
|
||||
free(root);
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
root = new_root;
|
||||
}
|
||||
}
|
||||
if ((*sw) == ISO7816_OK) {
|
||||
more_data = 0;
|
||||
}
|
||||
} while (more_data > 0);
|
||||
|
||||
// Now we can try parse the TLV and return it
|
||||
*result = root;
|
||||
if (*sw == ISO7816_OK && tlvdb_parse_root(root) == true) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
if (verbose == true) {
|
||||
PrintAndLogEx(WARNING, "Couldn't parse TLV answer.");
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int PivGetDataByCidAndPrint(Iso7816CommandChannel channel, const struct piv_container *cid, bool decodeTLV, bool verbose) {
|
||||
struct tlvdb_root *root = NULL;
|
||||
|
||||
if (cid == NULL) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Getting %s [" _GREEN_("%s") "]", cid->name, sprint_hex_inrow(cid->tlv_tag, cid->len));
|
||||
|
||||
uint16_t sw = 0;
|
||||
|
||||
if (PivGetData(channel, cid->tlv_tag, cid->len, verbose, &root, &sw) == PM3_SUCCESS) {
|
||||
switch (sw) {
|
||||
case ISO7816_OK:
|
||||
if (decodeTLV == true) {
|
||||
PrintTLV(&(root->db));
|
||||
} else {
|
||||
print_buffer(root->buf, root->len, 0);
|
||||
}
|
||||
break;
|
||||
case ISO7816_FILE_NOT_FOUND:
|
||||
PrintAndLogEx(FAILED, "Container not found.");
|
||||
break;
|
||||
case ISO7816_SECURITY_STATUS_NOT_SATISFIED:
|
||||
PrintAndLogEx(WARNING, "Security conditions not met.");
|
||||
break;
|
||||
default:
|
||||
if (verbose == true) {
|
||||
PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
}
|
||||
break;
|
||||
}
|
||||
tlvdb_root_free(root);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int PivGetDataByTagAndPrint(Iso7816CommandChannel channel, const uint8_t tag[], size_t tag_len, bool decodeTLV, bool verbose) {
|
||||
int idx = 0;
|
||||
|
||||
for (; PIV_CONTAINERS[idx].len != 0; idx++) {
|
||||
if ((tag_len == PIV_CONTAINERS[idx].len) && (memcmp(tag, PIV_CONTAINERS[idx].tlv_tag, tag_len) == 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (PIV_CONTAINERS[idx].len == 0) {
|
||||
struct piv_container cid = {0x00, tag, tag_len, PIV_OPTIONAL, "Getting unknown contained ID"};
|
||||
return PivGetDataByCidAndPrint(channel, &cid, decodeTLV, verbose);
|
||||
}
|
||||
return PivGetDataByCidAndPrint(channel, &(PIV_CONTAINERS[idx]), decodeTLV, verbose);
|
||||
}
|
||||
|
||||
static int PivAuthenticateSign(Iso7816CommandChannel channel, uint8_t alg_id, uint8_t key_id, uint8_t nonce[], size_t nonce_len, void **result, bool decodeTLV, bool verbose) {
|
||||
const size_t MAX_NONCE_LEN = 0x7a;
|
||||
if (nonce_len > MAX_NONCE_LEN) {
|
||||
if (verbose == true) {
|
||||
PrintAndLogEx(WARNING, "Nonce cannot exceed %zu bytes. Got %zu bytes.", MAX_NONCE_LEN, nonce_len);
|
||||
}
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
uint8_t apdu_buf[APDU_RES_LEN] = {0x7c, nonce_len + 4, 0x82, 0x00, 0x81, nonce_len};
|
||||
memcpy(&apdu_buf[6], nonce, nonce_len);
|
||||
sAPDU_t apdu = {
|
||||
0x00, 0x87, alg_id, key_id,
|
||||
6 + nonce_len, apdu_buf
|
||||
};
|
||||
|
||||
uint16_t sw = 0;
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 0;
|
||||
int res = Iso7816ExchangeEx(channel, false, true, apdu, false, 0, buf, APDU_RES_LEN, &len, &sw);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "Sending APDU failed with code %d", res);
|
||||
return res;
|
||||
}
|
||||
if (sw != ISO7816_OK) {
|
||||
if (verbose == true) {
|
||||
PrintAndLogEx(INFO, "Unexpected APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
}
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
if (verbose == true) {
|
||||
if (decodeTLV == true) {
|
||||
PrintTLVFromBuffer(buf, len);
|
||||
} else {
|
||||
print_buffer(buf, len, 0);
|
||||
}
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int PivSelect(Iso7816CommandChannel channel, bool activateField, bool leaveFieldOn, bool decodeTLV, bool silent, uint8_t applet[], size_t appletLen) {
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 0;
|
||||
uint16_t sw = 0;
|
||||
|
||||
int res = Iso7816Select(channel, activateField, leaveFieldOn, applet, appletLen, buf, sizeof(buf), &len, &sw);
|
||||
if ((sw != 0) && (silent == false)) {
|
||||
PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
}
|
||||
if (res != PM3_SUCCESS || sw != ISO7816_OK) {
|
||||
PrintAndLogEx(FAILED, "Applet selection failed. Card is not a PIV card.");
|
||||
return res;
|
||||
}
|
||||
if (silent == false) {
|
||||
if (decodeTLV == true) {
|
||||
PrintTLVFromBuffer(buf, len);
|
||||
} else {
|
||||
print_buffer(buf, len, 0);
|
||||
}
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdPIVSelect(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "piv select",
|
||||
"Executes select applet command",
|
||||
"piv select -s -> select card, select applet\n"
|
||||
"piv select -st --aid a00000030800001000 -> select card, select applet a00000030800001000, show result in TLV\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "Activate field and select applet"),
|
||||
arg_lit0("kK", "keep", "Keep field for next command"),
|
||||
arg_lit0("aA", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_str0(NULL, "aid", "<hex>", "Applet ID to select. By default A0000003080000100 will be used"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
bool activateField = arg_get_lit(ctx, 1);
|
||||
bool leaveSignalON = arg_get_lit(ctx, 2);
|
||||
bool APDULogging = arg_get_lit(ctx, 3);
|
||||
bool decodeTLV = arg_get_lit(ctx, 4);
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 5))
|
||||
channel = CC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
|
||||
uint8_t applet_id[APDU_AID_LEN] = {0};
|
||||
int aid_len = 0;
|
||||
CLIGetHexWithReturn(ctx, 6, applet_id, &aid_len);
|
||||
if (aid_len == 0) {
|
||||
memcpy(applet_id, PIV_APPLET, sizeof(PIV_APPLET));
|
||||
aid_len = sizeof(PIV_APPLET);
|
||||
}
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
SetAPDULogging(APDULogging);
|
||||
|
||||
return PivSelect(channel, activateField, leaveSignalON, decodeTLV, false, applet_id, aid_len);
|
||||
}
|
||||
|
||||
static int CmdPIVGetData(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "piv getdata",
|
||||
"Get a data container of a given tag",
|
||||
"piv getdata -s 5fc102 -> select card, select applet, get card holder unique identifer\n"
|
||||
"piv getdata -st 5fc102 -> select card, select applet, get card holder unique identifer, show result in TLV\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "Activate field and select applet"),
|
||||
arg_lit0("kK", "keep", "Keep field for next command"),
|
||||
arg_lit0("aA", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_str0(NULL, "aid", "<hex>", "Applet ID to select. By default A0000003080000100 will be used"),
|
||||
arg_str1(NULL, NULL, "<hex>", "Tag ID to read, between 1 and 3 bytes."),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
bool activateField = arg_get_lit(ctx, 1);
|
||||
bool leaveSignalON = arg_get_lit(ctx, 2);
|
||||
bool APDULogging = arg_get_lit(ctx, 3);
|
||||
bool decodeTLV = arg_get_lit(ctx, 4);
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 5))
|
||||
channel = CC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
|
||||
uint8_t applet_id[APDU_AID_LEN] = {0};
|
||||
int aid_len = 0;
|
||||
CLIGetHexWithReturn(ctx, 6, applet_id, &aid_len);
|
||||
if (aid_len == 0) {
|
||||
memcpy(applet_id, PIV_APPLET, sizeof(PIV_APPLET));
|
||||
aid_len = sizeof(PIV_APPLET);
|
||||
}
|
||||
|
||||
uint8_t tag[4] = {0};
|
||||
int tag_len = 0;
|
||||
CLIGetHexWithReturn(ctx, 7, tag, &tag_len);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if ((tag_len < 1) || (tag_len > 3)) {
|
||||
PrintAndLogEx(WARNING, "Tag should be between 1 and 3 bytes. Got %i", tag_len);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
SetAPDULogging(APDULogging);
|
||||
|
||||
int res = 0;
|
||||
if (activateField == true) {
|
||||
res = PivSelect(channel, activateField, true, decodeTLV, true, applet_id, aid_len);
|
||||
if (res != PM3_SUCCESS) {
|
||||
if (leaveSignalON == false) {
|
||||
DropFieldEx(channel);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
res = PivGetDataByTagAndPrint(channel, tag, tag_len, decodeTLV, false);
|
||||
if (leaveSignalON == false) {
|
||||
DropFieldEx(channel);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdPIVAuthenticateSign(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "piv sign",
|
||||
"Send a nonce and ask the PIV card to sign it",
|
||||
"piv sign -sk -> select card, select applet, sign a NULL nonce\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "Activate field and select applet"),
|
||||
arg_lit0("kK", "keep", "Keep field for next command"),
|
||||
arg_lit0("aA", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_str0(NULL, "aid", "<hex>", "Applet ID to select. By default A0000003080000100 will be used"),
|
||||
arg_str1(NULL, "nonce", "<hex>", "Nonce to sign."),
|
||||
arg_int0(NULL, "slot", "<dec id>", "Slot number. Default will be 0x9E (card auth cert)."),
|
||||
arg_int0(NULL, "alg", "<dec>", "Algorithm to use to sign. Example values: 06=RSA-1024, 07=RSA-2048, 11=ECC-P256 (default), 14=ECC-P384"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
bool activateField = arg_get_lit(ctx, 1);
|
||||
bool leaveSignalON = arg_get_lit(ctx, 2);
|
||||
bool APDULogging = arg_get_lit(ctx, 3);
|
||||
bool decodeTLV = arg_get_lit(ctx, 4);
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 5))
|
||||
channel = CC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
|
||||
uint8_t applet_id[APDU_AID_LEN] = {0};
|
||||
int aid_len = 0;
|
||||
CLIGetHexWithReturn(ctx, 6, applet_id, &aid_len);
|
||||
if (aid_len == 0) {
|
||||
memcpy(applet_id, PIV_APPLET, sizeof(PIV_APPLET));
|
||||
aid_len = sizeof(PIV_APPLET);
|
||||
}
|
||||
|
||||
uint8_t nonce[APDU_RES_LEN] = {0};
|
||||
int nonce_len = 0;
|
||||
CLIGetHexWithReturn(ctx, 7, nonce, &nonce_len);
|
||||
|
||||
int key_slot = arg_get_int_def(ctx, 8, 0x9e);
|
||||
int alg_id = arg_get_int_def(ctx, 9, 0x11);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (key_slot > 0xff) {
|
||||
PrintAndLogEx(FAILED, "Key slot must fit on 1 byte.");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (alg_id > 0xff) {
|
||||
PrintAndLogEx(FAILED, "Algorithm ID must fit on 1 byte");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
SetAPDULogging(APDULogging);
|
||||
|
||||
int res = 0;
|
||||
if (activateField == true) {
|
||||
res = PivSelect(channel, activateField, true, decodeTLV, true, applet_id, aid_len);
|
||||
if (res != PM3_SUCCESS) {
|
||||
if (leaveSignalON == false) {
|
||||
DropFieldEx(channel);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
res = PivAuthenticateSign(channel, (uint8_t)(alg_id & 0xff), (uint8_t)(key_slot & 0xff), nonce, nonce_len, NULL, decodeTLV, true);
|
||||
if (leaveSignalON == false) {
|
||||
DropFieldEx(channel);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdPIVScan(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "piv scan",
|
||||
"Scan a PIV card for known containers",
|
||||
"piv scan -s -> select card, select applet and run scan\n"
|
||||
"piv scan -st --aid a00000030800001000 -> select card, select applet a00000030800001000, show result of the scan in TLV\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "Activate field and select applet"),
|
||||
arg_lit0("kK", "keep", "Keep field for next command"),
|
||||
arg_lit0("aA", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_str0(NULL, "aid", "<hex>", "Applet ID to select. By default A0000003080000100 will be used"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
bool activateField = arg_get_lit(ctx, 1);
|
||||
bool leaveSignalON = arg_get_lit(ctx, 2);
|
||||
bool APDULogging = arg_get_lit(ctx, 3);
|
||||
bool decodeTLV = arg_get_lit(ctx, 4);
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 5))
|
||||
channel = CC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
|
||||
uint8_t applet_id[APDU_AID_LEN] = {0};
|
||||
int aid_len = 0;
|
||||
CLIGetHexWithReturn(ctx, 6, applet_id, &aid_len);
|
||||
if (aid_len == 0) {
|
||||
memcpy(applet_id, PIV_APPLET, sizeof(PIV_APPLET));
|
||||
aid_len = sizeof(PIV_APPLET);
|
||||
}
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
SetAPDULogging(APDULogging);
|
||||
if (aid_len == 0) {
|
||||
memcpy(applet_id, PIV_APPLET, sizeof(PIV_APPLET));
|
||||
aid_len = sizeof(PIV_APPLET);
|
||||
}
|
||||
if (activateField == true) {
|
||||
int res = PivSelect(channel, activateField, true, decodeTLV, true, applet_id, aid_len);
|
||||
if (res != PM3_SUCCESS) {
|
||||
if (leaveSignalON == false) {
|
||||
DropFieldEx(channel);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; PIV_CONTAINERS[i].len != 0; i++) {
|
||||
PivGetDataByCidAndPrint(channel, &(PIV_CONTAINERS[i]), decodeTLV, false);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
if (leaveSignalON == false) {
|
||||
DropFieldEx(channel);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdPIVList(const char *Cmd) {
|
||||
return CmdTraceListAlias(Cmd, "piv", "7816");
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"select", CmdPIVSelect, IfPm3Iso14443, "Select the PIV applet"},
|
||||
{"getdata", CmdPIVGetData, IfPm3Iso14443, "Gets a container on a PIV card"},
|
||||
{"authsign", CmdPIVAuthenticateSign, IfPm3Iso14443, "Authenticate with the card"},
|
||||
{"scan", CmdPIVScan, IfPm3Iso14443, "Scan PIV card for known containers"},
|
||||
|
||||
{"list", CmdPIVList, AlwaysAvailable, "List ISO7816 history"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdsHelp(CommandTable);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdPIV(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
26
client/src/cmdpiv.h
Normal file
26
client/src/cmdpiv.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// PIV commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef CMDPIV_H__
|
||||
#define CMDPIV_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int CmdPIV(const char *Cmd);
|
||||
|
||||
#endif
|
|
@ -404,7 +404,7 @@ static int CmdScriptRun(const char *Cmd) {
|
|||
PyImport_AppendInittab("_pm3", PyInit__pm3);
|
||||
#endif
|
||||
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 10
|
||||
Py_Initialize();
|
||||
Py_Initialize();
|
||||
#else
|
||||
PyConfig py_conf;
|
||||
PyConfig_InitIsolatedConfig(&py_conf);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -871,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);
|
||||
|
@ -900,16 +900,16 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
|||
|
||||
if (use_us) {
|
||||
PrintAndLogEx(NORMAL, " %10.1f | %10.1f | %s |fdt (Frame Delay Time): " _YELLOW_("%.1f"),
|
||||
(float)time1 / 13.56,
|
||||
(float)time2 / 13.56,
|
||||
" ",
|
||||
(float)(next_hdr->timestamp - end_of_transmission_timestamp) / 13.56);
|
||||
(float)time1 / 13.56,
|
||||
(float)time2 / 13.56,
|
||||
" ",
|
||||
(float)(next_hdr->timestamp - end_of_transmission_timestamp) / 13.56);
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " %10u | %10u | %s |fdt (Frame Delay Time): " _YELLOW_("%d"),
|
||||
time1,
|
||||
time2,
|
||||
" ",
|
||||
(next_hdr->timestamp - end_of_transmission_timestamp));
|
||||
time1,
|
||||
time2,
|
||||
" ",
|
||||
(next_hdr->timestamp - end_of_transmission_timestamp));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,9 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdemv.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "comms.h" // DropField
|
||||
#include "cmdsmartcard.h" // smart_select
|
||||
#include "comms.h" // DropField
|
||||
#include "cmdsmartcard.h" // smart_select
|
||||
#include "cmdtrace.h"
|
||||
#include "emvjson.h"
|
||||
#include "test/cryptotest.h"
|
||||
|
@ -35,6 +33,7 @@
|
|||
#include "ui.h"
|
||||
#include "emv_tags.h"
|
||||
#include "fileutils.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -1564,7 +1563,7 @@ static int CmdEMVScan(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "PPSE");
|
||||
res = EMVSelectPSE(channel, true, true, 2, buf, sizeof(buf), &len, &sw);
|
||||
|
||||
if (!res && sw == 0x9000) {
|
||||
if (!res && sw == ISO7816_OK) {
|
||||
if (decodeTLV)
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
|
||||
|
|
|
@ -17,13 +17,11 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "emvcore.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "comms.h" // DropField
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "comms.h" // DropField
|
||||
#include "cmdparser.h"
|
||||
#include "cmdsmartcard.h" // ExchangeAPDUSC
|
||||
#include "cmdsmartcard.h" // ExchangeAPDUSC
|
||||
#include "ui.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "cmdhf14b.h"
|
||||
|
@ -31,6 +29,7 @@
|
|||
#include "emv_tags.h"
|
||||
#include "emvjson.h"
|
||||
#include "util_posix.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
// Got from here. Thanks!
|
||||
// https://eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix
|
||||
|
@ -382,8 +381,6 @@ static int EMVCheckAID(Iso7816CommandChannel channel, bool decodeTLV, struct tlv
|
|||
int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) {
|
||||
uint8_t data[APDU_RES_LEN] = {0};
|
||||
size_t datalen = 0;
|
||||
uint8_t sfidata[0x11][APDU_RES_LEN];
|
||||
size_t sfidatalen[0x11] = {0};
|
||||
uint16_t sw = 0;
|
||||
int res;
|
||||
const char *PSE_or_PPSE = PSENum == 1 ? "PSE" : "PPSE";
|
||||
|
@ -392,7 +389,7 @@ int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFi
|
|||
res = EMVSelectPSE(channel, ActivateField, true, PSENum, data, sizeof(data), &datalen, &sw);
|
||||
|
||||
if (!res) {
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
PrintAndLogEx(FAILED, "Select PSE error. APDU error: %04x.", sw);
|
||||
return 1;
|
||||
}
|
||||
|
@ -403,6 +400,8 @@ int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFi
|
|||
// PSE/PPSE with SFI
|
||||
struct tlvdb *tsfi = tlvdb_find_path(t, (tlv_tag_t[]) {0x6f, 0xa5, 0x88, 0x00});
|
||||
if (tsfi) {
|
||||
uint8_t sfidata[0x11][APDU_RES_LEN];
|
||||
size_t sfidatalen[0x11] = {0};
|
||||
uint8_t sfin = 0;
|
||||
tlv_get_uint8(tlvdb_get_tlv(tsfi), &sfin);
|
||||
PrintAndLogEx(INFO, "* PPSE get SFI: 0x%02x.", sfin);
|
||||
|
@ -419,7 +418,7 @@ int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFi
|
|||
}
|
||||
|
||||
// error catch!
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
sfidatalen[ui] = 0;
|
||||
PrintAndLogEx(FAILED, "PPSE get Error. APDU error: %04x.", sw);
|
||||
break;
|
||||
|
@ -670,10 +669,6 @@ static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04};
|
|||
static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value };
|
||||
|
||||
int trDDA(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 0;
|
||||
uint16_t sw = 0;
|
||||
|
||||
struct emv_pk *pk = get_ca_pk(tlv);
|
||||
if (!pk) {
|
||||
PrintAndLogEx(ERR, "Error: Key not found, exiting");
|
||||
|
@ -768,6 +763,9 @@ int trDDA(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
tlvdb_free(atc_db);
|
||||
|
||||
} else {
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 0;
|
||||
uint16_t sw = 0;
|
||||
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||
if (dac_db) {
|
||||
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
||||
|
|
|
@ -44,19 +44,6 @@
|
|||
// const typeof( ((type *)0)->member ) *__mptr = (ptr);
|
||||
// (type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
|
||||
struct tlvdb {
|
||||
struct tlv tag;
|
||||
struct tlvdb *next;
|
||||
struct tlvdb *parent;
|
||||
struct tlvdb *children;
|
||||
};
|
||||
|
||||
struct tlvdb_root {
|
||||
struct tlvdb db;
|
||||
size_t len;
|
||||
unsigned char buf[0];
|
||||
};
|
||||
|
||||
static tlv_tag_t tlv_parse_tag(const unsigned char **buf, size_t *len) {
|
||||
tlv_tag_t tag;
|
||||
|
||||
|
@ -212,6 +199,7 @@ struct tlvdb *tlvdb_parse(const unsigned char *buf, size_t len) {
|
|||
err:
|
||||
tlvdb_free(&root->db);
|
||||
|
||||
free(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -248,9 +236,53 @@ struct tlvdb *tlvdb_parse_multi(const unsigned char *buf, size_t len) {
|
|||
err:
|
||||
tlvdb_free(&root->db);
|
||||
|
||||
free(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool tlvdb_parse_root(struct tlvdb_root *root) {
|
||||
if (root == NULL || root->len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t *tmp;
|
||||
size_t left;
|
||||
|
||||
tmp = root->buf;
|
||||
left = root->len;
|
||||
if (tlvdb_parse_one(&root->db, NULL, &tmp, &left) == true) {
|
||||
if (left == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool tlvdb_parse_root_multi(struct tlvdb_root *root) {
|
||||
if (root == NULL || root->len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t *tmp;
|
||||
size_t left;
|
||||
|
||||
tmp = root->buf;
|
||||
left = root->len;
|
||||
if (tlvdb_parse_one(&root->db, NULL, &tmp, &left) == true) {
|
||||
while (left > 0) {
|
||||
struct tlvdb *db = calloc(1, sizeof(*db));
|
||||
if (tlvdb_parse_one(db, NULL, &tmp, &left) == true) {
|
||||
tlvdb_add(&root->db, db);
|
||||
} else {
|
||||
free(db);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_fixed(tlv_tag_t tag, size_t len, const unsigned char *value) {
|
||||
struct tlvdb_root *root = calloc(1, sizeof(*root) + len);
|
||||
|
||||
|
@ -291,6 +323,21 @@ void tlvdb_free(struct tlvdb *tlvdb) {
|
|||
}
|
||||
}
|
||||
|
||||
void tlvdb_root_free(struct tlvdb_root *root) {
|
||||
if (root == NULL) {
|
||||
return;
|
||||
}
|
||||
if (root->db.children) {
|
||||
tlvdb_free(root->db.children);
|
||||
root->db.children = NULL;
|
||||
}
|
||||
if (root->db.next) {
|
||||
tlvdb_free(root->db.next);
|
||||
root->db.next = NULL;
|
||||
}
|
||||
free(root);
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_find_next(struct tlvdb *tlvdb, tlv_tag_t tag) {
|
||||
if (!tlvdb)
|
||||
return NULL;
|
||||
|
|
|
@ -31,14 +31,31 @@ struct tlv {
|
|||
const unsigned char *value;
|
||||
};
|
||||
|
||||
struct tlvdb;
|
||||
struct tlvdb {
|
||||
struct tlv tag;
|
||||
struct tlvdb *next;
|
||||
struct tlvdb *parent;
|
||||
struct tlvdb *children;
|
||||
};
|
||||
|
||||
struct tlvdb_root {
|
||||
struct tlvdb db;
|
||||
size_t len;
|
||||
unsigned char buf[0];
|
||||
};
|
||||
|
||||
typedef void (*tlv_cb)(void *data, const struct tlv *tlv, int level, bool is_leaf);
|
||||
|
||||
struct tlvdb *tlvdb_fixed(tlv_tag_t tag, size_t len, const unsigned char *value);
|
||||
struct tlvdb *tlvdb_external(tlv_tag_t tag, size_t len, const unsigned char *value);
|
||||
struct tlvdb *tlvdb_parse(const unsigned char *buf, size_t len);
|
||||
struct tlvdb *tlvdb_parse_multi(const unsigned char *buf, size_t len);
|
||||
|
||||
bool tlvdb_parse_root(struct tlvdb_root *root);
|
||||
bool tlvdb_parse_root_multi(struct tlvdb_root *root);
|
||||
|
||||
void tlvdb_free(struct tlvdb *tlvdb);
|
||||
void tlvdb_root_free(struct tlvdb_root *root);
|
||||
|
||||
struct tlvdb *tlvdb_elm_get_next(struct tlvdb *tlvdb);
|
||||
struct tlvdb *tlvdb_elm_get_children(struct tlvdb *tlvdb);
|
||||
|
|
|
@ -258,13 +258,13 @@ static size_t path_size(savePaths_t a) {
|
|||
if (a == spItemCount) {
|
||||
return 0;
|
||||
}
|
||||
return strlen( g_session.defaultPaths[a] );
|
||||
return strlen(g_session.defaultPaths[a]);
|
||||
}
|
||||
|
||||
char *newfilenamemcopy(const char *preferredName, const char *suffix) {
|
||||
if (preferredName == NULL || suffix == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t p_namelen = strlen(preferredName);
|
||||
if (str_endswith(preferredName, suffix))
|
||||
|
@ -328,7 +328,7 @@ int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t
|
|||
}
|
||||
|
||||
char *fileName = newfilenamemcopy(preferredName, ".eml");
|
||||
if (fileName == NULL) {
|
||||
if (fileName == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
|
@ -1162,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")) {
|
||||
|
@ -1187,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;
|
||||
}
|
||||
|
||||
|
@ -1206,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;
|
||||
|
||||
|
@ -1218,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;
|
||||
|
@ -1243,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;
|
||||
}
|
||||
|
@ -1268,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;
|
||||
|
||||
|
@ -1290,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;
|
||||
|
||||
|
@ -1311,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;
|
||||
|
||||
|
@ -1332,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;
|
||||
|
||||
|
@ -1342,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++) {
|
||||
|
@ -1368,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;
|
||||
|
||||
|
|
|
@ -489,7 +489,7 @@ static void flash_suggest_update_bootloader(void) {
|
|||
PrintAndLogEx(ERR, "------------- " _CYAN_("Follow these steps") " -------------------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(ERR, " 1) ./pm3-flash-bootrom");
|
||||
PrintAndLogEx(ERR, " 2) ./pm3-flash-all");
|
||||
PrintAndLogEx(ERR, " 2) ./pm3-flash-fullimage");
|
||||
PrintAndLogEx(ERR, " 3) ./pm3");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "---------------------------------------------------");
|
||||
|
|
|
@ -440,7 +440,8 @@ int APDUDecode(uint8_t *data, int len, APDU_t *apdu) {
|
|||
int APDUEncode(APDU_t *apdu, uint8_t *data, int *len) {
|
||||
if (len)
|
||||
*len = 0;
|
||||
|
||||
if (apdu == NULL)
|
||||
return 1;
|
||||
if (apdu->le > 0x10000)
|
||||
return 1;
|
||||
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "iso7816core.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "comms.h" // DropField
|
||||
#include "cmdparser.h"
|
||||
|
@ -29,6 +27,7 @@
|
|||
#include "cmdhf14b.h"
|
||||
#include "iso14b.h" // iso14b_raw_cmd_t
|
||||
#include "util_posix.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
//iceman: this logging setting, should be unified with client debug etc.
|
||||
static bool APDULogging = false;
|
||||
|
@ -170,7 +169,7 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
*sw = isw;
|
||||
}
|
||||
|
||||
if (isw != 0x9000) {
|
||||
if (isw != ISO7816_OK) {
|
||||
if (APDULogging) {
|
||||
if (*sw >> 8 == 0x61) {
|
||||
PrintAndLogEx(ERR, "APDU chaining len %02x", *sw & 0xFF);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "util.h"
|
||||
#include "comms.h" // clearCommandBuffer
|
||||
#include "commonutil.h" // ntohl (pm3 version)
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
|
||||
// Date type. This is the actual on-card format.
|
||||
typedef struct {
|
||||
|
@ -98,7 +99,7 @@ typedef struct {
|
|||
KEY_TYPE key, const char* defaultValue) { \
|
||||
struct _ksx6924_enum_ ## KEY_TYPE *r = bsearch( \
|
||||
&key, KSX6924_ENUM_ ## NAME, \
|
||||
sizeof(KSX6924_ENUM_ ## NAME) / sizeof(KSX6924_ENUM_ ## NAME [0]), \
|
||||
ARRAYLEN(KSX6924_ENUM_ ## NAME), \
|
||||
sizeof(KSX6924_ENUM_ ## NAME [0]), \
|
||||
_ksx6924_ ## KEY_TYPE ## _enum_compare); \
|
||||
if (r == NULL) { \
|
||||
|
@ -402,7 +403,7 @@ bool KSX6924TrySelect(void) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
if (sw) {
|
||||
PrintAndLogEx(FAILED,
|
||||
"Not a KS X 6924 card! APDU response: %04x - %s",
|
||||
|
@ -444,7 +445,7 @@ bool KSX6924GetBalance(uint32_t *result) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -476,7 +477,7 @@ bool KSX6924InitializeCard(uint8_t mpda1, uint8_t mpda2, uint8_t mpda3, uint8_t
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -574,7 +575,7 @@ bool KSX6924ProprietaryGetRecord(uint8_t id, uint8_t *result, size_t result_len)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sw != 0x9000) {
|
||||
if (sw != ISO7816_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,9 +32,9 @@
|
|||
#include "aes.h"
|
||||
#include "ui.h"
|
||||
#include "crc.h"
|
||||
#include "crc16.h" // crc16 ccitt
|
||||
#include "crc16.h" // crc16 ccitt
|
||||
#include "crc32.h"
|
||||
#include "protocols.h"
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
#include "cmdhf14a.h"
|
||||
#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
|
||||
#include "iso7816/iso7816core.h" // APDU logging
|
||||
|
@ -470,7 +470,7 @@ static int DESFIRESendApduEx(bool activate_field, sAPDU_t apdu, uint16_t le, uin
|
|||
if (sw)
|
||||
*sw = isw;
|
||||
|
||||
if (isw != 0x9000 &&
|
||||
if (isw != ISO7816_OK &&
|
||||
isw != DESFIRE_GET_ISO_STATUS(MFDES_S_OPERATION_OK) &&
|
||||
isw != DESFIRE_GET_ISO_STATUS(MFDES_S_SIGNATURE) &&
|
||||
isw != DESFIRE_GET_ISO_STATUS(MFDES_S_ADDITIONAL_FRAME) &&
|
||||
|
@ -1655,7 +1655,7 @@ static bool DesfireCheckISOAuthCmd(DesfireISOSelectWay way, uint32_t appID, char
|
|||
uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keyNum;
|
||||
res = DesfireExchangeISO(false, &dctx, (sAPDU_t) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, rndlen * 2, piccrnd}, 0, resp, &resplen, &sw);
|
||||
DropField();
|
||||
return (sw == 0x9000 || sw == 0x6982);
|
||||
return (sw == ISO7816_OK || sw == ISO7816_SECURITY_STATUS_NOT_SATISFIED);
|
||||
}
|
||||
|
||||
void DesfireCheckAuthCommands(DesfireISOSelectWay way, uint32_t appID, char *dfname, uint8_t keyNum, AuthCommandsChk_t *authCmdCheck) {
|
||||
|
@ -2301,9 +2301,9 @@ static const char *GetDesfireKeyType(uint8_t keytype) {
|
|||
}
|
||||
|
||||
const char *GetDesfireAccessRightStr(uint8_t right) {
|
||||
static char int_access_str[200];
|
||||
|
||||
if (right <= 0x0d) {
|
||||
static char int_access_str[200];
|
||||
snprintf(int_access_str, sizeof(int_access_str), "key 0x%02x", right);
|
||||
return int_access_str;
|
||||
}
|
||||
|
@ -2859,7 +2859,7 @@ int DesfireISOSelectEx(DesfireContext_t *dctx, bool fieldon, DesfireISOSelectCon
|
|||
size_t xresplen = 0;
|
||||
uint16_t sw = 0;
|
||||
int res = DesfireExchangeISO(fieldon, dctx, (sAPDU_t) {0x00, ISO7816_SELECT_FILE, cntr, ((resp == NULL) ? 0x0C : 0x00), datalen, data}, APDU_INCLUDE_LE_00, xresp, &xresplen, &sw);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
if (res == PM3_SUCCESS && sw != ISO7816_OK)
|
||||
return PM3_ESOFT;
|
||||
|
||||
if (resp != NULL && resplen != NULL) {
|
||||
|
@ -2885,7 +2885,7 @@ int DesfireISOSelectDF(DesfireContext_t *dctx, char *dfname, uint8_t *resp, size
|
|||
int DesfireISOGetChallenge(DesfireContext_t *dctx, DesfireCryptoAlgorithm keytype, uint8_t *resp, size_t *resplen) {
|
||||
uint16_t sw = 0;
|
||||
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_GET_CHALLENGE, 0x00, 0x00, 0x00, NULL}, DesfireGetRndLenForKey(keytype), resp, resplen, &sw);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
if (res == PM3_SUCCESS && sw != ISO7816_OK)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
|
@ -2900,7 +2900,7 @@ int DesfireISOExternalAuth(DesfireContext_t *dctx, bool app_level, uint8_t keynu
|
|||
|
||||
uint16_t sw = 0;
|
||||
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, DesfireGetRndLenForKey(keytype) * 2, data}, 0, resp, &resplen, &sw);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
if (res == PM3_SUCCESS && sw != ISO7816_OK)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
|
@ -2913,7 +2913,7 @@ int DesfireISOInternalAuth(DesfireContext_t *dctx, bool app_level, uint8_t keynu
|
|||
|
||||
uint16_t sw = 0;
|
||||
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_INTERNAL_AUTHENTICATION, p1, p2, keylen, data}, keylen * 2, resp, resplen, &sw);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
if (res == PM3_SUCCESS && sw != ISO7816_OK)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
|
@ -2929,7 +2929,7 @@ int DesfireISOReadBinary(DesfireContext_t *dctx, bool use_file_id, uint8_t filei
|
|||
|
||||
uint16_t sw = 0;
|
||||
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_READ_BINARY, p1, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
if (res == PM3_SUCCESS && sw != ISO7816_OK)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
|
@ -2948,7 +2948,7 @@ int DesfireISOUpdateBinary(DesfireContext_t *dctx, bool use_file_id, uint8_t fil
|
|||
|
||||
uint16_t sw = 0;
|
||||
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_UPDATE_BINARY, p1, p2, datalen, data}, 0, resp, &resplen, &sw);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
if (res == PM3_SUCCESS && sw != ISO7816_OK)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
|
@ -2959,7 +2959,7 @@ int DesfireISOReadRecords(DesfireContext_t *dctx, uint8_t recordnum, bool read_a
|
|||
|
||||
uint16_t sw = 0;
|
||||
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_READ_RECORDS, recordnum, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
if (res == PM3_SUCCESS && sw != ISO7816_OK)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
|
@ -2973,7 +2973,7 @@ int DesfireISOAppendRecord(DesfireContext_t *dctx, uint8_t fileid, uint8_t *data
|
|||
|
||||
uint16_t sw = 0;
|
||||
int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_APPEND_RECORD, 0x00, p2, datalen, data}, 0, resp, &resplen, &sw);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
if (res == PM3_SUCCESS && sw != ISO7816_OK)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
|
|
|
@ -74,22 +74,37 @@ AccessConditions_t MFAccessConditionsTrailer[] = {
|
|||
};
|
||||
|
||||
bool mfValidateAccessConditions(const uint8_t *data) {
|
||||
uint8_t ndata1 = (data[0]) & 0x0f;
|
||||
uint8_t ndata2 = (data[0] >> 4) & 0x0f;
|
||||
uint8_t ndata3 = (data[1]) & 0x0f;
|
||||
uint8_t data1 = (data[1] >> 4) & 0x0f;
|
||||
uint8_t data2 = (data[2]) & 0x0f;
|
||||
uint8_t data3 = (data[2] >> 4) & 0x0f;
|
||||
uint8_t nd1 = NIBBLE_LOW(data[0]);
|
||||
uint8_t nd2 = NIBBLE_HIGH(data[0]);
|
||||
uint8_t nd3 = NIBBLE_LOW(data[1]);
|
||||
uint8_t d1 = NIBBLE_HIGH(data[1]);
|
||||
uint8_t d2 = NIBBLE_LOW(data[2]);
|
||||
uint8_t d3 = NIBBLE_HIGH(data[2]);
|
||||
|
||||
return ((ndata1 == (data1 ^ 0xF)) && (ndata2 == (data2 ^ 0xF)) && (ndata3 == (data3 ^ 0xF)));
|
||||
return ((nd1 == (d1 ^ 0xF)) && (nd2 == (d2 ^ 0xF)) && (nd3 == (d3 ^ 0xF)));
|
||||
}
|
||||
bool mfReadOnlyAccessConditions(uint8_t blockn, const uint8_t *data) {
|
||||
|
||||
uint8_t d1 = NIBBLE_HIGH(data[1]) >> blockn;
|
||||
uint8_t d2 = NIBBLE_LOW(data[2]) >> blockn;
|
||||
uint8_t d3 = NIBBLE_HIGH(data[2]) >> blockn;
|
||||
uint8_t cond = (d1 & 0x01) << 2 | (d2 & 0x01) << 1 | (d3 & 0x01);
|
||||
|
||||
if (blockn == 3) {
|
||||
if ((cond == 0x02) || (cond == 0x06) || (cond == 0x07)) return true;
|
||||
} else {
|
||||
if ((cond == 0x02) || (cond == 0x05)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *mfGetAccessConditionsDesc(uint8_t blockn, const uint8_t *data) {
|
||||
uint8_t data1 = ((data[1] >> 4) & 0x0f) >> blockn;
|
||||
uint8_t data2 = ((data[2]) & 0x0f) >> blockn;
|
||||
uint8_t data3 = ((data[2] >> 4) & 0x0f) >> blockn;
|
||||
|
||||
uint8_t cond = (data1 & 0x01) << 2 | (data2 & 0x01) << 1 | (data3 & 0x01);
|
||||
const char *mfGetAccessConditionsDesc(uint8_t blockn, const uint8_t *data) {
|
||||
uint8_t d1 = NIBBLE_HIGH(data[1]) >> blockn;
|
||||
uint8_t d2 = NIBBLE_LOW(data[2]) >> blockn;
|
||||
uint8_t d3 = NIBBLE_HIGH(data[2]) >> blockn;
|
||||
|
||||
uint8_t cond = (d1 & 0x01) << 2 | (d2 & 0x01) << 1 | (d3 & 0x01);
|
||||
|
||||
if (blockn == 3) {
|
||||
for (int i = 0; i < ARRAYLEN(MFAccessConditionsTrailer); i++)
|
||||
|
|
|
@ -71,6 +71,7 @@ int MFPGetSignature(bool activateField, bool leaveSignalON, uint8_t *dataout, in
|
|||
int MFPGetVersion(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||
|
||||
bool mfValidateAccessConditions(const uint8_t *data);
|
||||
bool mfReadOnlyAccessConditions(uint8_t blockn, const uint8_t *data);
|
||||
const char *mfGetAccessConditionsDesc(uint8_t blockn, const uint8_t *data);
|
||||
|
||||
uint8_t mfNumBlocksPerSector(uint8_t sectorNo);
|
||||
|
|
|
@ -1466,7 +1466,7 @@ int convert_mfc_2_arr(uint8_t *in, uint16_t ilen, uint8_t *out, uint16_t *olen)
|
|||
ilen -= MFBLOCK_SIZE;
|
||||
*olen += MFBLOCK_SIZE;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static const vigik_pk_t vigik_rsa_pk[] = {
|
||||
|
@ -1499,24 +1499,24 @@ 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
|
||||
// Exponent V = 2
|
||||
// n = The public modulus n is the product of the secret prime factors p and q. Its length is 1024 bits.
|
||||
|
||||
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
|
||||
|
@ -1527,7 +1527,7 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
|
|||
|
||||
// signature = h( C || M1 || h(M2) )
|
||||
// 1024 - 786 - 160 - 16 -1
|
||||
// salt C
|
||||
// salt C
|
||||
// message M = 96 bytes, 768 bits
|
||||
// sha1 hash H = 20 bytes, 160 bits
|
||||
// padding = 20 bytes, 96 bits
|
||||
|
@ -1563,18 +1563,18 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
|
|||
mbedtls_mpi_init(&sqr);
|
||||
mbedtls_mpi_init(&res);
|
||||
|
||||
mbedtls_mpi_read_binary(&N, (const unsigned char*)n, PUBLIC_VIGIK_KEYLEN);
|
||||
mbedtls_mpi_read_binary(&N, (const unsigned char *)n, PUBLIC_VIGIK_KEYLEN);
|
||||
|
||||
//mbedtls_mpi_read_binary(&s, (const unsigned char*)signature, signature_len);
|
||||
mbedtls_mpi_read_binary(&s, (const unsigned char*)rev_sig, signature_len);
|
||||
mbedtls_mpi_read_binary(&s, (const unsigned char *)rev_sig, sizeof(d->rsa_signature));
|
||||
|
||||
// check is sign < (N/2)
|
||||
|
||||
|
||||
mbedtls_mpi n_2;
|
||||
mbedtls_mpi_init(&n_2);
|
||||
mbedtls_mpi_copy(&n_2, &N);
|
||||
mbedtls_mpi_shift_r(&n_2, 1);
|
||||
bool is_less = (mbedtls_mpi_cmp_mpi(&s, &n_2) > 0) ? false : true;
|
||||
bool is_less = (mbedtls_mpi_cmp_mpi(&s, &n_2) > 0) ? false : true;
|
||||
PrintAndLogEx(DEBUG, "z < (N/2) ..... %s", (is_less) ? _GREEN_("YES") : _RED_("NO"));
|
||||
mbedtls_mpi_free(&n_2);
|
||||
|
||||
|
@ -1644,10 +1644,10 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
|
|||
|
||||
PrintAndLogEx(DEBUG, "LSB............ " _GREEN_("%u"), lsb);
|
||||
if (g_debugMode == DEBUG) {
|
||||
mbedtls_mpi_write_file( "[=] N.............. ", &N, 16, NULL );
|
||||
mbedtls_mpi_write_file( "[=] signature...... ", &s, 16, NULL );
|
||||
mbedtls_mpi_write_file( "[=] square mod n... ", &sqr, 16, NULL );
|
||||
mbedtls_mpi_write_file( "[=] n-fs........... ", &res, 16, NULL );
|
||||
mbedtls_mpi_write_file("[=] N.............. ", &N, 16, NULL);
|
||||
mbedtls_mpi_write_file("[=] signature...... ", &s, 16, NULL);
|
||||
mbedtls_mpi_write_file("[=] square mod n... ", &sqr, 16, NULL);
|
||||
mbedtls_mpi_write_file("[=] n-fs........... ", &res, 16, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1656,9 +1656,9 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
|
|||
|
||||
// xor 0xDC01
|
||||
int count_zero = 0;
|
||||
for (int x = 0; x < sizeof(nfs); x +=2) {
|
||||
for (int x = 0; x < sizeof(nfs); x += 2) {
|
||||
nfs[x] ^= 0xDC;
|
||||
nfs[x+1] ^= 0x01;
|
||||
nfs[x + 1] ^= 0x01;
|
||||
|
||||
if (nfs[x] == 0x00)
|
||||
count_zero++;
|
||||
|
@ -1689,10 +1689,10 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
|
|||
PrintAndLogEx(INFO, "Hash byte... 0x%02X", ts.hash);
|
||||
switch(ts.rsa[126]) {
|
||||
case 0x11:
|
||||
PrintAndLogEx(INFO, "Hash algo ( 0x%02X ) - SHA1");
|
||||
PrintAndLogEx(INFO, "Hash algo ( 0x%02X ) - SHA1");
|
||||
break;
|
||||
case 0x22:
|
||||
PrintAndLogEx(INFO, "Hash algo ( 0x%02X ) - RIPEMD");
|
||||
PrintAndLogEx(INFO, "Hash algo ( 0x%02X ) - RIPEMD");
|
||||
break;
|
||||
case 0x33:
|
||||
PrintAndLogEx(INFO, "Hash algo ( 0x%02X ) - SHA1");
|
||||
|
@ -1711,7 +1711,7 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
|
|||
print_hex_noascii_break(ts.rsa, sizeof(ts.rsa) - 20, 32);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
mbedtls_mpi_free(&N);
|
||||
mbedtls_mpi_free(&s);
|
||||
mbedtls_mpi_free(&res);
|
||||
|
@ -1722,10 +1722,10 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
|
|||
PrintAndLogEx(INFO, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
|
||||
PrintAndLogEx(INFO, "RSA: 1024bit");
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -1736,41 +1736,39 @@ int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature
|
|||
PrintAndLogEx(INFO, "%.64s", vigik_rsa_pk[i].n + 64);
|
||||
PrintAndLogEx(INFO, "%.64s", vigik_rsa_pk[i].n + 128);
|
||||
PrintAndLogEx(INFO, "%.64s", vigik_rsa_pk[i].n + 192);
|
||||
|
||||
|
||||
PrintAndLogEx(INFO, "Signature:");
|
||||
print_hex_noascii_break(signature, signature_len, MFBLOCK_SIZE * 2);
|
||||
print_hex_noascii_break(d->rsa_signature, sizeof(d->rsa_signature), MFBLOCK_SIZE * 2);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Signature verification: " _GREEN_("successful"));
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int vigik_annotate(uint8_t *d) {
|
||||
int vigik_annotate(mfc_vigik_t *d) {
|
||||
if (d == NULL)
|
||||
return PM3_EINVARG;
|
||||
|
||||
mfc_vigik_t *foo = (mfc_vigik_t*)d;
|
||||
|
||||
PrintAndLogEx(INFO, "Manufacture......... %s", sprint_hex(foo->b0, sizeof(foo->b0)));
|
||||
PrintAndLogEx(INFO, "MAD................. %s", sprint_hex(foo->mad, sizeof(foo->mad)));
|
||||
PrintAndLogEx(INFO, "Counters............ %u", foo->counters);
|
||||
PrintAndLogEx(INFO, "rtf................. %s", sprint_hex(foo->rtf, sizeof(foo->rtf)));
|
||||
PrintAndLogEx(INFO, "Service code........ 0x%08x / %u - " _YELLOW_("%s"), foo->service_code, foo->service_code, vigik_get_service(foo->service_code));
|
||||
PrintAndLogEx(INFO, "Info flag........... %u -", foo->info_flag); // , sprint_bin(foo->info_flag, 1));
|
||||
PrintAndLogEx(INFO, "Key version......... %u", foo->key_version);
|
||||
PrintAndLogEx(INFO, "PTR Counter......... %u", foo->ptr_counter);
|
||||
PrintAndLogEx(INFO, "Counter num......... %u", foo->counter_num);
|
||||
PrintAndLogEx(INFO, "Slot access date.... %s", sprint_hex(foo->slot_access_date, sizeof(foo->slot_access_date)));
|
||||
PrintAndLogEx(INFO, "Slot dst duration... %u", foo->slot_dst_duration);
|
||||
PrintAndLogEx(INFO, "Other Slots......... %s", sprint_hex(foo->other_slots, sizeof(foo->other_slots)));
|
||||
PrintAndLogEx(INFO, "Services counter.... %u", foo->services_counter);
|
||||
PrintAndLogEx(INFO, "Loading date........ %s", sprint_hex(foo->loading_date, sizeof(foo->loading_date)));
|
||||
PrintAndLogEx(INFO, "Reserved null....... %u", foo->reserved_null);
|
||||
PrintAndLogEx(INFO, "Manufacture......... %s", sprint_hex(d->b0, sizeof(d->b0)));
|
||||
PrintAndLogEx(INFO, "MAD................. %s", sprint_hex(d->mad, sizeof(d->mad)));
|
||||
PrintAndLogEx(INFO, "Counters............ %u", d->counters);
|
||||
PrintAndLogEx(INFO, "rtf................. %s", sprint_hex(d->rtf, sizeof(d->rtf)));
|
||||
PrintAndLogEx(INFO, "Service code........ 0x%08x / %u - " _YELLOW_("%s"), d->service_code, d->service_code, vigik_get_service(d->service_code));
|
||||
PrintAndLogEx(INFO, "Info flag........... %u -", d->info_flag); // , sprint_bin(d->info_flag, 1));
|
||||
PrintAndLogEx(INFO, "Key version......... %u", d->key_version);
|
||||
PrintAndLogEx(INFO, "PTR Counter......... %u", d->ptr_counter);
|
||||
PrintAndLogEx(INFO, "Counter num......... %u", d->counter_num);
|
||||
PrintAndLogEx(INFO, "Slot access date.... %s", sprint_hex(d->slot_access_date, sizeof(d->slot_access_date)));
|
||||
PrintAndLogEx(INFO, "Slot dst duration... %u", d->slot_dst_duration);
|
||||
PrintAndLogEx(INFO, "Other Slots......... %s", sprint_hex(d->other_slots, sizeof(d->other_slots)));
|
||||
PrintAndLogEx(INFO, "Services counter.... %u", d->services_counter);
|
||||
PrintAndLogEx(INFO, "Loading date........ %s", sprint_hex(d->loading_date, sizeof(d->loading_date)));
|
||||
PrintAndLogEx(INFO, "Reserved null....... %u", d->reserved_null);
|
||||
PrintAndLogEx(INFO, "----------------------------------------------------------------");
|
||||
PrintAndLogEx(INFO, "");
|
||||
vigik_verify(d, 96, foo->rsa_signature, sizeof(foo->rsa_signature));
|
||||
vigik_verify(d);
|
||||
PrintAndLogEx(INFO, "----------------------------------------------------------------");
|
||||
PrintAndLogEx(INFO, "");
|
||||
return PM3_SUCCESS;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "common.h"
|
||||
|
||||
#include "util.h" // FILE_PATH_SIZE
|
||||
#include "protocol_vigik.h"
|
||||
|
||||
#define MIFARE_SECTOR_RETRY 10
|
||||
|
||||
|
@ -113,6 +114,6 @@ void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool i
|
|||
// remove all sector trailers in a MFC dump
|
||||
int convert_mfc_2_arr(uint8_t *in, uint16_t ilen, uint8_t *out, uint16_t *olen);
|
||||
const char *vigik_get_service(uint16_t service_code);
|
||||
int vigik_verify(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len);
|
||||
int vigik_annotate(uint8_t *d);
|
||||
int vigik_verify(mfc_vigik_t *d);
|
||||
int vigik_annotate(mfc_vigik_t *d);
|
||||
#endif
|
||||
|
|
|
@ -349,6 +349,7 @@ const static vocabulory_t vocabulory[] = {
|
|||
{ 0, "hf mf gen3freeze" },
|
||||
{ 0, "hf mf ggetblk" },
|
||||
{ 0, "hf mf gload" },
|
||||
{ 0, "hf mf gsave" },
|
||||
{ 0, "hf mf gsetblk" },
|
||||
{ 0, "hf mf gview" },
|
||||
{ 0, "hf mf ndefformat" },
|
||||
|
@ -736,6 +737,12 @@ const static vocabulory_t vocabulory[] = {
|
|||
{ 0, "nfc barcode read" },
|
||||
{ 0, "nfc barcode sim" },
|
||||
{ 1, "nfc barcode help" },
|
||||
{ 1, "piv help" },
|
||||
{ 0, "piv select" },
|
||||
{ 0, "piv getdata" },
|
||||
{ 0, "piv authsign" },
|
||||
{ 0, "piv scan" },
|
||||
{ 1, "piv list" },
|
||||
{ 1, "smart help" },
|
||||
{ 1, "smart list" },
|
||||
{ 0, "smart info" },
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#endif
|
||||
#include "ui.h"
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
|
||||
#include <stdio.h> // for Mingw readline
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -62,10 +61,18 @@ pthread_mutex_t g_print_lock = PTHREAD_MUTEX_INITIALIZER;
|
|||
|
||||
static void fPrintAndLog(FILE *stream, const char *fmt, ...);
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MKDIR_CHK _mkdir(path)
|
||||
#else
|
||||
#define MKDIR_CHK mkdir(path, 0700)
|
||||
#endif
|
||||
|
||||
|
||||
// needed by flasher, so let's put it here instead of fileutils.c
|
||||
int searchHomeFilePath(char **foundpath, const char *subdir, const char *filename, bool create_home) {
|
||||
if (foundpath == NULL)
|
||||
if (foundpath == NULL) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
const char *user_path = get_my_user_directory();
|
||||
if (user_path == NULL) {
|
||||
|
@ -75,20 +82,21 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
|
|||
|
||||
size_t pathlen = strlen(user_path) + strlen(PM3_USER_DIRECTORY) + 1;
|
||||
char *path = calloc(pathlen, sizeof(char));
|
||||
if (path == NULL)
|
||||
if (path == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
strcpy(path, user_path);
|
||||
strcat(path, PM3_USER_DIRECTORY);
|
||||
|
||||
int result;
|
||||
|
||||
#ifdef _WIN32
|
||||
struct _stat st;
|
||||
// Mingw _stat fails if path ends with /, so let's use a stripped path
|
||||
if (path[strlen(path) - 1] == '/') {
|
||||
path[strlen(path) - 1] = '\0';
|
||||
if (str_endswith(path, PATHSEP)) {
|
||||
memset(path + (strlen(path) - strlen(PATHSEP)), 0x00, strlen(PATHSEP));
|
||||
result = _stat(path, &st);
|
||||
path[strlen(path)] = '/';
|
||||
strcat(path, PATHSEP);
|
||||
} else {
|
||||
result = _stat(path, &st);
|
||||
}
|
||||
|
@ -96,19 +104,16 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
|
|||
struct stat st;
|
||||
result = stat(path, &st);
|
||||
#endif
|
||||
|
||||
if ((result != 0) && create_home) {
|
||||
|
||||
#ifdef _WIN32
|
||||
if (_mkdir(path))
|
||||
#else
|
||||
if (mkdir(path, 0700))
|
||||
#endif
|
||||
{
|
||||
if (MKDIR_CHK) {
|
||||
fprintf(stderr, "Could not create user directory %s\n", path);
|
||||
free(path);
|
||||
return PM3_EFILE;
|
||||
}
|
||||
}
|
||||
|
||||
if (subdir != NULL) {
|
||||
pathlen += strlen(subdir);
|
||||
char *tmp = realloc(path, pathlen * sizeof(char));
|
||||
|
@ -121,24 +126,20 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
|
|||
|
||||
#ifdef _WIN32
|
||||
// Mingw _stat fails if path ends with /, so let's use a stripped path
|
||||
if (path[strlen(path) - 1] == '/') {
|
||||
path[strlen(path) - 1] = '\0';
|
||||
if (str_endswith(path, PATHSEP)) {
|
||||
memset(path + (strlen(path) - strlen(PATHSEP)), 0x00, strlen(PATHSEP));
|
||||
result = _stat(path, &st);
|
||||
path[strlen(path)] = '/';
|
||||
strcat(path, PATHSEP);
|
||||
} else {
|
||||
result = _stat(path, &st);
|
||||
}
|
||||
#else
|
||||
result = stat(path, &st);
|
||||
#endif
|
||||
|
||||
if ((result != 0) && create_home) {
|
||||
|
||||
#ifdef _WIN32
|
||||
if (_mkdir(path))
|
||||
#else
|
||||
if (mkdir(path, 0700))
|
||||
#endif
|
||||
{
|
||||
if (MKDIR_CHK) {
|
||||
fprintf(stderr, "Could not create user directory %s\n", path);
|
||||
free(path);
|
||||
return PM3_EFILE;
|
||||
|
@ -150,15 +151,18 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
|
|||
*foundpath = path;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
pathlen += strlen(filename);
|
||||
char *tmp = realloc(path, pathlen * sizeof(char));
|
||||
if (tmp == NULL) {
|
||||
//free(path);
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
path = tmp;
|
||||
strcat(path, filename);
|
||||
*foundpath = path;
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -527,12 +531,11 @@ void memcpy_filter_emoji(void *dest, const void *src, size_t n, emojiMode_t mode
|
|||
uint8_t emojified_token_length = 0;
|
||||
char *current_token = NULL;
|
||||
uint8_t current_token_length = 0;
|
||||
char current_char;
|
||||
char *rdest = (char *)dest;
|
||||
char *rsrc = (char *)src;
|
||||
uint16_t si = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
current_char = rsrc[i];
|
||||
char current_char = rsrc[i];
|
||||
|
||||
if (current_token_length == 0) {
|
||||
// starting a new token.
|
||||
|
|
|
@ -36,7 +36,7 @@ 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;
|
||||
|
||||
// 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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,7 +148,7 @@ 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;
|
||||
|
|
|
@ -280,7 +280,6 @@ void cm_auth(const uint8_t *Gc, const uint8_t *Ci, const uint8_t *Q, uint8_t *Ch
|
|||
|
||||
static void cm_crypt(const CryptoAction ca, const uint8_t offset, const uint8_t len, const uint8_t *in, uint8_t *out, crypto_state s) {
|
||||
size_t pos;
|
||||
uint8_t bt;
|
||||
|
||||
next_n(true, 5, 0, s);
|
||||
next(true, offset, s);
|
||||
|
@ -288,7 +287,7 @@ static void cm_crypt(const CryptoAction ca, const uint8_t offset, const uint8_t
|
|||
next(true, len, s);
|
||||
for (pos = 0; pos < len; pos++) {
|
||||
// Perform the crypto operation
|
||||
bt = in[pos] ^ cm_byte(s);
|
||||
uint8_t bt = in[pos] ^ cm_byte(s);
|
||||
|
||||
// Generate output
|
||||
if (out) out[pos] = bt;
|
||||
|
|
|
@ -240,6 +240,12 @@ uint16_t ul_ev1_packgen_def(const uint8_t *uid) {
|
|||
return 0x0000;
|
||||
}
|
||||
|
||||
// MIFARE ULTRALIGHT OTP generators
|
||||
uint32_t ul_c_otpgenA(const uint8_t *uid) {
|
||||
return 0x534C544F;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------
|
||||
// MFC key generation stuff
|
||||
// Each algo implementation should offer two key generation functions.
|
||||
|
|
|
@ -36,6 +36,8 @@ uint16_t ul_ev1_packgenC(const uint8_t *uid);
|
|||
uint16_t ul_ev1_packgenD(const uint8_t *uid);
|
||||
uint16_t ul_ev1_packgenE(const uint8_t *uid);
|
||||
|
||||
uint32_t ul_c_otpgenA(const uint8_t *uid);
|
||||
|
||||
int mfc_algo_ving_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key);
|
||||
int mfc_algo_ving_all(uint8_t *uid, uint8_t *keys);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1030,7 +1030,7 @@
|
|||
},
|
||||
"help": {
|
||||
"command": "help",
|
||||
"description": "help Use `<command> help` for details of a command prefs { Edit client/device preferences... } -------- ----------------------- Technology ----------------------- analyse { Analyse utils... } data { Plot window / data buffer manipulation... } emv { EMV ISO-14443 / ISO-7816... } hf { High frequency commands... } hw { Hardware commands... } lf { Low frequency commands... } nfc { NFC commands... } reveng { CRC calculations from RevEng software... } smart { Smart card ISO-7816 commands... } script { Scripting commands... } trace { Trace manipulation... } wiegand { Wiegand format manipulation... } -------- ----------------------- General ----------------------- clear Clear screen hints Turn hints on / off msleep Add a pause in milliseconds rem Add a text line in log file quit exit Exit program",
|
||||
"description": "help Use `<command> help` for details of a command prefs { Edit client/device preferences... } -------- ----------------------- Technology ----------------------- analyse { Analyse utils... } data { Plot window / data buffer manipulation... } emv { EMV ISO-14443 / ISO-7816... } hf { High frequency commands... } hw { Hardware commands... } lf { Low frequency commands... } nfc { NFC commands... } piv { PIV commands... } reveng { CRC calculations from RevEng software... } smart { Smart card ISO-7816 commands... } script { Scripting commands... } trace { Trace manipulation... } wiegand { Wiegand format manipulation... } -------- ----------------------- General ----------------------- clear Clear screen hints Turn hints on / off msleep Add a pause in milliseconds rem Add a text line in log file quit exit Exit program",
|
||||
"notes": [],
|
||||
"offline": true,
|
||||
"options": [],
|
||||
|
@ -2189,7 +2189,9 @@
|
|||
"command": "hf emrtd dump",
|
||||
"description": "Dump all files on an eMRTD",
|
||||
"notes": [
|
||||
"hf emrtd dump"
|
||||
"hf emrtd dump",
|
||||
"hf emrtd dump --dir ../dump",
|
||||
"hf emrtd dump -n 123456789 -d 19890101 -e 20250401"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
|
@ -2198,9 +2200,9 @@
|
|||
"-d, --dateofbirth <YYMMDD> date of birth in YYMMDD format",
|
||||
"-e, --expiry <YYMMDD> expiry in YYMMDD format",
|
||||
"-m, --mrz <[0-9A-Z<]> 2nd line of MRZ, 44 chars",
|
||||
"--path <dirpath> save dump to the given dirpath"
|
||||
"--dir <str> save dump to the given dirpath"
|
||||
],
|
||||
"usage": "hf emrtd dump [-h] [-n <alphanum>] [-d <YYMMDD>] [-e <YYMMDD>] [-m <[0-9A-Z<]>] [--path <dirpath>]"
|
||||
"usage": "hf emrtd dump [-h] [-n <alphanum>] [-d <YYMMDD>] [-e <YYMMDD>] [-m <[0-9A-Z<]>] [--dir <str>]"
|
||||
},
|
||||
"hf emrtd help": {
|
||||
"command": "hf emrtd help",
|
||||
|
@ -2214,7 +2216,10 @@
|
|||
"command": "hf emrtd info",
|
||||
"description": "Display info about an eMRTD",
|
||||
"notes": [
|
||||
"hf emrtd info"
|
||||
"hf emrtd info",
|
||||
"hf emrtd info --dir ../dumps",
|
||||
"hf emrtd info -n 123456789 -d 19890101 -e 20250401",
|
||||
"hf emrtd info -n 123456789 -d 19890101 -e 20250401 -i"
|
||||
],
|
||||
"offline": true,
|
||||
"options": [
|
||||
|
@ -2223,10 +2228,10 @@
|
|||
"-d, --dateofbirth <YYMMDD> date of birth in YYMMDD format",
|
||||
"-e, --expiry <YYMMDD> expiry in YYMMDD format",
|
||||
"-m, --mrz <[0-9A-Z<]> 2nd line of MRZ, 44 chars (passports only)",
|
||||
"--path <dirpath> display info from offline dump stored in dirpath",
|
||||
"--dir <str> display info from offline dump stored in dirpath",
|
||||
"-i, --images show images"
|
||||
],
|
||||
"usage": "hf emrtd info [-hi] [-n <alphanum>] [-d <YYMMDD>] [-e <YYMMDD>] [-m <[0-9A-Z<]>] [--path <dirpath>]"
|
||||
"usage": "hf emrtd info [-hi] [-n <alphanum>] [-d <YYMMDD>] [-e <YYMMDD>] [-m <[0-9A-Z<]>] [--dir <str>]"
|
||||
},
|
||||
"hf emrtd list": {
|
||||
"command": "hf emrtd list",
|
||||
|
@ -2916,9 +2921,10 @@
|
|||
"-f, --file <fn> Dictionary file with default iclass keys",
|
||||
"--credit key is assumed to be the credit key",
|
||||
"--elite elite computations applied to key",
|
||||
"--raw no computations applied to key (raw)"
|
||||
"--raw no computations applied to key (raw)",
|
||||
"--shallow use shallow (ASK) reader modulation instead of OOK"
|
||||
],
|
||||
"usage": "hf iclass chk [-h] -f <fn> [--credit] [--elite] [--raw]"
|
||||
"usage": "hf iclass chk [-h] -f <fn> [--credit] [--elite] [--raw] [--shallow]"
|
||||
},
|
||||
"hf iclass configcard": {
|
||||
"command": "hf iclass configcard",
|
||||
|
@ -2970,9 +2976,10 @@
|
|||
"--raw raw, the key is interpreted as raw block 3/4",
|
||||
"--nr replay of NR/MAC",
|
||||
"-z, --dense dense dump output style",
|
||||
"--force force unsecure card read"
|
||||
"--force force unsecure card read",
|
||||
"--shallow use shallow (ASK) reader modulation instead of OOK"
|
||||
],
|
||||
"usage": "hf iclass dump [-hz] [-f <fn>] [-k <hex>] [--ki <dec>] [--credit <hex>] [--ci <dec>] [--elite] [--raw] [--nr] [--force]"
|
||||
"usage": "hf iclass dump [-hz] [-f <fn>] [-k <hex>] [--ki <dec>] [--credit <hex>] [--ci <dec>] [--elite] [--raw] [--nr] [--force] [--shallow]"
|
||||
},
|
||||
"hf iclass eload": {
|
||||
"command": "hf iclass eload",
|
||||
|
@ -3008,9 +3015,10 @@
|
|||
"--enckey <hex> 3DES transport key, 16 hex bytes",
|
||||
"--fc <dec> facility code",
|
||||
"--cn <dec> card number",
|
||||
"-w, --wiegand <format> see `wiegand list` for available formats"
|
||||
"-w, --wiegand <format> see `wiegand list` for available formats",
|
||||
"--shallow use shallow (ASK) reader modulation instead of OOK"
|
||||
],
|
||||
"usage": "hf iclass encode [-h] [--bin <bin>] --ki <dec> [--credit] [--elite] [--raw] [--enckey <hex>] [--fc <dec>] [--cn <dec>] [-w <format>]"
|
||||
"usage": "hf iclass encode [-h] [--bin <bin>] --ki <dec> [--credit] [--elite] [--raw] [--enckey <hex>] [--fc <dec>] [--cn <dec>] [-w <format>] [--shallow]"
|
||||
},
|
||||
"hf iclass encrypt": {
|
||||
"command": "hf iclass encrypt",
|
||||
|
@ -3077,9 +3085,10 @@
|
|||
],
|
||||
"offline": true,
|
||||
"options": [
|
||||
"-h, --help This help"
|
||||
"-h, --help This help",
|
||||
"--shallow use shallow (ASK) reader modulation instead of OOK"
|
||||
],
|
||||
"usage": "hf iclass info [-h]"
|
||||
"usage": "hf iclass info [-h] [--shallow]"
|
||||
},
|
||||
"hf iclass list": {
|
||||
"command": "hf iclass list",
|
||||
|
@ -3191,9 +3200,10 @@
|
|||
"--elite elite computations applied to key",
|
||||
"--raw no computations applied to key",
|
||||
"--nr replay of NR/MAC",
|
||||
"-v, --verbose verbose output"
|
||||
"-v, --verbose verbose output",
|
||||
"--shallow use shallow (ASK) reader modulation instead of OOK"
|
||||
],
|
||||
"usage": "hf iclass rdbl [-hv] [-k <hex>] [--ki <dec>] -b <dec> [--credit] [--elite] [--raw] [--nr]"
|
||||
"usage": "hf iclass rdbl [-hv] [-k <hex>] [--ki <dec>] -b <dec> [--credit] [--elite] [--raw] [--nr] [--shallow]"
|
||||
},
|
||||
"hf iclass reader": {
|
||||
"command": "hf iclass reader",
|
||||
|
@ -3204,9 +3214,10 @@
|
|||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-@ optional - continuous reader mode"
|
||||
"-@ optional - continuous reader mode",
|
||||
"--shallow use shallow (ASK) reader modulation instead of OOK"
|
||||
],
|
||||
"usage": "hf iclass reader [-h@]"
|
||||
"usage": "hf iclass reader [-h@] [--shallow]"
|
||||
},
|
||||
"hf iclass restore": {
|
||||
"command": "hf iclass restore",
|
||||
|
@ -3227,9 +3238,10 @@
|
|||
"--credit key is assumed to be the credit key",
|
||||
"--elite elite computations applied to key",
|
||||
"--raw no computations applied to key",
|
||||
"-v, --verbose verbose output"
|
||||
"-v, --verbose verbose output",
|
||||
"--shallow use shallow (ASK) reader modulation instead of OOK"
|
||||
],
|
||||
"usage": "hf iclass restore [-hv] -f <fn> [-k <hex>] [--ki <dec>] --first <dec> --last <dec> [--credit] [--elite] [--raw]"
|
||||
"usage": "hf iclass restore [-hv] -f <fn> [-k <hex>] [--ki <dec>] --first <dec> --last <dec> [--credit] [--elite] [--raw] [--shallow]"
|
||||
},
|
||||
"hf iclass sim": {
|
||||
"command": "hf iclass sim",
|
||||
|
@ -3301,9 +3313,10 @@
|
|||
"--elite elite computations applied to key",
|
||||
"--raw no computations applied to key",
|
||||
"--nr replay of NR/MAC",
|
||||
"-v, --verbose verbose output"
|
||||
"-v, --verbose verbose output",
|
||||
"--shallow use shallow (ASK) reader modulation instead of OOK"
|
||||
],
|
||||
"usage": "hf iclass wrbl [-hv] [-k <hex>] [--ki <dec>] -b <dec> -d <hex> [-m <hex>] [--credit] [--elite] [--raw] [--nr]"
|
||||
"usage": "hf iclass wrbl [-hv] [-k <hex>] [--ki <dec>] -b <dec> -d <hex> [-m <hex>] [--credit] [--elite] [--raw] [--nr] [--shallow]"
|
||||
},
|
||||
"hf jooki clone": {
|
||||
"command": "hf jooki clone",
|
||||
|
@ -3391,6 +3404,20 @@
|
|||
],
|
||||
"usage": "hf jooki sim [-h] [-b <base64>]"
|
||||
},
|
||||
"hf ksx6924 balance": {
|
||||
"command": "hf ksx6924 balance",
|
||||
"description": "Gets the current purse balance",
|
||||
"notes": [
|
||||
"hf ksx6924 balance"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-k, --keep keep field ON for next command",
|
||||
"-a, --apdu Show APDU requests and responses"
|
||||
],
|
||||
"usage": "hf ksx6924 balance [-hka]"
|
||||
},
|
||||
"hf ksx6924 help": {
|
||||
"command": "hf ksx6924 help",
|
||||
"description": "help This help",
|
||||
|
@ -3399,19 +3426,6 @@
|
|||
"options": [],
|
||||
"usage": ""
|
||||
},
|
||||
"hf ksx6924 select": {
|
||||
"command": "hf ksx6924 select",
|
||||
"description": "Selects KS X 6924 application, and leaves field up",
|
||||
"notes": [
|
||||
"hf ksx6924 select"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-a, --apdu Show APDU requests and responses"
|
||||
],
|
||||
"usage": "hf ksx6924 select [-ha]"
|
||||
},
|
||||
"hf ksx6924 info": {
|
||||
"command": "hf ksx6924 info",
|
||||
"description": "Get info about a KS X 6924 transit card. This application is used by T-Money (South Korea) and Snapper+ (Wellington, New Zealand).",
|
||||
|
@ -3426,23 +3440,9 @@
|
|||
],
|
||||
"usage": "hf ksx6924 info [-hka]"
|
||||
},
|
||||
"hf ksx6924 balance": {
|
||||
"command": "hf ksx6924 balance",
|
||||
"description": "Gets the current purse balance",
|
||||
"notes": [
|
||||
"hf ksx6924 balance"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-k, --keep keep field ON for next command",
|
||||
"-a, --apdu Show APDU requests and responses"
|
||||
],
|
||||
"usage": "hf ksx6924 balance [-hka]"
|
||||
},
|
||||
"hf ksx6924 init": {
|
||||
"command": "hf ksx6924 init",
|
||||
"description": "Perform transaction initialization (mpda)",
|
||||
"description": "Perform transaction initialization with Mpda (Money of Purchase Transaction)",
|
||||
"notes": [
|
||||
"hf ksx6924 init 000003e8 -> Mpda"
|
||||
],
|
||||
|
@ -3468,7 +3468,19 @@
|
|||
],
|
||||
"usage": "hf ksx6924 prec [-hka] <record 1byte HEX>"
|
||||
},
|
||||
|
||||
"hf ksx6924 select": {
|
||||
"command": "hf ksx6924 select",
|
||||
"description": "Selects KS X 6924 application, and leaves field up",
|
||||
"notes": [
|
||||
"hf ksx6924 select"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-a, --apdu Show APDU requests and responses"
|
||||
],
|
||||
"usage": "hf ksx6924 select [-ha]"
|
||||
},
|
||||
"hf legic crc": {
|
||||
"command": "hf legic crc",
|
||||
"description": "Calculates the legic crc8/crc16 on the given data",
|
||||
|
@ -3971,7 +3983,7 @@
|
|||
"--1k MIFARE Classic 1k / S50 (def)",
|
||||
"--2k MIFARE Classic/Plus 2k",
|
||||
"--4k MIFARE Classic 4k / S70",
|
||||
"--emu from emulator memory"
|
||||
"--emu to emulator memory"
|
||||
],
|
||||
"usage": "hf mf csave [-h] [-f <fn>] [--mini] [--1k] [--2k] [--4k] [--emu]"
|
||||
},
|
||||
|
@ -4348,6 +4360,27 @@
|
|||
],
|
||||
"usage": "hf mf gload [-hv] [--mini] [--1k] [--2k] [--4k] [-p <hex>] [-f <fn>] [--emu] [--start <dec>] [--end <dec>]"
|
||||
},
|
||||
"hf mf gsave": {
|
||||
"command": "hf mf gsave",
|
||||
"description": "Save `magic gen4 gtu` card memory into three files (BIN/EML/JSON)or into emulator memory",
|
||||
"notes": [
|
||||
"hf mf gsave",
|
||||
"hf mf gsave --4k",
|
||||
"hf mf gsave -p DEADBEEF -f hf-mf-01020304.json"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"--mini MIFARE Classic Mini / S20",
|
||||
"--1k MIFARE Classic 1k / S50 (def)",
|
||||
"--2k MIFARE Classic/Plus 2k",
|
||||
"--4k MIFARE Classic 4k / S70",
|
||||
"-p, --pwd <hex> password 4bytes",
|
||||
"-f, --file <fn> filename of dump",
|
||||
"--emu to emulator memory"
|
||||
],
|
||||
"usage": "hf mf gsave [-h] [--mini] [--1k] [--2k] [--4k] [-p <hex>] [-f <fn>] [--emu]"
|
||||
},
|
||||
"hf mf gsetblk": {
|
||||
"command": "hf mf gsetblk",
|
||||
"description": "Set block data on a magic gen4 GTU card",
|
||||
|
@ -4771,7 +4804,7 @@
|
|||
},
|
||||
"hf mf wrbl": {
|
||||
"command": "hf mf wrbl",
|
||||
"description": "Write MIFARE Classic block with 16 hex bytes of data Sector 0 / Block 0 - Manufacturer block When writing to block 0 you must use a VALID block 0 data (UID, BCC, SAK, ATQA) Writing an invalid block 0 means rendering your Magic GEN2 card undetectable. Look in the magic_cards_notes.md file for help to resolve it.",
|
||||
"description": "Write MIFARE Classic block with 16 hex bytes of data Sector 0 / Block 0 - Manufacturer block When writing to block 0 you must use a VALID block 0 data (UID, BCC, SAK, ATQA) Writing an invalid block 0 means rendering your Magic GEN2 card undetectable. Look in the magic_cards_notes.md file for help to resolve it. `--force` param is used to override warnings like bad ACL and BLOCK 0 writes. if not specified, it will exit if detected",
|
||||
"notes": [
|
||||
"hf mf wrbl --blk 1 -k FFFFFFFFFFFF -d 000102030405060708090a0b0c0d0e0f"
|
||||
],
|
||||
|
@ -4781,7 +4814,7 @@
|
|||
"--blk <dec> block number",
|
||||
"-a input key type is key A (def)",
|
||||
"-b input key type is key B",
|
||||
"--force enforce block0 writes",
|
||||
"--force override warnings",
|
||||
"-k, --key <hex> key, 6 hex bytes",
|
||||
"-d, --data <hex> bytes to write, 16 hex bytes"
|
||||
],
|
||||
|
@ -6176,7 +6209,7 @@
|
|||
},
|
||||
"hf mfu esave": {
|
||||
"command": "hf mfu esave",
|
||||
"description": "Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/eml/json) By default number of pages saved depends on defined tag type. You can overrife this with option --end.",
|
||||
"description": "Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/eml/json) By default number of pages saved depends on defined tag type. You can override this with option --end.",
|
||||
"notes": [
|
||||
"hf mfu esave",
|
||||
"hf mfu esave --end 255 -> saves whole memory",
|
||||
|
@ -6192,7 +6225,7 @@
|
|||
},
|
||||
"hf mfu eview": {
|
||||
"command": "hf mfu eview",
|
||||
"description": "Displays emulator memory By default number of pages shown depends on defined tag type. You can overrife this with option --end.",
|
||||
"description": "Displays emulator memory By default number of pages shown depends on defined tag type. You can override this with option --end.",
|
||||
"notes": [
|
||||
"hf mfu eview",
|
||||
"hf mfu eview --end 255 -> dumps whole memory"
|
||||
|
@ -9350,6 +9383,7 @@
|
|||
"command": "lf paradox clone",
|
||||
"description": "clone a paradox tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"notes": [
|
||||
"lf paradox clone --fc 96 --cn 40426 -> encode for T55x7 tag with fc and cn",
|
||||
"lf paradox clone --raw 0f55555695596a6a9999a59a -> encode for T55x7 tag",
|
||||
"lf paradox clone --raw 0f55555695596a6a9999a59a --q5 -> encode for Q5/T5555 tag",
|
||||
"lf paradox clone --raw 0f55555695596a6a9999a59a --em -> encode for EM4305/4469"
|
||||
|
@ -9358,10 +9392,12 @@
|
|||
"options": [
|
||||
"-h, --help This help",
|
||||
"-r, --raw <hex> raw hex data. 12 bytes max",
|
||||
"--fc <dec> facility code",
|
||||
"--cn <dec> card number",
|
||||
"--q5 optional - specify writing to Q5/T5555 tag",
|
||||
"--em optional - specify writing to EM4305/4469 tag"
|
||||
],
|
||||
"usage": "lf paradox clone [-h] [-r <hex>] [--q5] [--em]"
|
||||
"usage": "lf paradox clone [-h] [-r <hex>] [--fc <dec>] [--cn <dec>] [--q5] [--em]"
|
||||
},
|
||||
"lf paradox demod": {
|
||||
"command": "lf paradox demod",
|
||||
|
@ -10924,6 +10960,114 @@
|
|||
],
|
||||
"usage": "hf 14b ndefread [-hv] [-f <fn>]"
|
||||
},
|
||||
"piv authsign": {
|
||||
"command": "piv authsign",
|
||||
"description": "Send a nonce and ask the PIV card to sign it",
|
||||
"notes": [
|
||||
"piv sign -sk -> select card, select applet, sign a NULL nonce"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-s, -S, --select Activate field and select applet",
|
||||
"-k, -K, --keep Keep field for next command",
|
||||
"-a, -A, --apdu Show APDU requests and responses",
|
||||
"-t, -T, --tlv TLV decode results",
|
||||
"-w, -W, --wired Send data via contact (iso7816) interface. (def: Contactless interface)",
|
||||
"--aid <hex> Applet ID to select. By default A0000003080000100 will be used",
|
||||
"--nonce <hex> Nonce to sign.",
|
||||
"--slot <dec id> Slot number. Default will be 0x9E (card auth cert).",
|
||||
"--alg <dec> Algorithm to use to sign. Example values: 06=RSA-1024, 07=RSA-2048, 11=ECC-P256 (default), 14=ECC-P384"
|
||||
],
|
||||
"usage": "piv sign [-hskatw] [--aid <hex>] --nonce <hex> [--slot <dec id>] [--alg <dec>]"
|
||||
},
|
||||
"piv getdata": {
|
||||
"command": "piv getdata",
|
||||
"description": "Get a data container of a given tag",
|
||||
"notes": [
|
||||
"piv getdata -s 5fc102 -> select card, select applet, get card holder unique identifer",
|
||||
"piv getdata -st 5fc102 -> select card, select applet, get card holder unique identifer, show result in TLV"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-s, -S, --select Activate field and select applet",
|
||||
"-k, -K, --keep Keep field for next command",
|
||||
"-a, -A, --apdu Show APDU requests and responses",
|
||||
"-t, -T, --tlv TLV decode results",
|
||||
"-w, -W, --wired Send data via contact (iso7816) interface. (def: Contactless interface)",
|
||||
"--aid <hex> Applet ID to select. By default A0000003080000100 will be used",
|
||||
"<hex> Tag ID to read, between 1 and 3 bytes."
|
||||
],
|
||||
"usage": "piv getdata [-hskatw] [--aid <hex>] <hex>"
|
||||
},
|
||||
"piv help": {
|
||||
"command": "piv help",
|
||||
"description": "help This help list List ISO7816 history",
|
||||
"notes": [],
|
||||
"offline": true,
|
||||
"options": [],
|
||||
"usage": ""
|
||||
},
|
||||
"piv list": {
|
||||
"command": "piv list",
|
||||
"description": "Alias of `trace list -t 7816` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
|
||||
"notes": [
|
||||
"piv list --frame -> show frame delay times",
|
||||
"piv list -1 -> use trace buffer"
|
||||
],
|
||||
"offline": true,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-1, --buffer use data from trace buffer",
|
||||
"--frame show frame delay times",
|
||||
"-c mark CRC bytes",
|
||||
"-r show relative times (gap and duration)",
|
||||
"-u display times in microseconds instead of clock cycles",
|
||||
"-x show hexdump to convert to pcap(ng)",
|
||||
"or to import into Wireshark using encapsulation type \"ISO 14443\"",
|
||||
"-f, --file <fn> filename of dictionary"
|
||||
],
|
||||
"usage": "piv list [-h1crux] [--frame] [-f <fn>]"
|
||||
},
|
||||
"piv scan": {
|
||||
"command": "piv scan",
|
||||
"description": "Scan a PIV card for known containers",
|
||||
"notes": [
|
||||
"piv scan -s -> select card, select applet and run scan",
|
||||
"piv scan -st --aid a00000030800001000 -> select card, select applet a00000030800001000, show result of the scan in TLV"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-s, -S, --select Activate field and select applet",
|
||||
"-k, -K, --keep Keep field for next command",
|
||||
"-a, -A, --apdu Show APDU requests and responses",
|
||||
"-t, -T, --tlv TLV decode results",
|
||||
"-w, -W, --wired Send data via contact (iso7816) interface. (def: Contactless interface)",
|
||||
"--aid <hex> Applet ID to select. By default A0000003080000100 will be used"
|
||||
],
|
||||
"usage": "piv scan [-hskatw] [--aid <hex>]"
|
||||
},
|
||||
"piv select": {
|
||||
"command": "piv select",
|
||||
"description": "Executes select applet command",
|
||||
"notes": [
|
||||
"piv select -s -> select card, select applet",
|
||||
"piv select -st --aid a00000030800001000 -> select card, select applet a00000030800001000, show result in TLV"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-s, -S, --select Activate field and select applet",
|
||||
"-k, -K, --keep Keep field for next command",
|
||||
"-a, -A, --apdu Show APDU requests and responses",
|
||||
"-t, -T, --tlv TLV decode results",
|
||||
"-w, -W, --wired Send data via contact (iso7816) interface. (def: Contactless interface)",
|
||||
"--aid <hex> Applet ID to select. By default A0000003080000100 will be used"
|
||||
],
|
||||
"usage": "piv select [-hskatw] [--aid <hex>]"
|
||||
},
|
||||
"prefs get barmode": {
|
||||
"command": "prefs get barmode",
|
||||
"description": "Get preference of HF/LF tune command styled output in the client",
|
||||
|
@ -11616,8 +11760,8 @@
|
|||
}
|
||||
},
|
||||
"metadata": {
|
||||
"commands_extracted": 732,
|
||||
"commands_extracted": 739,
|
||||
"extracted_by": "PM3Help2JSON v1.00",
|
||||
"extracted_on": "2022-11-20T20:19:15"
|
||||
"extracted_on": "2023-01-15T01:24:39"
|
||||
}
|
||||
}
|
|
@ -370,7 +370,7 @@ Check column "offline" for their availability.
|
|||
|`hf ksx6924 select `|N |`Select application, and leave field up`
|
||||
|`hf ksx6924 info `|N |`Get info about a KS X 6924 (T-Money, Snapper+) transit card`
|
||||
|`hf ksx6924 balance `|N |`Get current purse balance`
|
||||
|`hf ksx6924 init `|N |`Perform transaction initialization with Mpda (Money of Purchase Transaction)`
|
||||
|`hf ksx6924 init `|N |`Perform transaction initialization with Mpda`
|
||||
|`hf ksx6924 prec `|N |`Send proprietary get record command (CLA=90, INS=4C)`
|
||||
|
||||
|
||||
|
@ -512,6 +512,7 @@ Check column "offline" for their availability.
|
|||
|`hf mf gen3freeze `|N |`Perma lock UID changes. irreversible`
|
||||
|`hf mf ggetblk `|N |`Read block from card`
|
||||
|`hf mf gload `|N |`Load dump to card`
|
||||
|`hf mf gsave `|N |`Save dump from card into file or emulator`
|
||||
|`hf mf gsetblk `|N |`Write block to card`
|
||||
|`hf mf gview `|N |`View card`
|
||||
|`hf mf ndefformat `|N |`Format MIFARE Classic Tag as NFC Tag`
|
||||
|
@ -1333,6 +1334,20 @@ Check column "offline" for their availability.
|
|||
|`nfc barcode help `|Y |`This help`
|
||||
|
||||
|
||||
### piv
|
||||
|
||||
{ PIV commands... }
|
||||
|
||||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`piv help `|Y |`This help`
|
||||
|`piv select `|N |`Select the PIV applet`
|
||||
|`piv getdata `|N |`Gets a container on a PIV card`
|
||||
|`piv authsign `|N |`Authenticate with the card`
|
||||
|`piv scan `|N |`Scan PIV card for known containers`
|
||||
|`piv list `|Y |`List ISO7816 history`
|
||||
|
||||
|
||||
### reveng
|
||||
|
||||
{ CRC calculations from RevEng software... }
|
||||
|
|
|
@ -108,6 +108,7 @@ Here are the supported values you can assign to `STANDALONE` in `Makefile.platfo
|
|||
| LF_HIDBRUTE | HID corporate 1000 bruteforce - Federico dotta & Maurizio Agazzini
|
||||
| LF_HIDFCBRUTE | LF HID facility code bruteforce - ss23
|
||||
| LF_ICEHID | LF HID collector to flashmem - Iceman1001
|
||||
| LF_NEDAP_SIM | LF Nedap ID simulator
|
||||
| LF_NEXID | Nexwatch credentials detection mode - jrjgjk & Zolorah
|
||||
| LF_PROXBRUTE | HID ProxII bruteforce - Brad Antoniewicz
|
||||
| LF_SAMYRUN (def)| HID26 read/clone/sim - Samy Kamkar
|
||||
|
|
|
@ -10,6 +10,9 @@ RUN pacman -S --noconfirm sudo git base-devel cmake libusb readline bzip2 arm-no
|
|||
RUN pacman -S --noconfirm python-pip
|
||||
RUN python3 -m pip install ansicolors sslcrypto
|
||||
|
||||
# OpenCL for hitag2crack
|
||||
RUN pacman -S --noconfirm ocl-icd
|
||||
|
||||
# Create rrg user
|
||||
RUN useradd -ms /bin/bash rrg
|
||||
RUN passwd -d rrg
|
||||
|
|
|
@ -32,18 +32,18 @@ This script does both setup the mirrors and pip install and then run a
|
|||
bunch of different builds with make and cmake together with the different combos
|
||||
of RDV4, GENERIC, BTADDON combos.
|
||||
|
||||
If all tests OK, the script will finish.
|
||||
If all tests OK, the script will finish with PASS.
|
||||
|
||||
|
||||
# Notes to run tests
|
||||
Add first the mirrors, see above, if needed.
|
||||
Add first the mirrors, see above, if needed.
|
||||
|
||||
The release test build script is to be run in proxmark root folder inside the docker env.
|
||||
```
|
||||
docker/archlinux/run_tests.sh;
|
||||
```
|
||||
```
|
||||
|
||||
Or if you want to run single test,
|
||||
Or if you want to run single test,
|
||||
|
||||
```
|
||||
make clean; make -j
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
# Iceman 2022
|
||||
#
|
||||
# This script is to be run from proxmark root folder inside the docker env
|
||||
# cd proxmark;
|
||||
# docker/archlinux/run_tests.sh;
|
||||
#
|
||||
# Script contains two phases.
|
||||
|
@ -40,18 +39,4 @@ pacman -Ss '^gcc$'
|
|||
# sudo pacman -S testing/gcc
|
||||
# sudo pacman -S gcc
|
||||
|
||||
# replace egrep to silence warning
|
||||
sed -i 's/egrep/grep -E/g' tools/pm3_tests.sh
|
||||
|
||||
# Makefile build tests
|
||||
make clean; make -j PLATFORM=PM3GENERIC; tools/pm3_tests.sh --long || exit 1
|
||||
make clean; make -j PLATFORM=PM3RDV4; tools/pm3_tests.sh --long || exit 1
|
||||
make clean; make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON; tools/pm3_tests.sh --long || exit 1
|
||||
# sudo make install; pushd /tmp; proxmark3 -c 'data load -f lf_EM4x05.pm3;lf search -1'; popd; sudo make uninstall
|
||||
|
||||
# cmake client build test
|
||||
#( cd client; rm -rf build; mkdir build;cd build;cmake ..;make -j ); PM3BIN=./client/build/proxmark3 tools/pm3_tests.sh client --long || exit 1
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake ..;make -j PLATFORM=PM3GENERIC ); PM3BIN=./client/build/proxmark3 tools/pm3_tests.sh client --long || exit 1
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake ..;make -j PLATFORM=PM3RDV4 ); PM3BIN=./client/build/proxmark3 tools/pm3_tests.sh client --long || exit 1
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake ..;make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON ); PM3BIN=./client/build/proxmark3 tools/pm3_tests.sh client || exit 1
|
||||
|
||||
tools/release_tests.sh
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
for os in archlinux debian-buster fedora-34 fedora-35 homebrew kali opensuse-leap opensuse-tumbleweed parrot-core-latest ubuntu-18.04 ubuntu-20.04 ubuntu-21.04; do
|
||||
for os in archlinux debian-buster fedora-36 fedora-37 homebrew kali opensuse-leap opensuse-tumbleweed parrot-core-latest ubuntu-18.04 ubuntu-20.04 ubuntu-22.04; do
|
||||
( cd $os && ./docker_build.sh )
|
||||
done
|
||||
|
|
|
@ -11,8 +11,12 @@ RUN apt-get update && \
|
|||
|
||||
RUN apt-get install -y python3-minimal && \
|
||||
apt-get install -y python3-pip && \
|
||||
apt-get clean && \
|
||||
python3 -m pip install ansicolors sslcrypto
|
||||
|
||||
RUN apt-get install -y opencl-dev && \
|
||||
apt-get clean
|
||||
|
||||
# Create rrg user
|
||||
RUN useradd -ms /bin/bash rrg
|
||||
RUN passwd -d rrg
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
# Notes on run_tests.sh script
|
||||
This script does both setup the mirrors and pip install and then run a
|
||||
bunch of different builds with make and cmake together with the different combos
|
||||
of RDV4, GENERIC, BTADDON combos.
|
||||
This script runs a bunch of different builds with make and cmake together
|
||||
with the different combos of RDV4, GENERIC, BTADDON combos.
|
||||
|
||||
If all tests OK, the script will finish.
|
||||
If all tests OK, the script will finish with PASS.
|
||||
|
||||
|
||||
# Notes to run tests
|
||||
|
@ -11,9 +10,9 @@ The script is to be run in proxmark root folder inside the docker env.
|
|||
|
||||
```
|
||||
docker/debian-bullseye/run_tests.sh;
|
||||
```
|
||||
```
|
||||
|
||||
Or if you want to run single test,
|
||||
Or if you want to run single test,
|
||||
|
||||
```
|
||||
sudo apt update
|
||||
|
|
8
docker/debian-bullseye/run_tests.sh
Executable file
8
docker/debian-bullseye/run_tests.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
# Iceman 2022
|
||||
#
|
||||
# This script is to be run from proxmark root folder inside the docker env
|
||||
# docker/debian-bullseye/run_tests.sh;
|
||||
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
tools/release_tests.sh
|
|
@ -1,26 +0,0 @@
|
|||
# Notes on run_tests.sh script
|
||||
This script does both strip the "recover_pk test" in pm3_tests.sh and then run a
|
||||
bunch of different builds with make and cmake together with the different combos
|
||||
of RDV4, GENERIC, BTADDON combos.
|
||||
|
||||
If all tests OK, the script will finish.
|
||||
|
||||
|
||||
# Notes to run tests
|
||||
The script is to be run in proxmark root folder inside the docker env.
|
||||
|
||||
```
|
||||
docker/fedora-34/run_tests.sh;
|
||||
```
|
||||
|
||||
Or if you want to run single test,
|
||||
|
||||
```
|
||||
sudo yum -y update
|
||||
make clean; make -j
|
||||
tools/pm3_tests.sh --long
|
||||
```
|
||||
|
||||
Warning, `recover_pk selftests` will fail on Fedora because they stripped down the available ECC curves in their OpenSSL.
|
||||
|
||||
So just comment the "recover_pk test"
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
docker build -t "pm3-fedora-34:1.0" .
|
|
@ -1,4 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
docker image rm pm3-fedora-34:1.0
|
||||
docker image rm fedora:34
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue