mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
@@ -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)
|
||||
|
||||
+16
-8
@@ -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;
|
||||
|
||||
+1
-2
@@ -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: {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
+51
-13
@@ -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.
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+8
-8
@@ -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)) {
|
||||
|
||||
+53
-28
@@ -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
|
||||
|
||||
+11
-7
@@ -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();
|
||||
}
|
||||
|
||||
+117
-91
@@ -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
|
||||
|
||||
+15
-1
@@ -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);
|
||||
|
||||
+233
-36
@@ -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();
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+80
-54
@@ -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);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user