Merge branch 'master' into master

Signed-off-by: lnv42 <34003959+lnv42@users.noreply.github.com>
This commit is contained in:
lnv42 2023-01-18 11:29:22 +01:00 committed by GitHub
commit 13106d4888
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
156 changed files with 3005 additions and 1167 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1814,17 +1814,17 @@ int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
static const uint8_t x_wup2[] = { 0x5D, 0x37, 0x21, 0x71, 0x71 };
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;
}

View file

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

View file

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

View file

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

View file

@ -293,9 +293,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

View file

@ -626,6 +626,7 @@ SRCS = mifare/aiddesfire.c \
cmdmain.c \
cmdnfc.c \
cmdparser.c \
cmdpiv.c \
cmdscript.c \
cmdsmartcard.c \
cmdtrace.c \

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -65,7 +65,7 @@ static uint8_t default_3des_keys[][16] = {
static uint8_t default_pwd_pack[][4] = {
{0xFF, 0xFF, 0xFF, 0xFF}, // PACK 0x00,0x00 -- factory default
{0x4E, 0x45, 0x78, 0x54},
{0x4E, 0x45, 0x78, 0x54}, // NExT
};
static uint32_t UL_TYPES_ARRAY[] = {
@ -1144,6 +1144,46 @@ Lego Dimensions,
E1 10 12 00 01 03 A0 0C 34 03 13 D1 01 0F 54 02 65 6E
*/
typedef struct {
const char *desc;
uint8_t mpos;
uint8_t mlen;
const char *match;
uint32_t (*otp)(const uint8_t *uid);
const char *hint;
} mfu_otp_identify_t;
static mfu_otp_identify_t mfu_otp_ident_table[] = {
{ "SALTO", 12, 4, "534C544F", ul_c_otpgenA, NULL },
// { "SAFLOK", 12, 4, NULL, ul_c_otpgenB, NULL },
// { "VINGCARD", 12, 4, NULL, ul_c_otpgenC, NULL },
// { "DORMA KABA", 12, 4, NULL, ul_c_otpgenD, NULL },
{ NULL, 0, 0, NULL, NULL, NULL }
};
static mfu_otp_identify_t *mfu_match_otp_fingerprint(uint8_t *data) {
uint8_t i = 0;
do {
int ml = 0;
uint8_t mtmp[40] = {0};
// static or dynamic created OTP to fingerprint.
if (mfu_otp_ident_table[i].match) {
param_gethex_to_eol(mfu_otp_ident_table[i].match, 0, mtmp, sizeof(mtmp), &ml);
} else {
uint32_t otp = mfu_otp_ident_table[i].otp(data);
num_to_bytes(otp, 4, mtmp);
}
bool m2 = (memcmp(mtmp, data + mfu_otp_ident_table[i].mpos, mfu_otp_ident_table[i].mlen) == 0);
if (m2) {
PrintAndLogEx(DEBUG, "(fingerprint) found %s", mfu_otp_ident_table[i].desc);
return &mfu_otp_ident_table[i];
}
} while (mfu_otp_ident_table[++i].desc);
return NULL;
}
typedef struct {
const char *desc;
const char *version;
@ -1184,7 +1224,7 @@ static mfu_identify_t mfu_ident_table[] = {
"Snackworld", "0004040101000B03",
9, 7, "483000E1100600",
NULL, NULL,
"hf mfu dump -k %08x"
"hf mfu dump -k"
},
{
"Amiibo", "0004040201001103",
@ -1324,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 ;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -230,6 +230,7 @@ static int CmdParadoxClone(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf paradox clone",
"clone a paradox tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
"lf paradox clone --fc 96 --cn 40426 -> encode for T55x7 tag with fc and cn\n"
"lf paradox clone --raw 0f55555695596a6a9999a59a -> encode for T55x7 tag\n"
"lf paradox clone --raw 0f55555695596a6a9999a59a --q5 -> encode for Q5/T5555 tag\n"
"lf paradox clone --raw 0f55555695596a6a9999a59a --em -> encode for EM4305/4469"
@ -238,6 +239,8 @@ static int CmdParadoxClone(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
arg_u64_0(NULL, "fc", "<dec>", "facility code"),
arg_u64_0(NULL, "cn", "<dec>", "card number"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end
@ -249,8 +252,10 @@ static int CmdParadoxClone(const char *Cmd) {
uint8_t raw[12] = {0};
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
bool q5 = arg_get_lit(ctx, 2);
bool em = arg_get_lit(ctx, 3);
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
bool q5 = arg_get_lit(ctx, 4);
bool em = arg_get_lit(ctx, 5);
CLIParserFree(ctx);
if (q5 && em) {
@ -258,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

View file

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

View file

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

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

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

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

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

View file

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

View file

@ -485,8 +485,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
uint32_t end_of_transmission_timestamp = 0;
uint8_t topaz_reader_command[9];
char explanation[40] = {0};
uint8_t mfData[32] = {0};
size_t mfDataLen = 0;
tracelog_hdr_t *first_hdr = (tracelog_hdr_t *)(trace);
tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + tracepos);
@ -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));
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -349,6 +349,7 @@ const static vocabulory_t vocabulory[] = {
{ 0, "hf mf gen3freeze" },
{ 0, "hf mf ggetblk" },
{ 0, "hf mf gload" },
{ 0, "hf mf gsave" },
{ 0, "hf mf gsetblk" },
{ 0, "hf mf gview" },
{ 0, "hf mf ndefformat" },
@ -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" },

View file

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

View file

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

View file

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

View file

@ -129,6 +129,9 @@ uint64_t HornerScheme(uint64_t num, uint64_t divider, uint64_t factor);
int num_CPUs(void); // number of logical CPUs
void str_lower(char *s); // converts string to lower case
void str_upper(char *s); // converts string to UPPER case
void strn_upper(char *s, size_t n);
bool str_startswith(const char *s, const char *pre); // check for prefix in string
bool str_endswith(const char *s, const char *suffix); // check for suffix in string
void clean_ascii(unsigned char *buf, size_t len);
@ -145,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;

View file

@ -280,7 +280,6 @@ void cm_auth(const uint8_t *Gc, const uint8_t *Ci, const uint8_t *Q, uint8_t *Ch
static void cm_crypt(const CryptoAction ca, const uint8_t offset, const uint8_t len, const uint8_t *in, uint8_t *out, crypto_state s) {
size_t pos;
uint8_t bt;
next_n(true, 5, 0, s);
next(true, offset, s);
@ -288,7 +287,7 @@ static void cm_crypt(const CryptoAction ca, const uint8_t offset, const uint8_t
next(true, len, s);
for (pos = 0; pos < len; pos++) {
// Perform the crypto operation
bt = in[pos] ^ cm_byte(s);
uint8_t bt = in[pos] ^ cm_byte(s);
// Generate output
if (out) out[pos] = bt;

View file

@ -240,6 +240,12 @@ uint16_t ul_ev1_packgen_def(const uint8_t *uid) {
return 0x0000;
}
// MIFARE ULTRALIGHT OTP generators
uint32_t ul_c_otpgenA(const uint8_t *uid) {
return 0x534C544F;
}
//------------------------------------
// MFC key generation stuff
// Each algo implementation should offer two key generation functions.

View file

@ -36,6 +36,8 @@ uint16_t ul_ev1_packgenC(const uint8_t *uid);
uint16_t ul_ev1_packgenD(const uint8_t *uid);
uint16_t ul_ev1_packgenE(const uint8_t *uid);
uint32_t ul_c_otpgenA(const uint8_t *uid);
int mfc_algo_ving_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key);
int mfc_algo_ving_all(uint8_t *uid, uint8_t *keys);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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

View file

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

View file

@ -1,3 +0,0 @@
#!/bin/bash
docker build -t "pm3-fedora-34:1.0" .

View file

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