diff --git a/.github/ISSUE_TEMPLATE/checklist-for-release.md b/.github/ISSUE_TEMPLATE/checklist-for-release.md index 514b454d7..8b5872891 100644 --- a/.github/ISSUE_TEMPLATE/checklist-for-release.md +++ b/.github/ISSUE_TEMPLATE/checklist-for-release.md @@ -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) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2875edde..97fa48f5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,17 +3,27 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Changed `hf emrtd info` - looking for lower case .bin extensions (@iceman1001) + - Changed `hf emrtd dump` - looking for lower case .bin extensions (@iceman1001) + - Changed `lf paradox clone` - it now accepts FC/CN (@mwalker33) + - Added standalone mode for simulatin Nedap ID (@anon) + - Changed `hf mfu info` - now also does a simple OTP fingerprinting (@iceman1001) + - Changed `hf mf wrbl` - now checks for strict readonly ACL's in the data to write (@iceman1001) + - Changed `hf mf view` - verbose printing if strict readonly ACL's exists in dump file (@iceman1001) + - Add command `piv authsign` to get a buffer signed by the selected key (@jmichelp) + - Add command `piv scan` which tries to read all known containers on PIV (@jmichelp) + - Add support for PIV commands, over wired and contactless interfaces (@jmichelp) - Add `--shallow` option to `hf iclass` reader commands to do shallow (ASK) reader modulation instead of OOK (@nvx) - Improved NXP SLI/SLIX series tag identification (@nvx) - Fixed buffer overflow in "lf em 4x05 sniff" (@HeinrichsH) - - Fixed potential NULL array printing (@jmichel) - - Added PIV aid to resource file (@jmichel) - - Fixed failing compilation on Proxspace environment due to how python is initialized (@jmichel) - - Fixed length check in sim module communications (@jmichel) + - Fixed potential NULL array printing (@jmichelp) + - Added PIV aid to resource file (@jmichelp) + - Fixed failing compilation on Proxspace environment due to how python is initialized (@jmichelp) + - Fixed length check in sim module communications (@jmichelp) - Changed timings in i2c.c when communicating with sim module (@iceman1001) - - Moved to non-deprecated API to initialize Python interpreter (@jmichel) + - Moved to non-deprecated API to initialize Python interpreter (@jmichelp) - Changed `sc upgrade` updated firmware v4.13 (RDV40) - frame buffer is now 384 bytes (@sentiprox) - - Fixed contact interface / smartcard APDU chaining logic and allow 256 bytes ADPU payload. Need SIM firmware 4.13 to work (@jmichel) + - Fixed contact interface / smartcard APDU chaining logic and allow 256 bytes ADPU payload. Need SIM firmware 4.13 to work (@jmichelp) - Fixed `lf hitag dump` - Should now work as described in the command help (@natmchugh) - Fixed SPI flash overflow when loading dictionnaries into flash. Breaking change: added 1 more sector for Mifare - dictionnaries should be loaded again (@jmichelp) - Added `hf mf gload, gsave, ggetblk, gsetblk` for Gen4 GTU in mifare classic mode (@DidierA) diff --git a/Makefile b/Makefile index 5452842cc..0cb778ec6 100644 --- a/Makefile +++ b/Makefile @@ -80,20 +80,20 @@ ifneq (,$(INSTALLSHARES)) endif ifneq (,$(INSTALLDOCS)) $(Q)$(INSTALLSUDO) $(RMDIR) $(foreach doc,$(INSTALLDOCS),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH)$(PATHSEP)$(notdir $(doc))) - $(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH) + $(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLDOCSRELPATH) endif ifneq (,$(INSTALLTOOLS)) $(Q)$(INSTALLSUDO) $(RM) $(foreach tool,$(INSTALLTOOLS),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)$(PATHSEP)$(notdir $(tool))) endif - $(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH) + $(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH) ifneq (,$(INSTALLSIMFW)) $(Q)$(INSTALLSUDO) $(RM) $(foreach fw,$(INSTALLSIMFW),$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)$(PATHSEP)$(notdir $(fw))) endif - $(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH) + $(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH) ifeq ($(platform),Linux) $(Q)$(INSTALLSUDO) $(RM) $(DESTDIR)$(UDEV_PREFIX)/77-pm3-usb-device-blacklist.rules endif - $(Q)$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH) + $(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH) # tests mfkey/check: FORCE diff --git a/Makefile.defs b/Makefile.defs index 8f9d5f271..bcbbaa67e 100644 --- a/Makefile.defs +++ b/Makefile.defs @@ -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 diff --git a/armsrc/Makefile b/armsrc/Makefile index c0703ccf4..5024aa1de 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -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: diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index 3c18e681b..6b9343683 100644 --- a/armsrc/Standalone/Makefile.hal +++ b/armsrc/Standalone/Makefile.hal @@ -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)),) diff --git a/armsrc/Standalone/Makefile.inc b/armsrc/Standalone/Makefile.inc index 15218912c..d3f88823e 100644 --- a/armsrc/Standalone/Makefile.inc +++ b/armsrc/Standalone/Makefile.inc @@ -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 diff --git a/armsrc/Standalone/lf_em4100rsww.c b/armsrc/Standalone/lf_em4100rsww.c index 727d188a3..dc202d49a 100644 --- a/armsrc/Standalone/lf_em4100rsww.c +++ b/armsrc/Standalone/lf_em4100rsww.c @@ -11,7 +11,7 @@ // then from shell: // hexdump lf.bin -e '5/1 "%02X" /0 "\n"' // -// To recall only LAST stored ID from flash use lf-last instead of lf file. +// To recall only LAST stored ID from flash use lf-last instead of lf file. // //----------------------------------------------------------------------------- // Modes of operation: diff --git a/armsrc/Standalone/lf_nedap_sim.c b/armsrc/Standalone/lf_nedap_sim.c new file mode 100644 index 000000000..726f13ca8 --- /dev/null +++ b/armsrc/Standalone/lf_nedap_sim.c @@ -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 +} diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 756ca4f4f..76d9ac3c0 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -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"); diff --git a/armsrc/felica.c b/armsrc/felica.c index 3cf75a0b4..0a74a30cc 100644 --- a/armsrc/felica.c +++ b/armsrc/felica.c @@ -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; diff --git a/armsrc/frozen.c b/armsrc/frozen.c index 455d9a3f2..a77d7dd9d 100644 --- a/armsrc/frozen.c +++ b/armsrc/frozen.c @@ -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; diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index a4a3630c7..db219bcf2 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -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; diff --git a/armsrc/i2c.c b/armsrc/i2c.c index 491e12a04..ca3cb46fd 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -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); } diff --git a/armsrc/iclass.c b/armsrc/iclass.c index a25fbd52c..5a68a8207 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -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; } diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 760736a5a..e4f1e4e93 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -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; } diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 3db9112af..74e75ddce 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -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); diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index fd9d86ccc..5c0905e68 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -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; diff --git a/bootrom/Makefile b/bootrom/Makefile index ec531f1af..edb0cc990 100644 --- a/bootrom/Makefile +++ b/bootrom/Makefile @@ -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: diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index a34348413..5519b2e77 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -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 diff --git a/client/Makefile b/client/Makefile index 500e820f0..03f022297 100644 --- a/client/Makefile +++ b/client/Makefile @@ -626,6 +626,7 @@ SRCS = mifare/aiddesfire.c \ cmdmain.c \ cmdnfc.c \ cmdparser.c \ + cmdpiv.c \ cmdscript.c \ cmdsmartcard.c \ cmdtrace.c \ diff --git a/client/deps/hardnested/hardnested_bf_core.c b/client/deps/hardnested/hardnested_bf_core.c index 64b0696aa..63eba8eba 100644 --- a/client/deps/hardnested/hardnested_bf_core.c +++ b/client/deps/hardnested/hardnested_bf_core.c @@ -530,7 +530,6 @@ stop_tests: bucket_states_tested += bucket_size[block_idx]; // prepare to set new states state_p = &states[KEYSTREAM_SIZE]; - continue; } } out: diff --git a/client/experimental_lib/CMakeLists.txt b/client/experimental_lib/CMakeLists.txt index 5c64fd135..3855d6884 100644 --- a/client/experimental_lib/CMakeLists.txt +++ b/client/experimental_lib/CMakeLists.txt @@ -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 diff --git a/client/luascripts/hf_14a_i2crevive.lua b/client/luascripts/hf_14a_i2crevive.lua index 3610979b6..59659bb5c 100644 --- a/client/luascripts/hf_14a_i2crevive.lua +++ b/client/luascripts/hf_14a_i2crevive.lua @@ -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 diff --git a/client/luascripts/hf_i2c_plus_2k_utils.lua b/client/luascripts/hf_i2c_plus_2k_utils.lua index 7e6b9b300..5e7652316 100644 --- a/client/luascripts/hf_i2c_plus_2k_utils.lua +++ b/client/luascripts/hf_i2c_plus_2k_utils.lua @@ -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 -b - - Write mode: + + Write mode: script run hf_i2c_plus_2k_utils -m w -s -b -d - + Dump mode: script run hf_i2c_plus_2k_utils -m d -s - + File mode: script run hf_i2c_plus_2k_utils -m f -s -f @@ -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 diff --git a/client/luascripts/hf_mf_dump-luxeo.lua b/client/luascripts/hf_mf_dump_luxeo.lua similarity index 98% rename from client/luascripts/hf_mf_dump-luxeo.lua rename to client/luascripts/hf_mf_dump_luxeo.lua index 2b2c5d9c7..aaf7d572f 100644 --- a/client/luascripts/hf_mf_dump-luxeo.lua +++ b/client/luascripts/hf_mf_dump_luxeo.lua @@ -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 diff --git a/client/luascripts/hf_mf_em_util.lua b/client/luascripts/hf_mf_em_util.lua index 69537d7dd..e82bc9d1e 100644 --- a/client/luascripts/hf_mf_em_util.lua +++ b/client/luascripts/hf_mf_em_util.lua @@ -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 diff --git a/client/luascripts/hf_mf_uidbruteforce.lua b/client/luascripts/hf_mf_uidbruteforce.lua index 62872e2a3..4835ba03b 100644 --- a/client/luascripts/hf_mf_uidbruteforce.lua +++ b/client/luascripts/hf_mf_uidbruteforce.lua @@ -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') diff --git a/client/luascripts/hf_mf_ultimatecard.lua b/client/luascripts/hf_mf_ultimatecard.lua index 4a70935bb..42a5e1887 100644 --- a/client/luascripts/hf_mf_ultimatecard.lua +++ b/client/luascripts/hf_mf_ultimatecard.lua @@ -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 diff --git a/client/luascripts/hf_mfu_amiibo_restore.lua b/client/luascripts/hf_mfu_amiibo_restore.lua index b83f3feb1..c31db7098 100644 --- a/client/luascripts/hf_mfu_amiibo_restore.lua +++ b/client/luascripts/hf_mfu_amiibo_restore.lua @@ -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 diff --git a/client/luascripts/hf_mfu_uidkeycalc-italy.lua b/client/luascripts/hf_mfu_uidkeycalc_italy.lua similarity index 96% rename from client/luascripts/hf_mfu_uidkeycalc-italy.lua rename to client/luascripts/hf_mfu_uidkeycalc_italy.lua index 4777a186d..d2fbdadde 100644 --- a/client/luascripts/hf_mfu_uidkeycalc-italy.lua +++ b/client/luascripts/hf_mfu_uidkeycalc_italy.lua @@ -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 " +script run hf_mfu_uidkeycalc_italy -h -u " ]] arguments = [[ -h : this help diff --git a/client/luascripts/lf_ident_json.lua b/client/luascripts/lf_ident_json.lua index fb0d82554..73794547c 100644 --- a/client/luascripts/lf_ident_json.lua +++ b/client/luascripts/lf_ident_json.lua @@ -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 ] [-v] +script run lf_ident_json.lua [-h] [-c] [-p password] [-s ] [-v] ]] arguments = [[ -h : this help diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index abe8a6bc2..563fda14f 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -17,17 +17,17 @@ //----------------------------------------------------------------------------- #include "cipursecore.h" -#include // memcpy memset - -#include "commonutil.h" // ARRAYLEN -#include "comms.h" // DropField -#include "util_posix.h" // msleep +#include // 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"); diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 4c2498a85..0858150d0 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -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 { diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index cddf52365..12440c676 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -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; diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index 84629d56e..c35df7238 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -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"); diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 83dc300db..f6714c5a2 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -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) { diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index d22df2459..bb0808a51 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -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", "", "date of birth in YYMMDD format"), arg_str0("e", "expiry", "", "expiry in YYMMDD format"), arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars"), - arg_str0(NULL, "path", "", "save dump to the given dirpath"), + arg_str0(NULL, "dir", "", "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", "", "date of birth in YYMMDD format"), arg_str0("e", "expiry", "", "expiry in YYMMDD format"), arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars (passports only)"), - arg_str0(NULL, "path", "", "display info from offline dump stored in dirpath"), + arg_str0(NULL, "dir", "", "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; } diff --git a/client/src/cmdhfepa.c b/client/src/cmdhfepa.c index 7ce9a3e97..66ce37d6b 100644 --- a/client/src/cmdhfepa.c +++ b/client/src/cmdhfepa.c @@ -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} }; diff --git a/client/src/cmdhffido.c b/client/src/cmdhffido.c index a00206c01..64cc8a43f 100644 --- a/client/src/cmdhffido.c +++ b/client/src/cmdhffido.c @@ -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; diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 4e555f909..94d710f98 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -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 diff --git a/client/src/cmdhfksx6924.c b/client/src/cmdhfksx6924.c index 6064a7611..7616ca766 100644 --- a/client/src/cmdhfksx6924.c +++ b/client/src/cmdhfksx6924.c @@ -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)); diff --git a/client/src/cmdhflist.c b/client/src/cmdhflist.c index 68a050158..a19ecdea9 100644 --- a/client/src/cmdhflist.c +++ b/client/src/cmdhflist.c @@ -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"); } diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 51a9a13f0..11d101391 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -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", "", "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", "", "key, 6 hex bytes"), arg_str0("d", "data", "", "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--dump.bin` and `hf-mf--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", "", "specify dump filename (bin/eml/json)"), arg_str0("k", "kfn", "", "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 diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index f3da73c2c..00c6306e7 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -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]; diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index c3701a76d..bc8c10859 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -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 ; } diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index 350df87f5..896157be4 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -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; diff --git a/client/src/cmdhfst25ta.c b/client/src/cmdhfst25ta.c index 0ccccd5d6..86dfe0584 100644 --- a/client/src/cmdhfst25ta.c +++ b/client/src/cmdhfst25ta.c @@ -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; diff --git a/client/src/cmdhftexkom.c b/client/src/cmdhftexkom.c index 88add72d6..2b54480ca 100644 --- a/client/src/cmdhftexkom.c +++ b/client/src/cmdhftexkom.c @@ -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 { diff --git a/client/src/cmdhftopaz.c b/client/src/cmdhftopaz.c index 8ad9c23ee..6311b50ed 100644 --- a/client/src/cmdhftopaz.c +++ b/client/src/cmdhftopaz.c @@ -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) { diff --git a/client/src/cmdhfwaveshare.c b/client/src/cmdhfwaveshare.c index ae2f74582..78c6ef825 100644 --- a/client/src/cmdhfwaveshare.c +++ b/client/src/cmdhfwaveshare.c @@ -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); diff --git a/client/src/cmdhfxerox.c b/client/src/cmdhfxerox.c index 578f797e0..fec69855e 100644 --- a/client/src/cmdhfxerox.c +++ b/client/src/cmdhfxerox.c @@ -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"); diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index f10fa8330..0efa5eafe 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -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; diff --git a/client/src/cmdlfem410x.c b/client/src/cmdlfem410x.c index ef9caf959..29ad61bc9 100644 --- a/client/src/cmdlfem410x.c +++ b/client/src/cmdlfem410x.c @@ -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 { diff --git a/client/src/cmdlfem4x05.c b/client/src/cmdlfem4x05.c index 8e6110c62..cff7203d2 100644 --- a/client/src/cmdlfem4x05.c +++ b/client/src/cmdlfem4x05.c @@ -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); } diff --git a/client/src/cmdlfhitag.c b/client/src/cmdlfhitag.c index ba7b72195..66fb3ea42 100644 --- a/client/src/cmdlfhitag.c +++ b/client/src/cmdlfhitag.c @@ -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; diff --git a/client/src/cmdlfindala.c b/client/src/cmdlfindala.c index 781db217b..fa59894e1 100644 --- a/client/src/cmdlfindala.c +++ b/client/src/cmdlfindala.c @@ -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; diff --git a/client/src/cmdlfparadox.c b/client/src/cmdlfparadox.c index f64c51be8..a2fa50f11 100644 --- a/client/src/cmdlfparadox.c +++ b/client/src/cmdlfparadox.c @@ -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", "", "raw hex data. 12 bytes max"), + arg_u64_0(NULL, "fc", "", "facility code"), + arg_u64_0(NULL, "cn", "", "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 diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index dccacc3b1..f1cb773fb 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -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)); diff --git a/client/src/cmdmain.c b/client/src/cmdmain.c index 99fef33d4..14e198f5c 100644 --- a/client/src/cmdmain.c +++ b/client/src/cmdmain.c @@ -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... }"}, diff --git a/client/src/cmdpiv.c b/client/src/cmdpiv.c new file mode 100644 index 000000000..dc6584f40 --- /dev/null +++ b/client/src/cmdpiv.c @@ -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_("")); + } 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", "", "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", "", "Applet ID to select. By default A0000003080000100 will be used"), + arg_str1(NULL, NULL, "", "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", "", "Applet ID to select. By default A0000003080000100 will be used"), + arg_str1(NULL, "nonce", "", "Nonce to sign."), + arg_int0(NULL, "slot", "", "Slot number. Default will be 0x9E (card auth cert)."), + arg_int0(NULL, "alg", "", "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", "", "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); +} + diff --git a/client/src/cmdpiv.h b/client/src/cmdpiv.h new file mode 100644 index 000000000..13b5fffe9 --- /dev/null +++ b/client/src/cmdpiv.h @@ -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 diff --git a/client/src/cmdscript.c b/client/src/cmdscript.c index 7a5a59130..35640922e 100644 --- a/client/src/cmdscript.c +++ b/client/src/cmdscript.c @@ -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); diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index 5fbf90b0d..d3096307a 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -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)); } } diff --git a/client/src/emv/cmdemv.c b/client/src/emv/cmdemv.c index bf1cde60d..71277d87b 100644 --- a/client/src/emv/cmdemv.c +++ b/client/src/emv/cmdemv.c @@ -17,11 +17,9 @@ //----------------------------------------------------------------------------- #include "cmdemv.h" - #include - -#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); diff --git a/client/src/emv/emvcore.c b/client/src/emv/emvcore.c index 17aa2610e..fbc59b1c0 100644 --- a/client/src/emv/emvcore.c +++ b/client/src/emv/emvcore.c @@ -17,13 +17,11 @@ //----------------------------------------------------------------------------- #include "emvcore.h" - #include - -#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); diff --git a/client/src/emv/tlv.c b/client/src/emv/tlv.c index f22bfea4c..67fa51b58 100644 --- a/client/src/emv/tlv.c +++ b/client/src/emv/tlv.c @@ -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; diff --git a/client/src/emv/tlv.h b/client/src/emv/tlv.h index 50d046659..39f1bcacd 100644 --- a/client/src/emv/tlv.h +++ b/client/src/emv/tlv.h @@ -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); diff --git a/client/src/fileutils.c b/client/src/fileutils.c index 22cf3ad5e..3182f47c3 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -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; diff --git a/client/src/flash.c b/client/src/flash.c index 6275db0bf..20729b2da 100644 --- a/client/src/flash.c +++ b/client/src/flash.c @@ -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, "---------------------------------------------------"); diff --git a/client/src/iso7816/apduinfo.c b/client/src/iso7816/apduinfo.c index b2d879b78..b7d77aca9 100644 --- a/client/src/iso7816/apduinfo.c +++ b/client/src/iso7816/apduinfo.c @@ -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; diff --git a/client/src/iso7816/iso7816core.c b/client/src/iso7816/iso7816core.c index 5db7d32aa..7e0dd2c7f 100644 --- a/client/src/iso7816/iso7816core.c +++ b/client/src/iso7816/iso7816core.c @@ -17,9 +17,7 @@ //----------------------------------------------------------------------------- #include "iso7816core.h" - #include - #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); diff --git a/client/src/ksx6924/ksx6924core.c b/client/src/ksx6924/ksx6924core.c index b04f87358..307573f74 100644 --- a/client/src/ksx6924/ksx6924core.c +++ b/client/src/ksx6924/ksx6924core.c @@ -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; } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index ab572b4d0..9c3326f83 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -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; diff --git a/client/src/mifare/mifare4.c b/client/src/mifare/mifare4.c index a1427bc9f..1ac6b6fed 100644 --- a/client/src/mifare/mifare4.c +++ b/client/src/mifare/mifare4.c @@ -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++) diff --git a/client/src/mifare/mifare4.h b/client/src/mifare/mifare4.h index 7905f3ab6..489add9f3 100644 --- a/client/src/mifare/mifare4.h +++ b/client/src/mifare/mifare4.h @@ -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); diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index 5ce88123d..56d10c608 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -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; -} \ No newline at end of file +} diff --git a/client/src/mifare/mifarehost.h b/client/src/mifare/mifarehost.h index 0212dd4f0..ccefbbd40 100644 --- a/client/src/mifare/mifarehost.h +++ b/client/src/mifare/mifarehost.h @@ -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 diff --git a/client/src/pm3line_vocabulory.h b/client/src/pm3line_vocabulory.h index 6b15007c3..5a517c645 100644 --- a/client/src/pm3line_vocabulory.h +++ b/client/src/pm3line_vocabulory.h @@ -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" }, diff --git a/client/src/ui.c b/client/src/ui.c index 0ffabc341..2281497c1 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -23,7 +23,6 @@ #endif #include "ui.h" #include "commonutil.h" // ARRAYLEN - #include // for Mingw readline #include #include @@ -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. diff --git a/client/src/ui.h b/client/src/ui.h index 7aff98eba..4042550b3 100644 --- a/client/src/ui.h +++ b/client/src/ui.h @@ -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; diff --git a/client/src/util.c b/client/src/util.c index 56eb3164a..63141d01c 100644 --- a/client/src/util.c +++ b/client/src/util.c @@ -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; diff --git a/client/src/util.h b/client/src/util.h index 616272c84..c29fbd50f 100644 --- a/client/src/util.h +++ b/client/src/util.h @@ -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; diff --git a/common/cryptorf/cryptolib.c b/common/cryptorf/cryptolib.c index eded5315c..b4abbdd54 100644 --- a/common/cryptorf/cryptolib.c +++ b/common/cryptorf/cryptolib.c @@ -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; diff --git a/common/generator.c b/common/generator.c index 41bd49d89..852ea2b61 100644 --- a/common/generator.c +++ b/common/generator.c @@ -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. diff --git a/common/generator.h b/common/generator.h index 5fc81ba25..1008d01fa 100644 --- a/common/generator.h +++ b/common/generator.h @@ -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); diff --git a/common/mbedtls/bignum.c b/common/mbedtls/bignum.c index 9b7bcdd1c..200ad7ca0 100644 --- a/common/mbedtls/bignum.c +++ b/common/mbedtls/bignum.c @@ -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) { diff --git a/doc/commands.json b/doc/commands.json index a94e5bc6a..1c21f81ba 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -1030,7 +1030,7 @@ }, "help": { "command": "help", - "description": "help Use ` 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 ` 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 date of birth in YYMMDD format", "-e, --expiry expiry in YYMMDD format", "-m, --mrz <[0-9A-Z<]> 2nd line of MRZ, 44 chars", - "--path save dump to the given dirpath" + "--dir save dump to the given dirpath" ], - "usage": "hf emrtd dump [-h] [-n ] [-d ] [-e ] [-m <[0-9A-Z<]>] [--path ]" + "usage": "hf emrtd dump [-h] [-n ] [-d ] [-e ] [-m <[0-9A-Z<]>] [--dir ]" }, "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 date of birth in YYMMDD format", "-e, --expiry expiry in YYMMDD format", "-m, --mrz <[0-9A-Z<]> 2nd line of MRZ, 44 chars (passports only)", - "--path display info from offline dump stored in dirpath", + "--dir display info from offline dump stored in dirpath", "-i, --images show images" ], - "usage": "hf emrtd info [-hi] [-n ] [-d ] [-e ] [-m <[0-9A-Z<]>] [--path ]" + "usage": "hf emrtd info [-hi] [-n ] [-d ] [-e ] [-m <[0-9A-Z<]>] [--dir ]" }, "hf emrtd list": { "command": "hf emrtd list", @@ -2916,9 +2921,10 @@ "-f, --file 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 [--credit] [--elite] [--raw]" + "usage": "hf iclass chk [-h] -f [--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 ] [-k ] [--ki ] [--credit ] [--ci ] [--elite] [--raw] [--nr] [--force]" + "usage": "hf iclass dump [-hz] [-f ] [-k ] [--ki ] [--credit ] [--ci ] [--elite] [--raw] [--nr] [--force] [--shallow]" }, "hf iclass eload": { "command": "hf iclass eload", @@ -3008,9 +3015,10 @@ "--enckey 3DES transport key, 16 hex bytes", "--fc facility code", "--cn card number", - "-w, --wiegand see `wiegand list` for available formats" + "-w, --wiegand see `wiegand list` for available formats", + "--shallow use shallow (ASK) reader modulation instead of OOK" ], - "usage": "hf iclass encode [-h] [--bin ] --ki [--credit] [--elite] [--raw] [--enckey ] [--fc ] [--cn ] [-w ]" + "usage": "hf iclass encode [-h] [--bin ] --ki [--credit] [--elite] [--raw] [--enckey ] [--fc ] [--cn ] [-w ] [--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 ] [--ki ] -b [--credit] [--elite] [--raw] [--nr]" + "usage": "hf iclass rdbl [-hv] [-k ] [--ki ] -b [--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 [-k ] [--ki ] --first --last [--credit] [--elite] [--raw]" + "usage": "hf iclass restore [-hv] -f [-k ] [--ki ] --first --last [--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 ] [--ki ] -b -d [-m ] [--credit] [--elite] [--raw] [--nr]" + "usage": "hf iclass wrbl [-hv] [-k ] [--ki ] -b -d [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow]" }, "hf jooki clone": { "command": "hf jooki clone", @@ -3391,6 +3404,20 @@ ], "usage": "hf jooki sim [-h] [-b ]" }, + "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] " }, - + "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 ] [--mini] [--1k] [--2k] [--4k] [--emu]" }, @@ -4348,6 +4360,27 @@ ], "usage": "hf mf gload [-hv] [--mini] [--1k] [--2k] [--4k] [-p ] [-f ] [--emu] [--start ] [--end ]" }, + "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 password 4bytes", + "-f, --file filename of dump", + "--emu to emulator memory" + ], + "usage": "hf mf gsave [-h] [--mini] [--1k] [--2k] [--4k] [-p ] [-f ] [--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 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 key, 6 hex bytes", "-d, --data 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 raw hex data. 12 bytes max", + "--fc facility code", + "--cn card number", "--q5 optional - specify writing to Q5/T5555 tag", "--em optional - specify writing to EM4305/4469 tag" ], - "usage": "lf paradox clone [-h] [-r ] [--q5] [--em]" + "usage": "lf paradox clone [-h] [-r ] [--fc ] [--cn ] [--q5] [--em]" }, "lf paradox demod": { "command": "lf paradox demod", @@ -10924,6 +10960,114 @@ ], "usage": "hf 14b ndefread [-hv] [-f ]" }, + "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 Applet ID to select. By default A0000003080000100 will be used", + "--nonce Nonce to sign.", + "--slot Slot number. Default will be 0x9E (card auth cert).", + "--alg 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 ] --nonce [--slot ] [--alg ]" + }, + "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 Applet ID to select. By default A0000003080000100 will be used", + " Tag ID to read, between 1 and 3 bytes." + ], + "usage": "piv getdata [-hskatw] [--aid ] " + }, + "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 filename of dictionary" + ], + "usage": "piv list [-h1crux] [--frame] [-f ]" + }, + "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 Applet ID to select. By default A0000003080000100 will be used" + ], + "usage": "piv scan [-hskatw] [--aid ]" + }, + "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 Applet ID to select. By default A0000003080000100 will be used" + ], + "usage": "piv select [-hskatw] [--aid ]" + }, "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" } } \ No newline at end of file diff --git a/doc/commands.md b/doc/commands.md index 4b91901f4..1c6110cea 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -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... } diff --git a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md index 06040b59e..ee8c63465 100644 --- a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md +++ b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md @@ -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 diff --git a/docker/archlinux/Dockerfile b/docker/archlinux/Dockerfile index 709b7b5d4..93584c098 100644 --- a/docker/archlinux/Dockerfile +++ b/docker/archlinux/Dockerfile @@ -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 diff --git a/docker/archlinux/README.md b/docker/archlinux/README.md index 35fdf0c78..872d46cb4 100644 --- a/docker/archlinux/README.md +++ b/docker/archlinux/README.md @@ -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 diff --git a/docker/archlinux/run_tests.sh b/docker/archlinux/run_tests.sh index 9c2b4daeb..53eeda9a3 100755 --- a/docker/archlinux/run_tests.sh +++ b/docker/archlinux/run_tests.sh @@ -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 diff --git a/docker/build-all.sh b/docker/build-all.sh index 3116d96dc..aba45382f 100755 --- a/docker/build-all.sh +++ b/docker/build-all.sh @@ -1,5 +1,5 @@ #!/bin/bash -for os in archlinux debian-buster fedora-34 fedora-35 homebrew kali opensuse-leap opensuse-tumbleweed parrot-core-latest ubuntu-18.04 ubuntu-20.04 ubuntu-21.04; do +for os in archlinux debian-buster fedora-36 fedora-37 homebrew kali opensuse-leap opensuse-tumbleweed parrot-core-latest ubuntu-18.04 ubuntu-20.04 ubuntu-22.04; do ( cd $os && ./docker_build.sh ) done diff --git a/docker/debian-bullseye/Dockerfile b/docker/debian-bullseye/Dockerfile index 53114b795..ff456b558 100644 --- a/docker/debian-bullseye/Dockerfile +++ b/docker/debian-bullseye/Dockerfile @@ -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 diff --git a/docker/debian-bullseye/README.md b/docker/debian-bullseye/README.md index 1170c19fe..e86881019 100644 --- a/docker/debian-bullseye/README.md +++ b/docker/debian-bullseye/README.md @@ -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 diff --git a/docker/debian-bullseye/run_tests.sh b/docker/debian-bullseye/run_tests.sh new file mode 100755 index 000000000..25e6d2a21 --- /dev/null +++ b/docker/debian-bullseye/run_tests.sh @@ -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 diff --git a/docker/fedora-34/README.md b/docker/fedora-34/README.md deleted file mode 100644 index 7930f99d0..000000000 --- a/docker/fedora-34/README.md +++ /dev/null @@ -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" \ No newline at end of file diff --git a/docker/fedora-34/docker_build.sh b/docker/fedora-34/docker_build.sh deleted file mode 100755 index 753d223a8..000000000 --- a/docker/fedora-34/docker_build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker build -t "pm3-fedora-34:1.0" . diff --git a/docker/fedora-34/docker_rm.sh b/docker/fedora-34/docker_rm.sh deleted file mode 100644 index eec1ba46c..000000000 --- a/docker/fedora-34/docker_rm.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -docker image rm pm3-fedora-34:1.0 -docker image rm fedora:34 diff --git a/docker/fedora-35/README.md b/docker/fedora-35/README.md deleted file mode 100644 index 966e86e7e..000000000 --- a/docker/fedora-35/README.md +++ /dev/null @@ -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-35/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" diff --git a/docker/fedora-35/docker_build.sh b/docker/fedora-35/docker_build.sh deleted file mode 100755 index 57eca95c0..000000000 --- a/docker/fedora-35/docker_build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker build -t "pm3-fedora-35:1.0" . diff --git a/docker/fedora-35/docker_rm.sh b/docker/fedora-35/docker_rm.sh deleted file mode 100644 index 100bd2690..000000000 --- a/docker/fedora-35/docker_rm.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -docker image rm pm3-fedora-35:1.0 -docker image rm fedora:35 diff --git a/docker/fedora-35/Dockerfile b/docker/fedora-36/Dockerfile similarity index 88% rename from docker/fedora-35/Dockerfile rename to docker/fedora-36/Dockerfile index 40788b62a..007af68c3 100644 --- a/docker/fedora-35/Dockerfile +++ b/docker/fedora-36/Dockerfile @@ -1,4 +1,4 @@ -FROM fedora:35 +FROM fedora:36 ENV LANG C # qt5-qtbase-devel skipped @@ -8,6 +8,8 @@ RUN yum -y update RUN yum -y install cmake python-pip RUN python3 -m pip install ansicolors sslcrypto +RUN yum -y install mesa-libOpenCL ocl-icd-devel + # Create rrg user RUN useradd -ms /bin/bash rrg RUN passwd -d rrg diff --git a/docker/fedora-36/README.md b/docker/fedora-36/README.md new file mode 100644 index 000000000..6648fb28d --- /dev/null +++ b/docker/fedora-36/README.md @@ -0,0 +1,21 @@ +# Notes on run_tests.sh script +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 with PASS. + + +# Notes to run tests +The script is to be run in proxmark root folder inside the docker env. + +``` +docker/fedora-36/run_tests.sh; +``` + +Or if you want to run single test, + +``` +sudo yum -y update +make clean; make -j +tools/pm3_tests.sh --long +``` diff --git a/docker/fedora-36/docker_build.sh b/docker/fedora-36/docker_build.sh new file mode 100755 index 000000000..1a2e2d392 --- /dev/null +++ b/docker/fedora-36/docker_build.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker build -t "pm3-fedora-36:1.0" . diff --git a/docker/fedora-36/docker_rm.sh b/docker/fedora-36/docker_rm.sh new file mode 100644 index 000000000..ea2b28809 --- /dev/null +++ b/docker/fedora-36/docker_rm.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +docker image rm pm3-fedora-36:1.0 +docker image rm fedora:36 diff --git a/docker/fedora-34/docker_run.sh b/docker/fedora-36/docker_run.sh similarity index 69% rename from docker/fedora-34/docker_run.sh rename to docker/fedora-36/docker_run.sh index 4be59d2c5..0e6e69925 100755 --- a/docker/fedora-34/docker_run.sh +++ b/docker/fedora-36/docker_run.sh @@ -1,3 +1,3 @@ #!/bin/bash -docker run --volume=$(pwd)/../..:/home/rrg/proxmark3 -w /home/rrg/proxmark3 -it pm3-fedora-34:1.0 +docker run --volume=$(pwd)/../..:/home/rrg/proxmark3 -w /home/rrg/proxmark3 -it pm3-fedora-36:1.0 diff --git a/docker/fedora-36/run_tests.sh b/docker/fedora-36/run_tests.sh new file mode 100755 index 000000000..05cdb7da8 --- /dev/null +++ b/docker/fedora-36/run_tests.sh @@ -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/fedora-36/run_tests.sh; + +sudo yum -y update +tools/release_tests.sh diff --git a/docker/fedora-34/Dockerfile b/docker/fedora-37/Dockerfile similarity index 88% rename from docker/fedora-34/Dockerfile rename to docker/fedora-37/Dockerfile index 90765a515..930767853 100644 --- a/docker/fedora-34/Dockerfile +++ b/docker/fedora-37/Dockerfile @@ -1,4 +1,4 @@ -FROM fedora:34 +FROM fedora:37 ENV LANG C # qt5-qtbase-devel skipped @@ -8,6 +8,8 @@ RUN yum -y update RUN yum -y install cmake python-pip RUN python3 -m pip install ansicolors sslcrypto +RUN yum -y install mesa-libOpenCL ocl-icd-devel + # Create rrg user RUN useradd -ms /bin/bash rrg RUN passwd -d rrg diff --git a/docker/fedora-37/README.md b/docker/fedora-37/README.md new file mode 100644 index 000000000..79c88e040 --- /dev/null +++ b/docker/fedora-37/README.md @@ -0,0 +1,20 @@ +# Notes on run_tests.sh script +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 with PASS. + +# Notes to run tests +The script is to be run in proxmark root folder inside the docker env. + +``` +docker/fedora-37/run_tests.sh; +``` + +Or if you want to run single test, + +``` +sudo yum -y update +make clean; make -j +tools/pm3_tests.sh --long +``` diff --git a/docker/fedora-37/docker_build.sh b/docker/fedora-37/docker_build.sh new file mode 100755 index 000000000..5e3049b68 --- /dev/null +++ b/docker/fedora-37/docker_build.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker build -t "pm3-fedora-37:1.0" . diff --git a/docker/fedora-37/docker_rm.sh b/docker/fedora-37/docker_rm.sh new file mode 100644 index 000000000..a9359d0fd --- /dev/null +++ b/docker/fedora-37/docker_rm.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +docker image rm pm3-fedora-37:1.0 +docker image rm fedora:37 diff --git a/docker/fedora-35/docker_run.sh b/docker/fedora-37/docker_run.sh similarity index 69% rename from docker/fedora-35/docker_run.sh rename to docker/fedora-37/docker_run.sh index d2e027507..eb51525b7 100755 --- a/docker/fedora-35/docker_run.sh +++ b/docker/fedora-37/docker_run.sh @@ -1,3 +1,3 @@ #!/bin/bash -docker run --volume=$(pwd)/../..:/home/rrg/proxmark3 -w /home/rrg/proxmark3 -it pm3-fedora-35:1.0 +docker run --volume=$(pwd)/../..:/home/rrg/proxmark3 -w /home/rrg/proxmark3 -it pm3-fedora-37:1.0 diff --git a/docker/fedora-37/run_tests.sh b/docker/fedora-37/run_tests.sh new file mode 100755 index 000000000..05cdb7da8 --- /dev/null +++ b/docker/fedora-37/run_tests.sh @@ -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/fedora-36/run_tests.sh; + +sudo yum -y update +tools/release_tests.sh diff --git a/docker/kali/Dockerfile b/docker/kali/Dockerfile index e8a506dc5..79d4bb9a6 100644 --- a/docker/kali/Dockerfile +++ b/docker/kali/Dockerfile @@ -9,9 +9,13 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends git ca-certificates build-essential cmake pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev libbluetooth-dev libpython3-dev libssl-dev sudo && \ apt-get clean -RUN apt install -y python3-minimal -RUN apt install -y python3-pip -RUN python3 -m pip install ansicolors sslcrypto +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 diff --git a/docker/kali/README.md b/docker/kali/README.md index e76d73ae2..dbf1f7f50 100644 --- a/docker/kali/README.md +++ b/docker/kali/README.md @@ -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/kali/run_tests.sh; -``` +``` -Or if you want to run single test, +Or if you want to run single test, ``` sudo apt update make clean; make -j diff --git a/docker/kali/run_tests.sh b/docker/kali/run_tests.sh index 27b1c608f..dec20763b 100755 --- a/docker/kali/run_tests.sh +++ b/docker/kali/run_tests.sh @@ -2,33 +2,7 @@ # 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. -# -# -- Init / setup phase -# Script to be run inside docker env. First install some dependencies for docker image. -# -# -- Build phase begins -# make builds -# cmake client builds -# of the different possible PLATFORM (PM3RDV4 / PM3GENERIC) and BTADDON combos +# docker/kali/run_tests.sh; sudo apt update && sudo apt upgrade -y - -# 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 diff --git a/docker/opensuse-leap/Dockerfile b/docker/opensuse-leap/Dockerfile index c8a5c7cf1..1af777d23 100644 --- a/docker/opensuse-leap/Dockerfile +++ b/docker/opensuse-leap/Dockerfile @@ -4,8 +4,14 @@ ENV LANG C # libqt5-qtbase-devel skipped RUN zypper --non-interactive install --no-recommends shadow sudo git patterns-devel-base-devel_basis gcc-c++ readline-devel libbz2-devel bluez-devel python3-devel libopenssl-devel -RUN zypper --non-interactive install cmake python3 python3-pip -RUN python3 -m pip install ansicolors sslcrypto +RUN zypper addrepo https://download.opensuse.org/repositories/home:wkazubski/15.4/home:wkazubski.repo && \ + zypper --gpg-auto-import-keys refresh && \ + zypper --non-interactive install cross-arm-none-eabi-gcc12 cross-arm-none-eabi-newlib + +RUN zypper --non-interactive install cmake python3 python3-pip && \ + python3 -m pip install ansicolors sslcrypto + +RUN zypper --non-interactive install ocl-icd-devel # Create rrg user RUN useradd -ms /bin/bash rrg diff --git a/docker/opensuse-leap/README.md b/docker/opensuse-leap/README.md index 47a3b5c32..ecda34706 100644 --- a/docker/opensuse-leap/README.md +++ b/docker/opensuse-leap/README.md @@ -1,24 +1,20 @@ # Notes on run_tests.sh script -This script does both setup 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. +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 with PASS. # Notes to run tests The script is to be run in proxmark root folder inside the docker env. ``` docker/opensuse-leap/run_tests.sh; -``` +``` -Or if you want to run single test, +Or if you want to run single test, ``` +sudo zypper refresh && sudo zypper --non-interactive update make clean; make -j -tools/pm3_tests.sh --long mfkey nonce2key mf_nonce_brute fpga_compress common client +tools/pm3_tests.sh --long ``` - - -No ARM compiler available ? diff --git a/docker/opensuse-leap/run_tests.sh b/docker/opensuse-leap/run_tests.sh new file mode 100755 index 000000000..d2d49211b --- /dev/null +++ b/docker/opensuse-leap/run_tests.sh @@ -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/opensuse-leap/run_tests.sh; + +sudo zypper refresh && sudo zypper --non-interactive update +tools/release_tests.sh diff --git a/docker/opensuse-tumbleweed/Dockerfile b/docker/opensuse-tumbleweed/Dockerfile index 5d4adbb8b..169d087c3 100644 --- a/docker/opensuse-tumbleweed/Dockerfile +++ b/docker/opensuse-tumbleweed/Dockerfile @@ -2,10 +2,16 @@ FROM opensuse/tumbleweed ENV LANG C # libqt5-qtbase-devel skipped -RUN zypper --non-interactive install --no-recommends shadow sudo git patterns-devel-base-devel_basis gcc-c++ readline-devel libbz2-devel bluez-devel python3-devel libopenssl-devel cross-arm-none-gcc11 cross-arm-none-newlib-devel +RUN zypper --non-interactive install --no-recommends shadow sudo git patterns-devel-base-devel_basis gcc-c++ readline-devel libbz2-devel bluez-devel python3-devel libopenssl-devel cross-arm-none-gcc12 cross-arm-none-newlib-devel -RUN zypper --non-interactive install cmake python3 python3-pip -RUN python3 -m pip install ansicolors sslcrypto +#RUN zypper addrepo https://download.opensuse.org/repositories/home:wkazubski/openSUSE_Tumbleweed/home:wkazubski.repo && \ +# zypper --gpg-auto-import-keys refresh && \ +# zypper --non-interactive install cross-arm-none-eabi-gcc12 cross-arm-none-eabi-newlib + +RUN zypper --non-interactive install cmake python3 python3-pip && \ + python3 -m pip install ansicolors sslcrypto + +RUN zypper --non-interactive install ocl-icd-devel # Create rrg user RUN useradd -ms /bin/bash rrg diff --git a/docker/opensuse-tumbleweed/README.md b/docker/opensuse-tumbleweed/README.md index 126042512..bd55e0c9d 100644 --- a/docker/opensuse-tumbleweed/README.md +++ b/docker/opensuse-tumbleweed/README.md @@ -1,24 +1,20 @@ # Notes on run_tests.sh script -This script does both setup 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. +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 with PASS. # Notes to run tests The script is to be run in proxmark root folder inside the docker env. ``` docker/opensuse-tumbleweed/run_tests.sh; -``` +``` -Or if you want to run single test, +Or if you want to run single test, ``` +sudo zypper refresh && sudo zypper --non-interactive update make clean; make -j -tools/pm3_tests.sh --long mfkey nonce2key mf_nonce_brute fpga_compress common client +tools/pm3_tests.sh --long ``` - - -No ARM compiler available ? diff --git a/docker/opensuse-tumbleweed/run_tests.sh b/docker/opensuse-tumbleweed/run_tests.sh new file mode 100755 index 000000000..9002131e9 --- /dev/null +++ b/docker/opensuse-tumbleweed/run_tests.sh @@ -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/opensuse-tumbleweed/run_tests.sh; + +sudo zypper refresh && sudo zypper --non-interactive update +tools/release_tests.sh diff --git a/docker/parrot-core-latest/Dockerfile b/docker/parrot-core-latest/Dockerfile index 8ca8f9856..a33af1d4c 100644 --- a/docker/parrot-core-latest/Dockerfile +++ b/docker/parrot-core-latest/Dockerfile @@ -9,10 +9,14 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends git ca-certificates build-essential cmake pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev libbluetooth-dev libpython3-dev libssl-dev sudo && \ apt-get clean -RUN apt install -y python3-minimal && \ - apt install -y python3-pip && \ +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 diff --git a/docker/parrot-core-latest/README.md b/docker/parrot-core-latest/README.md index 45ad548df..679c3a1eb 100644 --- a/docker/parrot-core-latest/README.md +++ b/docker/parrot-core-latest/README.md @@ -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/parrot-core-latest/run_tests.sh; -``` +``` -Or if you want to run single test, +Or if you want to run single test, ``` sudo apt update diff --git a/docker/parrot-core-latest/run_tests.sh b/docker/parrot-core-latest/run_tests.sh new file mode 100755 index 000000000..65b0737c4 --- /dev/null +++ b/docker/parrot-core-latest/run_tests.sh @@ -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/parrot-core-latest/run_tests.sh; + +sudo apt update && sudo apt upgrade -y +tools/release_tests.sh diff --git a/docker/ubuntu-18.04/Dockerfile b/docker/ubuntu-18.04/Dockerfile index 11c5afcd8..29c958a4d 100644 --- a/docker/ubuntu-18.04/Dockerfile +++ b/docker/ubuntu-18.04/Dockerfile @@ -10,10 +10,14 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends git ca-certificates build-essential cmake pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev libbluetooth-dev libssl-dev sudo && \ apt-get clean -RUN apt install -y python3-minimal && \ - apt install -y python3-pip && \ +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 diff --git a/docker/ubuntu-18.04/README.md b/docker/ubuntu-18.04/README.md index 0b7d2f748..6cc3b9ef2 100644 --- a/docker/ubuntu-18.04/README.md +++ b/docker/ubuntu-18.04/README.md @@ -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 diff --git a/docker/ubuntu-18.04/run_tests.sh b/docker/ubuntu-18.04/run_tests.sh new file mode 100755 index 000000000..1efdbc060 --- /dev/null +++ b/docker/ubuntu-18.04/run_tests.sh @@ -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/ubuntu-18.04/run_tests.sh; + +sudo apt update && sudo apt upgrade -y +tools/release_tests.sh diff --git a/docker/ubuntu-20.04/Dockerfile b/docker/ubuntu-20.04/Dockerfile index d9138aa0d..72f6ec6cf 100644 --- a/docker/ubuntu-20.04/Dockerfile +++ b/docker/ubuntu-20.04/Dockerfile @@ -9,10 +9,14 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends git ca-certificates build-essential cmake pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev libbluetooth-dev libpython3-dev libssl-dev sudo && \ apt-get clean -RUN apt install -y python3-minimal && \ - apt install -y python3-pip && \ +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 diff --git a/docker/ubuntu-20.04/README.md b/docker/ubuntu-20.04/README.md index d8c7b3f53..4c432eff1 100644 --- a/docker/ubuntu-20.04/README.md +++ b/docker/ubuntu-20.04/README.md @@ -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 diff --git a/docker/ubuntu-20.04/run_tests.sh b/docker/ubuntu-20.04/run_tests.sh new file mode 100755 index 000000000..aa98bc327 --- /dev/null +++ b/docker/ubuntu-20.04/run_tests.sh @@ -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/ubuntu-20.04/run_tests.sh; + +sudo apt update && sudo apt upgrade -y +tools/release_tests.sh diff --git a/docker/ubuntu-21.04/README.md b/docker/ubuntu-21.04/README.md deleted file mode 100644 index bb90abab8..000000000 --- a/docker/ubuntu-21.04/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# 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. - -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/ubuntu-21.04/run_tests.sh; -``` - -Or if you want to run single test, -``` -sudo apt update -make clean; make -j -tools/pm3_tests.sh --long -``` diff --git a/docker/ubuntu-21.04/docker_build.sh b/docker/ubuntu-21.04/docker_build.sh deleted file mode 100755 index 70e0349f8..000000000 --- a/docker/ubuntu-21.04/docker_build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker build -t "pm3-ubuntu-21.04:1.0" . diff --git a/docker/ubuntu-21.04/docker_rm.sh b/docker/ubuntu-21.04/docker_rm.sh deleted file mode 100644 index bb848bfe0..000000000 --- a/docker/ubuntu-21.04/docker_rm.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -docker image rm pm3-ubuntu-21.04:1.0 -docker image rm ubuntu:21.04 diff --git a/docker/ubuntu-21.04/Dockerfile b/docker/ubuntu-22.04/Dockerfile similarity index 76% rename from docker/ubuntu-21.04/Dockerfile rename to docker/ubuntu-22.04/Dockerfile index 4350e8aa3..9d867e785 100644 --- a/docker/ubuntu-21.04/Dockerfile +++ b/docker/ubuntu-22.04/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:21.04 +FROM ubuntu:22.04 ENV LANG C ENV DEBIAN_FRONTEND noninteractive @@ -9,10 +9,14 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends git ca-certificates build-essential cmake pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev libbluetooth-dev libpython3-dev libssl-dev sudo && \ apt-get clean -RUN apt install -y python3-minimal && \ - apt install -y python3-pip && \ +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 diff --git a/docker/ubuntu-22.04/README.md b/docker/ubuntu-22.04/README.md new file mode 100644 index 000000000..93d4462ad --- /dev/null +++ b/docker/ubuntu-22.04/README.md @@ -0,0 +1,20 @@ +# Notes on run_tests.sh script +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 with PASS. + + +# Notes to run tests +The script is to be run in proxmark root folder inside the docker env. + +``` +docker/ubuntu-22.04/run_tests.sh; +``` + +Or if you want to run single test, +``` +sudo apt update +make clean; make -j +tools/pm3_tests.sh --long +``` diff --git a/docker/ubuntu-22.04/docker_build.sh b/docker/ubuntu-22.04/docker_build.sh new file mode 100755 index 000000000..1cfd6c10a --- /dev/null +++ b/docker/ubuntu-22.04/docker_build.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker build -t "pm3-ubuntu-22.04:1.0" . diff --git a/docker/ubuntu-22.04/docker_rm.sh b/docker/ubuntu-22.04/docker_rm.sh new file mode 100644 index 000000000..e6a5f0302 --- /dev/null +++ b/docker/ubuntu-22.04/docker_rm.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +docker image rm pm3-ubuntu-22.04:1.0 +docker image rm ubuntu:22.04 diff --git a/docker/ubuntu-21.04/docker_run.sh b/docker/ubuntu-22.04/docker_run.sh similarity index 67% rename from docker/ubuntu-21.04/docker_run.sh rename to docker/ubuntu-22.04/docker_run.sh index d8fd6722f..04f8d99a0 100755 --- a/docker/ubuntu-21.04/docker_run.sh +++ b/docker/ubuntu-22.04/docker_run.sh @@ -1,3 +1,3 @@ #!/bin/bash -docker run --volume=$(pwd)/../..:/home/rrg/proxmark3 -w /home/rrg/proxmark3 -it pm3-ubuntu-21.04:1.0 +docker run --volume=$(pwd)/../..:/home/rrg/proxmark3 -w /home/rrg/proxmark3 -it pm3-ubuntu-22.04:1.0 diff --git a/docker/ubuntu-22.04/run_tests.sh b/docker/ubuntu-22.04/run_tests.sh new file mode 100755 index 000000000..4f8ce55ea --- /dev/null +++ b/docker/ubuntu-22.04/run_tests.sh @@ -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/ubuntu-22.04/run_tests.sh; + +sudo apt update && sudo apt upgrade -y +tools/release_tests.sh diff --git a/include/common.h b/include/common.h index bb3781c4a..a97545996 100644 --- a/include/common.h +++ b/include/common.h @@ -24,8 +24,8 @@ #include #ifdef _WIN32 -#define ABOVE "..\\" -#define PATHSEP "\\" +#define ABOVE "../" +#define PATHSEP "/" #else #define ABOVE "../" #define PATHSEP "/" @@ -60,7 +60,7 @@ struct version_information_t { char clean; /* 1: Tree was clean, no local changes. 0: Tree was unclean. 2: Couldn't be determined */ char gitversion[50]; /* String with the git revision */ char buildtime[30]; /* string with the build time */ - char armsrc[10]; /* sha256sum of sha256sum of armsrc files */ + char armsrc[10]; /* sha256sum of sha256sum of armsrc && common_arm files */ } PACKED; // debug diff --git a/include/protocol_vigik.h b/include/protocol_vigik.h index a61c4ce03..7512c1c2d 100644 --- a/include/protocol_vigik.h +++ b/include/protocol_vigik.h @@ -42,4 +42,4 @@ typedef struct vigik_pk_s { const char *n; } vigik_pk_t; -#endif \ No newline at end of file +#endif diff --git a/include/protocols.h b/include/protocols.h index 563938f52..1417fa71a 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -190,6 +190,9 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define MIFARE_CMD_RESTORE 0xC2 #define MIFARE_CMD_TRANSFER 0xB0 +#define MIFARE_MAGIC_GDM_AUTH_KEYA 0x80 +#define MIFARE_MAGIC_GDM_AUTH_KEYB 0x81 + #define MIFARE_EV1_PERSONAL_UID 0x40 #define MIFARE_EV1_SETMODE 0x43 #define MIFARE_EV1_UIDF0 0x00 @@ -450,9 +453,71 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define ISO7816_MANAGE_CHANNEL 0x70 #define ISO7816_GET_RESPONSE 0xC0 + // ISO7816-4 For response APDU's -#define ISO7816_OK 0x9000 -// 6x xx = ERROR +#define ISO7816_OK 0x9000 + +// 6x xx = APDU ERROR CODES + +// 61 xx +#define ISO7816_BYTES_REMAINING_00 0x6100 // Response bytes remaining + +// 62 xx +#define ISO7816_WARNING_STATE_UNCHANGED 0x6200 // Warning, card state unchanged +#define ISO7816_DATA_CORRUPT 0x6281 // Returned data may be corrupted +#define ISO7816_FILE_EOF 0x6282 // The end of the file has been reached before the end of reading +#define ISO7816_INVALID_DF 0x6283 // Invalid DF +#define ISO7816_INVALID_FILE 0x6284 // Selected file is not valid +#define ISO7816_FILE_TERMINATED 0x6285 // File is terminated + +// 63 xx +#define ISO7816_AUTH_FAILED 0x6300 // Authentification failed +#define ISO7816_FILE_FILLED 0x6381 // File filled up by the last write + +// 65 xx +#define ISO7816_MEMORY_FULL 0x6501 // Memory failure +#define ISO7816_WRITE_MEMORY_ERR 0x6581 // Write problem / Memory failure / Unknown mode + +// 67 xx +#define ISO7816_WRONG_LENGTH 0x6700 // Wrong length + +// 68 xx +#define ISO7816_LOGICAL_CHANNEL_NOT_SUPPORTED 0x6881 // Card does not support the operation on the specified logical channel +#define ISO7816_SECURE_MESSAGING_NOT_SUPPORTED 0x6882 // Card does not support secure messaging +#define ISO7816_LAST_COMMAND_EXPECTED 0x6883 // Last command in chain expected +#define ISO7816_COMMAND_CHAINING_NOT_SUPPORTED 0x6884 // Command chaining not supported + +// 69 xx +#define ISO7816_TRANSACTION_FAIL 0x6900 // No successful transaction executed during session +#define ISO7816_SELECT_FILE_ERR 0x6981 // Cannot select indicated file, command not compatible with file organization +#define ISO7816_SECURITY_STATUS_NOT_SATISFIED 0x6982 // Security condition not satisfied +#define ISO7816_FILE_INVALID 0x6983 // File invalid +#define ISO7816_DATA_INVALID 0x6984 // Data invalid +#define ISO7816_CONDITIONS_NOT_SATISFIED 0x6985 // Conditions of use not satisfied +#define ISO7816_COMMAND_NOT_ALLOWED 0x6986 // Command not allowed (no current EF) +#define ISO7816_SM_DATA_MISSING 0x6987 // Expected SM data objects missing +#define ISO7816_SM_DATA_INCORRECT 0x6988 // SM data objects incorrect +#define ISO7816_APPLET_SELECT_FAILED 0x6999 // Applet selection failed + +// 6A xx +#define ISO7816_INVALID_P1P2 0x6A00 // Bytes P1 and/or P2 are invalid +#define ISO7816_WRONG_DATA 0x6A80 // Wrong data +#define ISO7816_FUNC_NOT_SUPPORTED 0x6A81 // Function not supported +#define ISO7816_FILE_NOT_FOUND 0x6A82 // File not found +#define ISO7816_RECORD_NOT_FOUND 0x6A83 // Record not found +#define ISO7816_FILE_FULL 0x6A84 // Not enough memory space in the file +#define ISO7816_LC_TLV_CONFLICT 0x6A85 // LC / TLV conlict +#define ISO7816_INCORRECT_P1P2 0x6A86 // Incorrect parameters (P1,P2) +#define ISO7816_FILE_EXISTS 0x6A89 // File exists +#define ISO7816_NOT_IMPLEMENTED 0x6AFF // + +// 6x 00 +#define ISO7816_WRONG_P1P2 0x6B00 // Incorrect parameters (P1,P2) +#define ISO7816_CORRECT_LENGTH_00 0x6C00 // Correct Expected Length (Le) +#define ISO7816_INS_NOT_SUPPORTED 0x6D00 // INS value not supported +#define ISO7816_CLA_NOT_SUPPORTED 0x6E00 // CLA value not supported +#define ISO7816_UNKNOWN 0x6F00 // No precise diagnosis + // MIFARE DESFire command set: #define MFDES_AUTHENTICATE 0x0A // AUTHENTICATE_NATIVE diff --git a/tools/build_all_firmwares.sh b/tools/build_all_firmwares.sh index 5e1076684..c6bb8969d 100755 --- a/tools/build_all_firmwares.sh +++ b/tools/build_all_firmwares.sh @@ -30,11 +30,11 @@ mkdir -p "$DEST" mv bootrom/obj/bootrom.elf "$DEST/PM3BOOTROM.elf" # cf armsrc/Standalone/Makefile.hal -STANDALONE_MODES=(LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN LF_THAREXDE LF_NEXID) +STANDALONE_MODES=(LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_PROXBRUTE 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_14ASNIFF HF_15SNIFF HF_BOG HF_COLIN HF_ICECLASS HF_LEGICSIM HF_MFCSIM) +STANDALONE_MODES_REQ_FLASH=(LF_HIDFCBRUTE LF_ICEHID LF_NEXID LF_THAREXDE HF_BOG HF_COLIN HF_ICECLASS HF_LEGICSIM HF_MFCSIM) # PM3GENERIC 256kb, no flash, need to skip some parts to reduce size diff --git a/tools/cryptorf/sma.cpp b/tools/cryptorf/sma.cpp index eb9cf3c9d..d15b0e6a2 100644 --- a/tools/cryptorf/sma.cpp +++ b/tools/cryptorf/sma.cpp @@ -331,11 +331,10 @@ static inline uint8_t next_right_fast(uint8_t in, uint64_t *right) { static inline void sm_left_mask(const uint8_t *ks, uint8_t *mask, uint64_t rstate) { size_t pos; - uint8_t bt; for (pos = 0; pos < 16; pos++) { next_right_fast(0, &rstate); - bt = next_right_fast(0, &rstate) << 4; + uint8_t bt = next_right_fast(0, &rstate) << 4; next_right_fast(0, &rstate); bt |= next_right_fast(0, &rstate); @@ -349,7 +348,7 @@ static inline void sm_left_mask(const uint8_t *ks, uint8_t *mask, uint64_t rstat static inline uint32_t sm_right(const uint8_t *ks, uint8_t *mask, vector *pcrstates) { uint8_t tmp_mask[16]; - size_t pos, bits, bit, topbits; + size_t pos, bit, topbits; uint64_t rstate, counter; map bincstates; map::iterator it; @@ -358,7 +357,7 @@ static inline uint32_t sm_right(const uint8_t *ks, uint8_t *mask, vector *pcstates) { map bincstates; map::iterator it; - uint64_t counter, lstate; + uint64_t counter; size_t pos, bits, bit; uint8_t correct_bits[16]; uint8_t bt; @@ -526,7 +525,7 @@ static inline void sm_left(const uint8_t *ks, const uint8_t *mask, vector state.invalid = false; for (counter = 0; counter < 0x800000000ull; counter++) { - lstate = counter; + uint64_t lstate = counter; for (pos = 0; pos < 16; pos++) { lstate = (((lstate) >> 5) | ((uint64_t)left_addition[((lstate) & 0xf801f)] << 30)); diff --git a/tools/cryptorf/sma_multi.cpp b/tools/cryptorf/sma_multi.cpp index 577811f64..50b962248 100644 --- a/tools/cryptorf/sma_multi.cpp +++ b/tools/cryptorf/sma_multi.cpp @@ -165,6 +165,9 @@ void print_cs(const char *text, pcs s) { } static inline uint8_t mod(uint8_t a, uint8_t m) { + if (m == 0) { + return 0; // Actually, divide by zero error + } // Just return the input when this is less or equal than the modular value if (a < m) return a; @@ -199,18 +202,15 @@ static lookup_entry lookup_right[0x8000]; static uint8_t left_addition[0x100000]; static inline void init_lookup_left() { - uint8_t b3, b6, temp; - int i, index; - - for (i = 0; i < 0x400; i++) { - b6 = i & 0x1f; - b3 = (i >> 5) & 0x1f; - index = (b3 << 15) | b6; + for (int i = 0; i < 0x400; i++) { + uint8_t b6 = i & 0x1f; + uint8_t b3 = (i >> 5) & 0x1f; + int index = (b3 << 15) | b6; // b6 = bit_rotate_l(b6, 5); b6 = BIT_ROL(b6); - temp = mod(b3 + b6, 0x1f); + uint8_t temp = mod(b3 + b6, 0x1f); left_addition[index] = temp; lookup_left[index].addition = temp; lookup_left[index].out = ((temp ^ b3) & 0x0f); @@ -218,15 +218,12 @@ static inline void init_lookup_left() { } static inline void init_lookup_right() { - uint8_t b16, b18, temp; - int i, index; + for (int i = 0; i < 0x400; i++) { + uint8_t b18 = i & 0x1f; + uint8_t b16 = (i >> 5) & 0x1f; + int index = (b16 << 10) | b18; - for (i = 0; i < 0x400; i++) { - b18 = i & 0x1f; - b16 = (i >> 5) & 0x1f; - index = (b16 << 10) | b18; - - temp = mod(b18 + b16, 0x1f); + uint8_t temp = mod(b18 + b16, 0x1f); lookup_right[index].addition = temp; lookup_right[index].out = ((temp ^ b16) & 0x0f); } @@ -589,23 +586,21 @@ static void ice_sm_left(const uint8_t *ks, uint8_t *mask, vector *pcstates static inline uint32_t sm_right(const uint8_t *ks, uint8_t *mask, vector *pcrstates) { uint8_t tmp_mask[16]; - size_t pos, bits, bit, topbits; + size_t topbits = 0; map bincstates; map::iterator it; - uint8_t bt; - topbits = 0; for (uint64_t counter = 0; counter < 0x2000000; counter++) { // Reset the current bitcount of correct bits - bits = 0; + size_t bits = 0; // Copy the state we are going to test uint64_t rstate = counter; - for (pos = 0; pos < 16; pos++) { + for (size_t pos = 0; pos < 16; pos++) { next_right_fast(0, &rstate); - bt = next_right_fast(0, &rstate) << 4; + uint8_t bt = next_right_fast(0, &rstate) << 4; next_right_fast(0, &rstate); bt |= next_right_fast(0, &rstate); @@ -615,7 +610,7 @@ static inline uint32_t sm_right(const uint8_t *ks, uint8_t *mask, vector>= 1; @@ -744,7 +739,7 @@ static inline void search_gc_candidates_right(const uint64_t rstate_before_gc, c static inline void sm_left(const uint8_t *ks, const uint8_t *mask, vector *pcstates) { map bincstates; map::iterator it; - uint64_t counter, lstate; + uint64_t counter; size_t pos, bits; uint8_t correct_bits[16]; uint8_t bt; @@ -756,7 +751,7 @@ static inline void sm_left(const uint8_t *ks, const uint8_t *mask, vector state.invalid = false; for (counter = 0; counter < 0x800000000ull; counter++) { - lstate = counter; + uint64_t lstate = counter; for (pos = 0; pos < 16; pos++) { diff --git a/tools/hitag2crack/common/ht2crackutils.c b/tools/hitag2crack/common/ht2crackutils.c index cfac2bfd8..492676724 100644 --- a/tools/hitag2crack/common/ht2crackutils.c +++ b/tools/hitag2crack/common/ht2crackutils.c @@ -141,6 +141,8 @@ int fnf(uint64_t s) { // builds the lfsr for the prng (quick calcs for hitag2_nstep()) void buildlfsr(Hitag_State *hstate) { + if (hstate == NULL) + return; uint64_t state = hstate->shiftreg; uint64_t temp = state ^ (state >> 1); hstate->lfsr = state ^ (state >> 6) ^ (state >> 16) diff --git a/tools/mf_nonce_brute/iso14443crc.c b/tools/mf_nonce_brute/iso14443crc.c index 60631f4fb..c5acbb9be 100644 --- a/tools/mf_nonce_brute/iso14443crc.c +++ b/tools/mf_nonce_brute/iso14443crc.c @@ -20,11 +20,10 @@ void ComputeCrc14443(int CrcType, const unsigned char *Data, int Length, unsigned char *TransmitFirst, unsigned char *TransmitSecond) { - unsigned char chBlock; unsigned short wCrc = CrcType; do { - chBlock = *Data++; + unsigned char chBlock = *Data++; UpdateCrc14443(chBlock, &wCrc); } while (--Length); diff --git a/tools/mf_nonce_brute/mf_nonce_brute.c b/tools/mf_nonce_brute/mf_nonce_brute.c index 8d98e04cf..161f1c749 100644 --- a/tools/mf_nonce_brute/mf_nonce_brute.c +++ b/tools/mf_nonce_brute/mf_nonce_brute.c @@ -331,6 +331,8 @@ static bool checkValidCmd(uint32_t decrypted) { static bool checkValidCmdByte(uint8_t *cmd, uint16_t n) { bool ok = false; + if (cmd == NULL) + return false; for (int i = 0; i < 8; ++i) { if (cmd[0] == cmds[i][0]) { diff --git a/tools/mf_nonce_brute/mf_trace_brute.c b/tools/mf_nonce_brute/mf_trace_brute.c index 8bc255517..1d8a7c6fb 100644 --- a/tools/mf_nonce_brute/mf_trace_brute.c +++ b/tools/mf_nonce_brute/mf_trace_brute.c @@ -174,6 +174,8 @@ static char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const si static bool checkValidCmdByte(uint8_t *cmd, uint16_t n) { bool ok = false; + if (cmd == NULL) + return false; for (int i = 0; i < 8; ++i) { if (cmd[0] == cmds[i][0]) { diff --git a/tools/mfd_aes_brute/randoms.c b/tools/mfd_aes_brute/randoms.c index c957350ec..523366d9d 100644 --- a/tools/mfd_aes_brute/randoms.c +++ b/tools/mfd_aes_brute/randoms.c @@ -68,13 +68,12 @@ void make_key_turbopascal_n(uint32_t seed, uint8_t key[], const size_t keylen) { void make_key_posix_rand_r_n(uint32_t seed, uint8_t key[], const size_t keylen) { uint32_t lseed = seed; - int result; for (int i = 0; i < keylen; i++) { lseed *= 1103515245; lseed += 12345; - result = (uint16_t)(lseed / 0x10000) % 2048; + int result = (uint16_t)(lseed / 0x10000) % 2048; lseed *= 1103515245; lseed += 12345; diff --git a/tools/mkversion.sh b/tools/mkversion.sh index c1819f34e..f741f2980 100755 --- a/tools/mkversion.sh +++ b/tools/mkversion.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh # Output a version_pm3.c file that includes information about the current build # From mkversion.pl diff --git a/tools/pm3_tests.sh b/tools/pm3_tests.sh index a39615cb6..d03e488e6 100755 --- a/tools/pm3_tests.sh +++ b/tools/pm3_tests.sh @@ -293,7 +293,7 @@ while true; do echo -e "\n${C_BLUE}Testing mfd_aes_brute:${C_NC} ${MFDASEBRUTEBIN:=./tools/mfd_aes_brute/mfd_aes_brute}" if ! CheckFileExist "mfd_aes_brute exists" "$MFDASEBRUTEBIN"; then break; fi if ! CheckExecute "mfd_aes_brute test 1/2" "$MFDASEBRUTEBIN 1605394800 bb6aea729414a5b1eff7b16328ce37fd 82f5f498dbc29f7570102397a2e5ef2b6dc14a864f665b3c54d11765af81e95c" "key.................... .*261C07A23F2BC8262F69F10A5BDF3764"; then break; fi - if ! CheckExecute slow "mfd_aes_brute test 2/2" "$MFDASEBRUTEBIN 1136073600 3fda933e2953ca5e6cfbbf95d1b51ddf 97fe4b5de24188458d102959b888938c988e96fb98469ce7426f50f108eaa583" "key.................... .*E757178E13516A4F3171BC6EA85E165A"; then break; fi + if ! CheckExecute slow "mfd_aes_brute test 2/2" "$MFDASEBRUTEBIN 1546300800 3fda933e2953ca5e6cfbbf95d1b51ddf 97fe4b5de24188458d102959b888938c988e96fb98469ce7426f50f108eaa583" "key.................... .*E757178E13516A4F3171BC6EA85E165A"; then break; fi fi # hitag2crack not yet part of "all" # if $TESTALL || $TESTHITAG2CRACK; then diff --git a/tools/release_tests.sh b/tools/release_tests.sh new file mode 100755 index 000000000..728e546f3 --- /dev/null +++ b/tools/release_tests.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# To be run from proxmark3 root directory +set -x +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 && INSTALLSUDO=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' ) && INSTALLSUDO=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 +echo PASS