mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 13:53:55 -07:00
commit
5234b820e0
131 changed files with 1962078 additions and 1440 deletions
26
CHANGELOG.md
26
CHANGELOG.md
|
@ -3,7 +3,33 @@ 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]
|
||||
- Change many commands to cliparser (@iceman1001, @tcprst, @mwalker33,...)
|
||||
- ...
|
||||
- Added support for 10b UID in `hf 14a sim` (@doegox)
|
||||
- Added `HF_TCPRST` standalone mode which read and emulate IKEA Rothult cards (@tcprst)
|
||||
- Add Gallagher key checking/KDF on MIFARE Desfire (@NZSmartie)
|
||||
- Add dictionaries with common words of proper size (@will-caruana)
|
||||
- Add `hf mf supercard` (@iceman1001)
|
||||
- Add initial suport for MIFARE Key Diversification, cf AN10922 (@NZSmartie)
|
||||
- Change MIFARE detection improved (@VortixDev)
|
||||
- Change `hf 14b sriread` to `hf 14b rdbl` and `hf 14b dump` (@iceman1001)
|
||||
- Add continuous mode to `hf 14a reader` (@doegox and @iceman1001)
|
||||
- Add `lf em 4x05_sniff` to allow extracting commands and passwords used be cloners. (@mwalker33)
|
||||
- Removed 'hf iclass replay' - use the 'hf iclass dump' or 'hf iclass rdbl' with option "n" instead (@iceman1001). Concept taken from official repo (@pwpiwi)
|
||||
- Add Destron FDX-A support (@doegox and @iceman1001)
|
||||
- Add `lf em 4x05_chk` (@iceman1001)
|
||||
- Add `lf em 4x05_unlock` tear-off (@doegox and @iceman1001)
|
||||
- Added customizable 3DES key to hf mfu cauth (@socram8888)
|
||||
- Add generic `hw tearoff` and hooks in various write commands (@doegox and @iceman1001)
|
||||
- Add protect support for EM4x05 and fix various EM4x69/EM4x05 aspects (@doegox and @iceman1001)
|
||||
- Add incognito option to client to avoid mangling history & logs (@doegox)
|
||||
- Add option to hide/show plot sliders (@mwalker33)
|
||||
- Add "</>" key bindings to realign demod plot on samples (@doegox)
|
||||
- Add "T" key binding to trim plot (@doegox)
|
||||
- Add units options to `data timescale` (@doegox)
|
||||
- Add mouse scrolling to pan & zoom to plot (@doegox)
|
||||
- Add hf_14b_mobib Lua script (@iceman1001)
|
||||
- Add ASK CTx detection to hf 14b reader (@iceman1001 and @doegox)
|
||||
- Add low level support for 14b' aka Innovatron (@doegox)
|
||||
- Add doc/cliparser.md (@mwalker33)
|
||||
- Add `hf 14b apdu` - send APDU over ISO14443B (@iceman1001)
|
||||
|
|
|
@ -43,12 +43,18 @@ INSTALLDOCSRELPATH ?= share/doc/proxmark3
|
|||
platform = $(shell uname)
|
||||
DETECTED_OS=$(platform)
|
||||
|
||||
ifeq ($(platform),Darwin)
|
||||
AR= /usr/bin/ar rcs
|
||||
RANLIB= /usr/bin/ranlib
|
||||
ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
|
||||
DETECTED_COMPILER = clang
|
||||
else
|
||||
AR= ar rcs
|
||||
RANLIB= ranlib
|
||||
DETECTED_COMPILER = gcc
|
||||
endif
|
||||
|
||||
ifeq ($(platform),Darwin)
|
||||
AR= /usr/bin/ar rcs
|
||||
RANLIB= /usr/bin/ranlib
|
||||
else
|
||||
AR= ar rcs
|
||||
RANLIB= ranlib
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
|
@ -74,13 +80,15 @@ DEFCFLAGS += -Wswitch-enum -Wno-error=switch-enum
|
|||
# GCC 10 has issues with false positives on stringop-overflow, let's disable them for now (cf https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92955, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94335)
|
||||
# beware these flags didn't exist for GCC < 7
|
||||
ifeq ($(shell expr $(CC_VERSION) \>= 10), 1)
|
||||
ifneq ($(DETECTED_COMPILER), clang)
|
||||
DEFCFLAGS += -Wno-stringop-overflow -Wno-error=stringop-overflow
|
||||
endif
|
||||
endif
|
||||
ifeq ($(platform),Darwin)
|
||||
# their readline has strict-prototype issues
|
||||
DEFCFLAGS += -Wno-strict-prototypes
|
||||
# their readline has strict-prototype issues
|
||||
DEFCFLAGS += -Wno-strict-prototypes
|
||||
else
|
||||
DEFCFLAGS += -Wstrict-prototypes
|
||||
DEFCFLAGS += -Wstrict-prototypes
|
||||
endif
|
||||
|
||||
# Next ones are activated only if GCCEXTRA=1 or CLANGEXTRA=1
|
||||
|
|
|
@ -129,6 +129,16 @@ uint8_t *BigBuf_malloc(uint16_t chunksize) {
|
|||
return (uint8_t *)BigBuf + s_bigbuf_hi;
|
||||
}
|
||||
|
||||
// allocate a chunk of memory from BigBuf, and returns a pointer to it.
|
||||
// sets the memory to zero
|
||||
uint8_t *BigBuf_calloc(uint16_t chunksize) {
|
||||
uint8_t *mem = BigBuf_malloc(chunksize);
|
||||
if (mem != NULL) {
|
||||
memset(mem, 0x00, chunksize);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
// free ALL allocated chunks. The whole BigBuf is available for traces or samples again.
|
||||
void BigBuf_free(void) {
|
||||
s_bigbuf_hi = s_bigbuf_size;
|
||||
|
|
|
@ -34,6 +34,7 @@ void BigBuf_Clear_ext(bool verbose);
|
|||
void BigBuf_Clear_keep_EM(void);
|
||||
void BigBuf_Clear_EM(void);
|
||||
uint8_t *BigBuf_malloc(uint16_t);
|
||||
uint8_t *BigBuf_calloc(uint16_t);
|
||||
void BigBuf_free(void);
|
||||
void BigBuf_free_keep_EM(void);
|
||||
void BigBuf_print_status(void);
|
||||
|
@ -46,10 +47,8 @@ bool get_tracing(void);
|
|||
bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
|
||||
bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, uint32_t ts_end, uint8_t *parity, bool reader2tag);
|
||||
|
||||
|
||||
uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length);
|
||||
|
||||
|
||||
typedef struct {
|
||||
int max;
|
||||
int bit;
|
||||
|
|
|
@ -59,13 +59,16 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
| HF_MSDSAL | Read and emulate MSD Visa cards |
|
||||
| (default) | - Salvador Mendoza |
|
||||
+----------------------------------------------------------+
|
||||
| HF_TCPRST | IKEA Rothult read/sim/dump/emul |
|
||||
| | - Nick Draffen |
|
||||
+----------------------------------------------------------+
|
||||
| HF_YOUNG | Mifare sniff/simulation |
|
||||
| | - Craig Young |
|
||||
+----------------------------------------------------------+
|
||||
endef
|
||||
|
||||
STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RWC LF_HIDBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_AVEFUL HF_BOG HF_COLIN HF_ICECLASS HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_YOUNG
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_AVEFUL HF_BOG HF_COLIN HF_ICECLASS HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_TCPRST HF_YOUNG
|
||||
STANDALONE_MODES_REQ_SMARTCARD :=
|
||||
STANDALONE_MODES_REQ_FLASH := LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS
|
||||
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),)
|
||||
|
|
|
@ -41,6 +41,10 @@ endif
|
|||
ifneq (,$(findstring WITH_STANDALONE_HF_AVEFUL,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_aveful.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_TCPRST
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_TCPRST,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_tcprst.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_ICEHID
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_icehid.c
|
||||
|
|
|
@ -132,7 +132,7 @@ static void download_instructions(uint8_t t) {
|
|||
DbpString("The collected data was saved to SPIFFS. The file names below may differ");
|
||||
DbpString("1. " _YELLOW_("mem spiffs tree"));
|
||||
DbpString("2. " _YELLOW_("mem spiffs dump o " HF_ICLASS_ATTACK_BIN " f " HF_ICLASS_ATTACK_BIN));
|
||||
DbpString("3. " _YELLOW_("hf iclass loclass f " HF_ICLASS_ATTACK_BIN));
|
||||
DbpString("3. " _YELLOW_("hf iclass loclass -f " HF_ICLASS_ATTACK_BIN));
|
||||
break;
|
||||
}
|
||||
case ICE_STATE_READER: {
|
||||
|
|
490
armsrc/Standalone/hf_tcprst.c
Normal file
490
armsrc/Standalone/hf_tcprst.c
Normal file
|
@ -0,0 +1,490 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Nick Draffen, 2020
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// code for HF ST25TA IKEA Rothult read/sim/dump/emulation by Nick Draffen
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "standalone.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "appmain.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "util.h"
|
||||
#include "dbprint.h"
|
||||
#include "ticks.h"
|
||||
#include "string.h"
|
||||
#include "BigBuf.h"
|
||||
#include "iso14443a.h"
|
||||
#include "protocols.h"
|
||||
#include "cmd.h"
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" HF - IKEA Rothult ST25TA, Standalone Master Key Dump/Emulation (ISO14443) - (Nick Draffen)");
|
||||
}
|
||||
|
||||
/* This standalone implements four different modes: reading, simulating, dumping, & emulating.
|
||||
*
|
||||
* The initial mode is reading with LEDs A & D.
|
||||
* In this mode, the Proxmark is looking for an ST25TA card like those used by the IKEA Rothult,
|
||||
* it will act as reader, and store the UID for simulation.
|
||||
*
|
||||
* If the Proxmark gets an ST25TA UID, it will change to simulation mode (LEDs A & C) automatically.
|
||||
* During this mode the Proxmark will pretend to be the IKEA Rothult ST25TA master key, upon presentation
|
||||
* to an IKEA Rothult the Proxmark will steal the 16 byte Read Protection key used to authenticate to the card.
|
||||
*
|
||||
* Once it gets the key, it will switch to dump mode (LEDs C & D) automatically. During this mode the Proxmark
|
||||
* will act as a reader once again, but now we know the Read Protection key to authenticate to the card to dump
|
||||
* it's contents so we can achieve full emulation.
|
||||
*
|
||||
* Once it dumps the contents of the card, it will switch to emulation mode (LED C) automatically.
|
||||
* During this mode the Proxmark should function as the original ST25TA IKEA Rothult Master Key
|
||||
*
|
||||
* Keep pressing the button down will quit the standalone cycle.
|
||||
*
|
||||
* LEDs:
|
||||
* LED A & D = in reading mode
|
||||
* LED A & C = in simulation mode, to steal Read Protection key
|
||||
* LED C & D = in dump mode, to authenticate to card and dump NDEF content
|
||||
* LED C = in emulation mode
|
||||
* LED B = receiving/sending commands, activity
|
||||
*
|
||||
* Thanks to Salvador Mendoza for which this standalone mode is based off
|
||||
* Thanks to iceman for his assistance on the ST25TA research
|
||||
*/
|
||||
|
||||
void RunMod(void) {
|
||||
StandAloneMode();
|
||||
DbpString(_YELLOW_(">>") "IKEA Rothult ST25TA Standalone (tcprst) Started " _YELLOW_("<<"));
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
uint8_t stuid[7] = {0x00};
|
||||
|
||||
//For reading process
|
||||
iso14a_card_select_t card_a_info;
|
||||
uint8_t apdubuffer[MAX_FRAME_SIZE] = { 0x00 };
|
||||
|
||||
// APDUs necessary to dump NDEF
|
||||
// ----------------------------
|
||||
// Select NDEF Application
|
||||
uint8_t ndef_app[13] = {0x00, 0xa4, 0x04, 0x00, 0x07, 0xd2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01, 0x00};
|
||||
// Select NDEF File
|
||||
uint8_t ndef_sel[7] = {0x00, 0xa4, 0x00, 0x0c, 0x02, 0x00, 0x01};
|
||||
// Read verification without password
|
||||
uint8_t verify[5] = {0x00, 0x20, 0x00, 0x01, 0x00};
|
||||
// Read verification with password
|
||||
uint8_t verify_pwd[21] = {0x00, 0x20, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
// Read NDEF file contents
|
||||
uint8_t ndef_read[5] = {0x00, 0xb0, 0x00, 0x00, 0x1d};
|
||||
|
||||
uint8_t *apdus[5] = {ndef_app, ndef_sel, verify, verify_pwd, ndef_read};
|
||||
uint8_t apdusLen [5] = { sizeof(ndef_app), sizeof(ndef_sel), sizeof(verify), sizeof(verify_pwd), sizeof(ndef_read)};
|
||||
|
||||
// NDEF file contents
|
||||
uint8_t ndef[31] = {0x00, 0x1b, 0xd1, 0x01, 0x17, 0x54, 0x02, 0x7a, 0x68, 0xa2, 0x34, 0xcb, 0xd0, 0xe2, 0x03, 0xc7, 0x3e, 0x62, 0x0b, 0xe8, 0xc6, 0x3c, 0x85, 0x2c, 0xc5, 0x31, 0x31, 0x31, 0x32, 0x90, 0x00};
|
||||
uint8_t ndef_len = 31;
|
||||
|
||||
// Did we get the read protection key from the Rothult
|
||||
bool gotkey = false;
|
||||
// Did we get the NDEF file contents from the card
|
||||
bool gotndef = false;
|
||||
|
||||
|
||||
//ST25TA Rothult values
|
||||
#define SAK 0x20
|
||||
#define ATQA0 0x42
|
||||
#define ATQA1 0x00
|
||||
|
||||
// Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
|
||||
// Such a response is less time critical, so we can prepare them on the fly
|
||||
#define DYNAMIC_RESPONSE_BUFFER_SIZE 64
|
||||
#define DYNAMIC_MODULATION_BUFFER_SIZE 512
|
||||
|
||||
uint8_t flags = FLAG_7B_UID_IN_DATA; // ST25TA have 7B UID
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; // in case there is a read command received we shouldn't break
|
||||
|
||||
// to initialize the emulation
|
||||
uint8_t tagType = 10; // 10 = ST25TA IKEA Rothult
|
||||
tag_response_info_t *responses;
|
||||
uint32_t cuid = 0;
|
||||
uint32_t counters[3] = { 0x00, 0x00, 0x00 };
|
||||
uint8_t tearings[3] = { 0xbd, 0xbd, 0xbd };
|
||||
uint8_t pages = 0;
|
||||
|
||||
// command buffers
|
||||
uint8_t receivedCmd[MAX_FRAME_SIZE] = { 0x00 };
|
||||
uint8_t receivedCmdPar[MAX_PARITY_SIZE] = { 0x00 };
|
||||
|
||||
uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE] = {0};
|
||||
uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE] = {0};
|
||||
|
||||
// handler - command responses
|
||||
tag_response_info_t dynamic_response_info = {
|
||||
.response = dynamic_response_buffer,
|
||||
.response_n = 0,
|
||||
.modulation = dynamic_modulation_buffer,
|
||||
.modulation_n = 0
|
||||
};
|
||||
|
||||
// States for standalone
|
||||
#define STATE_READ 0
|
||||
#define STATE_SIM 1
|
||||
#define STATE_DUMP 2
|
||||
#define STATE_EMUL 3
|
||||
|
||||
uint8_t state = STATE_READ;
|
||||
|
||||
DbpString(_YELLOW_("[ ") "Initialized reading mode" _YELLOW_(" ]"));
|
||||
DbpString("\n"_YELLOW_("!!") "Waiting for an IKEA ST25TA card...");
|
||||
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
||||
// exit from RunMod, send a usbcommand.
|
||||
if (data_available()) break;
|
||||
|
||||
// Was our button held down or pressed?
|
||||
int button_pressed = BUTTON_HELD(1000);
|
||||
|
||||
if (button_pressed == BUTTON_HOLD) { //Holding down the button
|
||||
break;
|
||||
}
|
||||
|
||||
SpinDelay(500);
|
||||
|
||||
if (state == STATE_READ) {
|
||||
LED_D_ON();
|
||||
LED_A_ON();
|
||||
// Get UID of ST25TA Card to simulate
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||
|
||||
if (iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)) {
|
||||
|
||||
DbpString(_YELLOW_("+") "Found ISO 14443 Type A!");
|
||||
|
||||
if (card_a_info.sak == SAK && card_a_info.atqa[0] == ATQA0 && card_a_info.atqa[1] == ATQA1 && card_a_info.uidlen == 7) {
|
||||
DbpString(_YELLOW_("+") "Found ST25TA with UID: ");
|
||||
Dbhexdump(card_a_info.uidlen, card_a_info.uid, 0);
|
||||
memcpy(stuid, card_a_info.uid, card_a_info.uidlen);
|
||||
state = STATE_SIM;
|
||||
} else {
|
||||
DbpString("Found non-ST25TA card, ignoring.");
|
||||
}
|
||||
}
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
} else if (state == STATE_SIM) {
|
||||
LED_C_ON();
|
||||
|
||||
//Simulate tag to get PWD
|
||||
|
||||
// free eventually allocated BigBuf memory but keep Emulator Memory
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
memcpy(data, stuid, sizeof(stuid));
|
||||
|
||||
if (SimulateIso14443aInit(tagType, flags, data, &responses, &cuid, counters, tearings, &pages) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
DbpString(_YELLOW_("!!") "Error initializing the simulation process!");
|
||||
SpinDelay(500);
|
||||
state = STATE_READ;
|
||||
DbpString(_YELLOW_("[ ") "Initialized reading mode" _YELLOW_(" ]"));
|
||||
DbpString("\n" _YELLOW_("!!") "Waiting for an ST25TA card...");
|
||||
break;
|
||||
}
|
||||
|
||||
// We need to listen to the high-frequency, peak-detected path.
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
|
||||
|
||||
int len = 0; // command length
|
||||
int retval = PM3_SUCCESS; // to check emulation status
|
||||
|
||||
bool odd_reply = true;
|
||||
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
while (!gotkey) {
|
||||
LED_B_OFF();
|
||||
// Clean receive command buffer
|
||||
if (!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) {
|
||||
DbpString(_YELLOW_("!!") "Emulator stopped");
|
||||
retval = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
tag_response_info_t *p_response = NULL;
|
||||
LED_B_ON();
|
||||
|
||||
// dynamic_response_info will be in charge of responses
|
||||
dynamic_response_info.response_n = 0;
|
||||
|
||||
// Checking the commands order is important and elemental
|
||||
if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST
|
||||
odd_reply = !odd_reply;
|
||||
if (odd_reply)
|
||||
p_response = &responses[RESP_INDEX_ATQA];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { // Received a HALT
|
||||
p_response = NULL;
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP
|
||||
p_response = &responses[RESP_INDEX_ATQA];
|
||||
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1)
|
||||
p_response = &responses[RESP_INDEX_UIDC1];
|
||||
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2)
|
||||
p_response = &responses[RESP_INDEX_UIDC2];
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1)
|
||||
p_response = &responses[RESP_INDEX_SAKC1];
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2)
|
||||
p_response = &responses[RESP_INDEX_SAKC2];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
|
||||
p_response = &responses[RESP_INDEX_RATS];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_PPS) {
|
||||
p_response = &responses[RESP_INDEX_PPS];
|
||||
} else {
|
||||
DbpString(_YELLOW_("[ ") "Card reader command" _YELLOW_(" ]"));
|
||||
Dbhexdump(len, receivedCmd, false);
|
||||
|
||||
if (receivedCmd[0] == 0x02 || receivedCmd[0] == 0x03) { //Emulate an ST25TA IKEA Rothult Master Key
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
|
||||
if (memcmp("\x02\xa2\xb0\x00\x00\x1d\x51\x69", receivedCmd, 8) == 0) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
memcpy(dynamic_response_info.response + 1, ndef, 31);
|
||||
dynamic_response_info.response_n = 32;
|
||||
} else if (memcmp("\x02\x00\x20\x00\x01\x00\x6e\xa9", receivedCmd, 8) == 0) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x63;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
} else if (memcmp("\x03\x00\x20\x00\x01\x10", receivedCmd, 6) == 0) {
|
||||
memcpy(verify_pwd + 5, receivedCmd + 6, 16);
|
||||
DbpString("Reader sent password: ");
|
||||
Dbhexdump(16, verify_pwd + 5, 0);
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x90;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
gotkey = true;
|
||||
state = STATE_DUMP;
|
||||
} else {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x90;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
}
|
||||
} else {
|
||||
DbpString(_YELLOW_("!!") "Received unknown command!");
|
||||
memcpy(dynamic_response_info.response, receivedCmd, len);
|
||||
dynamic_response_info.response_n = len;
|
||||
}
|
||||
}
|
||||
if (dynamic_response_info.response_n > 0) {
|
||||
DbpString(_GREEN_("[ ") "Proxmark3 answer" _GREEN_(" ]"));
|
||||
Dbhexdump(dynamic_response_info.response_n, dynamic_response_info.response, false);
|
||||
DbpString("----");
|
||||
|
||||
// Add CRC bytes, always used in ISO 14443A-4 compliant cards
|
||||
AddCrc14A(dynamic_response_info.response, dynamic_response_info.response_n);
|
||||
dynamic_response_info.response_n += 2;
|
||||
|
||||
if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE) == false) {
|
||||
SpinDelay(500);
|
||||
DbpString(_YELLOW_("!!") "Error preparing Proxmark to answer!");
|
||||
continue;
|
||||
}
|
||||
p_response = &dynamic_response_info;
|
||||
}
|
||||
|
||||
if (p_response != NULL) {
|
||||
EmSendPrecompiledCmd(p_response);
|
||||
}
|
||||
}
|
||||
switch_off();
|
||||
|
||||
set_tracing(false);
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, retval, NULL, 0);
|
||||
|
||||
} else if (state == STATE_DUMP) {
|
||||
LED_A_OFF();
|
||||
LED_C_ON();
|
||||
LED_D_ON();
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||
|
||||
if (iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)) {
|
||||
|
||||
DbpString(_YELLOW_("+") "Found ISO 14443 Type A!");
|
||||
|
||||
for (uint8_t i = 0; i < 5; i++) {
|
||||
gotndef = false;
|
||||
LED_B_ON();
|
||||
uint8_t apdulen = iso14_apdu(apdus[i], (uint16_t) apdusLen[i], false, apdubuffer, NULL);
|
||||
|
||||
if (apdulen > 0) {
|
||||
DbpString(_YELLOW_("[ ") "Proxmark command" _YELLOW_(" ]"));
|
||||
Dbhexdump(apdusLen[i], apdus[i], false);
|
||||
DbpString(_GREEN_("[ ") "Card answer" _GREEN_(" ]"));
|
||||
Dbhexdump(apdulen - 2, apdubuffer, false);
|
||||
DbpString("----");
|
||||
|
||||
|
||||
if (i == 4) {
|
||||
if (apdubuffer[1] == 0x1b && apdubuffer[2] == 0xd1 && !gotndef) { //Get NDEF Data
|
||||
gotndef = true;
|
||||
memcpy(&ndef, &apdubuffer, apdulen - 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
DbpString(_YELLOW_("!!") "Error reading the card");
|
||||
}
|
||||
LED_B_OFF();
|
||||
}
|
||||
|
||||
if (gotndef) {
|
||||
DbpString(_RED_("[ ") "NDEF File" _RED_(" ]"));
|
||||
Dbhexdump(ndef_len, (uint8_t *)ndef, false);
|
||||
DbpString("---");
|
||||
LED_C_ON();
|
||||
state = STATE_EMUL;
|
||||
DbpString(_YELLOW_("[ ") "Initialized emulation mode" _YELLOW_(" ]"));
|
||||
DbpString("\n"_YELLOW_("!!") "Waiting for a card reader...");
|
||||
}
|
||||
}
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
||||
} else if (state == STATE_EMUL) {
|
||||
LED_D_OFF();
|
||||
LED_C_ON();
|
||||
|
||||
// free eventually allocated BigBuf memory but keep Emulator Memory
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
memcpy(data, stuid, sizeof(stuid));
|
||||
|
||||
if (SimulateIso14443aInit(tagType, flags, data, &responses, &cuid, counters, tearings, &pages) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
DbpString(_YELLOW_("!!") "Error initializing the simulation process!");
|
||||
SpinDelay(500);
|
||||
state = STATE_READ;
|
||||
DbpString(_YELLOW_("[ ") "Initialized reading mode" _YELLOW_(" ]"));
|
||||
DbpString("\n" _YELLOW_("!!") "Waiting for an ST25TA card...");
|
||||
break;
|
||||
}
|
||||
|
||||
// We need to listen to the high-frequency, peak-detected path.
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
|
||||
|
||||
int len = 0; // command length
|
||||
int retval = PM3_SUCCESS; // to check emulation status
|
||||
|
||||
bool odd_reply = true;
|
||||
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
for (;;) {
|
||||
LED_B_OFF();
|
||||
// Clean receive command buffer
|
||||
if (!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) {
|
||||
DbpString(_YELLOW_("!!") "Emulator stopped");
|
||||
retval = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
tag_response_info_t *p_response = NULL;
|
||||
LED_B_ON();
|
||||
|
||||
// dynamic_response_info will be in charge of responses
|
||||
dynamic_response_info.response_n = 0;
|
||||
|
||||
// Checking the commands order is important and elemental
|
||||
if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST
|
||||
odd_reply = !odd_reply;
|
||||
if (odd_reply)
|
||||
p_response = &responses[RESP_INDEX_ATQA];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { // Received a HALT
|
||||
p_response = NULL;
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP
|
||||
p_response = &responses[RESP_INDEX_ATQA];
|
||||
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1)
|
||||
p_response = &responses[RESP_INDEX_UIDC1];
|
||||
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2)
|
||||
p_response = &responses[RESP_INDEX_UIDC2];
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1)
|
||||
p_response = &responses[RESP_INDEX_SAKC1];
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2)
|
||||
p_response = &responses[RESP_INDEX_SAKC2];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
|
||||
p_response = &responses[RESP_INDEX_RATS];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_PPS) {
|
||||
p_response = &responses[RESP_INDEX_PPS];
|
||||
} else {
|
||||
DbpString(_YELLOW_("[ ") "Card reader command" _YELLOW_(" ]"));
|
||||
Dbhexdump(len, receivedCmd, false);
|
||||
|
||||
if (receivedCmd[0] == 0x02 || receivedCmd[0] == 0x03) { //Emulate an ST25TA IKEA Rothult Master Key
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
|
||||
if (memcmp("\x02\xa2\xb0\x00\x00\x1d\x51\x69", receivedCmd, 8) == 0) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
memcpy(dynamic_response_info.response + 1, ndef, 31);
|
||||
dynamic_response_info.response_n = 32;
|
||||
} else if (memcmp("\x02\x00\x20\x00\x01\x00\x6e\xa9", receivedCmd, 8) == 0) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x63;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
} else if (memcmp("\x03\x00\x20\x00\x01\x10", receivedCmd, 6) == 0) {
|
||||
memcpy(verify_pwd + 5, receivedCmd + 6, 16);
|
||||
DbpString("Reader sent password: ");
|
||||
Dbhexdump(16, verify_pwd + 5, 0);
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x90;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
} else {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x90;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
}
|
||||
} else {
|
||||
DbpString(_YELLOW_("!!") "Received unknown command!");
|
||||
memcpy(dynamic_response_info.response, receivedCmd, len);
|
||||
dynamic_response_info.response_n = len;
|
||||
}
|
||||
}
|
||||
if (dynamic_response_info.response_n > 0) {
|
||||
DbpString(_GREEN_("[ ") "Proxmark3 answer" _GREEN_(" ]"));
|
||||
Dbhexdump(dynamic_response_info.response_n, dynamic_response_info.response, false);
|
||||
DbpString("----");
|
||||
|
||||
// Add CRC bytes, always used in ISO 14443A-4 compliant cards
|
||||
AddCrc14A(dynamic_response_info.response, dynamic_response_info.response_n);
|
||||
dynamic_response_info.response_n += 2;
|
||||
|
||||
if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE) == false) {
|
||||
SpinDelay(500);
|
||||
DbpString(_YELLOW_("!!") "Error preparing Proxmark to answer!");
|
||||
continue;
|
||||
}
|
||||
p_response = &dynamic_response_info;
|
||||
}
|
||||
|
||||
if (p_response != NULL) {
|
||||
EmSendPrecompiledCmd(p_response);
|
||||
}
|
||||
}
|
||||
switch_off();
|
||||
|
||||
set_tracing(false);
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, retval, NULL, 0);
|
||||
}
|
||||
}
|
||||
DbpString(_YELLOW_("[=]") "exiting");
|
||||
LEDsoff();
|
||||
}
|
|
@ -46,6 +46,7 @@
|
|||
#include "util.h"
|
||||
#include "ticks.h"
|
||||
#include "commonutil.h"
|
||||
#include "crc16.h"
|
||||
|
||||
#ifdef WITH_LCD
|
||||
#include "LCD.h"
|
||||
|
@ -64,6 +65,9 @@
|
|||
#include "spiffs.h"
|
||||
#endif
|
||||
|
||||
int DBGLEVEL = DBG_ERROR;
|
||||
uint8_t g_trigger = 0;
|
||||
bool g_hf_field_active = false;
|
||||
extern uint32_t _stack_start, _stack_end;
|
||||
struct common_area common_area __attribute__((section(".commonarea")));
|
||||
static int button_status = BUTTON_NO_CLICK;
|
||||
|
@ -87,6 +91,12 @@ int tearoff_hook(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void hf_field_off(void) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
g_hf_field_active = false;
|
||||
}
|
||||
|
||||
void send_wtx(uint16_t wtx) {
|
||||
if (allow_send_wtx) {
|
||||
reply_ng(CMD_WTX, PM3_SUCCESS, (uint8_t *)&wtx, sizeof(wtx));
|
||||
|
@ -1181,7 +1191,11 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
|
||||
#ifdef WITH_ISO14443b
|
||||
case CMD_HF_SRI_READ: {
|
||||
ReadSTMemoryIso14443b(packet->oldarg[0]);
|
||||
struct p {
|
||||
uint8_t blockno;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
ReadSTBlock(payload->blockno);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO14443B_SNIFF: {
|
||||
|
@ -1498,9 +1512,10 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
struct p {
|
||||
uint8_t counter;
|
||||
uint32_t tearoff_time;
|
||||
uint8_t value[4];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
MifareU_Counter_Tearoff(payload->counter, payload->tearoff_time);
|
||||
MifareU_Counter_Tearoff(payload->counter, payload->tearoff_time, payload->value);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_STATIC_NONCE: {
|
||||
|
@ -1630,13 +1645,44 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
}
|
||||
case CMD_SMART_UPLOAD: {
|
||||
// upload file from client
|
||||
struct p {
|
||||
uint32_t idx;
|
||||
uint32_t bytes_in_packet;
|
||||
uint16_t crc;
|
||||
uint8_t data[400];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
uint8_t *mem = BigBuf_get_addr();
|
||||
memcpy(mem + packet->oldarg[0], packet->data.asBytes, PM3_CMD_DATA_SIZE);
|
||||
reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
|
||||
memcpy(mem + payload->idx, payload->data, payload->bytes_in_packet);
|
||||
|
||||
uint8_t a = 0, b = 0;
|
||||
compute_crc(CRC_14443_A, mem + payload->idx, payload->bytes_in_packet, &a, &b);
|
||||
int res = PM3_SUCCESS;
|
||||
if (payload->crc != (a << 8 | b)) {
|
||||
DbpString("CRC Failed");
|
||||
res = PM3_ESOFT;
|
||||
}
|
||||
reply_ng(CMD_SMART_UPLOAD, res, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_SMART_UPGRADE: {
|
||||
SmartCardUpgrade(packet->oldarg[0]);
|
||||
struct p {
|
||||
uint16_t fw_size;
|
||||
uint16_t crc;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
|
||||
uint8_t *fwdata = BigBuf_get_addr();
|
||||
uint8_t a = 0, b = 0;
|
||||
compute_crc(CRC_14443_A, fwdata, payload->fw_size, &a, &b);
|
||||
|
||||
if (payload->crc != (a << 8 | b)) {
|
||||
Dbprintf("CRC Failed, 0x[%04x] != 0x[%02x%02x]", payload->crc, a, b);
|
||||
reply_ng(CMD_SMART_UPGRADE, PM3_ESOFT, NULL, 0);
|
||||
} else {
|
||||
SmartCardUpgrade(payload->fw_size);
|
||||
}
|
||||
fwdata = NULL;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -2263,14 +2309,6 @@ void __attribute__((noreturn)) AppMain(void) {
|
|||
*p = 0xdeadbeef;
|
||||
}
|
||||
|
||||
if (common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) {
|
||||
/* Initialize common area */
|
||||
memset(&common_area, 0, sizeof(common_area));
|
||||
common_area.magic = COMMON_AREA_MAGIC;
|
||||
common_area.version = 1;
|
||||
}
|
||||
common_area.flags.osimage_present = 1;
|
||||
|
||||
LEDsoff();
|
||||
|
||||
// The FPGA gets its clock from us from PCK0 output, so set that up.
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
extern int g_rsamples; // = 0;
|
||||
extern uint8_t g_trigger;
|
||||
|
||||
extern bool g_hf_field_active;
|
||||
void hf_field_off(void);
|
||||
int tearoff_hook(void);
|
||||
|
||||
// ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV
|
||||
|
|
|
@ -476,7 +476,7 @@ static bool find_double_listen_window(bool bcommand) {
|
|||
// data transmission from card has to be stopped, because
|
||||
// a commamd shall be issued
|
||||
|
||||
// unfortunately the posititon in listen window (where
|
||||
// unfortunately the position in listen window (where
|
||||
// command request has to be sent) has gone, so if a
|
||||
// second window follows - sync on this to issue a command
|
||||
|
||||
|
@ -522,7 +522,7 @@ static bool find_em4x50_tag(void) {
|
|||
static bool request_receive_mode(void) {
|
||||
|
||||
// To issue a command we have to find a listen window first.
|
||||
// Because identification and sychronization at the same time is not
|
||||
// Because identification and synchronization at the same time is not
|
||||
// possible when using pulse lengths a double listen window is used.
|
||||
bool bcommand = true;
|
||||
return find_double_listen_window(bcommand);
|
||||
|
@ -559,7 +559,7 @@ static bool check_ack(bool bliw) {
|
|||
// "bit" of listen window)
|
||||
wait_timer(FPGA_TIMER_0, T0 * 2 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
|
||||
// check for listen window (if first bit cannot be inerpreted
|
||||
// check for listen window (if first bit cannot be interpreted
|
||||
// as a valid bit it must belong to a listen window)
|
||||
if (get_next_bit() == EM4X50_BIT_OTHER) {
|
||||
|
||||
|
@ -730,7 +730,7 @@ static bool standard_read(int *now) {
|
|||
int fwr = *now;
|
||||
uint8_t bits[EM4X50_TAG_WORD] = {0};
|
||||
|
||||
// start with the identification of two succsessive listening windows
|
||||
// start with the identification of two successive listening windows
|
||||
if (find_double_listen_window(false)) {
|
||||
|
||||
// read and save words until following double listen window is detected
|
||||
|
@ -884,7 +884,7 @@ static int write(uint8_t word[4], uint8_t address) {
|
|||
// send data
|
||||
em4x50_send_word(word);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
reply_ng(CMD_LF_EM4X50_WRITE, PM3_ETEAROFF, NULL, 0);
|
||||
return PM3_ETEAROFF;
|
||||
} else {
|
||||
|
@ -923,7 +923,7 @@ static int write_password(uint8_t password[4], uint8_t new_password[4]) {
|
|||
// send address data
|
||||
em4x50_send_word(password);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
reply_ng(CMD_LF_EM4X50_WRITE, PM3_ETEAROFF, NULL, 0);
|
||||
return PM3_ETEAROFF;
|
||||
} else {
|
||||
|
@ -1021,7 +1021,7 @@ void em4x50_write(em4x50_data_t *etd) {
|
|||
|
||||
void em4x50_write_password(em4x50_data_t *etd) {
|
||||
|
||||
// sinmple change of password
|
||||
// simple change of password
|
||||
|
||||
bool bsuccess = false;
|
||||
|
||||
|
@ -1073,7 +1073,7 @@ void em4x50_wipe(em4x50_data_t *etd) {
|
|||
// to verify result reset EM4x50
|
||||
if (reset()) {
|
||||
|
||||
// login not necessary because protectd word has been set to 0
|
||||
// login not necessary because protected word has been set to 0
|
||||
// -> no read protected words
|
||||
// -> selective read can be called immediately
|
||||
if (selective_read(addresses)) {
|
||||
|
|
81
armsrc/epa.c
81
armsrc/epa.c
|
@ -22,10 +22,12 @@
|
|||
#include "commonutil.h"
|
||||
#include "ticks.h"
|
||||
|
||||
#ifdef WITH_ISO14443a
|
||||
// Protocol and Parameter Selection Request for ISO 14443 type A cards
|
||||
// use regular (1x) speed in both directions
|
||||
// CRC is already included
|
||||
static const uint8_t pps[] = {0xD0, 0x11, 0x00, 0x52, 0xA6};
|
||||
#endif
|
||||
|
||||
// APDUs for communication with German Identification Card
|
||||
|
||||
|
@ -116,9 +118,25 @@ static char iso_type = 0;
|
|||
static int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response, uint16_t respmaxlen) {
|
||||
switch (iso_type) {
|
||||
case 'a':
|
||||
#ifdef WITH_ISO14443a
|
||||
return iso14_apdu(apdu, (uint16_t) length, false, response, NULL);
|
||||
#else
|
||||
(void) apdu;
|
||||
(void) length;
|
||||
(void) response;
|
||||
(void) respmaxlen;
|
||||
return PM3_ENOTIMPL;
|
||||
#endif
|
||||
case 'b':
|
||||
#ifdef WITH_ISO14443b
|
||||
return iso14443b_apdu(apdu, length, false, response, respmaxlen, NULL);
|
||||
#else
|
||||
(void) apdu;
|
||||
(void) length;
|
||||
(void) response;
|
||||
(void) respmaxlen;
|
||||
return PM3_ENOTIMPL;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -522,39 +540,46 @@ void EPA_PACE_Replay(PacketCommandNG *c) {
|
|||
//-----------------------------------------------------------------------------
|
||||
int EPA_Setup(void) {
|
||||
|
||||
// first, look for type A cards
|
||||
// power up the field
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||
iso14a_card_select_t card_a_info;
|
||||
int return_code = iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false);
|
||||
#ifdef WITH_ISO14443a
|
||||
{
|
||||
// first, look for type A cards
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
// power up the field
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||
iso14a_card_select_t card_a_info;
|
||||
int return_code = iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false);
|
||||
|
||||
if (return_code == 1) {
|
||||
uint8_t pps_response[3];
|
||||
uint8_t pps_response_par[1];
|
||||
// send the PPS request
|
||||
ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL);
|
||||
return_code = ReaderReceive(pps_response, pps_response_par);
|
||||
if (return_code != 3 || pps_response[0] != 0xD0) {
|
||||
return return_code == 0 ? 2 : return_code;
|
||||
if (return_code == 1) {
|
||||
uint8_t pps_response[3];
|
||||
uint8_t pps_response_par[1];
|
||||
// send the PPS request
|
||||
ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL);
|
||||
return_code = ReaderReceive(pps_response, pps_response_par);
|
||||
if (return_code != 3 || pps_response[0] != 0xD0) {
|
||||
return return_code == 0 ? 2 : return_code;
|
||||
}
|
||||
Dbprintf("ISO 14443 Type A");
|
||||
iso_type = 'a';
|
||||
return 0;
|
||||
}
|
||||
Dbprintf("ISO 14443 Type A");
|
||||
iso_type = 'a';
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef WITH_ISO14443b
|
||||
{
|
||||
// if we're here, there is no type A card, so we look for type B
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
// power up the field
|
||||
iso14443b_setup();
|
||||
iso14b_card_select_t card_b_info;
|
||||
int return_code = iso14443b_select_card(&card_b_info);
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
||||
// if we're here, there is no type A card, so we look for type B
|
||||
// power up the field
|
||||
iso14443b_setup();
|
||||
iso14b_card_select_t card_b_info;
|
||||
return_code = iso14443b_select_card(&card_b_info);
|
||||
|
||||
if (return_code == 0) {
|
||||
Dbprintf("ISO 14443 Type B");
|
||||
iso_type = 'b';
|
||||
return 0;
|
||||
if (return_code == 0) {
|
||||
Dbprintf("ISO 14443 Type B");
|
||||
iso_type = 'b';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Dbprintf("No card found");
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -103,8 +103,6 @@ static bool end = false;
|
|||
#define HITAG_T_TAG_CAPTURE_THREE_HALF 41
|
||||
#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57
|
||||
|
||||
#define DBGLEVEL 0
|
||||
|
||||
/*
|
||||
* Implementation of the crc8 calculation from Hitag S
|
||||
* from http://www.proxmark.org/files/Documents/125%20kHz%20-%20Hitag/HitagS.V11.pdf
|
||||
|
|
18
armsrc/i2c.c
18
armsrc/i2c.c
|
@ -181,7 +181,7 @@ static bool WaitSCL_L(void) {
|
|||
// It timeout reading response from card
|
||||
// Which ever comes first
|
||||
static bool WaitSCL_L_timeout(void) {
|
||||
volatile uint32_t delay = 18000;
|
||||
volatile uint32_t delay = 1800;
|
||||
while (delay--) {
|
||||
// exit on SCL LOW
|
||||
if (!SCL_read)
|
||||
|
@ -219,7 +219,7 @@ static bool I2C_WaitForSim(void) {
|
|||
// 8051 speaks with smart card.
|
||||
// 1000*50*3.07 = 153.5ms
|
||||
// 1byte transfer == 1ms with max frame being 256bytes
|
||||
if (!WaitSCL_H_delay(30 * 1000 * 50))
|
||||
if (!WaitSCL_H_delay(10 * 1000 * 50))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -634,6 +634,9 @@ bool sc_rx_bytes(uint8_t *dest, uint8_t *destlen) {
|
|||
|
||||
len = I2C_BufferRead(dest, *destlen, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN);
|
||||
|
||||
|
||||
LED_C_ON();
|
||||
|
||||
if (len > 1) {
|
||||
break;
|
||||
} else if (len == 1) {
|
||||
|
@ -706,12 +709,12 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
|
|||
}
|
||||
|
||||
void SmartCardAtr(void) {
|
||||
smart_card_atr_t card;
|
||||
LED_D_ON();
|
||||
set_tracing(true);
|
||||
I2C_Reset_EnterMainProgram();
|
||||
bool isOK = GetATR(&card, true);
|
||||
reply_mix(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
|
||||
smart_card_atr_t card;
|
||||
int res = GetATR(&card, true) ? PM3_SUCCESS : PM3_ETIMEOUT;
|
||||
reply_ng(CMD_SMART_ATR, res, (uint8_t *)&card, sizeof(smart_card_atr_t));
|
||||
set_tracing(false);
|
||||
LEDsoff();
|
||||
}
|
||||
|
@ -804,7 +807,7 @@ void SmartCardUpgrade(uint64_t arg0) {
|
|||
}
|
||||
|
||||
// writing takes time.
|
||||
WaitMS(100);
|
||||
WaitMS(50);
|
||||
|
||||
// read
|
||||
res = I2C_ReadFW(verfiydata, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT);
|
||||
|
@ -824,7 +827,8 @@ void SmartCardUpgrade(uint64_t arg0) {
|
|||
length -= size;
|
||||
pos += size;
|
||||
}
|
||||
reply_mix(CMD_ACK, isOK, pos, 0, 0, 0);
|
||||
|
||||
reply_ng(CMD_SMART_UPGRADE, (isOK) ? PM3_SUCCESS : PM3_ESOFT, NULL, 0);
|
||||
LED_C_OFF();
|
||||
BigBuf_free();
|
||||
}
|
||||
|
|
|
@ -28,12 +28,9 @@
|
|||
|
||||
#define MAX_ISO14A_TIMEOUT 524288
|
||||
static uint32_t iso14a_timeout;
|
||||
// if iso14443a not active - transmit/receive dont try to execute
|
||||
static bool hf_field_active = false;
|
||||
|
||||
static uint8_t colpos = 0;
|
||||
int g_rsamples = 0;
|
||||
uint8_t g_trigger = 0;
|
||||
|
||||
// the block number for the ISO14443-4 PCB
|
||||
static uint8_t iso14_pcb_blocknum = 0;
|
||||
|
||||
|
@ -109,7 +106,8 @@ static uint32_t LastProxToAirDuration;
|
|||
// Sequence E: 00001111 modulation with subcarrier during second half
|
||||
// Sequence F: 00000000 no modulation with subcarrier
|
||||
// Sequence COLL: 11111111 load modulation over the full bitlength.
|
||||
// Tricks the reader to think that multiple cards answer (at least one card with 1 and at least one card with 0).
|
||||
// Tricks the reader to think that multiple cards answer.
|
||||
// (at least one card with 1 and at least one card with 0)
|
||||
// READER TO CARD - miller
|
||||
// Sequence X: 00001100 drop after half a period
|
||||
// Sequence Y: 00000000 no drop
|
||||
|
@ -160,7 +158,7 @@ void printHf14aConfig(void) {
|
|||
);
|
||||
Dbprintf(" [r] RATS override.......%i %s%s%s",
|
||||
hf14aconfig.forcerats,
|
||||
(hf14aconfig.forcerats == 0) ? "( " _GREEN_("No") " q follow standard " : "",
|
||||
(hf14aconfig.forcerats == 0) ? "( " _GREEN_("No") " ) follow standard " : "",
|
||||
(hf14aconfig.forcerats == 1) ? "( " _RED_("Yes") " ) always do RATS" : "",
|
||||
(hf14aconfig.forcerats == 2) ? "( " _RED_("Yes") " ) always skip RATS" : ""
|
||||
);
|
||||
|
@ -380,6 +378,7 @@ RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) {
|
|||
return true; // we are finished with decoding the raw data sequence
|
||||
} else {
|
||||
Uart14aReset(); // Nothing received - start over
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (Uart.state == STATE_14A_START_OF_COMMUNICATION) { // error - must not follow directly after SOC
|
||||
|
@ -1003,10 +1002,14 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
static uint8_t rUIDc1[5] = { 0x00 };
|
||||
// For UID size 7,
|
||||
static uint8_t rUIDc2[5] = { 0x00 };
|
||||
// Prepare the mandatory SAK (for 4 and 7 byte UID)
|
||||
// For UID size 10,
|
||||
static uint8_t rUIDc3[5] = { 0x00 };
|
||||
// Prepare the mandatory SAK (for 4, 7 and 10 byte UID)
|
||||
static uint8_t rSAKc1[3] = { 0x00 };
|
||||
// Prepare the optional second SAK (for 7 byte UID), drop the cascade bit
|
||||
// Prepare the optional second SAK (for 7 and 10 byte UID), drop the cascade bit for 7b
|
||||
static uint8_t rSAKc2[3] = { 0x00 };
|
||||
// Prepare the optional third SAK (for 10 byte UID), drop the cascade bit
|
||||
static uint8_t rSAKc3[3] = { 0x00 };
|
||||
// dummy ATS (pseudo-ATR), answer to RATS
|
||||
// static uint8_t rRATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 };
|
||||
static uint8_t rRATS[] = { 0x05, 0x75, 0x80, 0x60, 0x02, 0x00, 0x00 };
|
||||
|
@ -1015,7 +1018,7 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
static uint8_t rVERSION[10] = { 0x00 };
|
||||
// READ_SIG response for EV1/NTAG
|
||||
static uint8_t rSIGN[34] = { 0x00 };
|
||||
// PPS respoonse
|
||||
// PPS response
|
||||
static uint8_t rPPS[3] = { 0xD0 };
|
||||
|
||||
switch (tagType) {
|
||||
|
@ -1096,10 +1099,10 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
sak = 0x0A;
|
||||
}
|
||||
break;
|
||||
case 10: { // JCOP31/41 Rothult
|
||||
case 10: { // ST25TA IKEA Rothult
|
||||
rATQA[0] = 0x42;
|
||||
rATQA[1] = 0x00;
|
||||
sak = 0x00;
|
||||
sak = 0x20;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1125,11 +1128,25 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
}
|
||||
}
|
||||
|
||||
if ((flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA) {
|
||||
if ((flags & FLAG_4B_UID_IN_DATA) == FLAG_4B_UID_IN_DATA) {
|
||||
rUIDc1[0] = data[0];
|
||||
rUIDc1[1] = data[1];
|
||||
rUIDc1[2] = data[2];
|
||||
rUIDc1[3] = data[3];
|
||||
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
|
||||
|
||||
// Configure the ATQA and SAK accordingly
|
||||
rATQA[0] &= 0xBF;
|
||||
rSAKc1[0] = sak & 0xFB;
|
||||
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
|
||||
|
||||
*cuid = bytes_to_num(data, 4);
|
||||
} else if ((flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA) {
|
||||
rUIDc1[0] = 0x88; // Cascade Tag marker
|
||||
rUIDc1[1] = data[0];
|
||||
rUIDc1[2] = data[1];
|
||||
rUIDc1[3] = data[2];
|
||||
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
|
||||
|
||||
rUIDc2[0] = data[3];
|
||||
rUIDc2[1] = data[4];
|
||||
|
@ -1138,37 +1155,49 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
rUIDc2[4] = rUIDc2[0] ^ rUIDc2[1] ^ rUIDc2[2] ^ rUIDc2[3];
|
||||
|
||||
// Configure the ATQA and SAK accordingly
|
||||
rATQA[0] &= 0xBF;
|
||||
rATQA[0] |= 0x40;
|
||||
sak |= 0x04;
|
||||
rSAKc1[0] = 0x04;
|
||||
rSAKc2[0] = sak & 0xFB;
|
||||
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
|
||||
AddCrc14A(rSAKc2, sizeof(rSAKc2) - 2);
|
||||
|
||||
*cuid = bytes_to_num(data + 3, 4);
|
||||
} else if ((flags & FLAG_4B_UID_IN_DATA) == FLAG_4B_UID_IN_DATA) {
|
||||
memcpy(rUIDc1, data, 4);
|
||||
} else if ((flags & FLAG_10B_UID_IN_DATA) == FLAG_10B_UID_IN_DATA) {
|
||||
rUIDc1[0] = 0x88; // Cascade Tag marker
|
||||
rUIDc1[1] = data[0];
|
||||
rUIDc1[2] = data[1];
|
||||
rUIDc1[3] = data[2];
|
||||
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
|
||||
|
||||
rUIDc2[0] = 0x88; // Cascade Tag marker
|
||||
rUIDc2[1] = data[3];
|
||||
rUIDc2[2] = data[4];
|
||||
rUIDc2[3] = data[5];
|
||||
rUIDc2[4] = rUIDc2[0] ^ rUIDc2[1] ^ rUIDc2[2] ^ rUIDc2[3];
|
||||
|
||||
rUIDc3[0] = data[6];
|
||||
rUIDc3[1] = data[7];
|
||||
rUIDc3[2] = data[8];
|
||||
rUIDc3[3] = data[9];
|
||||
rUIDc3[4] = rUIDc3[0] ^ rUIDc3[1] ^ rUIDc3[2] ^ rUIDc3[3];
|
||||
|
||||
// Configure the ATQA and SAK accordingly
|
||||
rATQA[0] &= 0xBF;
|
||||
sak &= 0xFB;
|
||||
*cuid = bytes_to_num(data, 4);
|
||||
rATQA[0] |= 0x80;
|
||||
rSAKc1[0] = 0x04;
|
||||
rSAKc2[0] = 0x04;
|
||||
rSAKc3[0] = sak & 0xFB;
|
||||
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
|
||||
AddCrc14A(rSAKc2, sizeof(rSAKc2) - 2);
|
||||
AddCrc14A(rSAKc3, sizeof(rSAKc3) - 2);
|
||||
|
||||
*cuid = bytes_to_num(data + 3 + 3, 4);
|
||||
} else {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("[-] ERROR: UID size not defined");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate BCC for the first 4 bytes of the UID.
|
||||
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
|
||||
|
||||
|
||||
if (tagType == 10) {
|
||||
rSAKc1[0] = 0x04;
|
||||
rSAKc2[0] = 0x20;
|
||||
} else {
|
||||
rSAKc1[0] = sak;
|
||||
rSAKc2[0] = sak & 0xFB;
|
||||
}
|
||||
|
||||
// crc
|
||||
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
|
||||
AddCrc14A(rSAKc2, sizeof(rSAKc2) - 2);
|
||||
|
||||
// Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present,
|
||||
// TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1
|
||||
// TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us)
|
||||
|
@ -1177,24 +1206,25 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
|
||||
AddCrc14A(rPPS, sizeof(rPPS) - 2);
|
||||
|
||||
#define TAG_RESPONSE_COUNT 9
|
||||
static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = {
|
||||
static tag_response_info_t responses_init[] = {
|
||||
{ .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type
|
||||
{ .response = rUIDc1, .response_n = sizeof(rUIDc1) }, // Anticollision cascade1 - respond with uid
|
||||
{ .response = rUIDc2, .response_n = sizeof(rUIDc2) }, // Anticollision cascade2 - respond with 2nd half of uid if asked
|
||||
{ .response = rUIDc3, .response_n = sizeof(rUIDc3) }, // Anticollision cascade3 - respond with 3rd half of uid if asked
|
||||
{ .response = rSAKc1, .response_n = sizeof(rSAKc1) }, // Acknowledge select - cascade 1
|
||||
{ .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2
|
||||
{ .response = rSAKc3, .response_n = sizeof(rSAKc3) }, // Acknowledge select - cascade 3
|
||||
{ .response = rRATS, .response_n = sizeof(rRATS) }, // dummy ATS (pseudo-ATR), answer to RATS
|
||||
{ .response = rVERSION, .response_n = sizeof(rVERSION) }, // EV1/NTAG GET_VERSION response
|
||||
{ .response = rSIGN, .response_n = sizeof(rSIGN) }, // EV1/NTAG READ_SIG response
|
||||
{ .response = rPPS, .response_n = sizeof(rPPS) } // PPS response
|
||||
};
|
||||
|
||||
// "precompile" responses. There are 9 predefined responses with a total of 72 bytes data to transmit.
|
||||
// "precompile" responses. There are 11 predefined responses with a total of 80 bytes data to transmit.
|
||||
// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
|
||||
// 72 * 8 data bits, 72 * 1 parity bits, 9 start bits, 9 stop bits, 9 correction bits -- 677 bytes buffer
|
||||
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 675
|
||||
// 576 + 72 + 9 + 9 + 9 == 675
|
||||
// 80 * 8 data bits, 80 * 1 parity bits, 11 start bits, 11 stop bits, 11 correction bits
|
||||
// 80 * 8 + 80 + 11 + 11 + 11 == 753
|
||||
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 753
|
||||
|
||||
uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE);
|
||||
// modulation buffer pointer and current buffer free space size
|
||||
|
@ -1203,7 +1233,7 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
|
||||
// Prepare the responses of the anticollision phase
|
||||
// there will be not enough time to do this at the moment the reader sends it REQA
|
||||
for (size_t i = 0; i < TAG_RESPONSE_COUNT; i++) {
|
||||
for (size_t i = 0; i < ARRAYLEN(responses_init); i++) {
|
||||
if (prepare_allocated_tag_modulation(&responses_init[i], &free_buffer_pointer, &free_buffer_size) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Not enough modulation buffer size, exit after %d elements", i);
|
||||
|
@ -1213,16 +1243,6 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
|
||||
*responses = responses_init;
|
||||
|
||||
// indices into responses array:
|
||||
#define ATQA 0
|
||||
#define UIDC1 1
|
||||
#define UIDC2 2
|
||||
#define SAKC1 3
|
||||
#define SAKC2 4
|
||||
#define RATS 5
|
||||
#define VERSION 6
|
||||
#define SIGNATURE 7
|
||||
#define PPS 8
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1287,16 +1307,18 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
|
||||
// To control where we are in the protocol
|
||||
#define ORDER_NONE 0
|
||||
#define ORDER_REQA 1
|
||||
#define ORDER_SELECT_ALL_CL1 2
|
||||
#define ORDER_SELECT_CL1 3
|
||||
//#define ORDER_REQA 1
|
||||
//#define ORDER_SELECT_ALL_CL1 2
|
||||
//#define ORDER_SELECT_CL1 3
|
||||
#define ORDER_HALTED 5
|
||||
#define ORDER_WUPA 6
|
||||
#define ORDER_AUTH 7
|
||||
#define ORDER_SELECT_ALL_CL2 20
|
||||
#define ORDER_SELECT_CL2 30
|
||||
//#define ORDER_SELECT_ALL_CL2 20
|
||||
//#define ORDER_SELECT_CL2 25
|
||||
//#define ORDER_SELECT_ALL_CL3 30
|
||||
//#define ORDER_SELECT_CL3 35
|
||||
#define ORDER_EV1_COMP_WRITE 40
|
||||
#define ORDER_RATS 70
|
||||
//#define ORDER_RATS 70
|
||||
|
||||
uint8_t order = ORDER_NONE;
|
||||
int retval = PM3_SUCCESS;
|
||||
|
@ -1414,19 +1436,23 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
} else if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST, but in HALTED, skip
|
||||
odd_reply = !odd_reply;
|
||||
if (odd_reply)
|
||||
p_response = &responses[ATQA];
|
||||
p_response = &responses[RESP_INDEX_ATQA];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP
|
||||
p_response = &responses[ATQA];
|
||||
p_response = &responses[RESP_INDEX_ATQA];
|
||||
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1)
|
||||
p_response = &responses[UIDC1];
|
||||
p_response = &responses[RESP_INDEX_UIDC1];
|
||||
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2)
|
||||
p_response = &responses[UIDC2];
|
||||
p_response = &responses[RESP_INDEX_UIDC2];
|
||||
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && len == 2) { // Received request for UID (cascade 3)
|
||||
p_response = &responses[RESP_INDEX_UIDC3];
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1)
|
||||
p_response = &responses[SAKC1];
|
||||
p_response = &responses[RESP_INDEX_SAKC1];
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2)
|
||||
p_response = &responses[SAKC2];
|
||||
p_response = &responses[RESP_INDEX_SAKC2];
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && len == 9) { // Received a SELECT (cascade 3)
|
||||
p_response = &responses[RESP_INDEX_SAKC3];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_PPS) {
|
||||
p_response = &responses[PPS];
|
||||
p_response = &responses[RESP_INDEX_PPS];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_READBLOCK && len == 4) { // Received a (plain) READ
|
||||
uint8_t block = receivedCmd[1];
|
||||
// if Ultralight or NTAG (4 byte blocks)
|
||||
|
@ -1448,7 +1474,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
// FM11005SH. 16blocks, 4bytes / block.
|
||||
// block0 = 2byte Customer ID (CID), 2byte Manufacture ID (MID)
|
||||
// block1 = 4byte UID.
|
||||
p_response = &responses[UIDC1];
|
||||
p_response = &responses[RESP_INDEX_UIDC1];
|
||||
} else { // all other tags (16 byte block tags)
|
||||
uint8_t emdata[MAX_MIFARE_FRAME_SIZE];
|
||||
emlGetMemBt(emdata, block, 16);
|
||||
|
@ -1510,7 +1536,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
}
|
||||
p_response = NULL;
|
||||
} else if (receivedCmd[0] == MIFARE_ULEV1_READSIG && len == 4 && tagType == 7) { // Received a READ SIGNATURE --
|
||||
p_response = &responses[SIGNATURE];
|
||||
p_response = &responses[RESP_INDEX_SIGNATURE];
|
||||
} else if (receivedCmd[0] == MIFARE_ULEV1_READ_CNT && len == 4 && tagType == 7) { // Received a READ COUNTER --
|
||||
uint8_t index = receivedCmd[1];
|
||||
if (index > 2) {
|
||||
|
@ -1559,7 +1585,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
p_response = NULL;
|
||||
order = ORDER_HALTED;
|
||||
} else if (receivedCmd[0] == MIFARE_ULEV1_VERSION && len == 3 && (tagType == 2 || tagType == 7)) {
|
||||
p_response = &responses[VERSION];
|
||||
p_response = &responses[RESP_INDEX_VERSION];
|
||||
} else if ((receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) && len == 4 && tagType != 2 && tagType != 7) { // Received an authentication request
|
||||
cardAUTHKEY = receivedCmd[0] - 0x60;
|
||||
cardAUTHSC = receivedCmd[1] / 4; // received block num
|
||||
|
@ -1577,7 +1603,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
EmSend4bit(CARD_NACK_NA);
|
||||
p_response = NULL;
|
||||
} else {
|
||||
p_response = &responses[RATS];
|
||||
p_response = &responses[RESP_INDEX_RATS];
|
||||
}
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_AUTH_1) { // ULC authentication, or Desfire Authentication
|
||||
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
|
||||
|
@ -1625,6 +1651,13 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
dynamic_response_info.response[1] = 0x63;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
} else if (memcmp("\x03\x00\x20\x00\x01\x10", receivedCmd, 6) == 0) {
|
||||
Dbprintf("Reader sent password: ");
|
||||
Dbhexdump(16, receivedCmd + 6, 0);
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x90;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
} else {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x90;
|
||||
|
@ -1778,9 +1811,10 @@ static void PrepareDelayedTransfer(uint16_t delay) {
|
|||
//-------------------------------------------------------------------------------------
|
||||
static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing) {
|
||||
|
||||
if (!hf_field_active)
|
||||
if (!g_hf_field_active) {
|
||||
Dbprintf("Warning: HF field is off, ignoring TransmitFor14443a command");
|
||||
return;
|
||||
|
||||
}
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
|
||||
|
||||
if (timing) {
|
||||
|
@ -2046,11 +2080,6 @@ int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) {
|
|||
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY));
|
||||
b = AT91C_BASE_SSC->SSC_RHR;
|
||||
(void) b;
|
||||
/*
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY));
|
||||
b = AT91C_BASE_SSC->SSC_THR;
|
||||
(void) b;
|
||||
*/
|
||||
|
||||
// wait for the FPGA to signal fdt_indicator == 1 (the FPGA is ready to queue new data in its delay line)
|
||||
for (uint8_t j = 0; j < 5; j++) { // allow timeout - better late than never
|
||||
|
@ -2069,13 +2098,6 @@ int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) {
|
|||
AT91C_BASE_SSC->SSC_THR = resp[i++];
|
||||
FpgaSendQueueDelay = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
}
|
||||
|
||||
/*
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR);
|
||||
(void)b;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN again:
|
||||
|
@ -2189,8 +2211,10 @@ bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_Start
|
|||
//-----------------------------------------------------------------------------
|
||||
bool GetIso14443aAnswerFromTag_Thinfilm(uint8_t *receivedResponse, uint8_t *received_len) {
|
||||
|
||||
if (!hf_field_active)
|
||||
if (!g_hf_field_active) {
|
||||
Dbprintf("Warning: HF field is off, ignoring GetIso14443aAnswerFromTag_Thinfilm command");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set FPGA mode to "reader listen mode", no modulation (listen
|
||||
// only, since we are receiving, not transmitting).
|
||||
|
@ -2237,7 +2261,7 @@ bool GetIso14443aAnswerFromTag_Thinfilm(uint8_t *receivedResponse, uint8_t *rec
|
|||
static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receivedResponsePar, uint16_t offset) {
|
||||
uint32_t c = 0;
|
||||
|
||||
if (!hf_field_active)
|
||||
if (!g_hf_field_active)
|
||||
return false;
|
||||
|
||||
// Set FPGA mode to "reader listen mode", no modulation (listen
|
||||
|
@ -2338,6 +2362,8 @@ void iso14443a_antifuzz(uint32_t flags) {
|
|||
uint8_t *receivedPar = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint8_t *resp = BigBuf_malloc(20);
|
||||
|
||||
memset(received, 0x00, MAX_FRAME_SIZE);
|
||||
memset(received, 0x00, MAX_PARITY_SIZE);
|
||||
memset(resp, 0xFF, 20);
|
||||
|
||||
LED_A_ON();
|
||||
|
@ -2376,6 +2402,7 @@ void iso14443a_antifuzz(uint32_t flags) {
|
|||
colpos = 8;
|
||||
}
|
||||
|
||||
// trigger a faulty/collision response
|
||||
EmSendCmdEx(resp, 5, true);
|
||||
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("ANTICOLL or SELECT %x", received[1]);
|
||||
LED_D_INV();
|
||||
|
@ -2496,16 +2523,19 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32
|
|||
sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2;
|
||||
|
||||
if (anticollision) {
|
||||
|
||||
// SELECT_ALL
|
||||
ReaderTransmit(sel_all, sizeof(sel_all), NULL);
|
||||
if (!ReaderReceive(resp, resp_par)) {
|
||||
Dbprintf("Card didn't answer to CL%i select all", cascade_level + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit
|
||||
memset(uid_resp, 0, 5);
|
||||
uint16_t uid_resp_bits = 0;
|
||||
uint16_t collision_answer_offset = 0;
|
||||
|
||||
// anti-collision-loop:
|
||||
while (Demod.collisionPos) {
|
||||
Dbprintf("Multiple tags detected. Collision after Bit %d", Demod.collisionPos);
|
||||
|
@ -2524,6 +2554,7 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32
|
|||
ReaderTransmitBits(sel_uid, 16 + uid_resp_bits, NULL);
|
||||
if (!ReaderReceiveOffset(resp, collision_answer_offset, resp_par)) return 0;
|
||||
}
|
||||
|
||||
// finally, add the last bits and BCC of the UID
|
||||
for (uint16_t i = collision_answer_offset; i < (Demod.len - 1) * 8; i++, uid_resp_bits++) {
|
||||
uint16_t UIDbit = (resp[i / 8] >> (i % 8)) & 0x01;
|
||||
|
@ -2620,9 +2651,10 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32
|
|||
// PICC compliant with iso14443a-4 ---> (SAK & 0x20 != 0)
|
||||
if ((sak & 0x20) == 0) return 2;
|
||||
} else if (hf14aconfig.forcerats == 2) {
|
||||
if ((sak & 0x20) != 0) Dbprintf("Skipping RATS according to hf 14a config");
|
||||
return 2;
|
||||
} // else force RATS
|
||||
|
||||
if ((sak & 0x20) == 0) Dbprintf("Forcing RATS according to hf 14a config");
|
||||
// RATS, Request for answer to select
|
||||
if (no_rats == false) {
|
||||
uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x00, 0x00 }; // FSD=256, FSDI=8, CID=0
|
||||
|
@ -2723,13 +2755,7 @@ void iso14443a_setup(uint8_t fpga_minor_mode) {
|
|||
NextTransferTime = 2 * DELAY_ARM2AIR_AS_READER;
|
||||
iso14a_set_timeout(1060); // 106 * 10ms default
|
||||
|
||||
hf_field_active = true;
|
||||
}
|
||||
|
||||
void hf_field_off(void) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
hf_field_active = false;
|
||||
g_hf_field_active = true;
|
||||
}
|
||||
|
||||
/* Peter Fillmore 2015
|
||||
|
|
|
@ -84,6 +84,21 @@ typedef struct {
|
|||
uint8_t *parity;
|
||||
} tUart14a;
|
||||
|
||||
// indices into responses array:
|
||||
typedef enum {
|
||||
RESP_INDEX_ATQA,
|
||||
RESP_INDEX_UIDC1,
|
||||
RESP_INDEX_UIDC2,
|
||||
RESP_INDEX_UIDC3,
|
||||
RESP_INDEX_SAKC1,
|
||||
RESP_INDEX_SAKC2,
|
||||
RESP_INDEX_SAKC3,
|
||||
RESP_INDEX_RATS,
|
||||
RESP_INDEX_VERSION,
|
||||
RESP_INDEX_SIGNATURE,
|
||||
RESP_INDEX_PPS
|
||||
} resp_index_t;
|
||||
|
||||
#ifndef AddCrc14A
|
||||
# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1)
|
||||
#endif
|
||||
|
@ -129,7 +144,6 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u
|
|||
int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats);
|
||||
int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades);
|
||||
void iso14a_set_trigger(bool enable);
|
||||
void hf_field_off(void);
|
||||
|
||||
int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen);
|
||||
int EmSend4bit(uint8_t resp);
|
||||
|
|
|
@ -717,6 +717,211 @@ void SimulateIso14443bTag(uint8_t *pupi) {
|
|||
switch_off(); //simulate
|
||||
}
|
||||
|
||||
/*
|
||||
void Simulate_iso14443b_srx_tag(uint8_t *uid) {
|
||||
|
||||
LED_A_ON();
|
||||
/ SRI512
|
||||
|
||||
> initiate 06 00 ISO14443B_INITIATE
|
||||
< xx crc crc
|
||||
> select 0e xx ISO14443B_SELECT
|
||||
< xx nn nn
|
||||
|
||||
> readblock 08 blck_no ISO14443B_READ_BLK
|
||||
< d0 d1 d2 d3 2byte crc
|
||||
|
||||
> get uid ISO14443B_GET_UID
|
||||
< 81 93 99 20 92 11 02 (8byte UID in MSB D002 199220 999381)
|
||||
|
||||
#define ISO14443B_REQB 0x05
|
||||
#define ISO14443B_ATTRIB 0x1D
|
||||
#define ISO14443B_HALT 0x50
|
||||
#define ISO14443B_INITIATE 0x06
|
||||
#define ISO14443B_SELECT 0x0E
|
||||
#define ISO14443B_GET_UID 0x0B
|
||||
#define ISO14443B_READ_BLK 0x08
|
||||
#define ISO14443B_WRITE_BLK 0x09
|
||||
#define ISO14443B_RESET 0x0C
|
||||
#define ISO14443B_COMPLETION 0x0F
|
||||
#define ISO14443B_AUTHENTICATE 0x0A
|
||||
#define ISO14443B_PING 0xBA
|
||||
#define ISO14443B_PONG 0xAB
|
||||
|
||||
|
||||
static const uint8_t resp_init_srx[] = { 0x73, 0x64, 0xb1 };
|
||||
uint8_t resp_select_srx[] = { 0x73, 0x64, 0xb1 };
|
||||
|
||||
// a default uid, or user supplied
|
||||
uint8_t resp_getuid_srx[10] = {
|
||||
0x81, 0x93, 0x99, 0x20, 0x92, 0x11, 0x02, 0xD0, 0x00, 0x00
|
||||
};
|
||||
|
||||
// ...UID supplied from user. Adjust ATQB response accordingly
|
||||
if (memcmp("\x00\x00\x00\x00\x00\x00\x00\x00", uid, 8) != 0) {
|
||||
memcpy(resp_getuid_srx, uid, 8);
|
||||
AddCrc14B(resp_getuid_srx, 8);
|
||||
}
|
||||
|
||||
// response to HLTB and ATTRIB
|
||||
static const uint8_t respOK[] = {0x00, 0x78, 0xF0};
|
||||
|
||||
// setup device.
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
// connect Demodulated Signal to ADC:
|
||||
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
|
||||
|
||||
// Set up the synchronous serial port
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
|
||||
|
||||
// allocate command receive buffer
|
||||
BigBuf_free();
|
||||
BigBuf_Clear_ext(false);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
uint16_t len, cmdsReceived = 0;
|
||||
int cardSTATE = SIM_NOFIELD;
|
||||
int vHf = 0; // in mV
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
|
||||
|
||||
// prepare "ATQB" tag answer (encoded):
|
||||
CodeIso14443bAsTag(respATQB, sizeof(respATQB));
|
||||
uint8_t *encodedATQB = BigBuf_malloc(ts->max);
|
||||
uint16_t encodedATQBLen = ts->max;
|
||||
memcpy(encodedATQB, ts->buf, ts->max);
|
||||
|
||||
|
||||
// prepare "OK" tag answer (encoded):
|
||||
CodeIso14443bAsTag(respOK, sizeof(respOK));
|
||||
uint8_t *encodedOK = BigBuf_malloc(ts->max);
|
||||
uint16_t encodedOKLen = ts->max;
|
||||
memcpy(encodedOK, ts->buf, ts->max);
|
||||
|
||||
// Simulation loop
|
||||
while (BUTTON_PRESS() == false) {
|
||||
WDT_HIT();
|
||||
|
||||
//iceman: limit with 2000 times..
|
||||
if (data_available()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// find reader field
|
||||
if (cardSTATE == SIM_NOFIELD) {
|
||||
|
||||
#if defined RDV4
|
||||
vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc(ADC_CHAN_HF_RDV40, 32)) >> 15;
|
||||
#else
|
||||
vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
|
||||
#endif
|
||||
if (vHf > MF_MINFIELDV) {
|
||||
cardSTATE = SIM_IDLE;
|
||||
LED_A_ON();
|
||||
}
|
||||
}
|
||||
if (cardSTATE == SIM_NOFIELD) continue;
|
||||
|
||||
// Get reader command
|
||||
if (!GetIso14443bCommandFromReader(receivedCmd, &len)) {
|
||||
Dbprintf("button pressed, received %d commands", cmdsReceived);
|
||||
break;
|
||||
}
|
||||
|
||||
// ISO14443-B protocol states:
|
||||
// REQ or WUP request in ANY state
|
||||
// WUP in HALTED state
|
||||
if (len == 5) {
|
||||
if ((receivedCmd[0] == ISO14443B_REQB && (receivedCmd[2] & 0x8) == 0x8 && cardSTATE == SIM_HALTED) ||
|
||||
receivedCmd[0] == ISO14443B_REQB) {
|
||||
LogTrace(receivedCmd, len, 0, 0, NULL, true);
|
||||
cardSTATE = SIM_SELECTING;
|
||||
}
|
||||
}
|
||||
|
||||
/
|
||||
* How should this flow go?
|
||||
* REQB or WUPB
|
||||
* send response ( waiting for Attrib)
|
||||
* ATTRIB
|
||||
* send response ( waiting for commands 7816)
|
||||
* HALT
|
||||
send halt response ( waiting for wupb )
|
||||
/
|
||||
|
||||
switch (cardSTATE) {
|
||||
//case SIM_NOFIELD:
|
||||
case SIM_HALTED:
|
||||
case SIM_IDLE: {
|
||||
LogTrace(receivedCmd, len, 0, 0, NULL, true);
|
||||
break;
|
||||
}
|
||||
case SIM_SELECTING: {
|
||||
TransmitFor14443b_AsTag(encodedATQB, encodedATQBLen);
|
||||
LogTrace(respATQB, sizeof(respATQB), 0, 0, NULL, false);
|
||||
cardSTATE = SIM_WORK;
|
||||
break;
|
||||
}
|
||||
case SIM_HALTING: {
|
||||
TransmitFor14443b_AsTag(encodedOK, encodedOKLen);
|
||||
LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false);
|
||||
cardSTATE = SIM_HALTED;
|
||||
break;
|
||||
}
|
||||
case SIM_ACKNOWLEDGE: {
|
||||
TransmitFor14443b_AsTag(encodedOK, encodedOKLen);
|
||||
LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false);
|
||||
cardSTATE = SIM_IDLE;
|
||||
break;
|
||||
}
|
||||
case SIM_WORK: {
|
||||
if (len == 7 && receivedCmd[0] == ISO14443B_HALT) {
|
||||
cardSTATE = SIM_HALTED;
|
||||
} else if (len == 11 && receivedCmd[0] == ISO14443B_ATTRIB) {
|
||||
cardSTATE = SIM_ACKNOWLEDGE;
|
||||
} else {
|
||||
// Todo:
|
||||
// - SLOT MARKER
|
||||
// - ISO7816
|
||||
// - emulate with a memory dump
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsReceived);
|
||||
|
||||
// CRC Check
|
||||
if (len >= 3) { // if crc exists
|
||||
|
||||
if (!check_crc(CRC_14443_B, receivedCmd, len)) {
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
DbpString("CRC fail");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
DbpString("CRC passed");
|
||||
}
|
||||
}
|
||||
cardSTATE = SIM_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
++cmdsReceived;
|
||||
}
|
||||
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen());
|
||||
|
||||
switch_off(); //simulate
|
||||
}
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
// An ISO 14443 Type B reader. We take layer two commands, code them
|
||||
// appropriately, and then send them to the tag. We then listen for the
|
||||
|
@ -1160,6 +1365,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t
|
|||
tosend_t *ts = get_tosend();
|
||||
CodeIso14443bAsReader(cmd, len);
|
||||
TransmitFor14443b_AsReader(start_time);
|
||||
if (g_trigger) LED_A_ON();
|
||||
*eof_time = *start_time + (10 * ts->max) + 10 + 2 + 10;
|
||||
LogTrace(cmd, len, *start_time, *eof_time, NULL, true);
|
||||
}
|
||||
|
@ -1540,7 +1746,8 @@ void iso14443b_setup(void) {
|
|||
//
|
||||
// I tried to be systematic and check every answer of the tag, every CRC, etc...
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool ReadSTBlock(uint8_t blocknr, uint8_t *block) {
|
||||
static int read_srx_block(uint8_t blocknr, uint8_t *block) {
|
||||
|
||||
uint8_t cmd[] = {ISO14443B_READ_BLK, blocknr, 0x00, 0x00};
|
||||
AddCrc14B(cmd, 2);
|
||||
|
||||
|
@ -1557,60 +1764,50 @@ static bool ReadSTBlock(uint8_t blocknr, uint8_t *block) {
|
|||
// Check if we got an answer from the tag
|
||||
if (retlen != 6) {
|
||||
DbpString("[!] expected 6 bytes from tag, got less...");
|
||||
return false;
|
||||
return PM3_EWRONGANSWER;
|
||||
}
|
||||
// The check the CRC of the answer
|
||||
if (!check_crc(CRC_14443_B, r_block, retlen)) {
|
||||
if (check_crc(CRC_14443_B, r_block, retlen) == false) {
|
||||
DbpString("CRC fail");
|
||||
return false;
|
||||
return PM3_ECRC;
|
||||
}
|
||||
|
||||
if (block) {
|
||||
memcpy(block, r_block, 4);
|
||||
}
|
||||
|
||||
Dbprintf("Address=%02x, Contents=%08x, CRC=%04x",
|
||||
blocknr,
|
||||
(r_block[3] << 24) + (r_block[2] << 16) + (r_block[1] << 8) + r_block[0],
|
||||
(r_block[4] << 8) + r_block[5]);
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("Address=%02x, Contents=%08x, CRC=%04x",
|
||||
blocknr,
|
||||
(r_block[3] << 24) + (r_block[2] << 16) + (r_block[1] << 8) + r_block[0],
|
||||
(r_block[4] << 8) + r_block[5]
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
void ReadSTMemoryIso14443b(uint16_t numofblocks) {
|
||||
|
||||
void ReadSTBlock(uint8_t blocknr) {
|
||||
iso14443b_setup();
|
||||
|
||||
uint8_t *mem = BigBuf_malloc((numofblocks + 1) * 4);
|
||||
|
||||
iso14b_card_select_t card;
|
||||
int res = iso14443b_select_srx_card(&card);
|
||||
int isOK = PM3_SUCCESS;
|
||||
|
||||
// 0: OK 2: attrib fail, 3:crc fail,
|
||||
if (res < 1) {
|
||||
isOK = PM3_ETIMEOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
++numofblocks;
|
||||
|
||||
for (uint8_t i = 0; i < numofblocks; i++) {
|
||||
|
||||
if (ReadSTBlock(i, mem + (i * 4)) == false) {
|
||||
isOK = PM3_ETIMEOUT;
|
||||
break;
|
||||
// 0: OK -1 wrong len, -2: attrib fail, -3:crc fail,
|
||||
switch (res) {
|
||||
case -1:
|
||||
case -3: {
|
||||
reply_ng(CMD_HF_SRI_READ, PM3_EWRONGANSWER, NULL, 0);
|
||||
goto out;
|
||||
}
|
||||
case -2: {
|
||||
reply_ng(CMD_HF_SRI_READ, PM3_ECRC, NULL, 0);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
// System area block (0xFF)
|
||||
if (ReadSTBlock(0xFF, mem + (numofblocks * 4)) == false)
|
||||
isOK = PM3_ETIMEOUT;
|
||||
uint8_t *data = BigBuf_malloc(4);
|
||||
res = read_srx_block(blocknr, data);
|
||||
reply_ng(CMD_HF_SRI_READ, res, data, 4);
|
||||
|
||||
out:
|
||||
|
||||
reply_ng(CMD_HF_SRI_READ, isOK, mem, numofblocks * 4);
|
||||
|
||||
BigBuf_free();
|
||||
switch_off();
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ int iso14443b_select_card_srx(iso14b_card_select_t *card);
|
|||
|
||||
void SimulateIso14443bTag(uint8_t *pupi);
|
||||
void AcquireRawAdcSamplesIso14443b(uint32_t parameter);
|
||||
void ReadSTMemoryIso14443b(uint16_t numofblocks);
|
||||
void ReadSTBlock(uint8_t blocknr);
|
||||
void SniffIso14443b(void);
|
||||
void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
|
||||
void SendRawCommand14443B_Ex(PacketCommandNG *c);
|
||||
|
|
|
@ -1708,6 +1708,11 @@ void SimTagIso15693(uint8_t *uid) {
|
|||
|
||||
bool exit_loop = false;
|
||||
while (exit_loop == false) {
|
||||
|
||||
button_pressed = BUTTON_PRESS();
|
||||
if (button_pressed || data_available())
|
||||
break;
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
// find reader field
|
||||
|
|
|
@ -450,7 +450,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
|||
// 2 = use 0x1B authentication.
|
||||
// datain : 4 first bytes is data to be written.
|
||||
// : 4/16 next bytes is authentication key.
|
||||
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
static void MifareUWriteBlockEx(uint8_t arg0, uint8_t arg1, uint8_t *datain, bool reply) {
|
||||
uint8_t blockNo = arg0;
|
||||
bool useKey = (arg1 == 1); //UL_C
|
||||
bool usePwd = (arg1 == 2); //UL_EV1/NTAG
|
||||
|
@ -507,12 +507,17 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
|||
|
||||
if (DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
|
||||
|
||||
reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
|
||||
if (reply)
|
||||
reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
set_tracing(false);
|
||||
}
|
||||
|
||||
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
MifareUWriteBlockEx(arg0, arg1, datain, true);
|
||||
}
|
||||
|
||||
// Arg0 : Block to write to.
|
||||
// Arg1 : 0 = use no authentication.
|
||||
// 1 = use 0x1A authentication.
|
||||
|
@ -2247,6 +2252,11 @@ void MifareCIdent(bool is_mfc) {
|
|||
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
|
||||
memset(par, 0x00, MAX_PARITY_SIZE);
|
||||
memset(buf, 0x00, PM3_CMD_DATA_SIZE);
|
||||
memset(uid, 0x00, 10);
|
||||
|
||||
uint32_t cuid = 0;
|
||||
uint8_t data[1] = {0x00};
|
||||
|
||||
|
@ -2278,52 +2288,56 @@ void MifareCIdent(bool is_mfc) {
|
|||
|
||||
ReaderTransmit(rats, sizeof(rats), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
// test for some MFC gen2
|
||||
if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10\xF0\x05", 11) == 0) {
|
||||
if (res) {
|
||||
|
||||
// super card ident
|
||||
uint8_t super[] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};
|
||||
ReaderTransmit(super, sizeof(super), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
if (res == 22) {
|
||||
isGen = MAGIC_SUPER;
|
||||
// test for some MFC gen2
|
||||
if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10\xF0\x05", 11) == 0) {
|
||||
|
||||
// super card ident
|
||||
uint8_t super[] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};
|
||||
ReaderTransmit(super, sizeof(super), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
if (res == 22) {
|
||||
isGen = MAGIC_SUPER;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some MFC 7b gen2
|
||||
if (memcmp(buf, "\x0D\x78\x00\x71\x02\x88\x49\xA1\x30\x20\x15\x06\x08\x56\x3D", 15) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for Ultralight magic gen2
|
||||
if (memcmp(buf, "\x0A\x78\x00\x81\x02\xDB\xA0\xC1\x19\x40\x2A\xB5", 12) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for Ultralight EV1 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x41\xDF", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some other Ultralight EV1 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x16\xD7", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some other Ultralight magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xB0\x00\x00\x00\x00\x00\x00\x00\x00\x18\x4D", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for NTAG213 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xA5\x00\x04\x04\x02\x01\x00\x0F\x03\x79\x0C", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some MFC 7b gen2
|
||||
if (memcmp(buf, "\x0D\x78\x00\x71\x02\x88\x49\xA1\x30\x20\x15\x06\x08\x56\x3D", 15) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
}
|
||||
// test for Ultralight magic gen2
|
||||
if (memcmp(buf, "\x0A\x78\x00\x81\x02\xDB\xA0\xC1\x19\x40\x2A\xB5", 12) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for Ultralight EV1 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x41\xDF", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some other Ultralight EV1 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x16\xD7", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some other Ultralight magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xB0\x00\x00\x00\x00\x00\x00\x00\x00\x18\x4D", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for NTAG213 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xA5\x00\x04\x04\x02\x01\x00\x0F\x03\x79\x0C", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
if (! is_mfc) {
|
||||
if (is_mfc == false) {
|
||||
// magic ntag test
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
SpinDelay(40);
|
||||
|
@ -2336,8 +2350,7 @@ void MifareCIdent(bool is_mfc) {
|
|||
isGen = MAGIC_NTAG21X;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_mfc) {
|
||||
} else {
|
||||
// magic MFC Gen3 test
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
SpinDelay(40);
|
||||
|
@ -2368,6 +2381,9 @@ void MifareHasStaticNonce(void) {
|
|||
int retval = PM3_SUCCESS;
|
||||
uint32_t nt = 0;
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
|
||||
memset(uid, 0x00, 10);
|
||||
|
||||
uint8_t data[1] = { NONCE_FAIL };
|
||||
struct Crypto1State mpcs = {0, 0};
|
||||
struct Crypto1State *pcs;
|
||||
|
@ -2384,7 +2400,7 @@ void MifareHasStaticNonce(void) {
|
|||
goto OUT;
|
||||
}
|
||||
|
||||
uint8_t rec[1] = {0x00};
|
||||
uint8_t rec[4] = {0x00};
|
||||
uint8_t recpar[1] = {0x00};
|
||||
// Transmit MIFARE_CLASSIC_AUTH 0x60, block 0
|
||||
int len = mifare_sendcmd_short(pcs, false, MIFARE_AUTH_KEYA, 0, rec, recpar, NULL);
|
||||
|
@ -2404,6 +2420,8 @@ void MifareHasStaticNonce(void) {
|
|||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
CHK_TIMEOUT();
|
||||
|
||||
memset(rec, 0x00, sizeof(rec));
|
||||
}
|
||||
|
||||
if (counter) {
|
||||
|
@ -2707,7 +2725,8 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t tearoff_time, uint8_t *datain) {
|
|||
if (tearoff_time > 43000)
|
||||
tearoff_time = 43000;
|
||||
|
||||
MifareUWriteBlock(blockNo, 0, data_fullwrite);
|
||||
MifareUWriteBlockEx(blockNo, 0, data_fullwrite, false);
|
||||
|
||||
|
||||
LEDsoff();
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
|
@ -2716,13 +2735,18 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t tearoff_time, uint8_t *datain) {
|
|||
|
||||
// write cmd to send, include CRC
|
||||
// 1b write, 1b block, 4b data, 2 crc
|
||||
uint8_t cmd[] = {MIFARE_ULC_WRITE, blockNo, data_testwrite[0], data_testwrite[1], data_testwrite[2], data_testwrite[3], 0, 0};
|
||||
uint8_t cmd[] = {
|
||||
MIFARE_ULC_WRITE, blockNo,
|
||||
data_testwrite[0], data_testwrite[1], data_testwrite[2], data_testwrite[3],
|
||||
0, 0
|
||||
};
|
||||
AddCrc14A(cmd, sizeof(cmd) - 2);
|
||||
|
||||
// anticollision / select card
|
||||
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
OnError(1);
|
||||
reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_EFAILED, NULL, 0);
|
||||
return;
|
||||
};
|
||||
// send
|
||||
|
@ -2740,7 +2764,7 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t tearoff_time, uint8_t *datain) {
|
|||
|
||||
//
|
||||
// Tear-off attack against MFU counter
|
||||
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) {
|
||||
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time, uint8_t *datain) {
|
||||
|
||||
if (tearoff_time > 43000)
|
||||
tearoff_time = 43000;
|
||||
|
@ -2754,10 +2778,10 @@ void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) {
|
|||
uint8_t cmd[] = {
|
||||
MIFARE_ULEV1_INCR_CNT,
|
||||
counter,
|
||||
0, // lsb
|
||||
0,
|
||||
0, // msb
|
||||
0, // rfu
|
||||
datain[0], // lsb
|
||||
datain[1],
|
||||
datain[2], // msb
|
||||
datain[3], // rfu
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
@ -2767,6 +2791,8 @@ void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) {
|
|||
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
OnError(1);
|
||||
switch_off();
|
||||
LEDsoff();
|
||||
return;
|
||||
};
|
||||
|
||||
|
@ -2775,6 +2801,6 @@ void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) {
|
|||
LED_D_ON();
|
||||
SpinDelayUsPrecision(tearoff_time);
|
||||
switch_off();
|
||||
|
||||
LEDsoff();
|
||||
reply_ng(CMD_HF_MFU_COUNTER_TEAROFF, PM3_SUCCESS, NULL, 0);
|
||||
}
|
||||
|
|
|
@ -64,5 +64,5 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
|
|||
|
||||
// Tear-off test for MFU
|
||||
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain);
|
||||
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time);
|
||||
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time, uint8_t *datain);
|
||||
#endif
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include "protocols.h"
|
||||
#include "desfire_crypto.h"
|
||||
|
||||
int DBGLEVEL = DBG_ERROR;
|
||||
|
||||
// crypto1 helpers
|
||||
void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out) {
|
||||
if (len != 1) {
|
||||
|
|
|
@ -18,14 +18,13 @@
|
|||
#include "BigBuf.h"
|
||||
#include "string.h"
|
||||
|
||||
static uint8_t *next_free_memory;
|
||||
extern struct common_area common_area;
|
||||
extern char __data_src_start__, __data_start__, __data_end__, __bss_start__, __bss_end__;
|
||||
|
||||
|
||||
static void uncompress_data_section(void) {
|
||||
next_free_memory = BigBuf_get_addr();
|
||||
int avail_in;
|
||||
memcpy(&avail_in, &__data_start__, sizeof(int));
|
||||
memcpy(&avail_in, &__data_src_start__, sizeof(int));
|
||||
int avail_out = &__data_end__ - &__data_start__; // uncompressed size. Correct.
|
||||
// uncompress data segment to RAM
|
||||
uintptr_t p = (uintptr_t)&__data_src_start__;
|
||||
|
@ -34,13 +33,21 @@ static void uncompress_data_section(void) {
|
|||
if (res < 0)
|
||||
return;
|
||||
// save the size of the compressed data section
|
||||
common_area.arg1 = res;
|
||||
common_area.arg1 = avail_in;
|
||||
}
|
||||
|
||||
void __attribute__((section(".startos"))) Vector(void);
|
||||
void Vector(void) {
|
||||
/* Stack should have been set up by the bootloader */
|
||||
|
||||
if (common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) {
|
||||
/* Initialize common area */
|
||||
memset(&common_area, 0, sizeof(common_area));
|
||||
common_area.magic = COMMON_AREA_MAGIC;
|
||||
common_area.version = 1;
|
||||
}
|
||||
common_area.flags.osimage_present = 1;
|
||||
|
||||
uncompress_data_section();
|
||||
|
||||
/* Set up (that is: clear) BSS. */
|
||||
|
|
|
@ -216,6 +216,7 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/uart/uart_posix.c
|
||||
${PM3_ROOT}/client/src/uart/uart_win32.c
|
||||
${PM3_ROOT}/client/src/ui/overlays.ui
|
||||
${PM3_ROOT}/client/src/aiddesfire.c
|
||||
${PM3_ROOT}/client/src/aidsearch.c
|
||||
${PM3_ROOT}/client/src/cmdanalyse.c
|
||||
${PM3_ROOT}/client/src/cmdcrc.c
|
||||
|
|
|
@ -29,26 +29,31 @@ endif
|
|||
AMIIBOLIBPATH = ./deps/amiitool
|
||||
AMIIBOLIBINC = -I$(AMIIBOLIBPATH)
|
||||
AMIIBOLIB = $(AMIIBOLIBPATH)/libamiibo.a
|
||||
AMIIBOLIBLD =
|
||||
|
||||
## Cliparser / Argtable3
|
||||
CLIPARSERLIBPATH = ./deps/cliparser
|
||||
CLIPARSERLIBINC = -I$(CLIPARSERLIBPATH)
|
||||
CLIPARSERLIB = $(CLIPARSERLIBPATH)/libcliparser.a
|
||||
CLIPARSERLIBLD =
|
||||
|
||||
## Hardnested
|
||||
HARDNESTEDLIBPATH = ./deps/hardnested
|
||||
HARDNESTEDLIBINC = -I$(HARDNESTEDLIBPATH)
|
||||
HARDNESTEDLIB = $(HARDNESTEDLIBPATH)/libhardnested.a
|
||||
HARDNESTEDLIBLD =
|
||||
|
||||
## Jansson
|
||||
JANSSONLIBPATH = ./deps/jansson
|
||||
JANSSONLIBINC = -I$(JANSSONLIBPATH)
|
||||
JANSSONLIB = $(JANSSONLIBPATH)/libjansson.a
|
||||
JANSSONLIBLD =
|
||||
|
||||
## Lua
|
||||
LUALIBPATH = ./deps/liblua
|
||||
LUALIBINC = -I$(LUALIBPATH)
|
||||
LUALIB = $(LUALIBPATH)/liblua.a
|
||||
LUALIBLD =
|
||||
LUAPLATFORM = generic
|
||||
ifneq (,$(findstring MINGW,$(platform)))
|
||||
LUAPLATFORM = mingw
|
||||
|
@ -56,7 +61,7 @@ else
|
|||
ifeq ($(platform),Darwin)
|
||||
LUAPLATFORM = macosx
|
||||
else
|
||||
LUALIB += -ldl
|
||||
LUALIBLD += -ldl
|
||||
LUAPLATFORM = linux
|
||||
endif
|
||||
endif
|
||||
|
@ -65,16 +70,19 @@ endif
|
|||
REVENGLIBPATH = ./deps/reveng
|
||||
REVENGLIBINC = -I$(REVENGLIBPATH)
|
||||
REVENGLIB = $(REVENGLIBPATH)/libreveng.a
|
||||
REVENGLIBLD =
|
||||
|
||||
## Tinycbor
|
||||
TINYCBORLIBPATH = ./deps/tinycbor
|
||||
TINYCBORLIBINC = -I$(TINYCBORLIBPATH)
|
||||
TINYCBORLIB = $(TINYCBORLIBPATH)/tinycbor.a
|
||||
TINYCBORLIBLD =
|
||||
|
||||
## Whereami
|
||||
WHEREAMILIBPATH = ./deps/whereami
|
||||
WHEREAMILIBINC = -I$(WHEREAMILIBPATH)
|
||||
WHEREAMILIB = $(WHEREAMILIBPATH)/libwhereami.a
|
||||
WHEREAMILIBLD =
|
||||
|
||||
##########################
|
||||
# common local libraries #
|
||||
|
@ -91,17 +99,20 @@ MBEDTLSLIB = $(OBJDIR)/libmbedtls.a
|
|||
|
||||
## Amiibo
|
||||
# not distributed as system library
|
||||
LDLIBS += $(AMIIBOLIB)
|
||||
STATICLIBS += $(AMIIBOLIB)
|
||||
LDLIBS += $(AMIIBOLIBLD)
|
||||
INCLUDES += $(AMIIBOLIBINC)
|
||||
|
||||
## Cliparser / Argtable3
|
||||
# not distributed as system library
|
||||
LDLIBS += $(CLIPARSERLIB)
|
||||
STATICLIBS += $(CLIPARSERLIB)
|
||||
LDLIBS += $(CLIPARSERLIBLD)
|
||||
INCLUDES += $(CLIPARSERLIBINC)
|
||||
|
||||
## Hardnested
|
||||
# not distributed as system library
|
||||
LDLIBS += $(HARDNESTEDLIB)
|
||||
STATICLIBS += $(HARDNESTEDLIB)
|
||||
LDLIBS +=$(HARDNESTEDLIBLD)
|
||||
INCLUDES += $(HARDNESTEDLIBINC)
|
||||
|
||||
## Jansson
|
||||
|
@ -109,12 +120,14 @@ ifneq ($(SKIPJANSSONSYSTEM),1)
|
|||
JANSSONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags jansson 2>/dev/null)
|
||||
JANSSONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs jansson 2>/dev/null)
|
||||
ifneq ($(JANSSONLDLIBS),)
|
||||
JANSSONLIB = $(JANSSONLDLIBS)
|
||||
JANSSONLIB =
|
||||
JANSSONLIBLD = $(JANSSONLDLIBS)
|
||||
JANSSONLIBINC = $(JANSSONINCLUDES)
|
||||
JANSSON_FOUND = 1
|
||||
endif
|
||||
endif
|
||||
LDLIBS += $(JANSSONLIB)
|
||||
STATICLIBS += $(JANSSONLIB)
|
||||
LDLIBS += $(JANSSONLIBLD)
|
||||
INCLUDES += $(JANSSONLIBINC)
|
||||
|
||||
## Lua
|
||||
|
@ -122,38 +135,45 @@ ifneq ($(SKIPLUASYSTEM),1)
|
|||
LUAINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags lua5.2 2>/dev/null)
|
||||
LUALDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs lua5.2 2>/dev/null)
|
||||
ifneq ($(LUALDLIBS),)
|
||||
LUALIB = $(LUALDLIBS)
|
||||
LUALIB =
|
||||
LUALIBLD = $(LUALDLIBS)
|
||||
LUALIBINC = $(LUAINCLUDES)
|
||||
LUA_FOUND = 1
|
||||
endif
|
||||
endif
|
||||
LDLIBS += $(LUALIB)
|
||||
STATICLIBS += $(LUALIB)
|
||||
LDLIBS += $(LUALIBLD)
|
||||
INCLUDES += $(LUALIBINC)
|
||||
|
||||
## mbed TLS
|
||||
# system library cannot be used because it is compiled by default without CMAC support
|
||||
LDLIBS +=$(MBEDTLSLIB)
|
||||
STATICLIBS += $(MBEDTLSLIB)
|
||||
LDLIBS += $(MBEDTLSLIBLD)
|
||||
INCLUDES += $(MBEDTLSLIBINC)
|
||||
|
||||
## Reveng
|
||||
# not distributed as system library
|
||||
LDLIBS += $(REVENGLIB)
|
||||
STATICLIBS += $(REVENGLIB)
|
||||
LDLIBS += $(REVENGLIBLD)
|
||||
INCLUDES += $(REVENGLIBINC)
|
||||
|
||||
## Tinycbor
|
||||
# not distributed as system library
|
||||
LDLIBS += $(TINYCBORLIB)
|
||||
STATICLIBS += $(TINYCBORLIB)
|
||||
LDLIBS += $(TINYCBORLIBLD)
|
||||
INCLUDES += $(TINYCBORLIBINC)
|
||||
|
||||
## Whereami
|
||||
ifneq ($(SKIPWHEREAMISYSTEM),1)
|
||||
ifneq (,$(wildcard /usr/include/whereami.h))
|
||||
WHEREAMILIB = -lwhereami
|
||||
WHEREAMILIB =
|
||||
WHEREAMILIBLD = -lwhereami
|
||||
WHEREAMILIBINC =
|
||||
WHEREAMI_FOUND = 1
|
||||
endif
|
||||
endif
|
||||
LDLIBS += $(WHEREAMILIB)
|
||||
STATICLIBS += $(WHEREAMILIB)
|
||||
LDLIBS += $(WHEREAMILIBLD)
|
||||
INCLUDES += $(WHEREAMILIBINC)
|
||||
|
||||
####################
|
||||
|
@ -176,12 +196,12 @@ ifneq ($(SKIPBT),1)
|
|||
BTINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags bluez 2>/dev/null)
|
||||
BTLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs bluez 2>/dev/null)
|
||||
ifneq ($(BTLDLIBS),)
|
||||
BTLIB = $(BTLDLIBS)
|
||||
BTLIBLD = $(BTLDLIBS)
|
||||
BTLIBINC = $(BTINCLUDES)
|
||||
BT_FOUND = 1
|
||||
endif
|
||||
endif
|
||||
LDLIBS += $(BTLIB)
|
||||
LDLIBS += $(BTLIBLD)
|
||||
INCLUDES += $(BTLIBINC)
|
||||
|
||||
## Math
|
||||
|
@ -198,7 +218,7 @@ ifneq ($(SKIPPYTHON),1)
|
|||
PYTHONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags python3 2>/dev/null)
|
||||
PYTHONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs python3 2>/dev/null)
|
||||
ifneq ($(PYTHONLDLIBS),)
|
||||
PYTHONLIB = $(PYTHONLDLIBS)
|
||||
PYTHONLIBLD = $(PYTHONLDLIBS)
|
||||
PYTHONLIBINC = $(PYTHONINCLUDES)
|
||||
PYTHON_FOUND = 1
|
||||
else
|
||||
|
@ -206,13 +226,13 @@ ifneq ($(SKIPPYTHON),1)
|
|||
PYTHONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags python3-embed 2>/dev/null)
|
||||
PYTHONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs python3-embed 2>/dev/null)
|
||||
ifneq ($(PYTHONLDLIBS),)
|
||||
PYTHONLIB = $(PYTHONLDLIBS)
|
||||
PYTHONLIBLD = $(PYTHONLDLIBS)
|
||||
PYTHONLIBINC = $(PYTHONINCLUDES)
|
||||
PYTHON_FOUND = 1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
LDLIBS += $(PYTHONLIB)
|
||||
LDLIBS += $(PYTHONLIBLD)
|
||||
INCLUDES += $(PYTHONLIBINC)
|
||||
|
||||
## QT5 (or QT4 fallback) (optional)
|
||||
|
@ -410,7 +430,8 @@ POSTCOMPILE = $(MV) -f $(OBJDIR)/$*.Td $(OBJDIR)/$*.d && $(TOUCH) $@
|
|||
# enumerations #
|
||||
################
|
||||
|
||||
SRCS = aidsearch.c \
|
||||
SRCS = aiddesfire.c \
|
||||
aidsearch.c \
|
||||
cmdanalyse.c \
|
||||
cmdcrc.c \
|
||||
cmddata.c \
|
||||
|
@ -583,9 +604,9 @@ all: $(BINS)
|
|||
all-static: LDLIBS:=-static $(LDLIBS)
|
||||
all-static: $(BINS)
|
||||
|
||||
proxmark3: $(OBJS) amiibo cliparser jansson hardnested lua mbedtls reveng tinycbor whereami lualibs/pm3_cmd.lua lualibs/mfc_default_keys.lua
|
||||
proxmark3: $(OBJS) $(STATICLIBS) lualibs/pm3_cmd.lua lualibs/mfc_default_keys.lua
|
||||
$(info [=] LD $@)
|
||||
$(Q)$(LD) $(PM3LDFLAGS) $(OBJS) $(LDLIBS) -o $@
|
||||
$(Q)$(LD) $(PM3LDFLAGS) $(OBJS) $(STATICLIBS) $(LDLIBS) -o $@
|
||||
|
||||
src/proxgui.cpp: src/ui/ui_overlays.h
|
||||
|
||||
|
@ -648,44 +669,43 @@ tarbin: $(BINS)
|
|||
###########################
|
||||
# local libraries targets #
|
||||
###########################
|
||||
|
||||
amiibo:
|
||||
$(AMIIBOLIB): .FORCE
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C $(AMIIBOLIBPATH) all
|
||||
|
||||
cliparser:
|
||||
$(CLIPARSERLIB): .FORCE
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C $(CLIPARSERLIBPATH) all
|
||||
|
||||
hardnested:
|
||||
$(HARDNESTEDLIB): .FORCE
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C $(HARDNESTEDLIBPATH) all
|
||||
|
||||
jansson:
|
||||
$(JANSSONLIB): .FORCE
|
||||
ifneq ($(JANSSON_FOUND),1)
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C $(JANSSONLIBPATH) all
|
||||
endif
|
||||
|
||||
lua:
|
||||
$(LUALIB): .FORCE
|
||||
ifneq ($(LUA_FOUND),1)
|
||||
$(info [*] MAKE $@ for $(LUAPLATFORM))
|
||||
$(Q)$(MAKE) --no-print-directory -C $(LUALIBPATH) $(LUAPLATFORM)
|
||||
endif
|
||||
|
||||
mbedtls:
|
||||
$(MBEDTLSLIB): .FORCE
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C $(MBEDTLSLIBPATH) OBJDIR=$(ROOT_DIR)$(OBJDIR) BINDIR=$(ROOT_DIR)$(OBJDIR) all
|
||||
|
||||
reveng:
|
||||
$(REVENGLIB): .FORCE
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C $(REVENGLIBPATH) all
|
||||
|
||||
tinycbor:
|
||||
$(TINYCBORLIB): .FORCE
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C $(TINYCBORLIBPATH) all
|
||||
|
||||
whereami:
|
||||
$(WHEREAMILIB): .FORCE
|
||||
ifneq ($(WHEREAMI_FOUND),1)
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C $(WHEREAMILIBPATH) all
|
||||
|
@ -695,7 +715,7 @@ endif
|
|||
# misc #
|
||||
########
|
||||
|
||||
.PHONY: all clean install uninstall tarbin amiibo cliparser hardnested jansson lua mbedtls reveng tinycbor whereami
|
||||
.PHONY: all clean install uninstall tarbin .FORCE
|
||||
|
||||
# version.c should be remade on every compilation
|
||||
src/version.c: default_version.c
|
||||
|
|
|
@ -94,6 +94,7 @@ add_library(pm3rrg_rdv4 SHARED
|
|||
${PM3_ROOT}/client/src/uart/uart_posix.c
|
||||
${PM3_ROOT}/client/src/uart/uart_win32.c
|
||||
${PM3_ROOT}/client/src/ui/overlays.ui
|
||||
${PM3_ROOT}/client/src/aiddesfire.c
|
||||
${PM3_ROOT}/client/src/aidsearch.c
|
||||
${PM3_ROOT}/client/src/cmdanalyse.c
|
||||
${PM3_ROOT}/client/src/cmdcrc.c
|
||||
|
@ -127,6 +128,7 @@ add_library(pm3rrg_rdv4 SHARED
|
|||
${PM3_ROOT}/client/src/cmdlfcotag.c
|
||||
${PM3_ROOT}/client/src/cmdlfdestron.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x05.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x50.c
|
||||
${PM3_ROOT}/client/src/cmdlffdxb.c
|
||||
${PM3_ROOT}/client/src/cmdlfgallagher.c
|
||||
|
@ -150,7 +152,6 @@ add_library(pm3rrg_rdv4 SHARED
|
|||
${PM3_ROOT}/client/src/cmdlfsecurakey.c
|
||||
${PM3_ROOT}/client/src/cmdlft55xx.c
|
||||
${PM3_ROOT}/client/src/cmdlfti.c
|
||||
${PM3_ROOT}/client/src/cmdlfverichip.c
|
||||
${PM3_ROOT}/client/src/cmdlfviking.c
|
||||
${PM3_ROOT}/client/src/cmdlfvisa2000.c
|
||||
${PM3_ROOT}/client/src/cmdmain.c
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
static char *g_android_executable_directory = NULL;
|
||||
static char *g_android_user_directory = NULL;
|
||||
|
||||
char version_information[] = {"ANDROID_LIBRARY 1.4.6 build by DXL"};
|
||||
char version_information[] = {""};
|
||||
|
||||
const char *get_my_executable_directory(void) {
|
||||
if (g_android_executable_directory == NULL) {
|
||||
|
|
|
@ -278,14 +278,14 @@ uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_
|
|||
uint8_t data[8];
|
||||
int datalen = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, paramnum), data, sizeof(data), &datalen);
|
||||
if (res == 0) {
|
||||
if (res == 0 && datalen > 0) {
|
||||
for (uint8_t i = 0; i < datalen; i++) {
|
||||
rv <<= 8;
|
||||
rv |= data[i];
|
||||
}
|
||||
} else {
|
||||
rv = def;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
15892
client/dictionaries/extras/12_byte_most_common_password.dic
Normal file
15892
client/dictionaries/extras/12_byte_most_common_password.dic
Normal file
File diff suppressed because it is too large
Load diff
15892
client/dictionaries/extras/12_byte_most_common_password_uppercase.dic
Normal file
15892
client/dictionaries/extras/12_byte_most_common_password_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
29124
client/dictionaries/extras/12_byte_words.dic
Normal file
29124
client/dictionaries/extras/12_byte_words.dic
Normal file
File diff suppressed because it is too large
Load diff
29124
client/dictionaries/extras/12_byte_words_uppercase.dic
Normal file
29124
client/dictionaries/extras/12_byte_words_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
2765
client/dictionaries/extras/16_byte_most_common_password.dic
Normal file
2765
client/dictionaries/extras/16_byte_most_common_password.dic
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
5182
client/dictionaries/extras/16_byte_words.dic
Normal file
5182
client/dictionaries/extras/16_byte_words.dic
Normal file
File diff suppressed because it is too large
Load diff
5182
client/dictionaries/extras/16_byte_words_uppercase.dic
Normal file
5182
client/dictionaries/extras/16_byte_words_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
10000
client/dictionaries/extras/4_byte_ascii_numbers.dic
Normal file
10000
client/dictionaries/extras/4_byte_ascii_numbers.dic
Normal file
File diff suppressed because it is too large
Load diff
26830
client/dictionaries/extras/4_byte_most_common_password.dic
Normal file
26830
client/dictionaries/extras/4_byte_most_common_password.dic
Normal file
File diff suppressed because it is too large
Load diff
26830
client/dictionaries/extras/4_byte_most_common_password_uppercase.dic
Normal file
26830
client/dictionaries/extras/4_byte_most_common_password_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
7186
client/dictionaries/extras/4_byte_words.dic
Normal file
7186
client/dictionaries/extras/4_byte_words.dic
Normal file
File diff suppressed because it is too large
Load diff
7186
client/dictionaries/extras/4_byte_words_uppercase.dic
Normal file
7186
client/dictionaries/extras/4_byte_words_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
531441
client/dictionaries/extras/6_byte_ascii_numbers.dic
Normal file
531441
client/dictionaries/extras/6_byte_ascii_numbers.dic
Normal file
File diff suppressed because it is too large
Load diff
248824
client/dictionaries/extras/6_byte_most_common_password.dic
Normal file
248824
client/dictionaries/extras/6_byte_most_common_password.dic
Normal file
File diff suppressed because it is too large
Load diff
248824
client/dictionaries/extras/6_byte_most_common_password_uppercase.dic
Normal file
248824
client/dictionaries/extras/6_byte_most_common_password_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
15918
client/dictionaries/extras/6_byte_words.dic
Normal file
15918
client/dictionaries/extras/6_byte_words.dic
Normal file
File diff suppressed because it is too large
Load diff
15918
client/dictionaries/extras/6_byte_words_uppercase.dic
Normal file
15918
client/dictionaries/extras/6_byte_words_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
305084
client/dictionaries/extras/8_byte_most_common_password.dic
Normal file
305084
client/dictionaries/extras/8_byte_most_common_password.dic
Normal file
File diff suppressed because it is too large
Load diff
305084
client/dictionaries/extras/8_byte_most_common_password_uppercase.dic
Normal file
305084
client/dictionaries/extras/8_byte_most_common_password_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
51627
client/dictionaries/extras/8_byte_words.dic
Normal file
51627
client/dictionaries/extras/8_byte_words.dic
Normal file
File diff suppressed because it is too large
Load diff
51627
client/dictionaries/extras/8_byte_words_uppercase.dic
Normal file
51627
client/dictionaries/extras/8_byte_words_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
79
client/dictionaries/extras/iclass_other.dic
Normal file
79
client/dictionaries/extras/iclass_other.dic
Normal file
|
@ -0,0 +1,79 @@
|
|||
0000000000000001
|
||||
0000000000000002
|
||||
0000000000000003
|
||||
0000000000000004
|
||||
0000000000000005
|
||||
0000000000000006
|
||||
0000000000000007
|
||||
0000000000000008
|
||||
0000000000000009
|
||||
000000000000000a
|
||||
000000000000000b
|
||||
000000000000000c
|
||||
000000000000000d
|
||||
000000000000000e
|
||||
000000000000000f
|
||||
1000000000000000
|
||||
2000000000000000
|
||||
3000000000000000
|
||||
4000000000000000
|
||||
5000000000000000
|
||||
6000000000000000
|
||||
7000000000000000
|
||||
8000000000000000
|
||||
9000000000000000
|
||||
A000000000000000
|
||||
B000000000000000
|
||||
C000000000000000
|
||||
D000000000000000
|
||||
E000000000000000
|
||||
F000000000000000
|
||||
aaaabbbbccccdddd
|
||||
1010101010101010
|
||||
0101010101010101
|
||||
1122334455667788
|
||||
2233445566778899
|
||||
33445566778899AA
|
||||
445566778899AABB
|
||||
5566778899AABBCC
|
||||
66778899AABBCCDD
|
||||
778899AABBCCDDEE
|
||||
8899AABBCCDDEEFF
|
||||
6969696969696969
|
||||
1212121212121212
|
||||
1234567887654321
|
||||
1111111122222222
|
||||
1313131313131313
|
||||
2000000020000000
|
||||
a0a1a2a3a4a5a6a7
|
||||
b0b1b2b3b4b5b6b7
|
||||
c0c1c2c3c4c5c6c7
|
||||
d0d1d2d3d4d5d6d7
|
||||
e0e1e2e3e4e5e6e7
|
||||
f0f1f2f3f4f5f6f7
|
||||
d3f7d3f7d3f7d3f7
|
||||
0102030405060708
|
||||
0001020304050607
|
||||
0f0e0d0c0b0a0908
|
||||
0123456789ABCDEF
|
||||
100f0e0d0c0b0a09
|
||||
4041424344454647
|
||||
3031323334353637
|
||||
605F5E5D5C5B5A59
|
||||
0000000000000000
|
||||
1111111111111111
|
||||
2222222222222222
|
||||
3333333333333333
|
||||
4444444444444444
|
||||
5555555555555555
|
||||
6666666666666666
|
||||
7777777777777777
|
||||
8888888888888888
|
||||
9999999999999999
|
||||
AAAAAAAAAAAAAAAA
|
||||
BBBBBBBBBBBBBBBB
|
||||
CCCCCCCCCCCCCCCC
|
||||
DDDDDDDDDDDDDDDD
|
||||
EEEEEEEEEEEEEEEE
|
||||
FFFFFFFFFFFFFFFF
|
||||
deadbeefdeadbeef
|
67
client/dictionaries/extras/readme.md
Normal file
67
client/dictionaries/extras/readme.md
Normal file
|
@ -0,0 +1,67 @@
|
|||
These are text password lists that can be used to brute force RFID passwords. There are a lot better ways to find a password, but I haven't seen anyone talk about using normal password lists against RFID tags or publishing a list exclusively for this purpose.
|
||||
|
||||
|
||||
_byte_most_common_password.dic files are extracted from the top 10 million password list.
|
||||
|
||||
_byte_words_uppercase files are extracted from a common English dictionary.
|
||||
|
||||
Since most evidence (how ever small) shows that uppercase passwords are normally used with RFID these lists have been coverted to upper case added.
|
||||
|
||||
Two sets for ascii numnber lists have also been in the event the password is an ascii number.
|
||||
|
||||
|
||||
**A better dictionary to use is:**
|
||||
|
||||
https://github.com/RfidResearchGroup/proxmark3/tree/master/client/dictionaries
|
||||
|
||||
These are shorter lists and known default keys. My lists are to be used after the dictionary lists have been exhausted, and after other possible attacks have failed.
|
||||
|
||||
|
||||
|
||||
**Some examples on what my lists could be used for:**
|
||||
|
||||
T55xx and the em4305 chips use a 4 character password
|
||||
|
||||
Mifare Classic uses a 6 characters password (which will be added soon)
|
||||
|
||||
iClass uses an 8 characters password
|
||||
|
||||
Mifare Pluse uses a 16 characters password
|
||||
|
||||
|
||||
|
||||
**Examples where my list could have helped find:**
|
||||
```
|
||||
50524F58 spells out PROX
|
||||
|
||||
50415353 spells out PASS
|
||||
```
|
||||
These wouldn't be found in the most common password list, but they would be in the upercase dictionary. Again, the more efficent way to do this would have been to run the t55xx_default_pwds.dic from https://github.com/RfidResearchGroup/proxmark3/tree/master/client/dictionaries. If they had not published that great default password list, then we still would have been able to find these passwords without needing to try all possiblities which could take years.
|
||||
|
||||
When looking at the Mifare Plus list in mfp_default_keys.dic, we see that there is some corresponding to ASCII with the passwords:
|
||||
```
|
||||
404142434445464748494a4b4c4d4e4f = @ABCDEFGHIJKLMNO
|
||||
|
||||
303132333435363738393a3b3c3d3e3f = 0123456789:;<=>?
|
||||
|
||||
605F5E5D5C5B5A59605F5E5D5C5B5A59 = `_^]\[ZY`_^]\[ZY
|
||||
```
|
||||
Those would not appear in any of the above lists, but this just shows more evidence of an ASCII collocation.
|
||||
|
||||
|
||||
|
||||
**iClass_Other.dic**
|
||||
|
||||
When reviewing default passwords from other lists you start seeing common password schemes being using. For example:
|
||||
|
||||
```
|
||||
a0a1a2a3a4a5
|
||||
b0b1b2b3b4b5
|
||||
from mfc_default_keys.dic
|
||||
|
||||
a0a1a2a3a4a5a6a7a0a1a2a3a4a5a6a7
|
||||
b0b1b2b3b4b5b6b7b0b1b2b3b4b5b6b7
|
||||
from mfp_default_keys.dic
|
||||
```
|
||||
|
||||
As you can see there are some common themes in the above case its a0 then a1 ect. In these default password lists I took those themes and expanded them to fit the iClass key space. If you combine this with the other list https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/iclass_default_keys.dic It still only takes 1 second to run through all 86 keys.
|
|
@ -653,7 +653,7 @@ C01FC822C6E5
|
|||
# More keys:
|
||||
8a19d40cf2b5
|
||||
ae8587108640
|
||||
135b88a94b8b, SafLock standalone door locks.
|
||||
135b88a94b8b # SafLock standalone door locks.
|
||||
#
|
||||
# Russian Troika card
|
||||
08B386463229
|
||||
|
@ -1208,4 +1208,4 @@ FEE2A3FBC5B6
|
|||
#
|
||||
0602721E8F06
|
||||
FC0B50AF8700
|
||||
F7BA51A9434E
|
||||
F7BA51A9434E
|
||||
|
|
|
@ -36,7 +36,7 @@ arguments = [[
|
|||
-k <key> - the current six byte key with write access
|
||||
-n <key> - the new key that will be written to the card
|
||||
-a <access> - the new access bytes that will be written to the card
|
||||
-x - execute the commands aswell.
|
||||
-x - execute the commands as well.
|
||||
]]
|
||||
|
||||
local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds
|
||||
|
|
|
@ -1,340 +1,355 @@
|
|||
[
|
||||
{
|
||||
"AID": "EEEE10",
|
||||
"Vendor": "NFC Forum",
|
||||
"Country": "US",
|
||||
"Name": "NFC Forum NDEF Tag",
|
||||
"Description": "(FID 03: Capability Container)",
|
||||
"Type": "ndef"
|
||||
},
|
||||
{
|
||||
"AID": "D3494F",
|
||||
"Vendor": "HID",
|
||||
"Country": "US",
|
||||
"Name": "SIO DESFire Ev1",
|
||||
"Description": "Field Encoder",
|
||||
"Type": "pacs"
|
||||
},
|
||||
{
|
||||
"AID": "D9494F",
|
||||
"Vendor": "HID",
|
||||
"Country": "US",
|
||||
"Name": "Access control",
|
||||
"Description": "Field Encoder",
|
||||
"Type": "pacs"
|
||||
},
|
||||
{
|
||||
"AID": "53494F",
|
||||
"Vendor": "HID",
|
||||
"Country": "US",
|
||||
"Name": "Access control",
|
||||
"Description": "HID Factory",
|
||||
"Type": "pacs"
|
||||
},
|
||||
{
|
||||
"AID": "4F5931",
|
||||
"Vendor": "Transport of London",
|
||||
"Country": "UK",
|
||||
"Name": "Oyster Card",
|
||||
"Description": "",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "422201",
|
||||
"Vendor": "Transport of Istanbul",
|
||||
"Country": "Turkey",
|
||||
"Name": "Istanbulkart",
|
||||
"Description": "",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "F21190",
|
||||
"Vendor": "Metropolitan Transportation Commission",
|
||||
"Country": "US",
|
||||
"Name": "Clipper Card",
|
||||
"Description": "",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "000357",
|
||||
"Vendor": "LEGIC",
|
||||
"Country": "DE",
|
||||
"Name": "Legic",
|
||||
"Description": "(FID 02: EF-CONF)",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "578000",
|
||||
"Vendor": "NORTIC",
|
||||
"Country": "",
|
||||
"Name": "NORTIC Card Issuer",
|
||||
"Description": "(FID 0C: Card Issuer Header)",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "578001",
|
||||
"Vendor": "NORTIC",
|
||||
"Country": "",
|
||||
"Name": "NORTIC Transport",
|
||||
"Description": "(FIDs 01: Transport Product Retailer; 02: Transport Service Provider; 03: Transport Special Event; 04: Transport Stored Value; 05: Transport General Event Log; 06: Transport SV Reload Log; 0A: Transport Environment; 0C: Transport Card Holder",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "784000",
|
||||
"Vendor": "NO1",
|
||||
"Country": "UAE",
|
||||
"Name": "Nol Card/Dubai",
|
||||
"Description": "Nol Card/Dubai",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "956B19",
|
||||
"Vendor": "PING PING",
|
||||
"Country": "",
|
||||
"Name": "PingPing Tag",
|
||||
"Description": "PingPing Tag",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "DB9800",
|
||||
"Vendor": "PING PING",
|
||||
"Country": "",
|
||||
"Name": "PingPing Tag",
|
||||
"Description": "PingPing Tag",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "DB9801",
|
||||
"Vendor": "PING PING",
|
||||
"Country": "",
|
||||
"Name": "PingPing Tag",
|
||||
"Description": "PingPing Tag",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "DB9802",
|
||||
"Vendor": "PING PING",
|
||||
"Country": "",
|
||||
"Name": "PingPing Tag",
|
||||
"Description": "PingPing Tag",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "F21030",
|
||||
"Vendor": "ORCA Card",
|
||||
"Country": "",
|
||||
"Name": "ORCA Card",
|
||||
"Description": "(FIDs 02: Trip History; 04: current balance)",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "F21190",
|
||||
"Vendor": "Clipper",
|
||||
"Country": "US",
|
||||
"Name": "Clipper Card/San Francisco Bay Area ",
|
||||
"Description": "(FIDs 02: current balance; 04: Refill History; 08: Card Information; 0E: Trip History)
|
||||
FFFFFF General Issuer Information (FIDs 00: MAD Version; 01: Card Holder; 02: Card Publisher)",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "F518F0",
|
||||
"Vendor": "Telenot Electronic GmbH",
|
||||
"Country": "DE",
|
||||
"Name": "Telenot Tag",
|
||||
"Description": "",
|
||||
"Type": "alarm system"
|
||||
},
|
||||
{
|
||||
"AID": "F38091",
|
||||
"Vendor": "Microtronic AG",
|
||||
"Country": "CH",
|
||||
"Name": "Microtronic Tag",
|
||||
"Description": "",
|
||||
"Type": "payment system"
|
||||
},
|
||||
|
||||
{
|
||||
"AID": "F88280",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "F5217D",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "F48EF1",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535501",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535502",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535503",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535504",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535505",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535506",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535507",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535508",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535509",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "53550A",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "53550B",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "F001D0",
|
||||
"Vendor": "Arabako Foru Aldundia",
|
||||
"Country": "",
|
||||
"Name": "BAT",
|
||||
"Description": "",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "05845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "15845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "25845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "35845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "55845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "65845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "75845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "C26001",
|
||||
"Vendor": "CAR2GO",
|
||||
"Country": "DE",
|
||||
"Name": "MemberCard",
|
||||
"Description": "CAR2GO - Member Card",
|
||||
"Type": "carsharing"
|
||||
}
|
||||
]
|
||||
[
|
||||
{
|
||||
"AID": "EEEE10",
|
||||
"Vendor": "NFC Forum",
|
||||
"Country": "US",
|
||||
"Name": "NFC Forum NDEF Tag",
|
||||
"Description": "(FID 03: Capability Container)",
|
||||
"Type": "ndef"
|
||||
},
|
||||
{
|
||||
"AID": "D3494F",
|
||||
"Vendor": "HID",
|
||||
"Country": "US",
|
||||
"Name": "SIO DESFire Ev1",
|
||||
"Description": "Field Encoder",
|
||||
"Type": "pacs"
|
||||
},
|
||||
{
|
||||
"AID": "D9494F",
|
||||
"Vendor": "HID",
|
||||
"Country": "US",
|
||||
"Name": "Access control",
|
||||
"Description": "Field Encoder",
|
||||
"Type": "pacs"
|
||||
},
|
||||
{
|
||||
"AID": "53494F",
|
||||
"Vendor": "HID",
|
||||
"Country": "US",
|
||||
"Name": "Access control",
|
||||
"Description": "HID Factory",
|
||||
"Type": "pacs"
|
||||
},
|
||||
{
|
||||
"AID": "4F5931",
|
||||
"Vendor": "Transport of London",
|
||||
"Country": "UK",
|
||||
"Name": "Oyster Card",
|
||||
"Description": "",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "422201",
|
||||
"Vendor": "Transport of Istanbul",
|
||||
"Country": "Turkey",
|
||||
"Name": "Istanbulkart",
|
||||
"Description": "",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "F21190",
|
||||
"Vendor": "Metropolitan Transportation Commission",
|
||||
"Country": "US",
|
||||
"Name": "Clipper Card",
|
||||
"Description": "",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "000357",
|
||||
"Vendor": "LEGIC",
|
||||
"Country": "DE",
|
||||
"Name": "Legic",
|
||||
"Description": "(FID 02: EF-CONF)",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "578000",
|
||||
"Vendor": "NORTIC",
|
||||
"Country": "",
|
||||
"Name": "NORTIC Card Issuer",
|
||||
"Description": "(FID 0C: Card Issuer Header)",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "578001",
|
||||
"Vendor": "NORTIC",
|
||||
"Country": "",
|
||||
"Name": "NORTIC Transport",
|
||||
"Description": "(FIDs 01: Transport Product Retailer; 02: Transport Service Provider; 03: Transport Special Event; 04: Transport Stored Value; 05: Transport General Event Log; 06: Transport SV Reload Log; 0A: Transport Environment; 0C: Transport Card Holder",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "784000",
|
||||
"Vendor": "NO1",
|
||||
"Country": "UAE",
|
||||
"Name": "Nol Card/Dubai",
|
||||
"Description": "Nol Card/Dubai",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "956B19",
|
||||
"Vendor": "PING PING",
|
||||
"Country": "",
|
||||
"Name": "PingPing Tag",
|
||||
"Description": "PingPing Tag",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "DB9800",
|
||||
"Vendor": "PING PING",
|
||||
"Country": "",
|
||||
"Name": "PingPing Tag",
|
||||
"Description": "PingPing Tag",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "DB9801",
|
||||
"Vendor": "PING PING",
|
||||
"Country": "",
|
||||
"Name": "PingPing Tag",
|
||||
"Description": "PingPing Tag",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "DB9802",
|
||||
"Vendor": "PING PING",
|
||||
"Country": "",
|
||||
"Name": "PingPing Tag",
|
||||
"Description": "PingPing Tag",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "F21030",
|
||||
"Vendor": "ORCA Card",
|
||||
"Country": "",
|
||||
"Name": "ORCA Card",
|
||||
"Description": "(FIDs 02: Trip History; 04: current balance)",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "F21190",
|
||||
"Vendor": "Clipper",
|
||||
"Country": "US",
|
||||
"Name": "Clipper Card/San Francisco Bay Area ",
|
||||
"Description": "(FIDs 02: current balance; 04: Refill History; 08: Card Information; 0E: Trip History)\\nFFFFFF General Issuer Information (FIDs 00: MAD Version; 01: Card Holder; 02: Card Publisher)",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "F518F0",
|
||||
"Vendor": "Telenot Electronic GmbH",
|
||||
"Country": "DE",
|
||||
"Name": "Telenot Tag",
|
||||
"Description": "",
|
||||
"Type": "alarm system"
|
||||
},
|
||||
{
|
||||
"AID": "F38091",
|
||||
"Vendor": "Microtronic AG",
|
||||
"Country": "CH",
|
||||
"Name": "Microtronic Tag",
|
||||
"Description": "",
|
||||
"Type": "payment system"
|
||||
},
|
||||
|
||||
{
|
||||
"AID": "F88280",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "F5217D",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "F48EF1",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535501",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535502",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535503",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535504",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535505",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535506",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535507",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535508",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "535509",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "53550A",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "53550B",
|
||||
"Vendor": "TU Delft",
|
||||
"Country": "NL",
|
||||
"Name": "Uni Delft",
|
||||
"Description": "",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "F001D0",
|
||||
"Vendor": "Arabako Foru Aldundia",
|
||||
"Country": "",
|
||||
"Name": "BAT",
|
||||
"Description": "",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "05845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "15845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "25845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "35845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "55845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "65845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "75845F",
|
||||
"Vendor": "InterCard GmbH Kartensysteme",
|
||||
"Country": "DE",
|
||||
"Name": "InterCard",
|
||||
"Description": "Campus Card",
|
||||
"Type": "student"
|
||||
},
|
||||
{
|
||||
"AID": "C26001",
|
||||
"Vendor": "CAR2GO",
|
||||
"Country": "DE",
|
||||
"Name": "MemberCard",
|
||||
"Description": "CAR2GO - Member Card",
|
||||
"Type": "carsharing"
|
||||
},
|
||||
{
|
||||
"AID": "2F81F4",
|
||||
"Vendor": "Gallagher",
|
||||
"Country": "NZ",
|
||||
"Name": "Access control",
|
||||
"Description": "Card Application Directory (CAD)",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "2081F4",
|
||||
"Vendor": "Gallagher",
|
||||
"Country": "NZ",
|
||||
"Name": "Access control",
|
||||
"Description": "Cardax Card Data Application",
|
||||
"Type": ""
|
||||
}
|
||||
]
|
||||
|
|
133
client/src/aiddesfire.c
Normal file
133
client/src/aiddesfire.c
Normal file
|
@ -0,0 +1,133 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// AID DESFire functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "aiddesfire.h"
|
||||
#include "pm3_cmd.h"
|
||||
#include "fileutils.h"
|
||||
#include "jansson.h"
|
||||
|
||||
static json_t *df_known_aids = NULL;
|
||||
|
||||
static int open_aiddf_file(json_t **root, bool verbose) {
|
||||
|
||||
char *path;
|
||||
int res = searchFile(&path, RESOURCES_SUBDIR, "aid_desfire", ".json", true);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
int retval = PM3_SUCCESS;
|
||||
json_error_t error;
|
||||
|
||||
*root = json_load_file(path, 0, &error);
|
||||
if (!*root) {
|
||||
PrintAndLogEx(ERR, "json (%s) error on line %d: %s", path, error.line, error.text);
|
||||
retval = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!json_is_array(*root)) {
|
||||
PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", path);
|
||||
retval = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "Loaded file " _YELLOW_("`%s`") " (%s) %zu records.", path, _GREEN_("ok"), json_array_size(*root));
|
||||
out:
|
||||
free(path);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int close_aiddf_file(json_t *root) {
|
||||
json_decref(root);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static const char *aiddf_json_get_str(json_t *data, const char *name) {
|
||||
|
||||
json_t *jstr = json_object_get(data, name);
|
||||
if (jstr == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!json_is_string(jstr)) {
|
||||
PrintAndLogEx(WARNING, _YELLOW_("`%s`") " is not a string", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *cstr = json_string_value(jstr);
|
||||
if (strlen(cstr) == 0)
|
||||
return NULL;
|
||||
|
||||
return cstr;
|
||||
}
|
||||
|
||||
static int print_aiddf_description(json_t *root, uint8_t aid[3], char *fmt, bool verbose) {
|
||||
char laid[7] = {0};
|
||||
sprintf(laid, "%02x%02x%02x", aid[2], aid[1], aid[0]); // must be lowercase
|
||||
|
||||
json_t *elm = NULL;
|
||||
|
||||
for (uint32_t idx = 0; idx < json_array_size(root); idx++) {
|
||||
json_t *data = json_array_get(root, idx);
|
||||
if (!json_is_object(data)) {
|
||||
PrintAndLogEx(ERR, "data [%d] is not an object\n", idx);
|
||||
continue;
|
||||
}
|
||||
const char *faid = aiddf_json_get_str(data, "AID");
|
||||
char lfaid[strlen(faid) + 1];
|
||||
strcpy(lfaid, faid);
|
||||
str_lower(lfaid);
|
||||
if (strcmp(laid, lfaid) == 0) {
|
||||
elm = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (elm == NULL) {
|
||||
PrintAndLogEx(INFO, fmt, " (unknown)");
|
||||
return PM3_ENODATA;
|
||||
}
|
||||
const char *vaid = aiddf_json_get_str(elm, "AID");
|
||||
const char *vendor = aiddf_json_get_str(elm, "Vendor");
|
||||
const char *country = aiddf_json_get_str(elm, "Country");
|
||||
const char *name = aiddf_json_get_str(elm, "Name");
|
||||
const char *description = aiddf_json_get_str(elm, "Description");
|
||||
const char *type = aiddf_json_get_str(elm, "Type");
|
||||
|
||||
if (name && vendor) {
|
||||
char result[4 + strlen(name) + strlen(vendor)];
|
||||
sprintf(result, " %s [%s]", name, vendor);
|
||||
PrintAndLogEx(INFO, fmt, result);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, " AID: %s", vaid);
|
||||
if (name)
|
||||
PrintAndLogEx(SUCCESS, " Name: %s", name);
|
||||
if (description)
|
||||
PrintAndLogEx(SUCCESS, " Description: %s", description);
|
||||
if (type)
|
||||
PrintAndLogEx(SUCCESS, " Type: %s", type);
|
||||
if (vendor)
|
||||
PrintAndLogEx(SUCCESS, " Vendor: %s", vendor);
|
||||
if (country)
|
||||
PrintAndLogEx(SUCCESS, " Country: %s", country);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int AIDDFDecodeAndPrint(uint8_t aid[3]) {
|
||||
open_aiddf_file(&df_known_aids, false);
|
||||
|
||||
char fmt[50];
|
||||
sprintf(fmt, " DF AID Function %02X%02X%02X :" _YELLOW_("%s"), aid[2], aid[1], aid[0], "%s");
|
||||
print_aiddf_description(df_known_aids, aid, fmt, false);
|
||||
close_aiddf_file(df_known_aids);
|
||||
return PM3_SUCCESS;
|
||||
}
|
16
client/src/aiddesfire.h
Normal file
16
client/src/aiddesfire.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// AID DESFire functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _AIDDESFIRE_H_
|
||||
#define _AIDDESFIRE_H_
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int AIDDFDecodeAndPrint(uint8_t aid[3]);
|
||||
|
||||
#endif // _AIDDESFIRE_H_
|
|
@ -398,19 +398,64 @@ static int CmdSetDebugMode(const char *Cmd) {
|
|||
//by marshmellow
|
||||
// max output to 512 bits if we have more
|
||||
// doesn't take inconsideration where the demod offset or bitlen found.
|
||||
void printDemodBuff(void) {
|
||||
int len = DemodBufferLen;
|
||||
if (len < 1) {
|
||||
PrintAndLogEx(INFO, "(printDemodBuff) no bits found in demod buffer");
|
||||
return;
|
||||
int printDemodBuff(uint8_t offset, bool strip_leading, bool invert, bool print_hex) {
|
||||
size_t len = DemodBufferLen;
|
||||
if (len == 0) {
|
||||
PrintAndLogEx(WARNING, "Demodbuffer is empty");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (len > 512) len = 512;
|
||||
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_bin_break(DemodBuffer, len, 32));
|
||||
uint8_t *buf = NULL;
|
||||
|
||||
if (strip_leading) {
|
||||
buf = (DemodBuffer + offset);
|
||||
|
||||
if (len > (DemodBufferLen - offset))
|
||||
len = (DemodBufferLen - offset);
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (buf[i] == 1) break;
|
||||
}
|
||||
offset += i;
|
||||
}
|
||||
|
||||
if (len > (DemodBufferLen - offset)) {
|
||||
len = (DemodBufferLen - offset);
|
||||
}
|
||||
|
||||
if (len > 512) {
|
||||
len = 512;
|
||||
}
|
||||
|
||||
if (invert) {
|
||||
buf = (DemodBuffer + offset);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (buf[i] == 1)
|
||||
buf[i] = 0;
|
||||
else {
|
||||
if (buf[i] == 0)
|
||||
buf[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (print_hex) {
|
||||
buf = (DemodBuffer + offset);
|
||||
char hex[512] = {0x00};
|
||||
int num_bits = binarraytohex(hex, sizeof(hex), (char *)buf, len);
|
||||
if (num_bits == 0) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "DemodBuffer: %s", hex);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "DemodBuffer:\n%s", sprint_bin_break(DemodBuffer + offset, len, 32));
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdPrintDemodBuff(const char *Cmd) {
|
||||
bool hexMode = false;
|
||||
bool print_hex = false;
|
||||
bool errors = false;
|
||||
bool lstrip = false;
|
||||
bool invert = false;
|
||||
|
@ -422,7 +467,7 @@ int CmdPrintDemodBuff(const char *Cmd) {
|
|||
case 'h':
|
||||
return usage_data_printdemodbuf();
|
||||
case 'x':
|
||||
hexMode = true;
|
||||
print_hex = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'o':
|
||||
|
@ -452,45 +497,7 @@ int CmdPrintDemodBuff(const char *Cmd) {
|
|||
//Validations
|
||||
if (errors) return usage_data_printdemodbuf();
|
||||
|
||||
if (DemodBufferLen == 0) {
|
||||
PrintAndLogEx(WARNING, "Demodbuffer is empty");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if (lstrip) {
|
||||
char *buf = (char *)(DemodBuffer + offset);
|
||||
length = (length > (DemodBufferLen - offset)) ? DemodBufferLen - offset : length;
|
||||
uint32_t i;
|
||||
for (i = 0; i < length; i++) {
|
||||
if (buf[i] == 1) break;
|
||||
}
|
||||
offset += i;
|
||||
}
|
||||
length = (length > (DemodBufferLen - offset)) ? DemodBufferLen - offset : length;
|
||||
|
||||
if (invert) {
|
||||
char *buf = (char *)(DemodBuffer + offset);
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
if (buf[i] == 1)
|
||||
buf[i] = 0;
|
||||
else {
|
||||
if (buf[i] == 0)
|
||||
buf[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hexMode) {
|
||||
char *buf = (char *)(DemodBuffer + offset);
|
||||
char hex[512] = {0x00};
|
||||
int numBits = binarraytohex(hex, sizeof(hex), buf, length);
|
||||
if (numBits == 0) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "DemodBuffer: %s", hex);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "DemodBuffer:\n%s", sprint_bin_break(DemodBuffer + offset, length, 32));
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
return printDemodBuff(offset, lstrip, invert, print_hex);
|
||||
}
|
||||
|
||||
//by marshmellow
|
||||
|
@ -596,7 +603,7 @@ int ASKDemod_ext(int clk, int invert, int maxErr, size_t maxLen, bool amplify, b
|
|||
else
|
||||
PrintAndLogEx(DEBUG, "ASK/Raw - Clock: %d - Decoded bitstream:", clk);
|
||||
|
||||
printDemodBuff();
|
||||
printDemodBuff(0, false, false, false);
|
||||
}
|
||||
uint64_t lo = 0;
|
||||
uint32_t hi = 0;
|
||||
|
@ -792,7 +799,7 @@ int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose) {
|
|||
setClockGrid(clk, startIdx + clk * offset / 2);
|
||||
if (g_debugMode || verbose) {
|
||||
PrintAndLogEx(DEBUG, "Biphase Decoded using offset %d | clock %d | #errors %d | start index %d\ndata\n", offset, clk, errCnt, (startIdx + clk * offset / 2));
|
||||
printDemodBuff();
|
||||
printDemodBuff(offset, false, false, false);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1204,7 +1211,7 @@ int FSKrawDemod(uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow, bo
|
|||
if (verbose || g_debugMode) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: (FSKrawDemod) Using Clock:%u, invert:%u, fchigh:%u, fclow:%u", rfLen, invert, fchigh, fclow);
|
||||
PrintAndLogEx(NORMAL, "%s decoded bitstream:", GetFSKType(fchigh, fclow, invert));
|
||||
printDemodBuff();
|
||||
printDemodBuff(0, false, invert, false);
|
||||
}
|
||||
goto out;
|
||||
} else {
|
||||
|
@ -1327,7 +1334,7 @@ int NRZrawDemod(int clk, int invert, int maxErr, bool verbose) {
|
|||
if (verbose || g_debugMode) {
|
||||
PrintAndLogEx(NORMAL, "NRZ demoded bitstream:");
|
||||
// Now output the bitstream to the scrollback by line of 16 bits
|
||||
printDemodBuff();
|
||||
printDemodBuff(0, false, invert, false);
|
||||
}
|
||||
|
||||
free(bits);
|
||||
|
@ -1352,14 +1359,14 @@ static int CmdNRZrawDemod(const char *Cmd) {
|
|||
}
|
||||
|
||||
// by marshmellow
|
||||
// takes 3 arguments - clock, invert, maxErr as integers
|
||||
// takes 3 arguments - clock, invert, max_err as integers
|
||||
// attempts to demodulate psk only
|
||||
// prints binary found and saves in demodbuffer for further commands
|
||||
int CmdPSK1rawDemod(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_p1();
|
||||
int clk = 0, invert = 0, maxErr = 100;
|
||||
sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr);
|
||||
int clk = 0, invert = 0, max_err = 100;
|
||||
sscanf(Cmd, "%i %i %i", &clk, &invert, &max_err);
|
||||
if (clk == 1) {
|
||||
invert = 1;
|
||||
clk = 0;
|
||||
|
@ -1368,7 +1375,7 @@ int CmdPSK1rawDemod(const char *Cmd) {
|
|||
PrintAndLogEx(WARNING, "Invalid value for invert: %i", invert);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
int ans = PSKDemod(clk, invert, maxErr, true);
|
||||
int ans = PSKDemod(clk, invert, max_err, true);
|
||||
//output
|
||||
if (ans != PM3_SUCCESS) {
|
||||
if (g_debugMode) PrintAndLogEx(ERR, "Error demoding: %d", ans);
|
||||
|
@ -1376,7 +1383,7 @@ int CmdPSK1rawDemod(const char *Cmd) {
|
|||
}
|
||||
PrintAndLogEx(NORMAL, "PSK1 demoded bitstream:");
|
||||
// Now output the bitstream to the scrollback by line of 16 bits
|
||||
printDemodBuff();
|
||||
printDemodBuff(0, false, invert, false);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1385,8 +1392,8 @@ int CmdPSK1rawDemod(const char *Cmd) {
|
|||
static int CmdPSK2rawDemod(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_p2();
|
||||
int clk = 0, invert = 0, maxErr = 100;
|
||||
sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr);
|
||||
int clk = 0, invert = 0, max_err = 100;
|
||||
sscanf(Cmd, "%i %i %i", &clk, &invert, &max_err);
|
||||
if (clk == 1) {
|
||||
invert = 1;
|
||||
clk = 0;
|
||||
|
@ -1395,7 +1402,7 @@ static int CmdPSK2rawDemod(const char *Cmd) {
|
|||
PrintAndLogEx(WARNING, "Invalid value for invert: %i", invert);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
int ans = PSKDemod(clk, invert, maxErr, true);
|
||||
int ans = PSKDemod(clk, invert, max_err, true);
|
||||
if (ans != PM3_SUCCESS) {
|
||||
if (g_debugMode) PrintAndLogEx(ERR, "Error demoding: %d", ans);
|
||||
return PM3_ESOFT;
|
||||
|
@ -1403,7 +1410,7 @@ static int CmdPSK2rawDemod(const char *Cmd) {
|
|||
psk1TOpsk2(DemodBuffer, DemodBufferLen);
|
||||
PrintAndLogEx(NORMAL, "PSK2 demoded bitstream:");
|
||||
// Now output the bitstream to the scrollback by line of 16 bits
|
||||
printDemodBuff();
|
||||
printDemodBuff(0, false, invert, false);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1645,6 +1652,7 @@ int CmdTuneSamples(const char *Cmd) {
|
|||
|
||||
int timeout = 0;
|
||||
int timeout_max = 20;
|
||||
PrintAndLogEx(INFO, "REMINDER: " _YELLOW_("'hw tune' doesn't actively tune your antennas") ", it's only informative");
|
||||
PrintAndLogEx(INFO, "Measuring antenna characteristics, please wait...");
|
||||
|
||||
clearCommandBuffer();
|
||||
|
|
|
@ -68,7 +68,8 @@ int PSKDemod(int clk, int invert, int maxErr, bool verbose);
|
|||
int NRZrawDemod(int clk, int invert, int maxErr, bool verbose); // used by cmd lf pac, lf t55xx
|
||||
|
||||
|
||||
void printDemodBuff(void);
|
||||
int printDemodBuff(uint8_t offset, bool strip_leading, bool invert, bool print_hex);
|
||||
|
||||
void setDemodBuff(uint8_t *buff, size_t size, size_t start_idx);
|
||||
bool getDemodBuff(uint8_t *buff, size_t *size);
|
||||
void save_restoreDB(uint8_t saveOpt);// option '1' to save DemodBuffer any other to restore
|
||||
|
|
|
@ -57,7 +57,7 @@ static int usage_hf_search(void) {
|
|||
}
|
||||
|
||||
static int usage_hf_sniff(void) {
|
||||
PrintAndLogEx(NORMAL, "The high frequence sniffer will assign all available memory on device for sniffed data");
|
||||
PrintAndLogEx(NORMAL, "The high frequency sniffer will assign all available memory on device for sniffed data");
|
||||
PrintAndLogEx(NORMAL, "Use " _YELLOW_("'data samples'")" command to download from device, and " _YELLOW_("'data plot'")" to look at it");
|
||||
PrintAndLogEx(NORMAL, "Press button to quit the sniffing.\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf sniff <skip pairs> <skip triggers>");
|
||||
|
@ -311,18 +311,7 @@ int CmdHFSniff(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdHFPlot(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf plot",
|
||||
"Plots HF signal after RF signal path and A/D conversion.",
|
||||
"This can be used after any hf command and will show the last few milliseconds of the HF signal.\n"
|
||||
"Note: If the last hf command terminated because of a timeout you will most probably see nothing.\n");
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
int handle_hf_plot(void) {
|
||||
|
||||
uint8_t buf[FPGA_TRACE_SIZE];
|
||||
|
||||
|
@ -333,7 +322,7 @@ int CmdHFPlot(const char *Cmd) {
|
|||
}
|
||||
|
||||
for (size_t i = 0; i < FPGA_TRACE_SIZE; i++) {
|
||||
GraphBuffer[i] = ((int)buf[i]) - 127;
|
||||
GraphBuffer[i] = ((int)buf[i]) - 128;
|
||||
}
|
||||
|
||||
GraphTraceLen = FPGA_TRACE_SIZE;
|
||||
|
@ -349,14 +338,31 @@ int CmdHFPlot(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdHFPlot(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf plot",
|
||||
"Plots HF signal after RF signal path and A/D conversion.",
|
||||
"This can be used after any hf command and will show the last few milliseconds of the HF signal.\n"
|
||||
"Note: If the last hf command terminated because of a timeout you will most probably see nothing.\n");
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
return handle_hf_plot();
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
|
||||
{"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("High Frequency") " -----------------------"},
|
||||
{"14a", CmdHF14A, AlwaysAvailable, "{ ISO14443A RFIDs... }"},
|
||||
{"14b", CmdHF14B, AlwaysAvailable, "{ ISO14443B RFIDs... }"},
|
||||
{"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"},
|
||||
// {"cryptorf", CmdHFCryptoRF, AlwaysAvailable, "{ CryptoRF RFIDs... }"},
|
||||
{"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"},
|
||||
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / Felica RFIDs... }"},
|
||||
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"},
|
||||
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
|
||||
{"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"},
|
||||
{"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"},
|
||||
|
@ -369,6 +375,8 @@ static command_t CommandTable[] = {
|
|||
{"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
|
||||
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
|
||||
{"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"},
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdTraceList, AlwaysAvailable, "List protocol data in trace buffer"},
|
||||
{"plot", CmdHFPlot, IfPm3Hfplot, "Plot signal"},
|
||||
{"tune", CmdHFTune, IfPm3Present, "Continuously measure HF antenna tuning"},
|
||||
|
|
|
@ -19,4 +19,5 @@ int CmdHFSearch(const char *Cmd);
|
|||
int CmdHFSniff(const char *Cmd);
|
||||
int CmdHFPlot(const char *Cmd);
|
||||
|
||||
int handle_hf_plot(void);
|
||||
#endif
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
#include "crc16.h"
|
||||
#include "util_posix.h" // msclock
|
||||
#include "aidsearch.h"
|
||||
#include "cmdhf.h" // handle HF plot
|
||||
#include "protocols.h" // MAGIC_GEN_1A
|
||||
#include "emv/dump.h" // dump_buffer
|
||||
|
||||
bool APDUInFramingEnable = true;
|
||||
|
||||
|
@ -208,8 +211,7 @@ static int usage_hf_14a_config(void) {
|
|||
}
|
||||
|
||||
static int usage_hf_14a_sim(void) {
|
||||
// PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n");
|
||||
PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 byte UID\n");
|
||||
PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14a sim [h] t <type> u <uid> [x] [e] [v]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
|
@ -223,8 +225,7 @@ static int usage_hf_14a_sim(void) {
|
|||
PrintAndLogEx(NORMAL, " 8 = MIFARE Classic 4k");
|
||||
PrintAndLogEx(NORMAL, " 9 = FM11RF005SH Shanghai Metro");
|
||||
PrintAndLogEx(NORMAL, " 10 = JCOP 31/41 Rothult");
|
||||
// PrintAndLogEx(NORMAL, " u : 4, 7 or 10 byte UID");
|
||||
PrintAndLogEx(NORMAL, " u : 4, 7 byte UID");
|
||||
PrintAndLogEx(NORMAL, " u : 4, 7 or 10 byte UID");
|
||||
PrintAndLogEx(NORMAL, " x : (Optional) Performs the 'reader attack', nr/ar attack against a reader");
|
||||
PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys");
|
||||
PrintAndLogEx(NORMAL, " v : (Optional) Verbose");
|
||||
|
@ -232,7 +233,7 @@ static int usage_hf_14a_sim(void) {
|
|||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344 x"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344556677"));
|
||||
// PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223445566778899AA\n");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 112233445566778899AA"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_14a_sniff(void) {
|
||||
|
@ -265,6 +266,7 @@ static int usage_hf_14a_reader(void) {
|
|||
PrintAndLogEx(NORMAL, " s silent (no messages)");
|
||||
PrintAndLogEx(NORMAL, " x just drop the signal field");
|
||||
PrintAndLogEx(NORMAL, " 3 ISO14443-3 select only (skip RATS)");
|
||||
PrintAndLogEx(NORMAL, " @ continuous mode. Updates hf plot as well");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -475,9 +477,9 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) {
|
|||
static int CmdHF14AReader(const char *Cmd) {
|
||||
|
||||
uint32_t cm = ISO14A_CONNECT;
|
||||
bool disconnectAfter = true, silent = false;
|
||||
bool disconnectAfter = true, silent = false, continuous = false;
|
||||
int cmdp = 0;
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
|
@ -494,6 +496,9 @@ static int CmdHF14AReader(const char *Cmd) {
|
|||
case 'x':
|
||||
cm &= ~ISO14A_CONNECT;
|
||||
break;
|
||||
case '@':
|
||||
continuous = true;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown command.");
|
||||
return PM3_EINVARG;
|
||||
|
@ -503,60 +508,86 @@ static int CmdHF14AReader(const char *Cmd) {
|
|||
|
||||
if (!disconnectAfter)
|
||||
cm |= ISO14A_NO_DISCONNECT;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, NULL, 0);
|
||||
|
||||
if (ISO14A_CONNECT & cm) {
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
iso14a_card_select_t card;
|
||||
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
|
||||
|
||||
/*
|
||||
0: couldn't read
|
||||
1: OK, with ATS
|
||||
2: OK, no ATS
|
||||
3: proprietary Anticollision
|
||||
*/
|
||||
uint64_t select_status = resp.oldarg[0];
|
||||
|
||||
if (select_status == 0) {
|
||||
if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (select_status == 3) {
|
||||
PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision");
|
||||
PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card.atqa[1], card.atqa[0]);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
|
||||
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02x %02x"), card.atqa[1], card.atqa[0]);
|
||||
PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02x [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
|
||||
|
||||
if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
|
||||
PrintAndLogEx(SUCCESS, " ATS: " _GREEN_("%s"), sprint_hex(card.ats, card.ats_len));
|
||||
}
|
||||
|
||||
if (!disconnectAfter) {
|
||||
if (!silent) PrintAndLogEx(SUCCESS, "Card is selected. You can now start sending commands");
|
||||
}
|
||||
if (continuous) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("Enter") " to exit");
|
||||
}
|
||||
do {
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, NULL, 0);
|
||||
|
||||
if (ISO14A_CONNECT & cm) {
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed");
|
||||
DropField();
|
||||
res = PM3_ESOFT;
|
||||
goto plot;
|
||||
}
|
||||
|
||||
iso14a_card_select_t card;
|
||||
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
|
||||
|
||||
/*
|
||||
0: couldn't read
|
||||
1: OK, with ATS
|
||||
2: OK, no ATS
|
||||
3: proprietary Anticollision
|
||||
*/
|
||||
uint64_t select_status = resp.oldarg[0];
|
||||
|
||||
if (select_status == 0) {
|
||||
if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed");
|
||||
DropField();
|
||||
res = PM3_ESOFT;
|
||||
goto plot;
|
||||
}
|
||||
|
||||
if (select_status == 3) {
|
||||
if (!(silent && continuous)) {
|
||||
PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision");
|
||||
PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card.atqa[1], card.atqa[0]);
|
||||
}
|
||||
DropField();
|
||||
res = PM3_ESOFT;
|
||||
goto plot;
|
||||
}
|
||||
if (!(silent && continuous)) {
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
|
||||
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02x %02x"), card.atqa[1], card.atqa[0]);
|
||||
PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02x [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
|
||||
|
||||
if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
|
||||
PrintAndLogEx(SUCCESS, " ATS: " _GREEN_("%s"), sprint_hex(card.ats, card.ats_len));
|
||||
}
|
||||
}
|
||||
if (!disconnectAfter) {
|
||||
if (!silent) PrintAndLogEx(SUCCESS, "Card is selected. You can now start sending commands");
|
||||
}
|
||||
}
|
||||
plot:
|
||||
if (continuous) {
|
||||
res = handle_hf_plot();
|
||||
if (res != PM3_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (kbd_enter_pressed()) {
|
||||
break;
|
||||
}
|
||||
|
||||
} while (continuous);
|
||||
|
||||
if (disconnectAfter) {
|
||||
if (!silent) PrintAndLogEx(INFO, "field dropped.");
|
||||
if (silent == false) {
|
||||
PrintAndLogEx(INFO, "field dropped.");
|
||||
}
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
if (continuous)
|
||||
return PM3_SUCCESS;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdHF14AInfo(const char *Cmd) {
|
||||
|
@ -657,7 +688,9 @@ int CmdHF14ASim(const char *Cmd) {
|
|||
param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen);
|
||||
uidlen >>= 1;
|
||||
switch (uidlen) {
|
||||
//case 10: flags |= FLAG_10B_UID_IN_DATA; break;
|
||||
case 10:
|
||||
flags |= FLAG_10B_UID_IN_DATA;
|
||||
break;
|
||||
case 7:
|
||||
flags |= FLAG_7B_UID_IN_DATA;
|
||||
break;
|
||||
|
@ -1410,7 +1443,7 @@ static int CmdHF14AAntiFuzz(const char *Cmd) {
|
|||
|
||||
CLIParserFree(ctx);
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443A_ANTIFUZZ, (uint8_t*)¶m, sizeof(param));
|
||||
SendCommandNG(CMD_HF_ISO14443A_ANTIFUZZ, (uint8_t *)¶m, sizeof(param));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1459,96 +1492,132 @@ typedef enum {
|
|||
MTOTHER = 32
|
||||
} nxp_mifare_type_t;
|
||||
|
||||
// According to NXP AN10833 Rev 3.6 MIFARE Type Identification, Table 6
|
||||
static int detect_nxp_card(uint8_t sak, uint16_t atqa) {
|
||||
// Based on NXP AN10833 Rev 3.6 and NXP AN10834 Rev 4.1
|
||||
static int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) {
|
||||
int type = MTNONE;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Possible types:");
|
||||
|
||||
if (sak == 0x00) {
|
||||
printTag("NTAG 20x / 21x / 21x TT / I2C plus");
|
||||
printTag("MIFARE Ultralight / C / EV1 / Nano");
|
||||
type = MTULTRALIGHT;
|
||||
}
|
||||
|
||||
if (sak == 0x01) {
|
||||
printTag("TNP3xxx (Activision Game Appliance)");
|
||||
type = MTCLASSIC;
|
||||
}
|
||||
|
||||
if ((sak & 0x04) == 0x04) {
|
||||
printTag("Any MIFARE CL1 / NTAG424DNA");
|
||||
type |= MTDESFIRE;
|
||||
}
|
||||
|
||||
if ((sak & 0x08) == 0x08) {
|
||||
printTag("MIFARE Classic 1K / Classic 1K CL2");
|
||||
printTag("MIFARE Plus 2K / Plus EV1 2K");
|
||||
printTag("MIFARE Plus CL2 2K / Plus CL2 EV1 2K");
|
||||
type |= MTCLASSIC;
|
||||
type |= MTPLUS;
|
||||
}
|
||||
|
||||
if ((sak & 0x09) == 0x09) {
|
||||
printTag("MIFARE Mini 0.3K / Mini CL2 0.3K");
|
||||
type |= MTMINI;
|
||||
}
|
||||
|
||||
if ((sak & 0x10) == 0x10) {
|
||||
printTag("MIFARE Plus 2K / Plus CL2 2K");
|
||||
type |= MTPLUS;
|
||||
}
|
||||
|
||||
if ((sak & 0x11) == 0x11) {
|
||||
printTag("MIFARE Plus 4K / Plus CL2 4K");
|
||||
type |= MTPLUS;
|
||||
}
|
||||
|
||||
if ((sak & 0x18) == 0x18) {
|
||||
if (atqa == 0x0042) {
|
||||
printTag("MIFARE Plus 4K / Plus EV1 4K");
|
||||
printTag("MIFARE Plus CL2 4K / Plus CL2 EV1 4K");
|
||||
type |= MTPLUS;
|
||||
} else {
|
||||
printTag("MIFARE Classic 4K / Classic 4K CL2");
|
||||
if ((sak & 0x02) != 0x02) {
|
||||
if ((sak & 0x19) == 0x19) {
|
||||
printTag("MIFARE Classic 2K");
|
||||
type |= MTCLASSIC;
|
||||
}
|
||||
}
|
||||
} else if ((sak & 0x38) == 0x38) {
|
||||
printTag("SmartMX with MIFARE Classic 4K");
|
||||
type |= MTCLASSIC;
|
||||
} else if ((sak & 0x18) == 0x18) {
|
||||
if (select_status == 1) {
|
||||
if ((atqa & 0x0040) == 0x0040) {
|
||||
printTag("MIFARE Plus EV1 4K CL2 in SL1");
|
||||
printTag("MIFARE Plus S 4K CL2 in SL1");
|
||||
printTag("MIFARE Plus X 4K CL2 in SL1");
|
||||
} else {
|
||||
printTag("MIFARE Plus EV1 4K in SL1");
|
||||
printTag("MIFARE Plus S 4K in SL1");
|
||||
printTag("MIFARE Plus X 4K in SL1");
|
||||
}
|
||||
|
||||
if ((sak & 0x20) == 0x20) {
|
||||
if (atqa == 0x0344) {
|
||||
printTag("MIFARE DESFire MF3ICD40");
|
||||
printTag("MIFARE DESFire EV1 2K/4K/8K / DESFire EV1 CL2 2K/4K/8K");
|
||||
printTag("MIFARE NTAG424DNA");
|
||||
type |= MTPLUS;
|
||||
} else {
|
||||
if ((atqa & 0x0040) == 0x0040) {
|
||||
printTag("MIFARE Classic 4K CL2");
|
||||
} else {
|
||||
printTag("MIFARE Classic 4K");
|
||||
}
|
||||
|
||||
type |= MTCLASSIC;
|
||||
}
|
||||
} else if ((sak & 0x09) == 0x09) {
|
||||
if ((atqa & 0x0040) == 0x0040) {
|
||||
printTag("MIFARE Mini 0.3K CL2");
|
||||
} else {
|
||||
printTag("MIFARE Mini 0.3K");
|
||||
}
|
||||
|
||||
type |= MTMINI;
|
||||
} else if ((sak & 0x28) == 0x28) {
|
||||
printTag("SmartMX with MIFARE Classic 1K");
|
||||
type |= MTCLASSIC;
|
||||
} else if ((sak & 0x08) == 0x08) {
|
||||
if (select_status == 1) {
|
||||
if ((atqa & 0x0040) == 0x0040) {
|
||||
printTag("MIFARE Plus EV1 2K CL2 in SL1");
|
||||
printTag("MIFARE Plus S 2K CL2 in SL1");
|
||||
printTag("MIFARE Plus X 2K CL2 in SL1");
|
||||
printTag("MIFARE Plus SE 1K CL2");
|
||||
} else {
|
||||
printTag("MIFARE Plus EV1 2K in SL1");
|
||||
printTag("MIFARE Plus S 2K in SL1");
|
||||
printTag("MIFARE Plus X 2K in SL1");
|
||||
printTag("MIFARE Plus SE 1K");
|
||||
}
|
||||
|
||||
type |= MTPLUS;
|
||||
} else {
|
||||
if ((atqa & 0x0040) == 0x0040) {
|
||||
printTag("MIFARE Classic 1K CL2");
|
||||
} else {
|
||||
printTag("MIFARE Classic 1K");
|
||||
}
|
||||
|
||||
type |= MTCLASSIC;
|
||||
}
|
||||
} else if ((sak & 0x11) == 0x11) {
|
||||
printTag("MIFARE Plus 4K in SL2");
|
||||
type |= MTPLUS;
|
||||
} else if ((sak & 0x10) == 0x10) {
|
||||
printTag("MIFARE Plus 2K in SL2");
|
||||
type |= MTPLUS;
|
||||
} else if ((sak & 0x01) == 0x01) {
|
||||
printTag("TNP3xxx (TagNPlay, Activision Game Appliance)");
|
||||
type |= MTCLASSIC;
|
||||
} else if ((sak & 0x24) == 0x24) {
|
||||
printTag("MIFARE DESFire CL1");
|
||||
printTag("MIFARE DESFire EV1 CL1");
|
||||
type |= MTDESFIRE;
|
||||
} else if (atqa == 0x0304) {
|
||||
printTag("MIFARE NTAG424DNA (Random ID feature)");
|
||||
} else if ((sak & 0x20) == 0x20) {
|
||||
if (select_status == 1) {
|
||||
if ((atqa & 0x0040) == 0x0040) {
|
||||
if ((atqa & 0x0300) == 0x0300) {
|
||||
printTag("MIFARE DESFire CL2");
|
||||
printTag("MIFARE DESFire EV1 256B/2K/4K/8K CL2");
|
||||
printTag("MIFARE DESFire EV2 2K/4K/8K/16K/32K");
|
||||
printTag("MIFARE DESFire Light 640B");
|
||||
} else {
|
||||
printTag("MIFARE Plus EV1 2K/4K CL2 in SL3");
|
||||
printTag("MIFARE Plus S 2K/4K CL2 in SL3");
|
||||
printTag("MIFARE Plus X 2K/4K CL2 in SL3");
|
||||
printTag("MIFARE Plus SE 1K CL2");
|
||||
type |= MTPLUS;
|
||||
}
|
||||
} else {
|
||||
printTag("MIFARE Plus EV1 2K/4K in SL3");
|
||||
printTag("MIFARE Plus S 2K/4K in SL3");
|
||||
printTag("MIFARE Plus X 2K/4K in SL3");
|
||||
printTag("MIFARE Plus SE 1K");
|
||||
type |= MTPLUS;
|
||||
}
|
||||
|
||||
printTag("NTAG 4xx");
|
||||
type |= MTDESFIRE;
|
||||
}
|
||||
} else if ((sak & 0x04) == 0x04) {
|
||||
printTag("Any MIFARE CL1");
|
||||
type |= MTDESFIRE;
|
||||
} else {
|
||||
printTag("MIFARE Plus 2K/4K / Plus EV1 2K/4K");
|
||||
printTag("MIFARE Plus CL2 2K/4K / Plus CL2 EV1 2K/4K");
|
||||
type |= MTPLUS;
|
||||
}
|
||||
}
|
||||
|
||||
if ((sak & 0x24) == 0x24) {
|
||||
if (atqa == 0x0344) {
|
||||
printTag("MIFARE DESFire CL1 / DESFire EV1 CL1");
|
||||
type |= MTDESFIRE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((sak & 0x28) == 0x28) {
|
||||
if (atqa == 0x0344) {
|
||||
printTag("MIFARE DESFire CL1 / DESFire EV1 CL1");
|
||||
type |= MTDESFIRE;
|
||||
printTag("MIFARE Ultralight");
|
||||
printTag("MIFARE Ultralight C");
|
||||
printTag("MIFARE Ultralight EV1");
|
||||
printTag("MIFARE Ultralight Nano");
|
||||
printTag("MIFARE Hospitality");
|
||||
printTag("NTAG 2xx");
|
||||
type |= MTULTRALIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == MTNONE) {
|
||||
PrintAndLogEx(WARNING, " failed to fingerprint");
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -1634,7 +1703,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
int nxptype = MTNONE;
|
||||
|
||||
if (card.uidlen <= 4) {
|
||||
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]));
|
||||
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status);
|
||||
|
||||
isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC);
|
||||
isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE);
|
||||
|
@ -1654,7 +1723,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
isST = true;
|
||||
break;
|
||||
case 0x04: // NXP
|
||||
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]));
|
||||
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status);
|
||||
|
||||
isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC);
|
||||
isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE);
|
||||
|
@ -1770,34 +1839,38 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
}
|
||||
|
||||
if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
|
||||
|
||||
PrintAndLogEx(INFO, "-------------------------- " _CYAN_("ATS") " --------------------------");
|
||||
bool ta1 = 0, tb1 = 0, tc1 = 0;
|
||||
int pos;
|
||||
|
||||
if (select_status == 2) {
|
||||
PrintAndLogEx(INFO, "SAK incorrectly claims that card doesn't support RATS");
|
||||
PrintAndLogEx(INFO, "--> SAK incorrectly claims that card doesn't support RATS <--");
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, " ATS: %s", sprint_hex(card.ats, card.ats_len));
|
||||
PrintAndLogEx(SUCCESS, " - TL : length is %d bytes", card.ats[0]);
|
||||
|
||||
if (card.ats[0] != card.ats_len - 2) {
|
||||
PrintAndLogEx(SUCCESS, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len);
|
||||
PrintAndLogEx(WARNING, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "ATS: " _YELLOW_("%s")"[ %02x %02x ]", sprint_hex(card.ats, card.ats_len - 2), card.ats[card.ats_len - 1], card.ats[card.ats_len]);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02x") "............... TL length is " _GREEN_("%d") " bytes", card.ats[0], card.ats[0]);
|
||||
|
||||
if (card.ats[0] > 1) { // there is a format byte (T0)
|
||||
ta1 = (card.ats[1] & 0x10) == 0x10;
|
||||
tb1 = (card.ats[1] & 0x20) == 0x20;
|
||||
tc1 = (card.ats[1] & 0x40) == 0x40;
|
||||
int16_t fsci = card.ats[1] & 0x0f;
|
||||
|
||||
PrintAndLogEx(SUCCESS, " - T0 : TA1 is%s present, TB1 is%s present, "
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ T0 TA1 is%s present, TB1 is%s present, "
|
||||
"TC1 is%s present, FSCI is %d (FSC = %d)",
|
||||
(ta1 ? "" : " NOT"),
|
||||
(tb1 ? "" : " NOT"),
|
||||
(tc1 ? "" : " NOT"),
|
||||
card.ats[1],
|
||||
(ta1 ? "" : _RED_(" NOT")),
|
||||
(tb1 ? "" : _RED_(" NOT")),
|
||||
(tc1 ? "" : _RED_(" NOT")),
|
||||
fsci,
|
||||
fsci < ARRAYLEN(atsFSC) ? atsFSC[fsci] : -1
|
||||
);
|
||||
}
|
||||
pos = 2;
|
||||
int pos = 2;
|
||||
if (ta1) {
|
||||
char dr[16], ds[16];
|
||||
dr[0] = ds[0] = '\0';
|
||||
|
@ -1809,19 +1882,23 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
if (card.ats[pos] & 0x04) strcat(dr, "8, ");
|
||||
if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0';
|
||||
if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0';
|
||||
PrintAndLogEx(SUCCESS, " - TA1 : different divisors are%s supported, "
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... TA1 different divisors are%s supported, "
|
||||
"DR: [%s], DS: [%s]",
|
||||
((card.ats[pos] & 0x80) ? " NOT" : ""),
|
||||
card.ats[pos],
|
||||
((card.ats[pos] & 0x80) ? _RED_(" NOT") : ""),
|
||||
dr,
|
||||
ds
|
||||
);
|
||||
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (tb1) {
|
||||
uint32_t sfgi = card.ats[pos] & 0x0F;
|
||||
uint32_t fwi = card.ats[pos] >> 4;
|
||||
PrintAndLogEx(SUCCESS, " - TB1 : SFGI = %d (SFGT = %s%d/fc), FWI = %d (FWT = %d/fc)",
|
||||
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... TB1 SFGI = %d (SFGT = %s%d/fc), FWI = " _YELLOW_("%d") " (FWT = %d/fc)",
|
||||
card.ats[pos],
|
||||
(sfgi),
|
||||
sfgi ? "" : "(not needed) ",
|
||||
sfgi ? (1 << 12) << sfgi : 0,
|
||||
|
@ -1832,31 +1909,39 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
}
|
||||
|
||||
if (tc1) {
|
||||
PrintAndLogEx(SUCCESS, " - TC1 : NAD is%s supported, CID is%s supported",
|
||||
(card.ats[pos] & 0x01) ? "" : " NOT",
|
||||
(card.ats[pos] & 0x02) ? "" : " NOT");
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... TC1 NAD is%s supported, CID is%s supported",
|
||||
card.ats[pos],
|
||||
(card.ats[pos] & 0x01) ? "" : _RED_(" NOT"),
|
||||
(card.ats[pos] & 0x02) ? "" : _RED_(" NOT")
|
||||
);
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (card.ats[0] > pos && card.ats[0] < card.ats_len - 2) {
|
||||
const char *tip = "";
|
||||
// ATS - Historial bytes and identify based on it
|
||||
if (card.ats[0] > pos && card.ats[0] <= card.ats_len - 2) {
|
||||
char tip[60];
|
||||
tip[0] = '\0';
|
||||
if (card.ats[0] - pos >= 7) {
|
||||
|
||||
snprintf(tip, sizeof(tip), " ");
|
||||
|
||||
if ((card.sak & 0x70) == 0x40) { // and no GetVersion()..
|
||||
|
||||
if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
|
||||
tip = "-> MIFARE Plus X 2K/4K (SL3)";
|
||||
snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus X 2K/4K (SL3)");
|
||||
|
||||
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
|
||||
|
||||
if ((card.atqa[0] & 0x02) == 0x02)
|
||||
tip = "-> MIFARE Plus S 2K (SL3)";
|
||||
snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus S 2K (SL3)");
|
||||
else if ((card.atqa[0] & 0x04) == 0x04)
|
||||
tip = "-> MIFARE Plus S 4K (SL3)";
|
||||
snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus S 4K (SL3)");
|
||||
|
||||
} else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) {
|
||||
tip = "-> MIFARE Plus SE 1K (17pF)";
|
||||
snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus SE 1K (17pF)");
|
||||
|
||||
} else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) {
|
||||
tip = "-> MIFARE Plus SE 1K (70pF)";
|
||||
snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus SE 1K (70pF)");
|
||||
}
|
||||
|
||||
} else { //SAK B4,5,6
|
||||
|
@ -1865,37 +1950,41 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
|
||||
|
||||
if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
|
||||
tip = "-> MIFARE Plus X 2K (SL1)";
|
||||
snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus X 2K (SL1)");
|
||||
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
|
||||
tip = "-> MIFARE Plus S 2K (SL1)";
|
||||
snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus S 2K (SL1)");
|
||||
} else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) {
|
||||
tip = "-> MIFARE Plus SE 1K (17pF)";
|
||||
snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus SE 1K (17pF)");
|
||||
} else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) {
|
||||
tip = "-> MIFARE Plus SE 1K (70pF)";
|
||||
snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus SE 1K (70pF)");
|
||||
}
|
||||
} else {
|
||||
if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
|
||||
tip = "-> MIFARE Plus X 4K (SL1)";
|
||||
snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus X 4K (SL1)");
|
||||
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
|
||||
tip = "-> MIFARE Plus S 4K (SL1)";
|
||||
snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus S 4K (SL1)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip);
|
||||
|
||||
uint8_t calen = card.ats[0] - pos;
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "-------------------- " _CYAN_("Historical bytes") " --------------------");
|
||||
|
||||
if (card.ats[pos] == 0xC1) {
|
||||
PrintAndLogEx(SUCCESS, " c1 -> Mifare or (multiple) virtual cards of various type");
|
||||
PrintAndLogEx(SUCCESS, " %02x -> Length is %d bytes", card.ats[pos + 1], card.ats[pos + 1]);
|
||||
PrintAndLogEx(INFO, " %s%s", sprint_hex(card.ats + pos, calen), tip);
|
||||
PrintAndLogEx(SUCCESS, " C1..................... Mifare or (multiple) virtual cards of various type");
|
||||
PrintAndLogEx(SUCCESS, " %02x.................. length is " _YELLOW_("%d") " bytes", card.ats[pos + 1], card.ats[pos + 1]);
|
||||
switch (card.ats[pos + 2] & 0xf0) {
|
||||
case 0x10:
|
||||
PrintAndLogEx(SUCCESS, " 1x -> MIFARE DESFire");
|
||||
PrintAndLogEx(SUCCESS, " 1x............... MIFARE DESFire");
|
||||
isMifareDESFire = true;
|
||||
isMifareClassic = false;
|
||||
isMifarePlus = false;
|
||||
break;
|
||||
case 0x20:
|
||||
PrintAndLogEx(SUCCESS, " 2x -> MIFARE Plus");
|
||||
PrintAndLogEx(SUCCESS, " 2x............... MIFARE Plus");
|
||||
isMifarePlus = true;
|
||||
isMifareDESFire = false;
|
||||
isMifareClassic = false;
|
||||
|
@ -1903,51 +1992,53 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
}
|
||||
switch (card.ats[pos + 2] & 0x0f) {
|
||||
case 0x00:
|
||||
PrintAndLogEx(SUCCESS, " x0 -> <1 kByte");
|
||||
PrintAndLogEx(SUCCESS, " x0............... < 1 kByte");
|
||||
break;
|
||||
case 0x01:
|
||||
PrintAndLogEx(SUCCESS, " x1 -> 1 kByte");
|
||||
PrintAndLogEx(SUCCESS, " x1............... 1 kByte");
|
||||
break;
|
||||
case 0x02:
|
||||
PrintAndLogEx(SUCCESS, " x2 -> 2 kByte");
|
||||
PrintAndLogEx(SUCCESS, " x2............... 2 kByte");
|
||||
break;
|
||||
case 0x03:
|
||||
PrintAndLogEx(SUCCESS, " x3 -> 4 kByte");
|
||||
PrintAndLogEx(SUCCESS, " x3............... 4 kByte");
|
||||
break;
|
||||
case 0x04:
|
||||
PrintAndLogEx(SUCCESS, " x4 -> 8 kByte");
|
||||
PrintAndLogEx(SUCCESS, " x4............... 8 kByte");
|
||||
break;
|
||||
}
|
||||
switch (card.ats[pos + 3] & 0xf0) {
|
||||
case 0x00:
|
||||
PrintAndLogEx(SUCCESS, " 0x -> Engineering sample");
|
||||
PrintAndLogEx(SUCCESS, " 0x............ Engineering sample");
|
||||
break;
|
||||
case 0x20:
|
||||
PrintAndLogEx(SUCCESS, " 2x -> Released");
|
||||
PrintAndLogEx(SUCCESS, " 2x............ Released");
|
||||
break;
|
||||
}
|
||||
switch (card.ats[pos + 3] & 0x0f) {
|
||||
case 0x00:
|
||||
PrintAndLogEx(SUCCESS, " x0 -> Generation 1");
|
||||
PrintAndLogEx(SUCCESS, " x0............ Generation 1");
|
||||
break;
|
||||
case 0x01:
|
||||
PrintAndLogEx(SUCCESS, " x1 -> Generation 2");
|
||||
PrintAndLogEx(SUCCESS, " x1............ Generation 2");
|
||||
break;
|
||||
case 0x02:
|
||||
PrintAndLogEx(SUCCESS, " x2 -> Generation 3");
|
||||
PrintAndLogEx(SUCCESS, " x2............ Generation 3");
|
||||
break;
|
||||
}
|
||||
switch (card.ats[pos + 4] & 0x0f) {
|
||||
case 0x00:
|
||||
PrintAndLogEx(SUCCESS, " x0 -> Only VCSL supported");
|
||||
PrintAndLogEx(SUCCESS, " x0......... Only VCSL supported");
|
||||
break;
|
||||
case 0x01:
|
||||
PrintAndLogEx(SUCCESS, " x1 -> VCS, VCSL, and SVC supported");
|
||||
PrintAndLogEx(SUCCESS, " x1......... VCS, VCSL, and SVC supported");
|
||||
break;
|
||||
case 0x0E:
|
||||
PrintAndLogEx(SUCCESS, " xE -> no VCS command supported");
|
||||
PrintAndLogEx(SUCCESS, " xE......... no VCS command supported");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
dump_buffer(&card.ats[pos], calen, NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2019,7 +2110,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
} else {
|
||||
PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported");
|
||||
if ((card.sak & 0x20) == 0x20) {
|
||||
PrintAndLogEx(INFO, "SAK incorrectly claims that card supports RATS");
|
||||
PrintAndLogEx(INFO, "--> SAK incorrectly claims that card supports RATS <--");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2028,7 +2119,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
isMagic = detect_mf_magic(true);
|
||||
}
|
||||
if (isMifareUltralight) {
|
||||
isMagic = detect_mf_magic(false);
|
||||
isMagic = (detect_mf_magic(false) == MAGIC_NTAG21X);
|
||||
}
|
||||
if (isMifareClassic) {
|
||||
int res = detect_classic_static_nonce();
|
||||
|
@ -2066,6 +2157,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
if (isST)
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf st info`"));
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
DropField();
|
||||
return select_status;
|
||||
}
|
||||
|
|
|
@ -959,57 +959,68 @@ static int CmdHF14BReader(const char *Cmd) {
|
|||
return readHF14B(verbose);
|
||||
}
|
||||
|
||||
/* New command to read the contents of a SRI512|SRIX4K tag
|
||||
* SRI* tags are ISO14443-B modulated memory tags,
|
||||
* this command just dumps the contents of the memory/
|
||||
*/
|
||||
static int CmdHF14BReadSri(const char *Cmd) {
|
||||
// Read SRI512|SRIX4K block
|
||||
static int CmdHF14BSriRdBl(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sriread",
|
||||
"Read contents of a SRI512 | SRIX4K tag",
|
||||
"hf 14b sriread\n"
|
||||
CLIParserInit(&ctx, "hf 14b rdbl",
|
||||
"Read SRI512 | SRIX4K block",
|
||||
"hf 14b rdbl -b 06\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int0("b", "block", "<dec>", "block number"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
int blockno = arg_get_int_def(ctx, 1, -1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
iso14b_card_select_t card;
|
||||
if (get_14b_UID(&card) == false) {
|
||||
PrintAndLogEx(WARNING, "no tag found");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
/*
|
||||
iso14b_card_select_t card;
|
||||
if (get_14b_UID(&card) == false) {
|
||||
PrintAndLogEx(WARNING, "no tag found");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if (card.uidlen != 8) {
|
||||
PrintAndLogEx(FAILED, "current dump command only work with SRI4K / SRI512 tags");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
if (card.uidlen != 8) {
|
||||
PrintAndLogEx(FAILED, "current read command only work with SRI4K / SRI512 tags");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// detect cardsize
|
||||
// 1 = 4096
|
||||
// 2 = 512
|
||||
uint8_t cardtype = get_st_cardsize(card.uid);
|
||||
uint8_t blocks = (cardtype == 1) ? 0x7F : 0x0F;
|
||||
// detect cardsize
|
||||
// 1 = 4096
|
||||
// 2 = 512
|
||||
uint8_t cardtype = get_st_cardsize(card.uid);
|
||||
uint8_t blocks = (cardtype == 1) ? 0x7F : 0x0F;
|
||||
*/
|
||||
struct {
|
||||
uint8_t blockno;
|
||||
} PACKED payload;
|
||||
|
||||
payload.blockno = blockno;
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_SRI_READ, blocks, 0, 0, NULL, 0);
|
||||
|
||||
// iceman: should download read data and print in client.
|
||||
return PM3_SUCCESS;
|
||||
SendCommandNG(CMD_HF_SRI_READ, (uint8_t *)&payload, sizeof(payload));
|
||||
if (WaitForResponseTimeout(CMD_HF_SRI_READ, &resp, TIMEOUT) == false) {
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
if (resp.status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "block %02u : " _GREEN_("%s") " | " _GREEN_("%s"), blockno, sprint_hex(resp.data.asBytes, resp.length), sprint_ascii(resp.data.asBytes, resp.length));
|
||||
}
|
||||
return resp.status;
|
||||
}
|
||||
|
||||
// New command to write a SRI512/SRIX4K tag.
|
||||
static int CmdHF14BWriteSri(const char *Cmd) {
|
||||
/*
|
||||
* For SRIX4K blocks 00 - 7F
|
||||
* hf 14b raw -c -k 09 $srix4kwblock $srix4kwdata
|
||||
* hf 14b raw --sr -c --data [09 $srix4kwblock $srix4kwdata
|
||||
*
|
||||
* For SR512 blocks 00 - 0F
|
||||
* hf 14b raw -c -k 09 $sr512wblock $sr512wdata
|
||||
* hf 14b raw --sr -c --data [09 $sr512wblock $sr512wdata]
|
||||
*
|
||||
* Special block FF = otp_lock_reg block.
|
||||
* Data len 4 bytes-
|
||||
|
@ -1064,7 +1075,7 @@ static int CmdHF14BWriteSri(const char *Cmd) {
|
|||
);
|
||||
}
|
||||
|
||||
sprintf(str, "--ss -c %02x %02x %02x %02x %02x %02x", ISO14443B_WRITE_BLK, blockno, data[0], data[1], data[2], data[3]);
|
||||
sprintf(str, "--sr -c --data %02x%02x%02x%02x%02x%02x", ISO14443B_WRITE_BLK, blockno, data[0], data[1], data[2], data[3]);
|
||||
return CmdHF14BCmdRaw(str);
|
||||
}
|
||||
|
||||
|
@ -1787,7 +1798,7 @@ static command_t CommandTable[] = {
|
|||
{"reader", CmdHF14BReader, IfPm3Iso14443b, "Act as a 14443B reader to identify a tag"},
|
||||
{"sim", CmdHF14BSim, IfPm3Iso14443b, "Fake ISO 14443B tag"},
|
||||
{"sniff", CmdHF14BSniff, IfPm3Iso14443b, "Eavesdrop ISO 14443B"},
|
||||
{"sriread", CmdHF14BReadSri, IfPm3Iso14443b, "Read contents of a SRI512 | SRIX4K tag"},
|
||||
{"rdbl", CmdHF14BSriRdBl, IfPm3Iso14443b, "Read SRI512/SRIX4x block"},
|
||||
{"sriwrite", CmdHF14BWriteSri, IfPm3Iso14443b, "Write data to a SRI512 | SRIX4K tag"},
|
||||
// {"valid", srix4kValid, AlwaysAvailable, "srix4k checksum test"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
|
|
|
@ -1116,13 +1116,13 @@ static int CmdHF15Sim(const char *Cmd) {
|
|||
CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (uidlen != 9) {
|
||||
if (uidlen != 8) {
|
||||
PrintAndLogEx(WARNING, "UID must include 16 HEX symbols");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, payload.uid));
|
||||
PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel");
|
||||
PrintAndLogEx(INFO, "press " _YELLOW_("`Pm3 button`") " to cancel");
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
|
@ -1853,10 +1853,10 @@ static int CmdHF15Restore(const char *Cmd) {
|
|||
if (addressed_mode) {
|
||||
char uidhex[17] = {0x00};
|
||||
hex_to_buffer((uint8_t *)uidhex, uid, sizeof(uid), sizeof(uidhex) - 1, 0, false, true);
|
||||
hex_to_buffer((uint8_t *)hex, data + i, blocksize, sizeof(hex) - 1, 0, false, true);
|
||||
hex_to_buffer((uint8_t *)hex, data + bytes, blocksize, sizeof(hex) - 1, 0, false, true);
|
||||
snprintf(tmpCmd, sizeof(tmpCmd), "%s %s %u %s", newPrefix, uidhex, i, hex);
|
||||
} else {
|
||||
hex_to_buffer((uint8_t *)hex, data + i, blocksize, sizeof(hex) - 1, 0, false, true);
|
||||
hex_to_buffer((uint8_t *)hex, data + bytes, blocksize, sizeof(hex) - 1, 0, false, true);
|
||||
snprintf(tmpCmd, sizeof(tmpCmd), "%s u %u %s", newPrefix, i, hex);
|
||||
}
|
||||
|
||||
|
|
|
@ -66,22 +66,12 @@ static int usage_hf_iclass_sim(void) {
|
|||
PrintAndLogEx(NORMAL, " -- execute loclass attack online part");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass sim 2"));
|
||||
PrintAndLogEx(NORMAL, " -- simulate full iCLASS 2k tag");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass eload f hf-iclass-AA162D30F8FF12F1-dump.bin"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass eload -f hf-iclass-AA162D30F8FF12F1-dump.bin"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass sim 3"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_iclass_eload(void) {
|
||||
PrintAndLogEx(NORMAL, "Loads iCLASS tag dump into emulator memory on device\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf iclass eload [h] f <filename>\n");
|
||||
PrintAndLogEx(NORMAL, "Options");
|
||||
PrintAndLogEx(NORMAL, " h : Show this help");
|
||||
PrintAndLogEx(NORMAL, " f <filename> : filename of dump");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass eload f hf-iclass-AA162D30F8FF12F1-dump.bin"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_hf_iclass_esave(void) {
|
||||
PrintAndLogEx(NORMAL, "Save emulator memory to file.");
|
||||
PrintAndLogEx(NORMAL, "if not filename is supplied, CSN will be used.");
|
||||
|
@ -272,27 +262,6 @@ static int usage_hf_iclass_managekeys(void) {
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_iclass_loclass(void) {
|
||||
PrintAndLogEx(NORMAL, "Execute the offline part of loclass attack");
|
||||
PrintAndLogEx(NORMAL, " An iclass dumpfile is assumed to consist of an arbitrary number of");
|
||||
PrintAndLogEx(NORMAL, " malicious CSNs, and their protocol responses");
|
||||
PrintAndLogEx(NORMAL, " The binary format of the file is expected to be as follows: ");
|
||||
PrintAndLogEx(NORMAL, " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
|
||||
PrintAndLogEx(NORMAL, " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
|
||||
PrintAndLogEx(NORMAL, " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
|
||||
PrintAndLogEx(NORMAL, " ... totalling N*24 bytes\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf iclass loclass [h] [t [l]] [f <filename>]\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h Show this help");
|
||||
PrintAndLogEx(NORMAL, " t Perform self-test");
|
||||
PrintAndLogEx(NORMAL, " t l Perform self-test, including long ones");
|
||||
PrintAndLogEx(NORMAL, " f <filename> Bruteforce iclass dumpfile");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass loclass f iclass-dump.bin"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass loclass t"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_iclass_chk(void) {
|
||||
PrintAndLogEx(NORMAL, "Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf iclass chk [h|e|r] [f (*.dic)]\n");
|
||||
|
@ -561,7 +530,7 @@ static void mem_app_config(const picopass_hdr *hdr) {
|
|||
PrintAndLogEx(INFO, " Write A...... credit");
|
||||
PrintAndLogEx(INFO, " Write B...... credit");
|
||||
PrintAndLogEx(INFO, " Debit........ debit or credit");
|
||||
PrintAndLogEx(INFO, " redit........ credit");
|
||||
PrintAndLogEx(INFO, " Credit....... credit");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -715,7 +684,7 @@ static int CmdHFiClassSim(const char *Cmd) {
|
|||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
memset(dump, 0, datalen);//<-- Need zeroes for the EPURSE - field (offical)
|
||||
memset(dump, 0, datalen);//<-- Need zeroes for the EPURSE - field (official)
|
||||
|
||||
uint8_t i = 0;
|
||||
for (i = 0 ; i < NUM_CSNS ; i++) {
|
||||
|
@ -730,7 +699,7 @@ static int CmdHFiClassSim(const char *Cmd) {
|
|||
saveFile("iclass_mac_attack", ".bin", dump, datalen);
|
||||
free(dump);
|
||||
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass h") "` to recover elite key");
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -h") "` to recover elite key");
|
||||
break;
|
||||
}
|
||||
case ICLASS_SIM_MODE_READER_ATTACK_KEYROLL: {
|
||||
|
@ -796,7 +765,7 @@ static int CmdHFiClassSim(const char *Cmd) {
|
|||
saveFile("iclass_mac_attack_keyroll_B", ".bin", dump, datalen);
|
||||
free(dump);
|
||||
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass h") "` to recover elite key");
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -h") "` to recover elite key");
|
||||
break;
|
||||
}
|
||||
case ICLASS_SIM_MODE_CSN:
|
||||
|
@ -884,50 +853,54 @@ static int CmdHFiClassReader(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdHFiClassELoad(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf iclass eload",
|
||||
"Loads iCLASS tag dump into emulator memory on device",
|
||||
"hf iclass eload -f hf-iclass-AA162D30F8FF12F1-dump.bin\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("f", "file", "<filename>", "filename of dump"),
|
||||
arg_lit0(NULL, "json", "load JSON type dump"),
|
||||
arg_lit0(NULL, "eml", "load EML type dump"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
|
||||
if (strlen(filename) == 0) {
|
||||
PrintAndLogEx(ERR, "Error: Please specify a filename");
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
DumpFileType_t dftype = BIN;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_hf_iclass_eload();
|
||||
case 'f':
|
||||
if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) {
|
||||
PrintAndLogEx(FAILED, "Filename too long");
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'j':
|
||||
dftype = JSON;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'e':
|
||||
dftype = EML;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
|
||||
bool use_json = arg_get_lit(ctx, 2);
|
||||
bool use_eml = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (use_json && use_eml) {
|
||||
PrintAndLogEx(ERR, "Error: can't specify both JSON & EML");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
//Validations
|
||||
if (errors || cmdp == 0) {
|
||||
return usage_hf_iclass_eload();
|
||||
if (use_json) {
|
||||
dftype = JSON;
|
||||
} else if (use_eml) {
|
||||
dftype = EML;
|
||||
}
|
||||
|
||||
size_t bytes_read = 2048;
|
||||
uint8_t *dump = calloc(2048, sizeof(uint8_t));
|
||||
if (!dump) {
|
||||
PrintAndLogEx(ERR, "error, cannot allocate memory ");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
size_t bytes_read = 2048;
|
||||
int res = 0;
|
||||
|
||||
switch (dftype) {
|
||||
|
@ -943,10 +916,10 @@ static int CmdHFiClassELoad(const char *Cmd) {
|
|||
res = loadFileJSON(filename, dump, 2048, &bytes_read, NULL);
|
||||
break;
|
||||
}
|
||||
case DICTIONARY:
|
||||
PrintAndLogEx(ERR, "No dictionary loaded");
|
||||
free(dump);
|
||||
return PM3_ESOFT;
|
||||
case DICTIONARY: {
|
||||
PrintAndLogEx(ERR, "Error: Only BIN/JSON/EML formats allowed");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
}
|
||||
|
||||
if (res != PM3_SUCCESS) {
|
||||
|
@ -2249,7 +2222,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (auth == false && verbose) {
|
||||
PrintAndLogEx(WARNING, "warning: no authentication used with read. Typical for cards configured toin `non-secure page`");
|
||||
PrintAndLogEx(WARNING, "warning: no authentication used with read. Typical for cards configured into `non-secure page`");
|
||||
|
||||
}
|
||||
|
||||
|
@ -2325,26 +2298,42 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdHFiClass_loclass(const char *Cmd) {
|
||||
char opt = tolower(param_getchar(Cmd, 0));
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf iclass loclass",
|
||||
"Execute the offline part of loclass attack\n"
|
||||
" An iclass dumpfile is assumed to consist of an arbitrary number of\n"
|
||||
" malicious CSNs, and their protocol responses\n"
|
||||
" The binary format of the file is expected to be as follows: \n"
|
||||
" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>\n"
|
||||
" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>\n"
|
||||
" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>\n"
|
||||
" ... totalling N*24 bytes",
|
||||
"hf iclass loclass -f iclass-dump.bin\n"
|
||||
"hf iclass loclass --test");
|
||||
|
||||
if (strlen(Cmd) < 1 || opt == 'h')
|
||||
return usage_hf_iclass_loclass();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("f", "file", "<filename>", "filename of Bruteforce iclass dumpfile"),
|
||||
arg_lit0(NULL, "test", "Perform self-test"),
|
||||
arg_lit0(NULL, "long", "Perform self-test, including long ones"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
if (opt == 'f') {
|
||||
char fileName[FILE_PATH_SIZE] = {0};
|
||||
if (param_getstr(Cmd, 1, fileName, sizeof(fileName)) > 0) {
|
||||
return bruteforceFileNoKeys(fileName);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "You must specify a filename");
|
||||
return PM3_EFILE;
|
||||
}
|
||||
} else if (opt == 't') {
|
||||
char opt2 = tolower(param_getchar(Cmd, 1));
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
|
||||
bool test = arg_get_lit(ctx, 2);
|
||||
bool longtest = arg_get_lit(ctx, 3);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (test || longtest) {
|
||||
int errors = testCipherUtils();
|
||||
errors += testMAC();
|
||||
errors += doKeyTests();
|
||||
errors += testElite(opt2 == 'l');
|
||||
errors += testElite(longtest);
|
||||
|
||||
if (errors != PM3_SUCCESS)
|
||||
PrintAndLogEx(ERR, "There were errors!!!");
|
||||
|
@ -2352,7 +2341,7 @@ static int CmdHFiClass_loclass(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
return usage_hf_iclass_loclass();
|
||||
return bruteforceFileNoKeys(filename);
|
||||
}
|
||||
|
||||
void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize) {
|
||||
|
|
|
@ -419,7 +419,7 @@ void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool
|
|||
|
||||
uint8_t key[8];
|
||||
if (check_known_default(csn, epurse, rmac, tmac, key)) {
|
||||
snprintf(exp, size, "( " _GREEN_("%s") ")", sprint_hex(key, 8));
|
||||
snprintf(exp, size, "( " _GREEN_("%s") " )", sprint_hex_inrow(key, 8));
|
||||
}
|
||||
curr_state = PICO_NONE;
|
||||
}
|
||||
|
@ -1360,7 +1360,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
|
|||
AuthData.ks3 = AuthData.at_enc ^ prng_successor(AuthData.nt, 96);
|
||||
|
||||
mfLastKey = GetCrypto1ProbableKey(&AuthData);
|
||||
PrintAndLogEx(NORMAL, " | | * |%48s %012"PRIx64" prng %s | |",
|
||||
PrintAndLogEx(NORMAL, " | | * |%49s " _GREEN_("%012" PRIX64) " prng %s | |",
|
||||
"key",
|
||||
mfLastKey,
|
||||
validate_prng_nonce(AuthData.nt) ? _GREEN_("WEAK") : _YELLOW_("HARD"));
|
||||
|
@ -1377,7 +1377,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
|
|||
// check last used key
|
||||
if (mfLastKey) {
|
||||
if (NestedCheckKey(mfLastKey, &AuthData, cmd, cmdsize, parity)) {
|
||||
PrintAndLogEx(NORMAL, " | | * |%60s %012"PRIx64"| |", "last used key", mfLastKey);
|
||||
PrintAndLogEx(NORMAL, " | | * |%60s " _GREEN_("%012" PRIX64) "| |", "last used key", mfLastKey);
|
||||
traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3);
|
||||
};
|
||||
}
|
||||
|
@ -1386,7 +1386,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
|
|||
if (!traceCrypto1) {
|
||||
for (int i = 0; i < ARRAYLEN(g_mifare_default_keys); i++) {
|
||||
if (NestedCheckKey(g_mifare_default_keys[i], &AuthData, cmd, cmdsize, parity)) {
|
||||
PrintAndLogEx(NORMAL, " | | * |%61s %012"PRIx64"| |", "key", g_mifare_default_keys[i]);
|
||||
PrintAndLogEx(NORMAL, " | | * |%61s " _GREEN_("%012" PRIX64) "| |", "key", g_mifare_default_keys[i]);
|
||||
|
||||
mfLastKey = g_mifare_default_keys[i];
|
||||
traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3);
|
||||
|
@ -1414,7 +1414,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
|
|||
AuthData.ks3 = ks3;
|
||||
AuthData.nt = ntx;
|
||||
mfLastKey = GetCrypto1ProbableKey(&AuthData);
|
||||
PrintAndLogEx(NORMAL, " | | * | nested probable key:%012"PRIx64" ks2:%08x ks3:%08x | |",
|
||||
PrintAndLogEx(NORMAL, " | | * | nested probable key: " _GREEN_("%012" PRIX64) " ks2:%08x ks3:%08x | |",
|
||||
mfLastKey,
|
||||
AuthData.ks2,
|
||||
AuthData.ks3);
|
||||
|
|
|
@ -22,6 +22,15 @@
|
|||
#include "protocols.h"
|
||||
#include "fileutils.h" //saveFile
|
||||
|
||||
/*
|
||||
iceman notes
|
||||
We can't dump LTO 5 or 6 tags yet since we don't have a datasheet.
|
||||
If you have access to datasheet, le me know!
|
||||
|
||||
LTO w Type info 00 01 has 101 blocks.
|
||||
LTO w Type info 00 03 has 255 blocks.
|
||||
LTO w Type info 00 xx has NN blocks.
|
||||
*/
|
||||
#define CM_MEM_MAX_SIZE 0x1FE0 // (32byte/block * 255block = 8160byte)
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
@ -185,6 +194,19 @@ static int CmdHfLTOInfo(const char *Cmd) {
|
|||
return infoLTO(true);
|
||||
}
|
||||
|
||||
static const char *lto_print_size(uint8_t ti) {
|
||||
switch (ti) {
|
||||
case 1:
|
||||
return "101 blocks / 3232 bytes";
|
||||
case 2:
|
||||
return "95 blocks / 3040 bytes";
|
||||
case 3:
|
||||
return "255 blocks / 8160 bytes";
|
||||
default :
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
int infoLTO(bool verbose) {
|
||||
|
||||
clearCommandBuffer();
|
||||
|
@ -199,8 +221,12 @@ int infoLTO(bool verbose) {
|
|||
|
||||
if (ret_val == PM3_SUCCESS) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "UID: " _YELLOW_("%s"), sprint_hex_inrow(serial_number, sizeof(serial_number)));
|
||||
PrintAndLogEx(SUCCESS, "TYPE INFO: " _YELLOW_("%s"), sprint_hex_inrow(type_info, sizeof(type_info)));
|
||||
PrintAndLogEx(SUCCESS, "UID......... " _YELLOW_("%s"), sprint_hex_inrow(serial_number, sizeof(serial_number)));
|
||||
PrintAndLogEx(SUCCESS, "Type info... " _YELLOW_("%s"), sprint_hex_inrow(type_info, sizeof(type_info)));
|
||||
PrintAndLogEx(SUCCESS, "Memory...... " _YELLOW_("%s"), lto_print_size(type_info[1]));
|
||||
if (type_info[1] > 3) {
|
||||
PrintAndLogEx(INFO, "Unknown LTO tag, report to @iceman!");
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
|
@ -442,11 +468,21 @@ int dumpLTO(uint8_t *dump, bool verbose) {
|
|||
lto_switch_off_field();
|
||||
return ret_val;
|
||||
}
|
||||
// 0003 == 255 blocks x 32 = 8160 bytes
|
||||
// 0002 == 95 blocks x 32 = 3040 bytes
|
||||
// 0001 == 101 blocks x 32 = 3232 bytes
|
||||
uint8_t blocks = 0xFF;
|
||||
if (type_info[1] == 0x01) {
|
||||
blocks = 0x65;
|
||||
} else if (type_info[1] == 0x02) {
|
||||
blocks = 0x5F;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Found LTO tag w " _YELLOW_("%s") " memory", lto_print_size(type_info[1]));
|
||||
|
||||
uint8_t block_data_d00_d15[18];
|
||||
uint8_t block_data_d16_d31[18];
|
||||
|
||||
for (uint8_t i = 0; i < 255; i++) {
|
||||
for (uint8_t i = 0; i < blocks; i++) {
|
||||
|
||||
ret_val = lto_rdbl(i, block_data_d00_d15, block_data_d16_d31, verbose);
|
||||
|
||||
|
@ -458,6 +494,8 @@ int dumpLTO(uint8_t *dump, bool verbose) {
|
|||
lto_switch_off_field();
|
||||
return ret_val;
|
||||
}
|
||||
PrintAndLogEx(INPLACE, "...reading block %d", i);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
lto_switch_off_field();
|
||||
|
@ -502,6 +540,7 @@ static int CmdHfLTODump(const char *Cmd) {
|
|||
}
|
||||
|
||||
int ret_val = dumpLTO(dump, true);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
if (ret_val != PM3_SUCCESS) {
|
||||
free(dump);
|
||||
return ret_val;
|
||||
|
|
|
@ -18,13 +18,16 @@
|
|||
#include "cmdtrace.h"
|
||||
#include "emv/dump.h"
|
||||
#include "mifare/mifaredefault.h" // mifare default key array
|
||||
#include "cliparser.h" // argtable
|
||||
#include "cliparser.h" // argtable
|
||||
#include "hardnested_bf_core.h" // SetSIMDInstr
|
||||
#include "mifare/mad.h"
|
||||
#include "mifare/ndef.h"
|
||||
#include "protocols.h"
|
||||
#include "util_posix.h" // msclock
|
||||
#include "util_posix.h" // msclock
|
||||
#include "cmdhfmfhard.h"
|
||||
#include "des.h" // des ecb
|
||||
#include "crapto1/crapto1.h" // prng_successor
|
||||
#include "cmdhf14a.h" // exchange APDU
|
||||
|
||||
#define MFBLOCK_SIZE 16
|
||||
|
||||
|
@ -627,7 +630,6 @@ static void decode_print_st(uint16_t blockno, uint8_t *data) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static uint16_t NumOfBlocks(char card) {
|
||||
switch (card) {
|
||||
case '0' :
|
||||
|
@ -696,7 +698,6 @@ static char GetFormatFromSector(uint8_t sectorNo) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static int CmdHF14AMfDarkside(const char *Cmd) {
|
||||
uint8_t blockno = 0, key_type = MIFARE_AUTH_KEYA;
|
||||
uint64_t key = 0;
|
||||
|
@ -2014,7 +2015,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
char ctmp;
|
||||
// Nested and Hardnested returned status
|
||||
uint64_t foundkey = 0;
|
||||
int16_t isOK = 0;
|
||||
int isOK = 0;
|
||||
int current_sector_i = 0, current_key_type_i = 0;
|
||||
// Dumping and transfere to simulater memory
|
||||
uint8_t block[16] = {0x00};
|
||||
|
@ -2372,8 +2373,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "======================= " _YELLOW_("START DARKSIDE ATTACK") " =======================");
|
||||
}
|
||||
|
||||
isOK = mfDarkside(FirstBlockOfSector(blockNo), keyType, &key64);
|
||||
isOK = mfDarkside(FirstBlockOfSector(blockNo), keyType + 0x60, &key64);
|
||||
|
||||
switch (isOK) {
|
||||
case -1 :
|
||||
|
@ -2393,17 +2393,18 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
PrintAndLogEx(WARNING, "\nAborted via keyboard.");
|
||||
goto noValidKeyFound;
|
||||
default :
|
||||
PrintAndLogEx(SUCCESS, "\nFound valid key: %012" PRIx64 "\n", key64);
|
||||
PrintAndLogEx(SUCCESS, "\nFound valid key: [ " _GREEN_("%012" PRIx64) " ]\n", key64);
|
||||
break;
|
||||
}
|
||||
|
||||
// Store the keys
|
||||
num_to_bytes(key64, 6, key);
|
||||
e_sector[blockNo].Key[keyType] = key64;
|
||||
e_sector[blockNo].foundKey[keyType] = 'S';
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "] (used for nested / hardnested attack)",
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%012" PRIx64) " ] (used for nested / hardnested attack)",
|
||||
blockNo,
|
||||
keyType ? 'B' : 'A',
|
||||
sprint_hex(key, sizeof(key))
|
||||
key64
|
||||
);
|
||||
} else {
|
||||
noValidKeyFound:
|
||||
|
@ -2962,7 +2963,7 @@ out:
|
|||
printKeyTable(sectorsCnt, e_sector);
|
||||
|
||||
if (use_flashmemory && found_keys == (sectorsCnt << 1)) {
|
||||
PrintAndLogEx(SUCCESS, "Card dumped aswell. run " _YELLOW_("`%s %c`"),
|
||||
PrintAndLogEx(SUCCESS, "Card dumped as well. run " _YELLOW_("`%s %c`"),
|
||||
"hf mf esave",
|
||||
GetFormatFromSector(sectorsCnt)
|
||||
);
|
||||
|
@ -3692,7 +3693,6 @@ static int CmdHF14AMfEGetSc(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int CmdHF14AMfEClear(const char *Cmd) {
|
||||
char c = tolower(param_getchar(Cmd, 0));
|
||||
if (c == 'h') return usage_hf14_eclr();
|
||||
|
@ -5266,6 +5266,147 @@ static int CmdHf14AGen3Freeze(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void des_decrypt(void *out, const void *in, const void *key) {
|
||||
mbedtls_des_context ctx;
|
||||
mbedtls_des_setkey_dec(&ctx, key);
|
||||
mbedtls_des_crypt_ecb(&ctx, in, out);
|
||||
}
|
||||
|
||||
static int CmdHf14AMfSuperCard(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mf supercard",
|
||||
"Extract info from a `super card`",
|
||||
"hf mf supercard");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("r", "reset", "reset card"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool reset_card = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
bool activate_field = true;
|
||||
bool keep_field_on = true;
|
||||
int res = 0;
|
||||
|
||||
if (reset_card) {
|
||||
|
||||
keep_field_on = false;
|
||||
uint8_t response[6];
|
||||
int resplen = 0;
|
||||
|
||||
// --------------- RESET CARD ----------------
|
||||
uint8_t aRESET[] = { 0x00, 0xa6, 0xc0, 0x00 };
|
||||
res = ExchangeAPDU14a(aRESET, sizeof(aRESET), activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res) {
|
||||
PrintAndLogEx(FAILED, "Super card reset [ " _RED_("fail") " ]");
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Super card reset [ " _GREEN_("ok") " ]");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint8_t responseA[22];
|
||||
uint8_t responseB[22];
|
||||
int respAlen = 0;
|
||||
int respBlen = 0;
|
||||
|
||||
// --------------- First ----------------
|
||||
uint8_t aFIRST[] = { 0x00, 0xa6, 0xb0, 0x00, 0x10 };
|
||||
res = ExchangeAPDU14a(aFIRST, sizeof(aFIRST), activate_field, keep_field_on, responseA, sizeof(responseA), &respAlen);
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
// --------------- Second ----------------
|
||||
activate_field = false;
|
||||
keep_field_on = false;
|
||||
|
||||
uint8_t aSECOND[] = { 0x00, 0xa6, 0xb0, 0x01, 0x10 };
|
||||
res = ExchangeAPDU14a(aSECOND, sizeof(aSECOND), activate_field, keep_field_on, responseB, sizeof(responseB), &respBlen);
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
// uint8_t inA[] = { 0x72, 0xD7, 0xF4, 0x3E, 0xFD, 0xAB, 0xF2, 0x35, 0xFD, 0x49, 0xEE, 0xDC, 0x44, 0x95, 0x43, 0xC4};
|
||||
// uint8_t inB[] = { 0xF0, 0xA2, 0x67, 0x6A, 0x04, 0x6A, 0x72, 0x12, 0x76, 0xA4, 0x1D, 0x02, 0x1F, 0xEA, 0x20, 0x85};
|
||||
|
||||
uint8_t outA[16] = {0};
|
||||
uint8_t outB[16] = {0};
|
||||
|
||||
uint8_t key[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||||
for (uint8_t i = 0; i < 16; i += 8) {
|
||||
des_decrypt(outA + i, responseA + i, key);
|
||||
des_decrypt(outB + i, responseB + i, key);
|
||||
}
|
||||
|
||||
PrintAndLogEx(DEBUG, " in : %s", sprint_hex_inrow(responseA, respAlen));
|
||||
PrintAndLogEx(DEBUG, "out : %s", sprint_hex_inrow(outA, sizeof(outA)));
|
||||
PrintAndLogEx(DEBUG, " in : %s", sprint_hex_inrow(responseB, respAlen));
|
||||
PrintAndLogEx(DEBUG, "out : %s", sprint_hex_inrow(outB, sizeof(outB)));
|
||||
|
||||
if (memcmp(outA, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) {
|
||||
PrintAndLogEx(INFO, "No trace recorded");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// second trace?
|
||||
if (memcmp(outB, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) {
|
||||
PrintAndLogEx(INFO, "Only one trace recorded");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
nonces_t data;
|
||||
|
||||
// first
|
||||
uint16_t NT0 = (outA[6] << 8) | outA[7];
|
||||
data.cuid = bytes_to_num(outA, 4);
|
||||
data.nonce = prng_successor(NT0, 31);
|
||||
data.nr = bytes_to_num(outA + 8, 4);
|
||||
data.ar = bytes_to_num(outA + 12, 4);
|
||||
data.at = 0;
|
||||
|
||||
// second
|
||||
NT0 = (outB[6] << 8) | outB[7];
|
||||
data.nonce2 = prng_successor(NT0, 31);;
|
||||
data.nr2 = bytes_to_num(outB + 8, 4);
|
||||
data.ar2 = bytes_to_num(outB + 12, 4);
|
||||
data.sector = GetSectorFromBlockNo(outA[5]);
|
||||
data.keytype = outA[4];
|
||||
data.state = FIRST;
|
||||
|
||||
PrintAndLogEx(DEBUG, "A Sector %02x", data.sector);
|
||||
PrintAndLogEx(DEBUG, "A NT %08x", data.nonce);
|
||||
PrintAndLogEx(DEBUG, "A NR %08x", data.nr);
|
||||
PrintAndLogEx(DEBUG, "A AR %08x", data.ar);
|
||||
PrintAndLogEx(DEBUG, "");
|
||||
PrintAndLogEx(DEBUG, "B NT %08x", data.nonce2);
|
||||
PrintAndLogEx(DEBUG, "B NR %08x", data.nr2);
|
||||
PrintAndLogEx(DEBUG, "B AR %08x", data.ar2);
|
||||
|
||||
uint64_t key64 = -1;
|
||||
res = mfkey32_moebius(&data, &key64);
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(SUCCESS, "UID: %s Sector %02x key %c [ " _GREEN_("%12" PRIX64) " ]"
|
||||
, sprint_hex_inrow(outA, 4)
|
||||
, data.sector
|
||||
, (data.keytype == 0x60) ? 'A' : 'B'
|
||||
, key64);
|
||||
} else {
|
||||
PrintAndLogEx(FAILED, "failed to recover any key");
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHF14AMfList, AlwaysAvailable, "List MIFARE history"},
|
||||
|
@ -5280,6 +5421,7 @@ static command_t CommandTable[] = {
|
|||
{"chk", CmdHF14AMfChk, IfPm3Iso14443a, "Check keys"},
|
||||
{"fchk", CmdHF14AMfChk_fast, IfPm3Iso14443a, "Check keys fast, targets all keys on card"},
|
||||
{"decrypt", CmdHf14AMfDecryptBytes, AlwaysAvailable, "[nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace"},
|
||||
{"supercard", CmdHf14AMfSuperCard, IfPm3Iso14443a, "Extract info from a `super card`"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("operations") " -----------------------"},
|
||||
{"auth4", CmdHF14AMfAuth4, IfPm3Iso14443a, "ISO14443-4 AES authentication"},
|
||||
{"dump", CmdHF14AMfDump, IfPm3Iso14443a, "Dump MIFARE Classic tag to binary file"},
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
#include "fileutils.h"
|
||||
#include "mifare/mifaredefault.h" // default keys
|
||||
#include "mifare/ndef.h" // NDEF
|
||||
#include "mifare/mad.h"
|
||||
#include "generator.h"
|
||||
#include "aiddesfire.h"
|
||||
|
||||
#define MAX_KEY_LEN 24
|
||||
#define MAX_KEYS_LIST_LEN 1024
|
||||
|
@ -63,6 +66,9 @@ typedef struct {
|
|||
uint8_t keyno;
|
||||
uint8_t keylen;
|
||||
uint8_t key[24];
|
||||
uint8_t kdfAlgo;
|
||||
uint8_t kdfInputLen;
|
||||
uint8_t kdfInput[31];
|
||||
} PACKED mfdes_authinput_t;
|
||||
|
||||
static mfdes_authinput_t currentauth[0xF] = {{.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}};
|
||||
|
@ -79,6 +85,16 @@ typedef struct mfdes_data {
|
|||
uint8_t *data;
|
||||
} PACKED mfdes_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t isOK;
|
||||
uint8_t uid[7];
|
||||
uint8_t uidlen;
|
||||
uint8_t versionHW[7];
|
||||
uint8_t versionSW[7];
|
||||
uint8_t details[14];
|
||||
} PACKED mfdes_info_res_t;
|
||||
|
||||
|
||||
typedef struct mfdes_value {
|
||||
uint8_t fileno; //01
|
||||
uint8_t value[16];
|
||||
|
@ -332,6 +348,20 @@ typedef struct {
|
|||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static const char *getEncryptionAlgoStr(uint8_t algo) {
|
||||
switch (algo) {
|
||||
case MFDES_ALGO_AES :
|
||||
return "AES";
|
||||
case MFDES_ALGO_3DES :
|
||||
return "3DES";
|
||||
case MFDES_ALGO_DES :
|
||||
return "DES";
|
||||
case MFDES_ALGO_3K3DES :
|
||||
return "3K3DES";
|
||||
default :
|
||||
return "";
|
||||
}
|
||||
}
|
||||
/*
|
||||
The 7 MSBits (= n) code the storage size itself based on 2^n,
|
||||
the LSBit is set to '0' if the size is exactly 2^n
|
||||
|
@ -660,6 +690,38 @@ static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) {
|
|||
return DESFIRE_UNKNOWN;
|
||||
}
|
||||
|
||||
static int mfdes_get_info(mfdes_info_res_t *info) {
|
||||
SendCommandNG(CMD_HF_DESFIRE_INFO, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_DESFIRE_INFO, &resp, 1500) == false) {
|
||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||
DropField();
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
memcpy(info, resp.data.asBytes, sizeof(mfdes_info_res_t));
|
||||
|
||||
if (resp.status != PM3_SUCCESS) {
|
||||
switch (info->isOK) {
|
||||
case 1:
|
||||
PrintAndLogEx(WARNING, "Can't select card");
|
||||
break;
|
||||
case 2:
|
||||
PrintAndLogEx(WARNING, "Card is most likely not DESFire. Wrong size UID");
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
PrintAndLogEx(WARNING, _RED_("Command unsuccessful"));
|
||||
break;
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rpayload) {
|
||||
// 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
|
||||
// 4 different crypto arg1 DES, 3DES, 3K3DES, AES
|
||||
|
@ -706,6 +768,27 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp
|
|||
Desfire_3k3des_key_new_with_version(keybytes, key);
|
||||
}
|
||||
|
||||
if (payload->kdfAlgo == MFDES_KDF_ALGO_AN10922) {
|
||||
mifare_kdf_an10922(key, payload->kdfInput, payload->kdfInputLen);
|
||||
if (g_debugMode) {
|
||||
PrintAndLogEx(INFO, " Derrived key: " _GREEN_("%s"), sprint_hex(key->data, key_block_size(key)));
|
||||
}
|
||||
} else if (payload->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER) {
|
||||
// We will overrite any provided KDF input since a gallagher specific KDF was requested.
|
||||
payload->kdfInputLen = 11;
|
||||
|
||||
if (mfdes_kdf_input_gallagher(tag->info.uid, tag->info.uidlen, payload->keyno, tag->selected_application, payload->kdfInput, &payload->kdfInputLen) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "Could not generate Gallagher KDF input");
|
||||
}
|
||||
|
||||
mifare_kdf_an10922(key, payload->kdfInput, payload->kdfInputLen);
|
||||
|
||||
if (g_debugMode) {
|
||||
PrintAndLogEx(INFO, " KDF Input: " _YELLOW_("%s"), sprint_hex(payload->kdfInput, payload->kdfInputLen));
|
||||
PrintAndLogEx(INFO, " Derrived key: " _GREEN_("%s"), sprint_hex(key->data, key_block_size(key)));
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t subcommand = MFDES_AUTHENTICATE;
|
||||
tag->authentication_scheme = AS_LEGACY;
|
||||
|
||||
|
@ -918,7 +1001,7 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp
|
|||
memset(tag->ivect, 0, MAX_CRYPTO_BLOCK_SIZE);
|
||||
tag->authenticated_key_no = payload->keyno;
|
||||
if (tag->authentication_scheme == AS_NEW) {
|
||||
cmac_generate_subkeys(tag->session_key);
|
||||
cmac_generate_subkeys(tag->session_key, MCD_RECEIVE);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1045,6 +1128,12 @@ static int handler_desfire_freemem(uint32_t *free_mem) {
|
|||
}
|
||||
|
||||
static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t new_algo, uint8_t *old_key, uint8_t old_algo, uint8_t aes_version) {
|
||||
|
||||
if (new_key == NULL || old_key == NULL) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// AID == 000000 6bits LSB needs to be 0
|
||||
key_no &= 0x0F;
|
||||
|
||||
/*
|
||||
|
@ -1052,24 +1141,34 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
|
|||
* changing the card master key to one of them require a key_no tweak.
|
||||
*/
|
||||
if (0x000000 == tag->selected_application) {
|
||||
|
||||
// PICC master key, 6bits LSB needs to be 0
|
||||
key_no = 0x00;
|
||||
|
||||
// PICC master key, keyalgo specific 2bit MSB
|
||||
switch (new_algo) {
|
||||
case MFDES_ALGO_DES:
|
||||
break;
|
||||
case MFDES_ALGO_3DES:
|
||||
break; // 00xx xxx
|
||||
case MFDES_ALGO_3K3DES:
|
||||
key_no |= 0x40;
|
||||
key_no |= 0x40; // 01xx xxx
|
||||
break;
|
||||
case MFDES_ALGO_AES:
|
||||
key_no |= 0x80;
|
||||
key_no |= 0x80; // 10xx xxx
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t data[24 * 4] = {key_no};
|
||||
// Variable length ciphered key data 26-42 bytes plus padding..
|
||||
uint8_t data[64] = {key_no};
|
||||
sAPDU apdu = {0x90, MFDES_CHANGE_KEY, 0x00, 0x00, 0x01, data}; // 0xC4
|
||||
|
||||
uint8_t new_key_length = 16;
|
||||
switch (new_algo) {
|
||||
case MFDES_ALGO_DES:
|
||||
new_key_length = 8;
|
||||
break;
|
||||
case MFDES_ALGO_3DES:
|
||||
case MFDES_ALGO_AES:
|
||||
new_key_length = 16;
|
||||
break;
|
||||
|
@ -1154,7 +1253,7 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
|
|||
tag->session_key = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// --- GET SIGNATURE
|
||||
|
@ -1169,14 +1268,14 @@ static int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signat
|
|||
PrintAndLogEx(DEBUG, "SIGNATURE=NULL");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
// DESFire Ev3 - wanted
|
||||
// ref: MIFARE Desfire Originality Signature Validation
|
||||
|
||||
// See tools/recover_pk.py to recover Pk from UIDs and signatures
|
||||
#define PUBLIC_DESFIRE_ECDA_KEYLEN 57
|
||||
const ecdsa_publickey_t nxp_desfire_public_keys[] = {
|
||||
{"NTAG424DNA, DESFire EV2", "048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410"},
|
||||
{"NTAG413DNA, DESFire EV1", "04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD"},
|
||||
{"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"},
|
||||
{"DESFire EV3", "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743"},
|
||||
{"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"},
|
||||
{"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"},
|
||||
{"Mifare Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}
|
||||
|
@ -1987,7 +2086,7 @@ static void swap16(uint8_t *data) {
|
|||
data[1] = tmp;
|
||||
};
|
||||
|
||||
static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid, uint8_t *key, int cmdKeyNo, mfdes_auth_res_t *rpayload) {
|
||||
static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid, uint8_t *key, int cmdKeyNo, uint8_t cmdKdfAlgo, uint8_t kdfInputLen, uint8_t *kdfInput, mfdes_auth_res_t *rpayload) {
|
||||
switch (cmdAuthMode) {
|
||||
case MFDES_AUTH_DES:
|
||||
if (cmdAuthAlgo != MFDES_ALGO_DES && cmdAuthAlgo != MFDES_ALGO_3DES) {
|
||||
|
@ -2036,6 +2135,33 @@ static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid,
|
|||
break;
|
||||
}
|
||||
|
||||
switch (cmdKdfAlgo) {
|
||||
case MFDES_KDF_ALGO_AN10922:
|
||||
// TODO: 2TDEA and 3TDEA keys use an input length of 1-15 bytes
|
||||
if (cmdAuthAlgo != MFDES_ALGO_AES) {
|
||||
PrintAndLogEx(FAILED, "Crypto algo not valid for the KDF AN10922 algo.");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (kdfInputLen < 1 || kdfInputLen > 31) {
|
||||
PrintAndLogEx(FAILED, "KDF AN10922 algo requires an input of length 1-31 bytes.");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
break;
|
||||
case MFDES_KDF_ALGO_GALLAGHER:
|
||||
// TODO: 2TDEA and 3TDEA keys use an input length of 1-15 bytes
|
||||
if (cmdAuthAlgo != MFDES_ALGO_AES) {
|
||||
PrintAndLogEx(FAILED, "Crypto algo not valid for the KDF AN10922 algo.");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
break;
|
||||
// KDF input arg is ignored as it'll be generated.
|
||||
case MFDES_KDF_ALGO_NONE:
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "KDF algo %d is not supported.", cmdKdfAlgo);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// KEY
|
||||
int res = handler_desfire_select_application(aid);
|
||||
if (res != PM3_SUCCESS) return res;
|
||||
|
@ -2053,6 +2179,9 @@ static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid,
|
|||
payload.mode = cmdAuthMode;
|
||||
payload.algo = cmdAuthAlgo;
|
||||
payload.keyno = cmdKeyNo;
|
||||
payload.kdfAlgo = cmdKdfAlgo;
|
||||
payload.kdfInputLen = kdfInputLen;
|
||||
memcpy(payload.kdfInput, kdfInput, kdfInputLen);
|
||||
|
||||
int error = handler_desfire_auth(&payload, rpayload);
|
||||
if (error == PM3_SUCCESS) {
|
||||
|
@ -3232,43 +3361,14 @@ static int CmdHF14ADesFormatPICC(const char *Cmd) {
|
|||
static int CmdHF14ADesInfo(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
DropField();
|
||||
SendCommandNG(CMD_HF_DESFIRE_INFO, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_DESFIRE_INFO, &resp, 1500) == false) {
|
||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||
DropField();
|
||||
return PM3_ETIMEOUT;
|
||||
mfdes_info_res_t info;
|
||||
int res = mfdes_get_info(&info);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
struct p {
|
||||
uint8_t isOK;
|
||||
uint8_t uid[7];
|
||||
uint8_t uidlen;
|
||||
uint8_t versionHW[7];
|
||||
uint8_t versionSW[7];
|
||||
uint8_t details[14];
|
||||
} PACKED;
|
||||
|
||||
struct p *package = (struct p *) resp.data.asBytes;
|
||||
|
||||
if (resp.status != PM3_SUCCESS) {
|
||||
switch (package->isOK) {
|
||||
case 1:
|
||||
PrintAndLogEx(WARNING, "Can't select card");
|
||||
break;
|
||||
case 2:
|
||||
PrintAndLogEx(WARNING, "Card is most likely not DESFire. Wrong size UID");
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
PrintAndLogEx(WARNING, _RED_("Command unsuccessful"));
|
||||
break;
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
nxp_cardtype_t cardtype = getCardType(package->versionHW[3], package->versionHW[4]);
|
||||
nxp_cardtype_t cardtype = getCardType(info.versionHW[3], info.versionHW[4]);
|
||||
if (cardtype == PLUS_EV1) {
|
||||
PrintAndLogEx(INFO, "Card seems to be MIFARE Plus EV1. Try " _YELLOW_("`hf mfp info`"));
|
||||
return PM3_SUCCESS;
|
||||
|
@ -3277,30 +3377,30 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(package->uid, package->uidlen));
|
||||
PrintAndLogEx(SUCCESS, " Batch number: " _GREEN_("%s"), sprint_hex(package->details + 7, 5));
|
||||
PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), package->details[12], package->details[13]);
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(info.uid, info.uidlen));
|
||||
PrintAndLogEx(SUCCESS, " Batch number: " _GREEN_("%s"), sprint_hex(info.details + 7, 5));
|
||||
PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), info.details[12], info.details[13]);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information"));
|
||||
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(package->versionHW[0]));
|
||||
PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), package->versionHW[1]);
|
||||
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), package->versionHW[2]);
|
||||
PrintAndLogEx(INFO, " Version: %s", getVersionStr(package->versionHW[3], package->versionHW[4]));
|
||||
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(package->versionHW[5]));
|
||||
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionHW[6], true));
|
||||
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(info.versionHW[0]));
|
||||
PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), info.versionHW[1]);
|
||||
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), info.versionHW[2]);
|
||||
PrintAndLogEx(INFO, " Version: %s", getVersionStr(info.versionHW[3], info.versionHW[4]));
|
||||
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(info.versionHW[5]));
|
||||
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(info.versionHW[6], true));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Software Information"));
|
||||
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(package->versionSW[0]));
|
||||
PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), package->versionSW[1]);
|
||||
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), package->versionSW[2]);
|
||||
PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), package->versionSW[3], package->versionSW[4]);
|
||||
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(package->versionSW[5]));
|
||||
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionSW[6], false));
|
||||
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(info.versionSW[0]));
|
||||
PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), info.versionSW[1]);
|
||||
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), info.versionSW[2]);
|
||||
PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), info.versionSW[3], info.versionSW[4]);
|
||||
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(info.versionSW[5]));
|
||||
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(info.versionSW[6], false));
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Card capabilities"));
|
||||
uint8_t major = package->versionSW[3];
|
||||
uint8_t minor = package->versionSW[4];
|
||||
uint8_t major = info.versionSW[3];
|
||||
uint8_t minor = info.versionSW[4];
|
||||
if (major == 0 && minor == 4)
|
||||
PrintAndLogEx(INFO, "\t0.4 - DESFire MF3ICD40, No support for APDU (only native commands)");
|
||||
if (major == 0 && minor == 5)
|
||||
|
@ -3330,7 +3430,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
|
||||
if (handler_desfire_signature(signature, &signature_len) == PM3_SUCCESS) {
|
||||
desfire_print_signature(package->uid, package->uidlen, signature, signature_len, cardtype);
|
||||
desfire_print_signature(info.uid, info.uidlen, signature, signature_len, cardtype);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "--- Card doesn't support GetSignature cmd");
|
||||
}
|
||||
|
@ -3539,8 +3639,14 @@ static int CmdHF14ADesDump(const char *Cmd) {
|
|||
aid[2] = app_ids[i + 2];
|
||||
|
||||
PrintAndLogEx(SUCCESS, " AID : " _GREEN_("%02X%02X%02X"), aid[2], aid[1], aid[0]);
|
||||
PrintAndLogEx(SUCCESS, " AID Function Cluster 0x%02X: " _YELLOW_("%s"), aid[2], cluster_to_text(aid[2]));
|
||||
|
||||
if ((aid[2] >> 4) == 0xF) {
|
||||
uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4);
|
||||
PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid);
|
||||
PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8));
|
||||
MADDFDecodeAndPrint(short_aid);
|
||||
} else {
|
||||
AIDDFDecodeAndPrint(aid);
|
||||
}
|
||||
for (uint8_t m = 0; m < dfname_count; m++) {
|
||||
if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) {
|
||||
PrintAndLogEx(SUCCESS, " - DF " _YELLOW_("%02X%02X") " Name : " _YELLOW_("%s"), dfnames[m].fid[1], dfnames[m].fid[0], dfnames[m].name);
|
||||
|
@ -3705,8 +3811,14 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
|
|||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, " AID : " _GREEN_("%02X%02X%02X"), aid[2], aid[1], aid[0]);
|
||||
PrintAndLogEx(SUCCESS, " AID Function Cluster 0x%02X: " _YELLOW_("%s"), aid[2], cluster_to_text(aid[2]));
|
||||
|
||||
if ((aid[2] >> 4) == 0xF) {
|
||||
uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4);
|
||||
PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid);
|
||||
PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8));
|
||||
MADDFDecodeAndPrint(short_aid);
|
||||
} else {
|
||||
AIDDFDecodeAndPrint(aid);
|
||||
}
|
||||
for (uint8_t m = 0; m < dfname_count; m++) {
|
||||
if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) {
|
||||
PrintAndLogEx(SUCCESS, " - DF " _YELLOW_("%02X%02X") " Name : " _YELLOW_("%s"), dfnames[m].fid[1], dfnames[m].fid[0], dfnames[m].name);
|
||||
|
@ -3827,6 +3939,10 @@ static int CmdHF14ADesChangeKey(const char *Cmd) {
|
|||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "changing key number 0x%02x", cmdKeyNo);
|
||||
PrintAndLogEx(INFO, "old key: %s (%s)", sprint_hex_inrow(key, keylen), getEncryptionAlgoStr(cmdAuthAlgo));
|
||||
PrintAndLogEx(INFO, "new key: %s (%s)", sprint_hex_inrow(newkey, newkeylen), getEncryptionAlgoStr(newcmdAuthAlgo));
|
||||
|
||||
int error = mifare_desfire_change_key(cmdKeyNo, newkey, newcmdAuthAlgo, key, cmdAuthAlgo, aesversion);
|
||||
if (error == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, " Successfully changed key.");
|
||||
|
@ -3870,6 +3986,8 @@ static int CmdHF14ADesAuth(const char *Cmd) {
|
|||
arg_strx0("a", "aid", "<aid>", "AID used for authentification (HEX 3 bytes)"),
|
||||
arg_int0("n", "keyno", "<keyno>", "Key number used for authentification"),
|
||||
arg_str0("k", "key", "<Key>", "Key for checking (HEX 8-24 bytes)"),
|
||||
arg_int0("d", "kdf", "<kdf>", "Key Derivation Function (KDF) (0=None, 1=AN10922, 2=Gallagher)"),
|
||||
arg_str0("i", "kdfi", "<kdfi>", "KDF input (HEX 1-31 bytes)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -3886,6 +4004,13 @@ static int CmdHF14ADesAuth(const char *Cmd) {
|
|||
uint8_t key[24] = {0};
|
||||
int keylen = 0;
|
||||
CLIGetHexWithReturn(ctx, 5, key, &keylen);
|
||||
|
||||
// Get KDF input
|
||||
uint8_t kdfInput[31] = {0};
|
||||
int kdfInputLen = 0;
|
||||
uint8_t cmdKDFAlgo = arg_get_int_def(ctx, 6, 0);
|
||||
CLIGetHexWithReturn(ctx, 7, kdfInput, &kdfInputLen);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cmdAuthAlgo == MFDES_ALGO_AES) {
|
||||
|
@ -3931,7 +4056,7 @@ static int CmdHF14ADesAuth(const char *Cmd) {
|
|||
}
|
||||
|
||||
mfdes_auth_res_t rpayload;
|
||||
int error = desfire_authenticate(cmdAuthMode, cmdAuthAlgo, aid, key, cmdKeyNo, &rpayload);
|
||||
int error = desfire_authenticate(cmdAuthMode, cmdAuthAlgo, aid, key, cmdKeyNo, cmdKDFAlgo, kdfInputLen, kdfInput, &rpayload);
|
||||
if (error == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, " Key : " _GREEN_("%s"), sprint_hex(key, keylength));
|
||||
PrintAndLogEx(SUCCESS, " SESSION : " _GREEN_("%s"), sprint_hex(rpayload.sessionkey, keylength));
|
||||
|
@ -3989,6 +4114,7 @@ static int AuthCheckDesfire(uint8_t *aid,
|
|||
uint8_t deskeyList[MAX_KEYS_LIST_LEN][8], uint32_t deskeyListLen,
|
||||
uint8_t aeskeyList[MAX_KEYS_LIST_LEN][16], uint32_t aeskeyListLen,
|
||||
uint8_t k3kkeyList[MAX_KEYS_LIST_LEN][24], uint32_t k3kkeyListLen,
|
||||
uint8_t cmdKdfAlgo, uint8_t kdfInputLen, uint8_t *kdfInput,
|
||||
uint8_t foundKeys[4][0xE][24 + 1], bool *result) {
|
||||
|
||||
uint32_t curaid = (aid[0] & 0xFF) + ((aid[1] & 0xFF) << 8) + ((aid[2] & 0xFF) << 16);
|
||||
|
@ -4005,6 +4131,14 @@ static int AuthCheckDesfire(uint8_t *aid,
|
|||
bool aes = false;
|
||||
bool k3kdes = false;
|
||||
|
||||
uint8_t num_keys = 0;
|
||||
uint8_t key_setting = 0;
|
||||
res = handler_desfire_getkeysettings(&key_setting, &num_keys);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Could not get key settings");
|
||||
return res;
|
||||
}
|
||||
|
||||
if (memcmp(aid, "\x00\x00\x00", 3) != 0) {
|
||||
uint8_t file_ids[33] = {0};
|
||||
uint32_t file_ids_len = 0;
|
||||
|
@ -4036,7 +4170,7 @@ static int AuthCheckDesfire(uint8_t *aid,
|
|||
usedkeys[read_access] = 1;
|
||||
|
||||
if (res == PM3_SUCCESS) {
|
||||
switch (fileset_len >> 6) {
|
||||
switch (num_keys >> 6) {
|
||||
case 0:
|
||||
des = true;
|
||||
tdes = true;
|
||||
|
@ -4078,7 +4212,7 @@ static int AuthCheckDesfire(uint8_t *aid,
|
|||
if (usedkeys[keyno] == 1 && foundKeys[0][keyno][0] == 0) {
|
||||
for (uint32_t curkey = 0; curkey < deskeyListLen; curkey++) {
|
||||
mfdes_auth_res_t rpayload;
|
||||
error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_DES, aid, deskeyList[curkey], keyno, &rpayload);
|
||||
error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_DES, aid, deskeyList[curkey], keyno, 0, 0, NULL, &rpayload);
|
||||
if (error == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "AID 0x%06X, Found DES Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(deskeyList[curkey], 8));
|
||||
foundKeys[0][keyno][0] = 0x01;
|
||||
|
@ -4110,7 +4244,7 @@ static int AuthCheckDesfire(uint8_t *aid,
|
|||
if (usedkeys[keyno] == 1 && foundKeys[1][keyno][0] == 0) {
|
||||
for (uint32_t curkey = 0; curkey < aeskeyListLen; curkey++) {
|
||||
mfdes_auth_res_t rpayload;
|
||||
error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_3DES, aid, aeskeyList[curkey], keyno, &rpayload);
|
||||
error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_3DES, aid, aeskeyList[curkey], keyno, 0, 0, NULL, &rpayload);
|
||||
if (error == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "AID 0x%06X, Found 3DES Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(aeskeyList[curkey], 16));
|
||||
foundKeys[1][keyno][0] = 0x01;
|
||||
|
@ -4142,7 +4276,7 @@ static int AuthCheckDesfire(uint8_t *aid,
|
|||
if (usedkeys[keyno] == 1 && foundKeys[2][keyno][0] == 0) {
|
||||
for (uint32_t curkey = 0; curkey < aeskeyListLen; curkey++) {
|
||||
mfdes_auth_res_t rpayload;
|
||||
error = desfire_authenticate(MFDES_AUTH_AES, MFDES_ALGO_AES, aid, aeskeyList[curkey], keyno, &rpayload);
|
||||
error = desfire_authenticate(MFDES_AUTH_AES, MFDES_ALGO_AES, aid, aeskeyList[curkey], keyno, cmdKdfAlgo, kdfInputLen, kdfInput, &rpayload);
|
||||
if (error == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "AID 0x%06X, Found AES Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(aeskeyList[curkey], 16));
|
||||
foundKeys[2][keyno][0] = 0x01;
|
||||
|
@ -4174,7 +4308,7 @@ static int AuthCheckDesfire(uint8_t *aid,
|
|||
if (usedkeys[keyno] == 1 && foundKeys[3][keyno][0] == 0) {
|
||||
for (uint32_t curkey = 0; curkey < k3kkeyListLen; curkey++) {
|
||||
mfdes_auth_res_t rpayload;
|
||||
error = desfire_authenticate(MFDES_AUTH_ISO, MFDES_ALGO_3K3DES, aid, k3kkeyList[curkey], keyno, &rpayload);
|
||||
error = desfire_authenticate(MFDES_AUTH_ISO, MFDES_ALGO_3K3DES, aid, k3kkeyList[curkey], keyno, 0, 0, NULL, &rpayload);
|
||||
if (error == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "AID 0x%06X, Found 3K3 Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(k3kkeyList[curkey], 24));
|
||||
foundKeys[3][keyno][0] = 0x01;
|
||||
|
@ -4231,6 +4365,8 @@ static int CmdHF14aDesChk(const char *Cmd) {
|
|||
arg_str0(NULL, "startp2b", "<Pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
|
||||
arg_str0("j", "json", "<file>", "Json file to save keys"),
|
||||
arg_lit0("v", "verbose", "Verbose mode."),
|
||||
arg_int0("f", "kdf", "<kdf>", "Key Derivation Function (KDF) (0=None, 1=AN10922, 2=Gallagher)"),
|
||||
arg_str0("i", "kdfi", "<kdfi>", "KDF input (HEX 1-31 bytes)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -4310,6 +4446,12 @@ static int CmdHF14aDesChk(const char *Cmd) {
|
|||
|
||||
bool verbose = arg_get_lit(ctx, 8);
|
||||
|
||||
// Get KDF input
|
||||
uint8_t kdfInput[31] = {0};
|
||||
int kdfInputLen = 0;
|
||||
uint8_t cmdKDFAlgo = arg_get_int_def(ctx, 9, 0);
|
||||
CLIGetHexWithReturn(ctx, 10, kdfInput, &kdfInputLen);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// 1-byte pattern search mode
|
||||
|
@ -4351,34 +4493,41 @@ static int CmdHF14aDesChk(const char *Cmd) {
|
|||
endFilePosition = 0;
|
||||
}
|
||||
|
||||
if (aeskeyListLen == 0) {
|
||||
PrintAndLogEx(ERR, "Aes key list is empty. Nothing to check.");
|
||||
if (aeskeyListLen == 0 && deskeyListLen == 0 && k3kkeyListLen == 0) {
|
||||
PrintAndLogEx(ERR, "No keys provided. Nothing to check.");
|
||||
return PM3_EINVARG;
|
||||
} else {
|
||||
}
|
||||
|
||||
if (aeskeyListLen != 0) {
|
||||
PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " aes keys", aeskeyListLen);
|
||||
}
|
||||
|
||||
if (deskeyListLen == 0) {
|
||||
PrintAndLogEx(ERR, "Des key list is empty. Nothing to check.");
|
||||
return PM3_EINVARG;
|
||||
} else {
|
||||
if (deskeyListLen != 0) {
|
||||
PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " des keys", deskeyListLen);
|
||||
}
|
||||
|
||||
if (k3kkeyListLen == 0) {
|
||||
PrintAndLogEx(ERR, "K3k key list is empty. Nothing to check.");
|
||||
return PM3_EINVARG;
|
||||
} else {
|
||||
if (k3kkeyListLen != 0) {
|
||||
PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " k3kdes keys", k3kkeyListLen);
|
||||
}
|
||||
|
||||
if (!verbose)
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(INFO, "Search keys:");
|
||||
|
||||
bool result = false;
|
||||
uint8_t app_ids[78] = {0};
|
||||
uint32_t app_ids_len = 0;
|
||||
|
||||
clearCommandBuffer();
|
||||
|
||||
mfdes_info_res_t info = {0};
|
||||
res = mfdes_get_info(&info);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
// TODO: Store this UID someowhere not global
|
||||
memcpy(tag->info.uid, info.uid, info.uidlen);
|
||||
tag->info.uidlen = info.uidlen;
|
||||
|
||||
if (handler_desfire_appids(app_ids, &app_ids_len) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Can't get list of applications on tag");
|
||||
DropField();
|
||||
|
@ -4387,7 +4536,7 @@ static int CmdHF14aDesChk(const char *Cmd) {
|
|||
|
||||
if (aidlength != 0) {
|
||||
memcpy(&app_ids[0], aid, 3);
|
||||
app_ids_len = 1;
|
||||
app_ids_len = 3;
|
||||
}
|
||||
|
||||
for (uint32_t x = 0; x < app_ids_len / 3; x++) {
|
||||
|
@ -4395,7 +4544,7 @@ static int CmdHF14aDesChk(const char *Cmd) {
|
|||
uint32_t curaid = (app_ids[x * 3] & 0xFF) + ((app_ids[(x * 3) + 1] & 0xFF) << 8) + ((app_ids[(x * 3) + 2] & 0xFF) << 16);
|
||||
PrintAndLogEx(ERR, "Checking aid 0x%06X...", curaid);
|
||||
|
||||
res = AuthCheckDesfire(&app_ids[x * 3], deskeyList, deskeyListLen, aeskeyList, aeskeyListLen, k3kkeyList, k3kkeyListLen, foundKeys, &result);
|
||||
res = AuthCheckDesfire(&app_ids[x * 3], deskeyList, deskeyListLen, aeskeyList, aeskeyListLen, k3kkeyList, k3kkeyListLen, cmdKDFAlgo, kdfInputLen, kdfInput, foundKeys, &result);
|
||||
if (res == PM3_EOPABORTED) {
|
||||
break;
|
||||
}
|
||||
|
@ -4411,7 +4560,7 @@ static int CmdHF14aDesChk(const char *Cmd) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (dict_filenamelen && endFilePosition) {
|
||||
if (dict_filenamelen) {
|
||||
if (verbose == false)
|
||||
PrintAndLogEx(NORMAL, "d" NOLF);
|
||||
|
||||
|
@ -4510,6 +4659,8 @@ static int CmdHF14aDesNDEF(const char *Cmd) {
|
|||
CLIGetHexWithReturn(ctx, 3, key, &keylen);
|
||||
bool keyB = arg_get_lit(ctx, 4);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint16_t ndefAID = 0xe103;
|
||||
if (aidlen == 2)
|
||||
ndefAID = (aid[0] << 8) + aid[1];
|
||||
|
@ -4579,6 +4730,33 @@ static int CmdHF14aDesNDEF(const char *Cmd) {
|
|||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
static int CmdHF14aDesMAD(const char *Cmd) {
|
||||
DropField();
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfdes mad",
|
||||
"Prints MIFARE Application directory (MAD)",
|
||||
"hf mfdes mad -> shows MAD data\n"
|
||||
"hf mfdes mad -v -> shows MAD parsed and raw data\n"
|
||||
"hf mfdes mad -a e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows MAD data with custom AID and key");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_litn("v", "verbose", 0, 2, "show technical data"),
|
||||
arg_str0("", "aid", "<aid>", "replace default aid for MAD"),
|
||||
arg_str0("k", "key", "<key>", "replace default key for MAD"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfdes mad -v`") " for more details");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
/*static int CmdTest(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
uint8_t IV[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
@ -4605,28 +4783,32 @@ static int CmdHF14aDesNDEF(const char *Cmd) {
|
|||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("general") " -----------------------"},
|
||||
{"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "Tries a MIFARE DesFire Authentication"},
|
||||
{"changekey", CmdHF14ADesChangeKey, IfPm3Iso14443a, "Change Key"},
|
||||
{"chk", CmdHF14aDesChk, IfPm3Iso14443a, "Check keys"},
|
||||
{"enum", CmdHF14ADesEnumApplications, IfPm3Iso14443a, "Tries enumerate all applications"},
|
||||
{"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"},
|
||||
{"getuid", CmdHF14ADesGetUID, IfPm3Iso14443a, "Get random uid"},
|
||||
{"info", CmdHF14ADesInfo, IfPm3Iso14443a, "Tag information"},
|
||||
{"list", CmdHF14ADesList, AlwaysAvailable, "List DESFire (ISO 14443A) history"},
|
||||
{"enum", CmdHF14ADesEnumApplications, IfPm3Iso14443a, "Tries enumerate all applications"},
|
||||
{"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "Tries a MIFARE DesFire Authentication"},
|
||||
{"getuid", CmdHF14ADesGetUID, IfPm3Iso14443a, "Get random uid"},
|
||||
{"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"},
|
||||
// {"ndef", CmdHF14aDesNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
||||
// {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records from card"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("AID") " -----------------------"},
|
||||
{"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"},
|
||||
{"deleteaid", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application ID"},
|
||||
{"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("Files") " -----------------------"},
|
||||
{"changevalue", CmdHF14ADesChangeValue, IfPm3Iso14443a, "Write value of a value file (credit/debit/clear)"},
|
||||
{"clearfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"},
|
||||
{"createfile", CmdHF14ADesCreateFile, IfPm3Iso14443a, "Create Standard/Backup File"},
|
||||
{"createvaluefile", CmdHF14ADesCreateValueFile, IfPm3Iso14443a, "Create Value File"},
|
||||
{"createrecordfile", CmdHF14ADesCreateRecordFile, IfPm3Iso14443a, "Create Linear/Cyclic Record File"},
|
||||
{"deletefile", CmdHF14ADesDeleteFile, IfPm3Iso14443a, "Create Delete File"},
|
||||
{"clearfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"},
|
||||
{"dump", CmdHF14ADesDump, IfPm3Iso14443a, "Dump all files"},
|
||||
{"getvalue", CmdHF14ADesGetValueData, IfPm3Iso14443a, "Get value of file"},
|
||||
{"readdata", CmdHF14ADesReadData, IfPm3Iso14443a, "Read data from standard/backup/record file"},
|
||||
{"writedata", CmdHF14ADesWriteData, IfPm3Iso14443a, "Write data to standard/backup/record file"},
|
||||
{"getvalue", CmdHF14ADesGetValueData, IfPm3Iso14443a, "Get value of file"},
|
||||
{"changevalue", CmdHF14ADesChangeValue, IfPm3Iso14443a, "Write value of a value file (credit/debit/clear)"},
|
||||
{"changekey", CmdHF14ADesChangeKey, IfPm3Iso14443a, "Change Key"},
|
||||
{"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"},
|
||||
{"dump", CmdHF14ADesDump, IfPm3Iso14443a, "Dump all files"},
|
||||
{"chk", CmdHF14aDesChk, IfPm3Iso14443a, "Check keys"},
|
||||
// {"ndef", CmdHF14aDesNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -377,7 +377,7 @@ static int CmdHFMFPInfo(const char *Cmd) {
|
|||
// DESFire answers 0x1C or 67 00
|
||||
// Plus answers 0x0B, 0x09, 0x06
|
||||
// Which tag answers 6D 00 ??
|
||||
if (data[0] != 0x0b && data[0] != 0x09 && data[0] != 0x1C && data[0] != 0x67) {
|
||||
if (data[0] != 0x0b && data[0] != 0x09 && data[0] != 0x1C && data[0] != 0x67 && data[0] != 0x6d) {
|
||||
PrintAndLogEx(INFO, _RED_("Send copy to iceman of this command output!"));
|
||||
PrintAndLogEx(INFO, "data: %s", sprint_hex(data, datalen));
|
||||
}
|
||||
|
|
|
@ -681,6 +681,7 @@ static int CmdConnect(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"-------------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("Hardware") " -----------------------"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"connect", CmdConnect, AlwaysAvailable, "connect Proxmark3 to serial port"},
|
||||
{"dbg", CmdDbg, IfPm3Present, "Set Proxmark3 debug level"},
|
||||
|
|
|
@ -113,7 +113,7 @@ static int usage_lf_read(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_lf_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Simulate low frequence tag from graphbuffer.");
|
||||
PrintAndLogEx(NORMAL, "Simulate low frequency tag from graphbuffer.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf sim [h] <gap>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h This help");
|
||||
|
@ -126,7 +126,7 @@ static int usage_lf_sim(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_lf_sniff(void) {
|
||||
PrintAndLogEx(NORMAL, "Sniff low frequence signal.");
|
||||
PrintAndLogEx(NORMAL, "Sniff low frequency signal.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf sniff [h] [q] [s #samples] [@]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h This help");
|
||||
|
@ -1526,7 +1526,7 @@ out:
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "-------------- " _CYAN_("Direct") " --------------"},
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "-------------- " _CYAN_("Low Frequency") " --------------"},
|
||||
{"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"},
|
||||
{"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"},
|
||||
{"destron", CmdLFDestron, AlwaysAvailable, "{ FDX-A Destron RFIDs... }"},
|
||||
|
|
|
@ -330,8 +330,10 @@ int demodAWID(bool verbose) {
|
|||
free(bits);
|
||||
|
||||
PrintAndLogEx(DEBUG, "DEBUG: AWID idx: %d, Len: %zu Printing Demod Buffer:", idx, size);
|
||||
if (g_debugMode)
|
||||
printDemodBuff();
|
||||
if (g_debugMode) {
|
||||
printDemodBuff(0, false, false, true);
|
||||
printDemodBuff(0, false, false, false);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -199,9 +199,11 @@ void printEM410x(uint32_t hi, uint64_t id) {
|
|||
if (hi) {
|
||||
//output 88 bit em id
|
||||
PrintAndLogEx(NORMAL, "\nEM TAG ID : "_YELLOW_("%06X%016" PRIX64), hi, id);
|
||||
PrintAndLogEx(NORMAL, "Clock rate : "_YELLOW_("RF/%d"), g_DemodClock);
|
||||
} else {
|
||||
//output 40 bit em id
|
||||
PrintAndLogEx(NORMAL, "\nEM TAG ID : "_YELLOW_("%010" PRIX64), id);
|
||||
PrintAndLogEx(NORMAL, "Clock rate : "_YELLOW_("RF/%d"), g_DemodClock);
|
||||
PrintAndLogEx(NORMAL, "\nPossible de-scramble patterns\n");
|
||||
PrintAndLogEx(NORMAL, "Unique TAG ID : %010" PRIX64, id2lo);
|
||||
PrintAndLogEx(NORMAL, "HoneyWell IdentKey {");
|
||||
|
@ -316,8 +318,9 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo) {
|
|||
setClockGrid(g_DemodClock, g_DemodStartIdx + ((idx + 1)*g_DemodClock));
|
||||
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Em410x idx: %zu, Len: %zu, Printing Demod Buffer:", idx, size);
|
||||
if (g_debugMode)
|
||||
printDemodBuff();
|
||||
if (g_debugMode) {
|
||||
printDemodBuff(0, false, false, true);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printEM410x(*hi, *lo);
|
||||
|
@ -652,7 +655,7 @@ static command_t CommandTable[] = {
|
|||
{"4x50_dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"},
|
||||
{"4x50_info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"},
|
||||
{"4x50_write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"},
|
||||
{"4x50_write_password", CmdEM4x50WritePassword, IfPm3EM4x50, "change passwword of EM4x50 tag"},
|
||||
{"4x50_write_password", CmdEM4x50WritePassword, IfPm3EM4x50, "change password of EM4x50 tag"},
|
||||
{"4x50_read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"},
|
||||
{"4x50_wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
|
|
|
@ -98,11 +98,13 @@ static em_tech_type_t em_get_card_type(uint32_t config) {
|
|||
uint8_t t = (config >> 1) & 0xF;
|
||||
switch (t) {
|
||||
case 4:
|
||||
return EM_4X69;
|
||||
return EM_4469;
|
||||
case 8:
|
||||
return EM_4205;
|
||||
case 9:
|
||||
return EM_4305;
|
||||
case 12:
|
||||
return EM_4369;
|
||||
}
|
||||
return EM_UNKNOWN;
|
||||
}
|
||||
|
@ -111,10 +113,12 @@ static const char *em_get_card_str(uint32_t config) {
|
|||
switch (em_get_card_type(config)) {
|
||||
case EM_4305:
|
||||
return "EM4305";
|
||||
case EM_4X69:
|
||||
case EM_4469:
|
||||
return "EM4469";
|
||||
case EM_4205:
|
||||
return "EM4205";
|
||||
case EM_4369:
|
||||
return "EM4369";
|
||||
case EM_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
|
@ -171,16 +175,19 @@ static int doPreambleSearch(size_t *startIdx) {
|
|||
// do not set it too long else an error preamble followed by 010 could be seen as success.
|
||||
size_t size = (11 > DemodBufferLen) ? DemodBufferLen : 11;
|
||||
*startIdx = 0;
|
||||
|
||||
// skip first two 0 bits as they might have been missed in the demod
|
||||
uint8_t preamble[EM_PREAMBLE_LEN] = {0, 0, 0, 0, 1, 0, 1, 0};
|
||||
uint8_t errpreamble[EM_PREAMBLE_LEN] = {0, 0, 0, 0, 0, 0, 0, 1};
|
||||
|
||||
if (!preambleSearchEx(DemodBuffer, preamble, EM_PREAMBLE_LEN, &size, startIdx, true)) {
|
||||
uint8_t errpreamble[EM_PREAMBLE_LEN] = {0, 0, 0, 0, 0, 0, 0, 1};
|
||||
|
||||
if (!preambleSearchEx(DemodBuffer, errpreamble, EM_PREAMBLE_LEN, &size, startIdx, true)) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - EM4305 preamble not found :: %zu", *startIdx);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
return PM3_EFAILED; // Error preamble found
|
||||
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -211,6 +218,18 @@ static bool detectPSK(void) {
|
|||
ans = PSKDemod(0, 0, 6, false);
|
||||
if (ans != PM3_SUCCESS) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: PSK1 Demod failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// In order to hit the INVERT, we need to demod here
|
||||
if (DemodBufferLen < 11) {
|
||||
PrintAndLogEx(INFO, " demod buff len less than PREAMBLE lEN");
|
||||
}
|
||||
|
||||
size_t size = (11 > DemodBufferLen) ? DemodBufferLen : 11;
|
||||
size_t startIdx = 0;
|
||||
uint8_t preamble[EM_PREAMBLE_LEN] = {0, 0, 0, 0, 1, 0, 1, 0};
|
||||
if (!preambleSearchEx(DemodBuffer, preamble, EM_PREAMBLE_LEN, &size, &startIdx, true)) {
|
||||
|
||||
//try psk1 inverted
|
||||
ans = PSKDemod(0, 1, 6, false);
|
||||
|
@ -218,7 +237,13 @@ static bool detectPSK(void) {
|
|||
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: PSK1 inverted Demod failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!preambleSearchEx(DemodBuffer, preamble, EM_PREAMBLE_LEN, &size, &startIdx, true)) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: PSK1 inverted Demod failed 2");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// either PSK1 or PSK1 inverted is ok from here.
|
||||
// lets check PSK2 later.
|
||||
return true;
|
||||
|
@ -324,6 +349,7 @@ static int em4x05_demod_resp(uint32_t *word, bool onlyPreamble) {
|
|||
res = doPreambleSearch(&idx);
|
||||
if (res == PM3_SUCCESS)
|
||||
break;
|
||||
|
||||
if (res == PM3_EFAILED)
|
||||
found_err = true;
|
||||
|
||||
|
@ -331,9 +357,11 @@ static int em4x05_demod_resp(uint32_t *word, bool onlyPreamble) {
|
|||
res = doPreambleSearch(&idx);
|
||||
if (res == PM3_SUCCESS)
|
||||
break;
|
||||
|
||||
if (res == PM3_EFAILED)
|
||||
found_err = true;
|
||||
}
|
||||
|
||||
if (found_err)
|
||||
return PM3_EFAILED;
|
||||
|
||||
|
@ -360,7 +388,7 @@ static bool em4x05_verify_write(uint8_t addr, uint32_t pwd, bool use_pwd, uint32
|
|||
int res = em4x05_read_word_ext(addr, pwd, use_pwd, &r);
|
||||
if (res == PM3_SUCCESS) {
|
||||
return (r == data);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -381,7 +409,7 @@ int em4x05_clone_tag(uint32_t *blockdata, uint8_t numblocks, uint32_t pwd, bool
|
|||
if (i == numblocks - 1) {
|
||||
conn.block_after_ACK = false;
|
||||
}
|
||||
|
||||
|
||||
if (i != 0) {
|
||||
blockdata[i] = reflect(blockdata[i], 32);
|
||||
}
|
||||
|
@ -538,7 +566,7 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
uint32_t word = 0;
|
||||
|
||||
const char *info[] = {"Info/User", "UID", "Password", "User", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "Lock", "Lock"};
|
||||
const char *info4x69 [] = {"Info", "UID", "Password", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User"};
|
||||
const char *info4x69 [] = {"Info", "UID", "Password", "Lock", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User"};
|
||||
|
||||
// EM4305 vs EM4469
|
||||
em_tech_type_t card_type = em_get_card_type(block0);
|
||||
|
@ -567,7 +595,7 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
|
||||
|
||||
// To flag any blocks locked we need to read blocks 14 and 15 first
|
||||
// dont swap endin until we get block lock flags.
|
||||
// dont swap endian until we get block lock flags.
|
||||
status14 = em4x05_read_word_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word);
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
if ((word & 0x00008000) != 0x00) {
|
||||
|
@ -635,16 +663,14 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
data[14] = BSWAP_32(data[14]);
|
||||
data[15] = BSWAP_32(data[15]);
|
||||
|
||||
} else if (card_type == EM_4X69) {
|
||||
} else if (card_type == EM_4369 || card_type == EM_4469) {
|
||||
|
||||
// To flag any blocks locked we need to read blocks 14 and 15 first
|
||||
// dont swap endin until we get block lock flags.
|
||||
// To flag any blocks locked we need to read block 3 first
|
||||
// dont swap endian until we get block lock flags.
|
||||
status14 = em4x05_read_word_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word);
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
if ((word & 0x00008000) != 0x00) {
|
||||
lock_bits = word;
|
||||
gotLockBits = true;
|
||||
}
|
||||
lock_bits = word;
|
||||
gotLockBits = true;
|
||||
data[EM4469_PROT_BLOCK] = word;
|
||||
} else {
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
|
@ -652,8 +678,8 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
|
||||
uint32_t lockbit;
|
||||
|
||||
for (; addr < 15; addr++) {
|
||||
lockbit = (lock_bits >> addr) & 1;
|
||||
for (; addr < 16; addr++) {
|
||||
lockbit = (lock_bits >> (addr * 2)) & 3;
|
||||
if (addr == 2) {
|
||||
if (usePwd) {
|
||||
data[addr] = BSWAP_32(pwd);
|
||||
|
@ -688,15 +714,17 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
// saveFile (binary) passes in the .bin extension.
|
||||
if (strcmp(filename, "") == 0) {
|
||||
|
||||
if (card_type == EM_4X69) {
|
||||
sprintf(filename, "lf-4x69-%08X-dump", BSWAP_32(data[1]));
|
||||
if (card_type == EM_4369) {
|
||||
sprintf(filename, "lf-4369-%08X-dump", BSWAP_32(data[1]));
|
||||
} else if (card_type == EM_4469) {
|
||||
sprintf(filename, "lf-4469-%08X-dump", BSWAP_32(data[1]));
|
||||
} else {
|
||||
sprintf(filename, "lf-4x05-%08X-dump", BSWAP_32(data[1]));
|
||||
}
|
||||
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
saveFileJSON(filename, (card_type == EM_4X69) ? jsfEM4x69 : jsfEM4x05, (uint8_t *)data, 16 * sizeof(uint32_t), NULL);
|
||||
saveFileJSON(filename, (card_type == EM_4369 || card_type == EM_4469) ? jsfEM4x69 : jsfEM4x05, (uint8_t *)data, 16 * sizeof(uint32_t), NULL);
|
||||
|
||||
saveFileEML(filename, (uint8_t *)data, 16 * sizeof(uint32_t), sizeof(uint32_t));
|
||||
saveFile(filename, ".bin", data, sizeof(data));
|
||||
|
@ -880,7 +908,74 @@ int CmdEM4x05Wipe(const char *Cmd) {
|
|||
return success;
|
||||
}
|
||||
|
||||
static void printEM4x05config(uint32_t wordData) {
|
||||
static const char *printEM4x05_known(uint32_t word) {
|
||||
|
||||
switch (word) {
|
||||
// case EM4305_DEFAULT_CONFIG_BLOCK:
|
||||
case EM4305_PRESCO_CONFIG_BLOCK: {
|
||||
return "EM4305 DEFAULT / PRESCO";
|
||||
}
|
||||
// case EM4305_PAXTON_CONFIG_BLOCK:
|
||||
case EM4305_EM_UNIQUE_CONFIG_BLOCK: {
|
||||
return "EM UNIQUE / PAXTON";
|
||||
}
|
||||
case EM4305_VISA2000_CONFIG_BLOCK: {
|
||||
return "VISA2000";
|
||||
}
|
||||
case EM4305_VIKING_CONFIG_BLOCK: {
|
||||
return "VIKING";
|
||||
}
|
||||
case EM4305_NORALSY_CONFIG_BLOCK: {
|
||||
return "NORALSY";
|
||||
}
|
||||
case EM4305_SECURAKEY_CONFIG_BLOCK: {
|
||||
return "SECURAKEY";
|
||||
}
|
||||
// case EM4305_HID_26_CONFIG_BLOCK:
|
||||
// case EM4305_PARADOX_CONFIG_BLOCK:
|
||||
case EM4305_AWID_CONFIG_BLOCK: {
|
||||
return "HID26 / PARADOX / AWID";
|
||||
}
|
||||
case EM4305_PYRAMID_CONFIG_BLOCK: {
|
||||
return "PYRAMID";
|
||||
}
|
||||
case EM4305_IOPROX_CONFIG_BLOCK: {
|
||||
return "IOPROX";
|
||||
}
|
||||
// case EM4305_KERI_CONFIG_BLOCK:
|
||||
case EM4305_INDALA_64_CONFIG_BLOCK: {
|
||||
return "INDALA 64 / KERI";
|
||||
}
|
||||
case EM4305_INDALA_224_CONFIG_BLOCK: {
|
||||
return "INDALA 224";
|
||||
}
|
||||
case EM4305_MOTOROLA_CONFIG_BLOCK: {
|
||||
return "MOTOROLA";
|
||||
}
|
||||
case EM4305_NEXWATCH_CONFIG_BLOCK: {
|
||||
return "NEXWATCH";
|
||||
}
|
||||
// case EM4305_NEDAP_64_CONFIG_BLOCK:
|
||||
case EM4305_JABLOTRON_CONFIG_BLOCK: {
|
||||
return "JABLOTRON / NEDAP 64";
|
||||
}
|
||||
case EM4305_GUARDPROXII_CONFIG_BLOCK: {
|
||||
return "GUARD PROXII";
|
||||
}
|
||||
case EM4305_NEDAP_128_CONFIG_BLOCK: {
|
||||
return "NEDAP 128";
|
||||
}
|
||||
case EM4305_PAC_CONFIG_BLOCK: {
|
||||
return "PAC/Stanley";
|
||||
}
|
||||
case EM4305_VERICHIP_CONFIG_BLOCK: {
|
||||
return "VERICHIP";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static void printEM4x05config(em_tech_type_t card_type, uint32_t wordData) {
|
||||
uint16_t datarate = (((wordData & 0x3F) + 1) * 2);
|
||||
uint8_t encoder = ((wordData >> 6) & 0xF);
|
||||
char enc[14];
|
||||
|
@ -966,24 +1061,55 @@ static void printEM4x05config(uint32_t wordData) {
|
|||
uint8_t raw = (wordData & EM4x05_READ_AFTER_WRITE) >> 22;
|
||||
uint8_t disable = (wordData & EM4x05_DISABLE_ALLOWED) >> 23;
|
||||
uint8_t rtf = (wordData & EM4x05_READER_TALK_FIRST) >> 24;
|
||||
uint8_t pigeon = (wordData & (1 << 26)) >> 26;
|
||||
uint8_t invert = (wordData & EM4x05_INVERT) >> 25;
|
||||
uint8_t pigeon = (wordData & EM4x05_PIGEON) >> 26;
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Config Information") " ------------------------");
|
||||
PrintAndLogEx(INFO, "ConfigWord: %08X (Word 4)", wordData);
|
||||
PrintAndLogEx(INFO, "ConfigWord: %08X ( " _YELLOW_("%s") " )", wordData, printEM4x05_known(wordData));
|
||||
|
||||
PrintAndLogEx(INFO, " Data Rate: %02u | "_YELLOW_("RF/%u"), wordData & 0x3F, datarate);
|
||||
PrintAndLogEx(INFO, " Encoder: %u | " _YELLOW_("%s"), encoder, enc);
|
||||
PrintAndLogEx(INFO, " PSK CF: %u | %s", PSKcf, cf);
|
||||
PrintAndLogEx(INFO, " Delay: %u | %s", delay, cdelay);
|
||||
if (card_type == EM_4369 || card_type == EM_4469) {
|
||||
PrintAndLogEx(INFO, " PSK CF: %u | %s", PSKcf, cf);
|
||||
} else if (PSKcf != 0) {
|
||||
PrintAndLogEx(INFO, "co10..c011: %u | %s", PSKcf, _RED_("Not used, must be set to logic 0"));
|
||||
}
|
||||
if (card_type == EM_4305) {
|
||||
PrintAndLogEx(INFO, " Delay: %u | %s", delay, cdelay);
|
||||
} else if (delay != 0) {
|
||||
PrintAndLogEx(INFO, "co12..c013: %u | %s", delay, _RED_("Not used, must be set to logic 0"));
|
||||
}
|
||||
PrintAndLogEx(INFO, " LastWordR: %02u | Address of last word for default read - meaning %u blocks are output", LWR, numblks);
|
||||
PrintAndLogEx(INFO, " ReadLogin: %u | Read login is %s", readLogin, readLogin ? _YELLOW_("required") : _GREEN_("not required"));
|
||||
PrintAndLogEx(INFO, " ReadHKL: %u | Read housekeeping words login is %s", readHKL, readHKL ? _YELLOW_("required") : _GREEN_("not required"));
|
||||
if (card_type == EM_4369 || card_type == EM_4469) {
|
||||
PrintAndLogEx(INFO, " ReadHKL: %u | Read housekeeping words (3,4) login is %s", readHKL, readHKL ? _YELLOW_("required") : _GREEN_("not required"));
|
||||
} else if (readHKL != 0) {
|
||||
PrintAndLogEx(INFO, " c019: %u | %s", readHKL, _RED_("Not used, must be set to logic 0"));
|
||||
}
|
||||
PrintAndLogEx(INFO, "WriteLogin: %u | Write login is %s", writeLogin, writeLogin ? _YELLOW_("required") : _GREEN_("not required"));
|
||||
PrintAndLogEx(INFO, " WriteHKL: %u | Write housekeeping words login is %s", writeHKL, writeHKL ? _YELLOW_("required") : _GREEN_("not Required"));
|
||||
PrintAndLogEx(INFO, " R.A.W.: %u | Read after write is %s", raw, raw ? "on" : "off");
|
||||
if (card_type == EM_4369 || card_type == EM_4469) {
|
||||
PrintAndLogEx(INFO, " WriteHKL: %u | Write housekeeping words (2,3,4) login is %s", writeHKL, writeHKL ? _YELLOW_("required") : _GREEN_("not Required"));
|
||||
} else if (writeHKL != 0) {
|
||||
PrintAndLogEx(INFO, " c021: %u | %s", writeHKL, _RED_("Not used, must be set to logic 0"));
|
||||
}
|
||||
if (card_type == EM_4369 || card_type == EM_4469) {
|
||||
PrintAndLogEx(INFO, " R.A.W.: %u | Read after write is %s", raw, raw ? "on" : "off");
|
||||
} else if (raw != 0) {
|
||||
PrintAndLogEx(INFO, " c022: %u | %s", raw, _RED_("Not used, must be set to logic 0"));
|
||||
}
|
||||
PrintAndLogEx(INFO, " Disable: %u | Disable command is %s", disable, disable ? "accepted" : "not accepted");
|
||||
PrintAndLogEx(INFO, " R.T.F.: %u | Reader talk first is %s", rtf, rtf ? _YELLOW_("enabled") : "disabled");
|
||||
PrintAndLogEx(INFO, " Pigeon: %u | Pigeon mode is %s", pigeon, pigeon ? _YELLOW_("enabled") : "disabled");
|
||||
if (card_type == EM_4369) {
|
||||
PrintAndLogEx(INFO, " Invert: %u | Invert data? %s", invert, invert ? _YELLOW_("yes") : "no");
|
||||
} else if (invert != 0) {
|
||||
PrintAndLogEx(INFO, " c025: %u | %s", invert, _RED_("Not used, must be set to logic 0"));
|
||||
}
|
||||
if (card_type == EM_4305) {
|
||||
PrintAndLogEx(INFO, " Pigeon: %u | Pigeon mode is %s", pigeon, pigeon ? _YELLOW_("enabled") : "disabled");
|
||||
} else if (pigeon != 0) {
|
||||
PrintAndLogEx(INFO, " c026: %u | %s", pigeon, _RED_("Not used, must be set to logic 0"));
|
||||
}
|
||||
}
|
||||
|
||||
static void printEM4x05info(uint32_t block0, uint32_t serial) {
|
||||
|
@ -1011,7 +1137,7 @@ static void printEM4x05info(uint32_t block0, uint32_t serial) {
|
|||
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
||||
|
||||
PrintAndLogEx(SUCCESS, " Block0: " _GREEN_("%08x") " (Word 0)", block0);
|
||||
PrintAndLogEx(SUCCESS, " Block0: " _GREEN_("%08x"), block0);
|
||||
PrintAndLogEx(SUCCESS, " Chip Type: %3u | " _YELLOW_("%s"), chipType, em_get_card_str(block0));
|
||||
|
||||
switch (cap) {
|
||||
|
@ -1048,6 +1174,7 @@ static void printEM4x05ProtectionBits(uint32_t word, uint8_t addr) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//quick test for EM4x05/EM4x69 tag
|
||||
bool em4x05_isblock0(uint32_t *word) {
|
||||
return (em4x05_read_word_ext(0, 0, false, word) == PM3_SUCCESS);
|
||||
|
@ -1072,7 +1199,7 @@ int CmdEM4x05Info(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
|
||||
// based on Block0 , decide type.
|
||||
int card_type = em_get_card_type(block0);
|
||||
em_tech_type_t card_type = em_get_card_type(block0);
|
||||
|
||||
// read word 1 (serial #) doesn't need pwd
|
||||
// continue if failed, .. non blocking fail.
|
||||
|
@ -1082,10 +1209,12 @@ int CmdEM4x05Info(const char *Cmd) {
|
|||
|
||||
// read word 4 (config block)
|
||||
// needs password if one is set
|
||||
if (em4x05_read_word_ext(EM_CONFIG_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
|
||||
if (em4x05_read_word_ext(EM_CONFIG_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(DEBUG, "(CmdEM4x05Info) failed to read CONFIG BLOCK");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
printEM4x05config(word);
|
||||
printEM4x05config(card_type, word);
|
||||
|
||||
// if 4469 read EM4469_PROT_BLOCK
|
||||
// if 4305 read 14,15
|
||||
|
@ -1107,13 +1236,14 @@ int CmdEM4x05Info(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
} else if (card_type == EM_4X69) {
|
||||
} else if (card_type == EM_4369 || card_type == EM_4469) {
|
||||
// read word 3 to see which is being used for the protection bits
|
||||
if (em4x05_read_word_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
printEM4x05ProtectionBits(word, EM4469_PROT_BLOCK);
|
||||
}
|
||||
|
||||
//something went wrong
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -1169,7 +1299,7 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", pwd);
|
||||
found = true;
|
||||
} else if (status != PM3_EFAILED) {
|
||||
PrintAndLogEx(WARNING, "No answer from tag");
|
||||
PrintAndLogEx(WARNING, "no answer from tag");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1177,8 +1307,6 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
uint8_t *keyBlock = NULL;
|
||||
if (found == false) {
|
||||
|
||||
PrintAndLogEx(INFO, "press " _YELLOW_("'enter'") " to cancel the command");
|
||||
|
||||
uint32_t keycount = 0;
|
||||
|
||||
int res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount);
|
||||
|
@ -1190,6 +1318,8 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "press " _YELLOW_("'enter'") " to cancel the command");
|
||||
|
||||
for (uint32_t c = 0; c < keycount; ++c) {
|
||||
|
||||
if (!session.pm3_present) {
|
||||
|
@ -1213,7 +1343,7 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
found = true;
|
||||
break;
|
||||
} else if (status != PM3_EFAILED) {
|
||||
PrintAndLogEx(WARNING, "No answer from tag");
|
||||
PrintAndLogEx(WARNING, "no answer from tag");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1690,7 +1820,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
return exit_code;
|
||||
}
|
||||
|
||||
static size_t em4x05_Sniff_GetNextBitStart (size_t idx, size_t sc, int *data, size_t *pulsesamples) {
|
||||
static size_t em4x05_Sniff_GetNextBitStart(size_t idx, size_t sc, int *data, size_t *pulsesamples) {
|
||||
while ((idx < sc) && (data[idx] <= 10)) // find a going high
|
||||
idx++;
|
||||
|
||||
|
@ -1698,7 +1828,7 @@ static size_t em4x05_Sniff_GetNextBitStart (size_t idx, size_t sc, int *data, si
|
|||
idx++;
|
||||
|
||||
(*pulsesamples) = 0;
|
||||
while ((idx < sc) && ((data[idx+1] - data[idx]) < 10 )) { // find "sharp rise"
|
||||
while ((idx < sc) && ((data[idx + 1] - data[idx]) < 10)) { // find "sharp rise"
|
||||
(*pulsesamples)++;
|
||||
idx++;
|
||||
}
|
||||
|
@ -1706,7 +1836,7 @@ static size_t em4x05_Sniff_GetNextBitStart (size_t idx, size_t sc, int *data, si
|
|||
return idx;
|
||||
}
|
||||
|
||||
uint32_t static em4x05_Sniff_GetBlock (char *bits, bool fwd) {
|
||||
uint32_t static em4x05_Sniff_GetBlock(char *bits, bool fwd) {
|
||||
uint32_t value = 0;
|
||||
uint8_t idx;
|
||||
bool parityerror = false;
|
||||
|
@ -1752,7 +1882,7 @@ uint32_t static em4x05_Sniff_GetBlock (char *bits, bool fwd) {
|
|||
if (parity != (bits[35] - '0'))
|
||||
parityerror = true;
|
||||
|
||||
if (parityerror) printf ("parity error : ");
|
||||
if (parityerror) printf("parity error : ");
|
||||
|
||||
if (!fwd) {
|
||||
uint32_t t1 = value;
|
||||
|
@ -1793,19 +1923,21 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("1", "buf","Use the data in the buffer"),
|
||||
arg_lit0("1", "buf", "Use the data in the buffer"),
|
||||
arg_lit0("r", "rev", "Reverse the bit order for data blocks"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
sampleData = !arg_get_lit(ctx,1);
|
||||
fwd = arg_get_lit(ctx,2);
|
||||
sampleData = !arg_get_lit(ctx, 1);
|
||||
fwd = arg_get_lit(ctx, 2);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// setup and sample data from Proxmark
|
||||
// if not directed to existing sample/graphbuffer
|
||||
if (sampleData) {
|
||||
if (!IfPm3Lf()) {
|
||||
if (IfPm3Lf() == false) {
|
||||
PrintAndLogEx(WARNING, "Only offline mode is available");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
@ -1825,26 +1957,26 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
haveData = false;
|
||||
pwd = false;
|
||||
|
||||
idx = em4x05_Sniff_GetNextBitStart (idx, GraphTraceLen, GraphBuffer, &pulseSamples);
|
||||
idx = em4x05_Sniff_GetNextBitStart(idx, GraphTraceLen, GraphBuffer, &pulseSamples);
|
||||
pktOffset = idx;
|
||||
if (pulseSamples >= 10) { // Should be 18 so a bit less to allow for processing
|
||||
|
||||
|
||||
// Use first bit to get "0" bit samples as a reference
|
||||
ZeroWidth = idx;
|
||||
idx = em4x05_Sniff_GetNextBitStart (idx, GraphTraceLen, GraphBuffer, &pulseSamples);
|
||||
idx = em4x05_Sniff_GetNextBitStart(idx, GraphTraceLen, GraphBuffer, &pulseSamples);
|
||||
ZeroWidth = idx - ZeroWidth;
|
||||
|
||||
if (ZeroWidth <= 50) {
|
||||
pktOffset -= ZeroWidth;
|
||||
memset(bits,0x00,sizeof(bits));
|
||||
memset(bits, 0x00, sizeof(bits));
|
||||
bitidx = 0;
|
||||
|
||||
while ((idx < GraphTraceLen) && !eop) {
|
||||
CycleWidth = idx;
|
||||
idx = em4x05_Sniff_GetNextBitStart (idx, GraphTraceLen, GraphBuffer, &pulseSamples);
|
||||
idx = em4x05_Sniff_GetNextBitStart(idx, GraphTraceLen, GraphBuffer, &pulseSamples);
|
||||
|
||||
CycleWidth = idx - CycleWidth;
|
||||
if ((CycleWidth > 300) || (CycleWidth < (ZeroWidth-5))) { // to long or too short
|
||||
if ((CycleWidth > 300) || (CycleWidth < (ZeroWidth - 5))) { // to long or too short
|
||||
eop = true;
|
||||
bits[bitidx++] = '0'; // Append last zero from the last bit find
|
||||
cmdText[0] = 0;
|
||||
|
@ -1855,73 +1987,73 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
// Read Word 1001 <adr> => 4 + 7 => 11
|
||||
// Protect 1100 <data> => 4 + 45 => 49
|
||||
// Disable 1010 <data> => 4 + 45 => 49
|
||||
// -> disaable 1010 11111111 0 11111111 0 11111111 0 11111111 0 00000000 0
|
||||
// -> disable 1010 11111111 0 11111111 0 11111111 0 11111111 0 00000000 0
|
||||
|
||||
// Check to see if we got the leading 0
|
||||
if (((strncmp (bits,"00011",5) == 0)&& (bitidx == 50)) ||
|
||||
((strncmp (bits,"00101",5) == 0)&& (bitidx == 57)) ||
|
||||
((strncmp (bits,"01001",5) == 0)&& (bitidx == 12)) ||
|
||||
((strncmp (bits,"01100",5) == 0)&& (bitidx == 50)) ||
|
||||
((strncmp (bits,"01010",5) == 0)&& (bitidx == 50))) {
|
||||
memcpy (bits,&bits[1],bitidx-1);
|
||||
bitidx--;
|
||||
printf ("Trim leading 0\n");
|
||||
if (((strncmp(bits, "00011", 5) == 0) && (bitidx == 50)) ||
|
||||
((strncmp(bits, "00101", 5) == 0) && (bitidx == 57)) ||
|
||||
((strncmp(bits, "01001", 5) == 0) && (bitidx == 12)) ||
|
||||
((strncmp(bits, "01100", 5) == 0) && (bitidx == 50)) ||
|
||||
((strncmp(bits, "01010", 5) == 0) && (bitidx == 50))) {
|
||||
memmove(bits, &bits[1], bitidx - 1);
|
||||
bitidx--;
|
||||
printf("Trim leading 0\n");
|
||||
}
|
||||
bits[bitidx] = 0;
|
||||
// printf ("==> %s\n",bits);
|
||||
// printf ("==> %s\n",bits);
|
||||
// logon
|
||||
if ((strncmp (bits,"0011",4) == 0) && (bitidx == 49)) {
|
||||
if ((strncmp(bits, "0011", 4) == 0) && (bitidx == 49)) {
|
||||
haveData = true;
|
||||
pwd = true;
|
||||
sprintf (cmdText,"Logon");
|
||||
sprintf (blkAddr," ");
|
||||
tmpValue = em4x05_Sniff_GetBlock (&bits[4], fwd);
|
||||
sprintf (dataText,"%08X",tmpValue);
|
||||
sprintf(cmdText, "Logon");
|
||||
sprintf(blkAddr, " ");
|
||||
tmpValue = em4x05_Sniff_GetBlock(&bits[4], fwd);
|
||||
sprintf(dataText, "%08X", tmpValue);
|
||||
}
|
||||
|
||||
// write
|
||||
if ((strncmp (bits,"0101",4) == 0) && (bitidx == 56)) {
|
||||
if ((strncmp(bits, "0101", 4) == 0) && (bitidx == 56)) {
|
||||
haveData = true;
|
||||
sprintf (cmdText,"Write");
|
||||
sprintf(cmdText, "Write");
|
||||
tmpValue = (bits[4] - '0') + ((bits[5] - '0') << 1) + ((bits[6] - '0') << 2) + ((bits[7] - '0') << 3);
|
||||
sprintf (blkAddr,"%d",tmpValue);
|
||||
sprintf(blkAddr, "%d", tmpValue);
|
||||
if (tmpValue == 2)
|
||||
pwd = true;
|
||||
tmpValue = em4x05_Sniff_GetBlock (&bits[11], fwd);
|
||||
sprintf (dataText,"%08X",tmpValue);
|
||||
tmpValue = em4x05_Sniff_GetBlock(&bits[11], fwd);
|
||||
sprintf(dataText, "%08X", tmpValue);
|
||||
}
|
||||
|
||||
// read
|
||||
if ((strncmp (bits,"1001",4) == 0) && (bitidx == 11)) {
|
||||
if ((strncmp(bits, "1001", 4) == 0) && (bitidx == 11)) {
|
||||
haveData = true;
|
||||
pwd = false;
|
||||
sprintf (cmdText,"Read");
|
||||
sprintf(cmdText, "Read");
|
||||
tmpValue = (bits[4] - '0') + ((bits[5] - '0') << 1) + ((bits[6] - '0') << 2) + ((bits[7] - '0') << 3);
|
||||
sprintf (blkAddr,"%d",tmpValue);
|
||||
sprintf (dataText," ");
|
||||
sprintf(blkAddr, "%d", tmpValue);
|
||||
sprintf(dataText, " ");
|
||||
}
|
||||
|
||||
// protect
|
||||
if ((strncmp (bits,"1100",4) == 0) && (bitidx == 49)) {
|
||||
if ((strncmp(bits, "1100", 4) == 0) && (bitidx == 49)) {
|
||||
haveData = true;
|
||||
pwd = false;
|
||||
sprintf (cmdText,"Protect");
|
||||
sprintf (blkAddr," ");
|
||||
tmpValue = em4x05_Sniff_GetBlock (&bits[11], fwd);
|
||||
sprintf (dataText,"%08X",tmpValue);
|
||||
sprintf(cmdText, "Protect");
|
||||
sprintf(blkAddr, " ");
|
||||
tmpValue = em4x05_Sniff_GetBlock(&bits[11], fwd);
|
||||
sprintf(dataText, "%08X", tmpValue);
|
||||
}
|
||||
|
||||
// disable
|
||||
if ((strncmp (bits,"1010",4) == 0) && (bitidx == 49)) {
|
||||
if ((strncmp(bits, "1010", 4) == 0) && (bitidx == 49)) {
|
||||
haveData = true;
|
||||
pwd = false;
|
||||
sprintf (cmdText,"Disable");
|
||||
sprintf (blkAddr," ");
|
||||
tmpValue = em4x05_Sniff_GetBlock (&bits[11], fwd);
|
||||
sprintf (dataText,"%08X",tmpValue);
|
||||
sprintf(cmdText, "Disable");
|
||||
sprintf(blkAddr, " ");
|
||||
tmpValue = em4x05_Sniff_GetBlock(&bits[11], fwd);
|
||||
sprintf(dataText, "%08X", tmpValue);
|
||||
}
|
||||
|
||||
// bits[bitidx] = 0;
|
||||
// bits[bitidx] = 0;
|
||||
} else {
|
||||
i = (CycleWidth - ZeroWidth) / 28;
|
||||
bits[bitidx++] = '0';
|
||||
|
@ -1936,9 +2068,9 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
// Print results
|
||||
if (haveData) { //&& (minWidth > 1) && (maxWidth > minWidth)){
|
||||
if (pwd)
|
||||
PrintAndLogEx(SUCCESS, "%6llu | %-10s | "_YELLOW_("%8s")" | "_YELLOW_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits);
|
||||
PrintAndLogEx(SUCCESS, "%6zu | %-10s | "_YELLOW_("%8s")" | "_YELLOW_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits);
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, "%6llu | %-10s | "_GREEN_("%8s")" | "_GREEN_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits);
|
||||
PrintAndLogEx(SUCCESS, "%6zu | %-10s | "_GREEN_("%8s")" | "_GREEN_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,8 @@ typedef enum {
|
|||
EM_UNKNOWN,
|
||||
EM_4205,
|
||||
EM_4305,
|
||||
EM_4X69,
|
||||
EM_4369,
|
||||
EM_4469,
|
||||
} em_tech_type_t;
|
||||
|
||||
int CmdLFEM4X05(const char *Cmd);
|
||||
|
|
|
@ -137,11 +137,17 @@ int demodHID(bool verbose) {
|
|||
}
|
||||
|
||||
wiegand_message_t packed = initialize_message_object(hi2, hi, lo);
|
||||
HIDTryUnpack(&packed, false);
|
||||
if (HIDTryUnpack(&packed, false) == false) {
|
||||
PrintAndLogEx(INFO, "raw: " _GREEN_("%08x%08x%08x"), hi2, hi, lo);
|
||||
printDemodBuff(0, false, false, true);
|
||||
}
|
||||
|
||||
PrintAndLogEx(DEBUG, "DEBUG: HID idx: %d, Len: %zu, Printing Demod Buffer: ", idx, size);
|
||||
if (g_debugMode)
|
||||
printDemodBuff();
|
||||
if (g_debugMode) {
|
||||
PrintAndLogEx(DEBUG, "raw: " _GREEN_("%08x%08x%08x"), hi2, hi, lo);
|
||||
|
||||
printDemodBuff(0, false, false, false);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -433,8 +439,6 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
cn_hi.OEM = arg_get_int_def(ctx, 6, 0);
|
||||
delay = arg_get_int_def(ctx, 7, 1000);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (arg_get_lit(ctx, 8) && arg_get_lit(ctx, 9)) {
|
||||
direction = 0;
|
||||
} else if (arg_get_lit(ctx, 8)) {
|
||||
|
@ -443,6 +447,8 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
direction = 2;
|
||||
}
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Wiegand format#.. %i", format_idx);
|
||||
PrintAndLogEx(INFO, "OEM#............. %u", cn_hi.OEM);
|
||||
|
@ -470,7 +476,7 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
cn_low = cn_hi;
|
||||
|
||||
// main loop
|
||||
// iceman: could add options for bruteforcing OEM, ISSUE or FC aswell..
|
||||
// iceman: could add options for bruteforcing OEM, ISSUE or FC as well..
|
||||
bool exitloop = false;
|
||||
bool fin_hi, fin_low;
|
||||
fin_hi = fin_low = false;
|
||||
|
|
|
@ -268,7 +268,7 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) {
|
|||
|
||||
if (g_debugMode) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Indala - printing demodbuffer");
|
||||
printDemodBuff();
|
||||
printDemodBuff(0, false, false, false);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -185,7 +185,8 @@ int demodIOProx(bool verbose) {
|
|||
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox crc failed");
|
||||
|
||||
PrintAndLogEx(DEBUG, "DEBUG: IO prox idx: %d, Len: %zu, Printing demod buffer:", idx, size);
|
||||
printDemodBuff();
|
||||
printDemodBuff(0, false, false, true);
|
||||
printDemodBuff(0, false, false, false);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cmdlfem4x05.h" //
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
typedef enum {Scramble = 0, Descramble = 1} KeriMSScramble_t;
|
||||
|
@ -154,7 +154,7 @@ int demodKeri(bool verbose) {
|
|||
|
||||
raw1 = bytebits_to_byte(DemodBuffer, 32);
|
||||
raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
|
||||
|
||||
|
||||
CmdPrintDemodBuff("x");
|
||||
}
|
||||
|
||||
|
@ -166,7 +166,7 @@ int demodKeri(bool verbose) {
|
|||
ID &= 0x7FFFFFFF;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "KERI - Internal ID: " _GREEN_("%u") ", Raw: %08X%08X", ID, raw1, raw2);
|
||||
|
||||
|
||||
// Just need to the low 32 bits without the 111 trailer
|
||||
CmdKeriMSScramble(Descramble, &fc, &cardid, &raw2);
|
||||
|
||||
|
@ -187,7 +187,7 @@ static int CmdKeriRead(const char *Cmd) {
|
|||
|
||||
static int CmdKeriClone(const char *Cmd) {
|
||||
|
||||
bool q5 = false, em4305 = false;
|
||||
bool q5 = false, em = false;
|
||||
|
||||
uint8_t keritype[2] = {'i'}; // default to internalid
|
||||
int typeLen = 0;
|
||||
|
@ -227,13 +227,13 @@ static int CmdKeriClone(const char *Cmd) {
|
|||
char cardtype[16] = {"T55x7"};
|
||||
if (arg_get_lit(ctx, 1)) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype) ,"Q5/T5555");
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
q5 = true;
|
||||
}
|
||||
if (arg_get_lit(ctx, 5)) {
|
||||
blocks[0] = EM4305_KERI_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype) ,"EM4305/4469");
|
||||
em4305 = true;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
em = true;
|
||||
}
|
||||
|
||||
typeLen = sizeof(keritype);
|
||||
|
@ -242,8 +242,8 @@ static int CmdKeriClone(const char *Cmd) {
|
|||
fc = arg_get_int_def(ctx, 3, 0);
|
||||
cid = arg_get_int_def(ctx, 4, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em4305) {
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
@ -273,12 +273,12 @@ static int CmdKeriClone(const char *Cmd) {
|
|||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res;
|
||||
if (em4305) {
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf keri read`") " to verify");
|
||||
return res;
|
||||
|
|
|
@ -197,7 +197,7 @@ int demodNedap(bool verbose) {
|
|||
|
||||
badgeId = r1 * 10000 + r2 * 1000 + r3 * 100 + r4 * 10 + r5;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "NEDAP - Card: " _YELLOW_("%05u") " subtype: " _YELLOW_("%1u")" customer code: " _YELLOW_("%03x") ", Raw: %s", badgeId, subtype, customerCode, sprint_hex(data, size / 8));
|
||||
PrintAndLogEx(SUCCESS, "NEDAP - Card: " _YELLOW_("%05u") " subtype: " _YELLOW_("%1u")" customer code: " _YELLOW_("%03x") ", Raw: " _YELLOW_("%s"), badgeId, subtype, customerCode, sprint_hex_inrow(data, size / 8));
|
||||
PrintAndLogEx(DEBUG, "Checksum (%s) 0x%04X", _GREEN_("ok"), checksum);
|
||||
|
||||
} else {
|
||||
|
|
|
@ -192,8 +192,9 @@ int demodParadox(bool verbose) {
|
|||
);
|
||||
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Paradox idx: %d, len: %zu, Printing Demod Buffer:", idx, size);
|
||||
if (g_debugMode)
|
||||
printDemodBuff();
|
||||
if (g_debugMode) {
|
||||
printDemodBuff(0, false, false, false);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -196,15 +196,16 @@ int demodPyramid(bool verbose) {
|
|||
PrintAndLogEx(SUCCESS, "Pyramid - len: " _GREEN_("%d") " -unknown- Card: " _GREEN_("%d") ", Raw: %08x%08x%08x%08x", fmtLen, cardnum, rawHi3, rawHi2, rawHi, rawLo);
|
||||
}
|
||||
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Pyramid: checksum : 0x%02X - %02X - %s"
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Pyramid: checksum : 0x%02X - 0x%02X - %s"
|
||||
, checksum
|
||||
, checkCS
|
||||
, (checksum == checkCS) ? _GREEN_("ok") : _RED_("fail")
|
||||
);
|
||||
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Pyramid: idx: %d, Len: %d, Printing Demod Buffer:", idx, 128);
|
||||
if (g_debugMode)
|
||||
printDemodBuff();
|
||||
if (g_debugMode) {
|
||||
printDemodBuff(0, false, false, false);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -3040,8 +3040,14 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
if (errors || cmdp == 0) return usage_t55xx_chk();
|
||||
if (errors) return usage_t55xx_chk();
|
||||
|
||||
if (strlen(filename) == 0) {
|
||||
snprintf(filename, sizeof(filename), "t55xx_default_pwds");
|
||||
use_pwd_file = true;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
/*
|
||||
// block 7, page1 = false, usepwd = false, override = false, pwd = 00000000
|
||||
if ( T55xxReadBlock(7, false, false, false, 0x00000000) == PM3_SUCCESS) {
|
||||
|
@ -3064,7 +3070,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
|||
timeout++;
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
if (timeout > 180) {
|
||||
PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting...");
|
||||
PrintAndLogEx(WARNING, "\nno response from Proxmark3. Aborting...");
|
||||
return PM3_ENODATA;
|
||||
}
|
||||
}
|
||||
|
@ -3076,21 +3082,21 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
|||
struct p *packet = (struct p *)resp.data.asBytes;
|
||||
|
||||
if (packet->found) {
|
||||
PrintAndLogEx(SUCCESS, "\nFound a candidate [ " _YELLOW_("%08"PRIX32) " ]", packet->candidate);
|
||||
PrintAndLogEx(SUCCESS, "\nfound a candidate [ " _YELLOW_("%08"PRIX32) " ]", packet->candidate);
|
||||
|
||||
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, packet->candidate, downlink_mode)) {
|
||||
found = t55xxTryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, packet->candidate);
|
||||
if (found) {
|
||||
PrintAndLogEx(SUCCESS, "Found valid password [ " _GREEN_("%08"PRIX32) " ]", packet->candidate);
|
||||
PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", packet->candidate);
|
||||
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Check pwd failed");
|
||||
PrintAndLogEx(WARNING, "check pwd failed");
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Check pwd failed");
|
||||
PrintAndLogEx(WARNING, "check pwd failed");
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Check pwd failed");
|
||||
PrintAndLogEx(WARNING, "check pwd failed");
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
@ -3098,7 +3104,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
|||
// try calculated password
|
||||
if (useCardPassword) {
|
||||
|
||||
PrintAndLogEx(INFO, "Testing %08"PRIX32" generated ", cardPassword);
|
||||
PrintAndLogEx(INFO, "testing %08"PRIX32" generated ", cardPassword);
|
||||
for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) {
|
||||
|
||||
if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, cardPassword, dl_mode)) {
|
||||
|
@ -3107,7 +3113,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
|||
|
||||
found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, cardPassword);
|
||||
if (found) {
|
||||
PrintAndLogEx(SUCCESS, "Found valid password : [ " _GREEN_("%08"PRIX32) " ]", cardPassword);
|
||||
PrintAndLogEx(SUCCESS, "found valid password : [ " _GREEN_("%08"PRIX32) " ]", cardPassword);
|
||||
dl_mode = 4; // Exit other downlink mode checks
|
||||
}
|
||||
|
||||
|
@ -3116,22 +3122,24 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
if ((!found) && (use_pwd_file)) {
|
||||
if ((found == false) && use_pwd_file) {
|
||||
uint32_t keycount = 0;
|
||||
|
||||
int res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount);
|
||||
if (res != PM3_SUCCESS || keycount == 0 || keyBlock == NULL) {
|
||||
PrintAndLogEx(WARNING, "No keys found in file");
|
||||
PrintAndLogEx(WARNING, "no keys found in file");
|
||||
if (keyBlock != NULL)
|
||||
free(keyBlock);
|
||||
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "press " _YELLOW_("'enter'") " to cancel the command");
|
||||
|
||||
for (uint32_t c = 0; c < keycount; ++c) {
|
||||
|
||||
if (!session.pm3_present) {
|
||||
PrintAndLogEx(WARNING, "Device offline\n");
|
||||
PrintAndLogEx(WARNING, "device offline\n");
|
||||
free(keyBlock);
|
||||
return PM3_ENODATA;
|
||||
}
|
||||
|
@ -3143,7 +3151,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
|||
|
||||
uint32_t curr_password = bytes_to_num(keyBlock + 4 * c, 4);
|
||||
|
||||
PrintAndLogEx(INFO, "Testing %08"PRIX32, curr_password);
|
||||
PrintAndLogEx(INFO, "testing %08"PRIX32, curr_password);
|
||||
for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) {
|
||||
|
||||
if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, curr_password, dl_mode)) {
|
||||
|
@ -3152,7 +3160,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
|||
|
||||
found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, curr_password);
|
||||
if (found) {
|
||||
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08"PRIX32) " ]", curr_password);
|
||||
PrintAndLogEx(SUCCESS, "found valid password: [ " _GREEN_("%08"PRIX32) " ]", curr_password);
|
||||
dl_mode = 4; // Exit other downlink mode checks
|
||||
c = keycount; // Exit loop
|
||||
}
|
||||
|
@ -3163,7 +3171,8 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!found) PrintAndLogEx(WARNING, "Check pwd failed");
|
||||
if (found == false)
|
||||
PrintAndLogEx(WARNING, "check pwd failed");
|
||||
|
||||
free(keyBlock);
|
||||
|
||||
|
|
|
@ -187,21 +187,21 @@ static int CmdVisa2kClone(const char *Cmd) {
|
|||
bool q5 = tolower(param_getchar(Cmd, 1)) == 'q';
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype) ,"Q5/T5555");
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
bool em4305 = tolower(param_getchar(Cmd, 1)) == 'e';
|
||||
if (em4305) {
|
||||
bool em = tolower(param_getchar(Cmd, 1)) == 'e';
|
||||
if (em) {
|
||||
blocks[0] = EM4305_VISA2000_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype) ,"EM4305/4469");
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
if (q5 && em4305) {
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
||||
blocks[2] = id;
|
||||
blocks[3] = (visa_parity(id) << 4) | visa_chksum(id);
|
||||
|
||||
|
@ -209,7 +209,7 @@ static int CmdVisa2kClone(const char *Cmd) {
|
|||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res;
|
||||
if (em4305) {
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
|
|
|
@ -262,16 +262,16 @@ static command_t CommandTable[] = {
|
|||
{"hf", CmdHF, AlwaysAvailable, "{ High frequency commands... }"},
|
||||
{"hw", CmdHW, AlwaysAvailable, "{ Hardware commands... }"},
|
||||
{"lf", CmdLF, AlwaysAvailable, "{ Low frequency commands... }"},
|
||||
{"mem", CmdFlashMem, IfPm3Flash, "{ Flash Memory manipulation... }"},
|
||||
{"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software }"},
|
||||
{"mem", CmdFlashMem, IfPm3Flash, "{ Flash memory manipulation... }"},
|
||||
{"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software... }"},
|
||||
{"smart", CmdSmartcard, AlwaysAvailable, "{ Smart card ISO-7816 commands... }"},
|
||||
{"script", CmdScript, AlwaysAvailable, "{ Scripting commands }"},
|
||||
{"script", CmdScript, AlwaysAvailable, "{ Scripting commands... }"},
|
||||
{"trace", CmdTrace, AlwaysAvailable, "{ Trace manipulation... }"},
|
||||
{"usart", CmdUsart, IfPm3FpcUsartFromUsb, "{ USART commands... }"},
|
||||
{"wiegand", CmdWiegand, AlwaysAvailable, "{ Wiegand format manipulation... }"},
|
||||
{"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"},
|
||||
{"auto", CmdAuto, IfPm3Present, "Automated detection process for unknown tags"},
|
||||
{"clear", CmdClear, AlwaysAvailable, "clear screen"},
|
||||
{"clear", CmdClear, AlwaysAvailable, "Clear screen"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help. Use " _YELLOW_("'<command> help'") " for details of a particular command."},
|
||||
{"hints", CmdHints, AlwaysAvailable, "Turn hints on / off"},
|
||||
{"msleep", CmdMsleep, AlwaysAvailable, "Add a pause in milliseconds"},
|
||||
|
|
|
@ -8,12 +8,10 @@
|
|||
// Proxmark3 RDV40 Smartcard module commands
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdsmartcard.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "protocols.h"
|
||||
#include "cmdtrace.h"
|
||||
#include "proxmark3.h"
|
||||
|
@ -23,6 +21,7 @@
|
|||
#include "emv/dump.h"
|
||||
#include "ui.h"
|
||||
#include "fileutils.h"
|
||||
#include "crc16.h" // crc
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -313,7 +312,7 @@ static void PrintATR(uint8_t *atr, size_t atrlen) {
|
|||
PrintAndLogEx(WARNING, "Invalid ATR length. len: %zu, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K);
|
||||
|
||||
if (K > 0)
|
||||
PrintAndLogEx(INFO, "Historical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]);
|
||||
PrintAndLogEx(INFO, "Historical bytes | len %02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]);
|
||||
|
||||
if (K > 1) {
|
||||
PrintAndLogEx(INFO, "\tHistorical bytes");
|
||||
|
@ -626,45 +625,72 @@ static int CmdSmartUpgrade(const char *Cmd) {
|
|||
|
||||
PrintAndLogEx(SUCCESS, "Sim module firmware uploading to PM3");
|
||||
|
||||
PacketResponseNG resp;
|
||||
|
||||
//Send to device
|
||||
uint32_t index = 0;
|
||||
uint32_t bytes_sent = 0;
|
||||
uint32_t bytes_remaining = firmware_size;
|
||||
|
||||
// fast push mode
|
||||
conn.block_after_ACK = true;
|
||||
|
||||
while (bytes_remaining > 0) {
|
||||
uint32_t bytes_in_packet = MIN(PM3_CMD_DATA_SIZE, bytes_remaining);
|
||||
if (bytes_in_packet == bytes_remaining) {
|
||||
// Disable fast mode on last packet
|
||||
conn.block_after_ACK = false;
|
||||
}
|
||||
|
||||
struct {
|
||||
uint32_t idx;
|
||||
uint32_t bytes_in_packet;
|
||||
uint16_t crc;
|
||||
uint8_t data[400];
|
||||
} PACKED upload;
|
||||
|
||||
uint32_t bytes_in_packet = MIN(sizeof(upload.data), bytes_remaining);
|
||||
|
||||
upload.idx = index + bytes_sent;
|
||||
upload.bytes_in_packet = bytes_in_packet;
|
||||
memcpy(upload.data, firmware + bytes_sent, bytes_in_packet);
|
||||
|
||||
uint8_t a = 0, b = 0;
|
||||
compute_crc(CRC_14443_A, upload.data, bytes_in_packet, &a, &b);
|
||||
upload.crc = (a << 8 | b);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_SMART_UPLOAD, index + bytes_sent, bytes_in_packet, 0, firmware + bytes_sent, bytes_in_packet);
|
||||
if (!WaitForResponseTimeout(CMD_ACK, NULL, 2000)) {
|
||||
SendCommandNG(CMD_SMART_UPLOAD, (uint8_t *)&upload, sizeof(upload));
|
||||
if (!WaitForResponseTimeout(CMD_SMART_UPLOAD, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
free(firmware);
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
if (resp.status != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "uploading to device failed");
|
||||
free(firmware);
|
||||
return resp.status;
|
||||
}
|
||||
bytes_remaining -= bytes_in_packet;
|
||||
bytes_sent += bytes_in_packet;
|
||||
PrintAndLogEx(INPLACE, "%d bytes sent", bytes_sent);
|
||||
}
|
||||
free(firmware);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "Sim module firmware updating, don\'t turn off your PM3!");
|
||||
|
||||
// trigger the firmware upgrade
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_SMART_UPGRADE, firmware_size, 0, 0, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
struct {
|
||||
uint16_t fw_size;
|
||||
uint16_t crc;
|
||||
} PACKED payload;
|
||||
payload.fw_size = firmware_size;
|
||||
|
||||
uint8_t a = 0, b = 0;
|
||||
compute_crc(CRC_14443_A, firmware, firmware_size, &a, &b);
|
||||
payload.crc = (a << 8 | b);
|
||||
|
||||
free(firmware);
|
||||
SendCommandNG(CMD_SMART_UPGRADE, (uint8_t *)&payload, sizeof(payload));
|
||||
if (!WaitForResponseTimeout(CMD_SMART_UPGRADE, &resp, 2500)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
if ((resp.oldarg[0] & 0xFF)) {
|
||||
|
||||
if (resp.status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Sim module firmware upgrade " _GREEN_("successful"));
|
||||
PrintAndLogEx(HINT, "run " _YELLOW_("`hw status`") " to validate the fw version ");
|
||||
} else {
|
||||
|
@ -698,13 +724,12 @@ static int CmdSmartInfo(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SMART_ATR, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
if (!WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500)) {
|
||||
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
uint8_t isok = resp.oldarg[0] & 0xFF;
|
||||
if (!isok) {
|
||||
if (resp.status != PM3_SUCCESS) {
|
||||
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -771,13 +796,12 @@ static int CmdSmartReader(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SMART_ATR, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
if (!WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500)) {
|
||||
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
uint8_t isok = resp.oldarg[0] & 0xFF;
|
||||
if (!isok) {
|
||||
if (resp.status != PM3_SUCCESS) {
|
||||
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -816,11 +840,10 @@ static int CmdSmartSetClock(const char *Cmd) {
|
|||
struct {
|
||||
uint32_t new_clk;
|
||||
} PACKED payload;
|
||||
|
||||
payload.new_clk = new_clk;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SMART_SETCLOCK, (uint8_t*)&payload, sizeof(payload));
|
||||
SendCommandNG(CMD_SMART_SETCLOCK, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_SMART_SETCLOCK, &resp, 2500)) {
|
||||
PrintAndLogEx(WARNING, "smart card select failed");
|
||||
|
@ -1186,14 +1209,13 @@ bool smart_select(bool silent, smart_card_atr_t *atr) {
|
|||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SMART_ATR, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
if (!WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500)) {
|
||||
|
||||
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t isok = resp.oldarg[0] & 0xFF;
|
||||
if (!isok) {
|
||||
if (resp.status != PM3_SUCCESS) {
|
||||
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -606,8 +606,8 @@ int CmdTraceList(const char *Cmd) {
|
|||
"trace list -t hitags -> interpret as " _YELLOW_("HitagS") " communications\n"
|
||||
"trace list -t lto -> interpret as " _YELLOW_("LTO-CM") " communications\n"
|
||||
"trace list -t cryptorf -> interpret as " _YELLOW_("CryptoRF") " communitcations\n"
|
||||
"trace list -t 14a f -> show frame delay times\n"
|
||||
"trace list -t 14a 1 -> use trace buffer "
|
||||
"trace list -t 14a -f -> show frame delay times\n"
|
||||
"trace list -t 14a -1 -> use trace buffer "
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
|
|
|
@ -517,3 +517,21 @@ void APDUPrintEx(APDUStruct apdu, size_t maxdatalen) {
|
|||
if (maxdatalen > 0)
|
||||
PrintAndLogEx(INFO, "data: %s%s", sprint_hex(apdu.data, MIN(apdu.lc, maxdatalen)), apdu.lc > maxdatalen ? "..." : "");
|
||||
}
|
||||
|
||||
void SAPDUPrint(sAPDU apdu, size_t maxdatalen) {
|
||||
PrintAndLogEx(INFO, "APDU: CLA 0x%02x, INS 0x%02x, P1 0x%02x, P2 0x%02x, Lc 0x%02x(%d)",
|
||||
apdu.CLA,
|
||||
apdu.INS,
|
||||
apdu.P1,
|
||||
apdu.P2,
|
||||
apdu.Lc,
|
||||
apdu.Lc
|
||||
);
|
||||
|
||||
size_t len = apdu.Lc;
|
||||
if (maxdatalen > 0)
|
||||
len = MIN(apdu.Lc, maxdatalen);
|
||||
|
||||
PrintAndLogEx(INFO, "data { %s%s }", sprint_hex(apdu.data, len), apdu.Lc > len ? "..." : "");
|
||||
}
|
||||
|
||||
|
|
|
@ -63,4 +63,5 @@ extern int APDUEncodeS(sAPDU *sapdu, bool extended, uint16_t le, uint8_t *data,
|
|||
extern void APDUPrint(APDUStruct apdu);
|
||||
extern void APDUPrintEx(APDUStruct apdu, size_t maxdatalen);
|
||||
|
||||
void SAPDUPrint(sAPDU apdu, size_t maxdatalen);
|
||||
#endif
|
||||
|
|
|
@ -720,7 +720,8 @@ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_
|
|||
|
||||
fflush(f);
|
||||
fclose(f);
|
||||
PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s")"--> 0xffffffffffff has been inserted for unknown keys.", fileName);
|
||||
PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s"), fileName);
|
||||
PrintAndLogEx(INFO, " OBS! --> 0xFFFFFFFFFFFF <-- has been inserted for unknown keys.");
|
||||
free(fileName);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -122,6 +122,9 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs,
|
|||
}
|
||||
if (paddr < FLASH_START || (paddr + filesz) > flash_end) {
|
||||
PrintAndLogEx(ERR, "Error: PHDR is not contained in Flash");
|
||||
if ((paddr + filesz) > flash_end) {
|
||||
PrintAndLogEx(ERR, "Firmware probably too big for your device");
|
||||
}
|
||||
return PM3_EFILE;
|
||||
}
|
||||
if (vaddr >= FLASH_START && vaddr < flash_end && (flags & PF_W)) {
|
||||
|
|
|
@ -251,7 +251,7 @@ static void xor(const uint8_t *ivect, uint8_t *data, const size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
void cmac_generate_subkeys(desfirekey_t key) {
|
||||
void cmac_generate_subkeys(desfirekey_t key, MifareCryptoDirection direction) {
|
||||
int kbs = key_block_size(key);
|
||||
const uint8_t R = (kbs == 8) ? 0x1B : 0x87;
|
||||
|
||||
|
@ -261,7 +261,7 @@ void cmac_generate_subkeys(desfirekey_t key) {
|
|||
uint8_t ivect[kbs];
|
||||
memset(ivect, 0, kbs);
|
||||
|
||||
mifare_cypher_blocks_chained(NULL, key, ivect, l, kbs, MCD_RECEIVE, MCO_ENCYPHER);
|
||||
mifare_cypher_blocks_chained(NULL, key, ivect, l, kbs, direction, MCO_ENCYPHER);
|
||||
|
||||
bool xor = false;
|
||||
|
||||
|
@ -306,6 +306,45 @@ void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t le
|
|||
free(buffer);
|
||||
}
|
||||
|
||||
// This function is almot like cmac(...). but with some key differences.
|
||||
void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len) {
|
||||
int kbs = key_block_size(key);
|
||||
int kbs2 = kbs * 2;
|
||||
if (key == NULL || kbs == 0 || data == NULL || len < 1 || len > 31) {
|
||||
return;
|
||||
}
|
||||
|
||||
cmac_generate_subkeys(key, MCD_SEND);
|
||||
|
||||
uint8_t *buffer = malloc(kbs2);
|
||||
uint8_t *ivect = malloc(kbs);
|
||||
|
||||
memset(ivect, 0, kbs);
|
||||
|
||||
buffer[0] = 0x01;
|
||||
memcpy(&buffer[1], data, len++);
|
||||
|
||||
if (len != (kbs2)) {
|
||||
buffer[len++] = 0x80;
|
||||
while (len % kbs2) {
|
||||
buffer[len++] = 0x00;
|
||||
}
|
||||
xor(key->cmac_sk2, buffer + kbs, kbs);
|
||||
} else {
|
||||
xor(key->cmac_sk1, buffer + kbs, kbs);
|
||||
}
|
||||
|
||||
mbedtls_aes_context actx;
|
||||
mbedtls_aes_init(&actx);
|
||||
mbedtls_aes_setkey_enc(&actx, key->data, kbs * 8);
|
||||
mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_ENCRYPT, kbs2, ivect, buffer, buffer);
|
||||
mbedtls_aes_free(&actx);
|
||||
|
||||
memcpy(key->data, buffer + kbs, kbs);
|
||||
free(ivect);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
size_t key_block_size(const desfirekey_t key) {
|
||||
if (key == NULL)
|
||||
return 0;
|
||||
|
|
|
@ -126,9 +126,11 @@ size_t key_block_size(const desfirekey_t key);
|
|||
size_t padded_data_length(const size_t nbytes, const size_t block_size);
|
||||
size_t maced_data_length(const desfirekey_t key, const size_t nbytes);
|
||||
size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int communication_settings);
|
||||
void cmac_generate_subkeys(desfirekey_t key);
|
||||
void cmac_generate_subkeys(desfirekey_t key, MifareCryptoDirection direction);
|
||||
void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac);
|
||||
|
||||
void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t dataLen);
|
||||
|
||||
void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc);
|
||||
void desfire_crc32_append(uint8_t *data, const size_t len);
|
||||
void iso14443a_crc_append(uint8_t *data, size_t len);
|
||||
|
|
|
@ -372,3 +372,13 @@ int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) {
|
|||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int MADDFDecodeAndPrint(uint32_t short_aid) {
|
||||
open_mad_file(&mad_known_aids, false);
|
||||
|
||||
char fmt[50];
|
||||
sprintf(fmt, " MAD AID Function 0x%04X :" _YELLOW_("%s"), short_aid, "%s");
|
||||
print_aid_description(mad_known_aids, short_aid, fmt, false);
|
||||
close_mad_file(mad_known_aids);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2);
|
|||
int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen, bool swapmad);
|
||||
int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMAD2);
|
||||
int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose);
|
||||
int MADDFDecodeAndPrint(uint32_t short_aid);
|
||||
int MADCardHolderInfoDecode(uint8_t *data, size_t dataLen, bool verbose);
|
||||
|
||||
#endif // _MAD_H_
|
||||
|
|
|
@ -502,7 +502,7 @@ static void set_my_user_directory(void) {
|
|||
// if not found, default to current directory
|
||||
if (my_user_directory == NULL) {
|
||||
my_user_directory = GetCurrentDir(_cwd_Buffer, sizeof(_cwd_Buffer));
|
||||
// change all slashs to / (windows should not care...
|
||||
// change all slashes to / (windows should not care...
|
||||
for (int i = 0; i < strlen(_cwd_Buffer); i++)
|
||||
if (_cwd_Buffer[i] == '\\') _cwd_Buffer[i] = '/';
|
||||
// my_user_directory = ".";
|
||||
|
@ -1044,7 +1044,7 @@ int main(int argc, char *argv[]) {
|
|||
InitGraphics(argc, argv, script_cmds_file, script_cmd, stayInCommandLoop);
|
||||
MainGraphics();
|
||||
# else
|
||||
// for *nix distro's, check enviroment variable to verify a display
|
||||
// for *nix distro's, check environment variable to verify a display
|
||||
char *display = getenv("DISPLAY");
|
||||
if (display && strlen(display) > 1) {
|
||||
InitGraphics(argc, argv, script_cmds_file, script_cmd, stayInCommandLoop);
|
||||
|
|
|
@ -189,6 +189,29 @@ static bool Unpack_Kastle(wiegand_message_t *packed, wiegand_card_t *card) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool Pack_Kantech(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||
memset(packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
|
||||
if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
|
||||
if (card->IssueLevel > 0) return false; // Not used in this format
|
||||
if (card->OEM > 0) return false; // Not used in this format
|
||||
|
||||
packed->Length = 32;
|
||||
set_linear_field(packed, card->FacilityCode, 7, 8);
|
||||
set_linear_field(packed, card->CardNumber, 15, 16);
|
||||
return add_HID_header(packed);
|
||||
}
|
||||
|
||||
static bool Unpack_Kantech(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||
memset(card, 0, sizeof(wiegand_card_t));
|
||||
|
||||
if (packed->Length != 32) return false; // Wrong length? Stop here.
|
||||
card->FacilityCode = get_linear_field(packed, 7, 8);
|
||||
card->CardNumber = get_linear_field(packed, 15, 16);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Pack_D10202(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||
memset(packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
|
@ -240,11 +263,13 @@ static bool Unpack_H10306(wiegand_message_t *packed, wiegand_card_t *card) {
|
|||
|
||||
if (packed->Length != 34) return false; // Wrong length? Stop here.
|
||||
|
||||
card->CardNumber = (packed->Bot >> 1) & 0xFFFF;
|
||||
card->FacilityCode = ((packed->Mid & 1) << 15) | ((packed->Bot >> 17) & 0xFF);
|
||||
card->FacilityCode = get_linear_field(packed, 1, 16);
|
||||
card->CardNumber = get_linear_field(packed, 17, 16);
|
||||
|
||||
card->ParityValid =
|
||||
((evenparity32((packed->Mid & 0x00000001) ^ (packed->Bot & 0xFFFE0000)) & 1) == ((packed->Mid >> 1) & 1)) &&
|
||||
((oddparity32(packed->Bot & 0x0001FFFE) & 1) == ((packed->Bot & 1)));
|
||||
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 16))) &&
|
||||
(get_bit_by_position(packed, 33) == oddparity32(get_linear_field(packed, 17, 16)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -487,11 +512,12 @@ static bool Pack_H10304(wiegand_card_t *card, wiegand_message_t *packed) {
|
|||
if (card->OEM > 0) return false; // Not used in this format
|
||||
|
||||
packed->Length = 37; // Set number of bits
|
||||
packed->Bot |= (card->CardNumber & 0x0007FFFF) << 1;
|
||||
packed->Bot |= (card->FacilityCode & 0x00000FFF) << 20;
|
||||
packed->Mid |= (card->FacilityCode & 0x0000F000) >> 12;
|
||||
packed->Mid |= (evenparity32((packed->Mid & 0x0000000F) ^ (packed->Bot & 0xFFFC0000)) & 1) << 4;
|
||||
packed->Bot |= (oddparity32(packed->Bot & 0x0007FFFE) & 1);
|
||||
|
||||
set_linear_field(packed, card->FacilityCode, 1, 16);
|
||||
set_linear_field(packed, card->CardNumber, 17, 19);
|
||||
|
||||
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0);
|
||||
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36);
|
||||
return add_HID_header(packed);
|
||||
}
|
||||
|
||||
|
@ -500,11 +526,97 @@ static bool Unpack_H10304(wiegand_message_t *packed, wiegand_card_t *card) {
|
|||
|
||||
if (packed->Length != 37) return false; // Wrong length? Stop here.
|
||||
|
||||
card->CardNumber = (packed->Bot >> 1) & 0x0007FFFF;
|
||||
card->FacilityCode = ((packed->Mid & 0xF) << 12) | ((packed->Bot >> 20));
|
||||
card->FacilityCode = get_linear_field(packed, 1, 16);
|
||||
card->CardNumber = get_linear_field(packed, 17, 19);
|
||||
card->ParityValid =
|
||||
(evenparity32((packed->Mid & 0x0000000F) ^ (packed->Bot & 0xFFFC0000)) == ((packed->Mid >> 4) & 1)) &&
|
||||
(oddparity32(packed->Bot & 0x0007FFFE) == (packed->Bot & 1));
|
||||
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 18))) &&
|
||||
(get_bit_by_position(packed, 36) == oddparity32(get_linear_field(packed, 18, 18)));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Pack_HGeneric37(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||
memset(packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
if (card->FacilityCode > 0) return false; // Not used in this format
|
||||
if (card->CardNumber > 0x0007FFFF) return false; // Can't encode CN.
|
||||
if (card->IssueLevel > 0) return false; // Not used in this format
|
||||
if (card->OEM > 0) return false; // Not used in this format
|
||||
|
||||
packed->Length = 37; // Set number of bits
|
||||
|
||||
set_linear_field(packed, card->CardNumber, 4, 32);
|
||||
|
||||
set_bit_by_position(packed, 1, 36); // Always 1
|
||||
|
||||
// even1
|
||||
set_bit_by_position(packed,
|
||||
evenparity32(
|
||||
get_nonlinear_field(packed, 8, (uint8_t[]) {4, 8, 12, 16, 20, 24, 28, 32})
|
||||
)
|
||||
, 0
|
||||
);
|
||||
// odd1
|
||||
set_bit_by_position(packed,
|
||||
oddparity32(
|
||||
get_nonlinear_field(packed, 8, (uint8_t[]) {6, 10, 14, 18, 22, 26, 30, 34})
|
||||
)
|
||||
, 2
|
||||
);
|
||||
// even2
|
||||
set_bit_by_position(packed,
|
||||
evenparity32(
|
||||
get_nonlinear_field(packed, 8, (uint8_t[]) {7, 11, 15, 19, 23, 27, 31, 35})
|
||||
)
|
||||
, 3
|
||||
);
|
||||
return add_HID_header(packed);
|
||||
}
|
||||
|
||||
static bool Unpack_HGeneric37(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||
memset(card, 0, sizeof(wiegand_card_t));
|
||||
|
||||
if (packed->Length != 37) return false; // Wrong length? Stop here.
|
||||
if (get_bit_by_position(packed, 36) != 1) return false; // Always 1 in this format
|
||||
|
||||
card->CardNumber = get_linear_field(packed, 4, 32);
|
||||
card->ParityValid =
|
||||
(get_bit_by_position(packed, 0) == evenparity32(get_nonlinear_field(packed, 8, (uint8_t[]) {4, 8, 12, 16, 20, 24, 28, 32}))) &&
|
||||
(get_bit_by_position(packed, 2) == oddparity32(get_nonlinear_field(packed, 8, (uint8_t[]) {6, 10, 14, 18, 22, 28, 30, 34}))) &&
|
||||
(get_bit_by_position(packed, 3) == evenparity32(get_nonlinear_field(packed, 8, (uint8_t[]) {7, 11, 15, 19, 23, 27, 31, 35})))
|
||||
;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Pack_MDI37(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||
memset(packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
if (card->FacilityCode > 0x0000F) return false; // Can't encode FC.
|
||||
if (card->CardNumber > 0x1FFFFFFF) return false; // Can't encode CN.
|
||||
if (card->IssueLevel > 0) return false; // Not used in this format
|
||||
if (card->OEM > 0) return false; // Not used in this format
|
||||
|
||||
packed->Length = 37; // Set number of bits
|
||||
|
||||
set_linear_field(packed, card->FacilityCode, 3, 4);
|
||||
set_linear_field(packed, card->CardNumber, 7, 29);
|
||||
|
||||
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0);
|
||||
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36);
|
||||
return add_HID_header(packed);
|
||||
}
|
||||
|
||||
static bool Unpack_MDI37(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||
memset(card, 0, sizeof(wiegand_card_t));
|
||||
|
||||
if (packed->Length != 37) return false; // Wrong length? Stop here.
|
||||
|
||||
card->FacilityCode = get_linear_field(packed, 3, 4);;
|
||||
card->CardNumber = get_linear_field(packed, 7, 29);
|
||||
|
||||
card->ParityValid =
|
||||
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 18))) &&
|
||||
(get_bit_by_position(packed, 36) == oddparity32(get_linear_field(packed, 18, 18)))
|
||||
;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -580,24 +692,148 @@ static bool Unpack_C1k48s(wiegand_message_t *packed, wiegand_card_t *card) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool Pack_CasiRusco40(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||
|
||||
memset(packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
if (card->FacilityCode > 0) return false; // Can't encode FC.
|
||||
if (card->CardNumber > 0xFFFFFFFFFF) return false; // Can't encode CN.
|
||||
if (card->IssueLevel > 0) return false; // Not used in this format
|
||||
if (card->OEM > 0) return false; // Not used in this format
|
||||
|
||||
packed->Length = 40; // Set number of bits
|
||||
set_linear_field(packed, card->CardNumber, 1, 38);
|
||||
|
||||
return add_HID_header(packed);
|
||||
}
|
||||
|
||||
static bool Unpack_CasiRusco40(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||
memset(card, 0, sizeof(wiegand_card_t));
|
||||
|
||||
if (packed->Length != 40) return false; // Wrong length? Stop here.
|
||||
|
||||
card->CardNumber = get_linear_field(packed, 1, 38);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Pack_Optus(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||
|
||||
memset(packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
if (card->FacilityCode > 0x3FF) return false; // Can't encode FC.
|
||||
if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
|
||||
if (card->IssueLevel > 0) return false; // Not used in this format
|
||||
if (card->OEM > 0) return false; // Not used in this format
|
||||
|
||||
packed->Length = 34; // Set number of bits
|
||||
set_linear_field(packed, card->CardNumber, 1, 16);
|
||||
set_linear_field(packed, card->FacilityCode, 22, 11);
|
||||
|
||||
return add_HID_header(packed);
|
||||
}
|
||||
|
||||
static bool Unpack_Optus(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||
memset(card, 0, sizeof(wiegand_card_t));
|
||||
|
||||
if (packed->Length != 34) return false; // Wrong length? Stop here.
|
||||
|
||||
card->CardNumber = get_linear_field(packed, 1, 16);
|
||||
card->FacilityCode = get_linear_field(packed, 22, 11);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Pack_Smartpass(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||
|
||||
memset(packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
if (card->FacilityCode > 0x3FF) return false; // Can't encode FC.
|
||||
if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
|
||||
if (card->IssueLevel > 0x7) return false; // Not used in this format
|
||||
if (card->OEM > 0) return false; // Not used in this format
|
||||
|
||||
packed->Length = 34; // Set number of bits
|
||||
|
||||
set_linear_field(packed, card->FacilityCode, 1, 13);
|
||||
set_linear_field(packed, card->IssueLevel, 14, 3);
|
||||
set_linear_field(packed, card->CardNumber, 17, 16);
|
||||
return add_HID_header(packed);
|
||||
}
|
||||
|
||||
static bool Unpack_Smartpass(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||
memset(card, 0, sizeof(wiegand_card_t));
|
||||
|
||||
if (packed->Length != 34) return false; // Wrong length? Stop here.
|
||||
|
||||
card->FacilityCode = get_linear_field(packed, 1, 13);
|
||||
card->IssueLevel = get_linear_field(packed, 14, 3);
|
||||
card->CardNumber = get_linear_field(packed, 17, 16);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Pack_bqt(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||
|
||||
memset(packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
|
||||
if (card->CardNumber > 0xFFFFFF) return false; // Can't encode CN.
|
||||
if (card->IssueLevel > 0) return false; // Not used in this format
|
||||
if (card->OEM > 0) return false; // Not used in this format
|
||||
|
||||
packed->Length = 34; // Set number of bits
|
||||
|
||||
set_linear_field(packed, card->FacilityCode, 1, 8);
|
||||
set_linear_field(packed, card->CardNumber, 9, 24);
|
||||
|
||||
set_bit_by_position(packed,
|
||||
evenparity32(get_linear_field(packed, 1, 16))
|
||||
, 0);
|
||||
set_bit_by_position(packed,
|
||||
oddparity32(get_linear_field(packed, 17, 16))
|
||||
, 33);
|
||||
|
||||
return add_HID_header(packed);
|
||||
}
|
||||
|
||||
static bool Unpack_bqt(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||
memset(card, 0, sizeof(wiegand_card_t));
|
||||
|
||||
if (packed->Length != 34) return false; // Wrong length? Stop here.
|
||||
|
||||
card->FacilityCode = get_linear_field(packed, 1, 8);
|
||||
card->CardNumber = get_linear_field(packed, 9, 24);
|
||||
|
||||
card->ParityValid =
|
||||
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 16))) &&
|
||||
(get_bit_by_position(packed, 33) == oddparity32(get_linear_field(packed, 17, 16)));
|
||||
return true;
|
||||
}
|
||||
|
||||
static const cardformat_t FormatTable[] = {
|
||||
{"H10301", Pack_H10301, Unpack_H10301, "HID H10301 26-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
|
||||
{"Tecom27", Pack_Tecom27, Unpack_Tecom27, "Tecom 27-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"2804W", Pack_2804W, Unpack_2804W, "2804 Wiegand", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"2804W", Pack_2804W, Unpack_2804W, "2804 Wiegand 28-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"ATSW30", Pack_ATSW30, Unpack_ATSW30, "ATS Wiegand 30-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"ADT31", Pack_ADT31, Unpack_ADT31, "HID ADT 31-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"ADT31", Pack_ADT31, Unpack_ADT31, "HID ADT 31-bit", {1, 1, 0, 0, 0}}, // from cardinfo.barkweb.com.au
|
||||
{"Kastle", Pack_Kastle, Unpack_Kastle, "Kastle 32-bit", {1, 1, 1, 0, 1}}, // from @xilni; PR #23 on RfidResearchGroup/proxmark3
|
||||
{"Kantech", Pack_Kantech, Unpack_Kantech, "Indala/Kantech KFS 32-bit", {1, 1, 0, 0, 0}}, // from cardinfo.barkweb.com.au
|
||||
|
||||
{"D10202", Pack_D10202, Unpack_D10202, "HID D10202 33-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"H10306", Pack_H10306, Unpack_H10306, "HID H10306 34-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
|
||||
{"N10002", Pack_N10002, Unpack_N10002, "HID N10002 34-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"N10002", Pack_N10002, Unpack_N10002, "HID N10002 34-bit", {1, 1, 0, 0, 0}}, // from cardinfo.barkweb.com.au
|
||||
{"Optus34", Pack_Optus, Unpack_Optus, "Indala Optus 34-bit", {1, 1, 0, 0, 0}}, // from cardinfo.barkweb.com.au
|
||||
{"Smartpass", Pack_Smartpass, Unpack_Smartpass, "Cardkey Smartpass 34-bit", {1, 1, 1, 0, 0}}, // from cardinfo.barkweb.com.au
|
||||
{"BQT", Pack_bqt, Unpack_bqt, "BQT 34-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"C1k35s", Pack_C1k35s, Unpack_C1k35s, "HID Corporate 1000 35-bit standard layout", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
|
||||
{"C15001", Pack_C15001, Unpack_C15001, "HID KeyScan 36-bit", {1, 1, 0, 1, 1}}, // from Proxmark forums
|
||||
{"S12906", Pack_S12906, Unpack_S12906, "HID Simplex 36-bit", {1, 1, 1, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"Sie36", Pack_Sie36, Unpack_Sie36, "HID 36-bit Siemens", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"H10320", Pack_H10320, Unpack_H10320, "HID H10320 36-bit BCD", {1, 0, 0, 0, 1}}, // from Proxmark forums
|
||||
{"H10302", Pack_H10302, Unpack_H10302, "HID H10302 37-bit huge ID", {1, 0, 0, 0, 1}}, // from Proxmark forums
|
||||
{"H10304", Pack_H10304, Unpack_H10304, "HID H10304 37-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
|
||||
{"H10304", Pack_H10304, Unpack_H10304, "HID H10304 37-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"HGeneric37", Pack_HGeneric37, Unpack_HGeneric37, "HID Generic 37-bit", {1, 0, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"MDI37", Pack_MDI37, Unpack_MDI37, "PointGuard MDI 37-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"P10001", Pack_P10001, Unpack_P10001, "HID P10001 Honeywell 40-bit", {1, 1, 0, 1, 0}}, // from cardinfo.barkweb.com.au
|
||||
{"Casi40", Pack_CasiRusco40, Unpack_CasiRusco40, "Casi-Rusco 40-bit", {1, 0, 0, 0, 0}}, // from cardinfo.barkweb.com.au
|
||||
{"C1k48s", Pack_C1k48s, Unpack_C1k48s, "HID Corporate 1000 48-bit standard layout", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
|
||||
{NULL, NULL, NULL, NULL, {0, 0, 0, 0, 0}} // Must null terminate array
|
||||
};
|
||||
|
@ -709,7 +945,8 @@ bool HIDTryUnpack(wiegand_message_t *packed, bool ignore_parity) {
|
|||
++i;
|
||||
}
|
||||
if (result == false && packed->Length) {
|
||||
PrintAndLogEx(SUCCESS, "Unknown. Bit len %d", packed->Length);
|
||||
PrintAndLogEx(SUCCESS, "(wiegand unpack) unknown bit len %d", packed->Length);
|
||||
PrintAndLogEx(HINT, "Try 0xFFFF's http://cardinfo.barkweb.com.au/");
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -423,6 +423,47 @@ uint32_t lf_t55xx_white_pwdgen(uint32_t id) {
|
|||
return pwd;
|
||||
}
|
||||
|
||||
// Gallagher Desfire Key Diversification Input for Cardax Card Data Application
|
||||
int mfdes_kdf_input_gallagher(uint8_t *uid, uint8_t uidLen, uint8_t keyNo, uint32_t aid, uint8_t *kdfInputOut, uint8_t *kdfInputLen) {
|
||||
if (uid == NULL || (uidLen != 4 && uidLen != 7) || keyNo > 2 || kdfInputOut == NULL || kdfInputLen == NULL) {
|
||||
if (g_debugMode) {
|
||||
PrintAndLogEx(WARNING, "Invalid arguments");
|
||||
}
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// Verify the AppID is a valid Gallagher AppID
|
||||
if ((aid & 0xF0FFFF) != 0x2081F4) {
|
||||
if (g_debugMode) {
|
||||
PrintAndLogEx(WARNING, "Invalid Gallagher AID %06X", aid);
|
||||
}
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
// If the keyNo == 1, then omit the UID.
|
||||
if (keyNo != 1) {
|
||||
if (*kdfInputLen < (4 + uidLen)) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
memcpy(kdfInputOut, uid, uidLen);
|
||||
len += uidLen;
|
||||
} else if (*kdfInputLen < 4) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
kdfInputOut[len++] = keyNo;
|
||||
|
||||
kdfInputOut[len++] = aid & 0xff;
|
||||
kdfInputOut[len++] = (aid >> 8) & 0xff;
|
||||
kdfInputOut[len++] = (aid >> 16) & 0xff;
|
||||
|
||||
*kdfInputLen = len;
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
// Self tests
|
||||
//------------------------------------
|
||||
|
|
|
@ -43,5 +43,7 @@ int mfc_algo_sky_all(uint8_t *uid, uint8_t *keys);
|
|||
|
||||
uint32_t lf_t55xx_white_pwdgen(uint32_t id);
|
||||
|
||||
int mfdes_kdf_input_gallagher(uint8_t *uid, uint8_t uidLen, uint8_t keyNo, uint32_t aid, uint8_t *kdfInputOut, uint8_t *kdfInputLen);
|
||||
|
||||
int generator_selftest(void);
|
||||
#endif
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue