mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
Merge branch 'master' into bruteforce-smart-mode
This commit is contained in:
commit
32a55654c4
51 changed files with 3575 additions and 2300 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -3,6 +3,19 @@ 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]
|
||||
- Added `hf 14b raw --pico` - now supports picopass anticollision over ISO14443-B (@iceman1001)
|
||||
- Changed `hf 14b *` - worked apdu and comms. Improved output. Uses NG packets (@iceman1001)
|
||||
- Fixed `data manrawdecode` - now copy to demodbuf even if em4100 decode fails (@iceman1001)
|
||||
- Changed `nfc decode` - now supports Android Managed Provision NDEF message decoding (@iceman1001)
|
||||
- Changed `hf_cardhopper` - Allow button presses to break, handle non-zero CID from reader by relaying RATS and improving PPS and WTX handling, more reliably cook ATS, ignore client packets on serial line (@nvx)
|
||||
- Fixed `data diff` - client no longer crashes when using short widths on long filenames (@iceman1001)
|
||||
- Added `hf 15 wipe` - fills card memory with zeros (@iceman1001)
|
||||
- Changed `hf xerox info` - now prints some part info (@iceman1001)
|
||||
- Added `hf xerox view` - view dump files of fuji/xerox tags (@iceman1001)
|
||||
- Changed `hf 15 findafi` - improved the params (@iceman1001)
|
||||
- Changed `hf 15 rdbl/rdmulti/dump` - should handle 4 vs 8 bytes block sizes in cards (@iceman1001)
|
||||
- Changed `hf 15 *` - all 15 commands now uses NG packets (@iceman1001)
|
||||
- Changed `hf 15 raw` - now supports "-k" keep field on and "-s" select (@iceman1001)
|
||||
- Changed `prefs set client.debug` - now also toggles the client side APDU logging (@iceman1001)
|
||||
- Changed `hf 14b sriwrbl` - now supports --force to override block checks. Thanks @gentilkiwi for the idea! (@iceman1001)
|
||||
- Changed `hf 14b sriwrbl` - now tries to verify the write (@iceman1001)
|
||||
|
|
|
@ -92,9 +92,9 @@ uint32_t BigBuf_get_size(void) {
|
|||
// get the address of the emulator memory. Allocate part of Bigbuf for it, if not yet done
|
||||
uint8_t *BigBuf_get_EM_addr(void) {
|
||||
// not yet allocated
|
||||
if (emulator_memory == NULL)
|
||||
emulator_memory = BigBuf_malloc(CARD_MEMORY_SIZE);
|
||||
|
||||
if (emulator_memory == NULL) {
|
||||
emulator_memory = BigBuf_calloc(CARD_MEMORY_SIZE);
|
||||
}
|
||||
return emulator_memory;
|
||||
}
|
||||
|
||||
|
@ -366,8 +366,9 @@ void tosend_stuffbit(int b) {
|
|||
}
|
||||
|
||||
dmabuf16_t *get_dma16(void) {
|
||||
if (dma_16.buf == NULL)
|
||||
if (dma_16.buf == NULL) {
|
||||
dma_16.buf = (uint16_t *)BigBuf_malloc(DMA_BUFFER_SIZE * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
return &dma_16;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC
|
||||
#define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these
|
||||
#define CARD_MEMORY_SIZE 4096
|
||||
#define DMA_BUFFER_SIZE 512
|
||||
#define DMA_BUFFER_SIZE (512 + 256)
|
||||
|
||||
// 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits
|
||||
#define TOSEND_BUFFER_SIZE (9 * MAX_FRAME_SIZE + 1 + 1 + 2)
|
||||
|
|
|
@ -78,7 +78,9 @@ void RunMod(void) {
|
|||
// Ensure debug logs don't polute stream
|
||||
#ifdef CARDHOPPER_USB
|
||||
g_reply_via_usb = false;
|
||||
g_reply_via_fpc = true;
|
||||
#else
|
||||
g_reply_via_usb = true;
|
||||
g_reply_via_fpc = false;
|
||||
#endif
|
||||
|
||||
|
@ -100,6 +102,11 @@ void RunMod(void) {
|
|||
packet_t modeRx = { 0 };
|
||||
read_packet(&modeRx);
|
||||
|
||||
if (BUTTON_PRESS()) {
|
||||
DbpString(_CYAN_("[@]") " Button pressed - Breaking from mode loop");
|
||||
break;
|
||||
}
|
||||
|
||||
if (memcmp(magicREAD, modeRx.dat, sizeof(magicREAD)) == 0) {
|
||||
DbpString(_CYAN_("[@]") " I am a READER. I talk to a CARD.");
|
||||
become_reader();
|
||||
|
@ -137,6 +144,20 @@ static void become_reader(void) {
|
|||
read_packet(rx);
|
||||
if (memcmp(magicRSRT, rx->dat, sizeof(magicRSRT)) == 0) break;
|
||||
|
||||
if (rx->dat[0] == ISO14443A_CMD_RATS && rx->len == 4) {
|
||||
// got RATS from reader, reset the card
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
SpinDelay(40);
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||
|
||||
// re-select the card without RATS to allow replaying the real RATS
|
||||
int ret = iso14443a_select_card(NULL, NULL, NULL, true, 0, true);
|
||||
if (ret && ret != 1) {
|
||||
Dbprintf(_RED_("[!]") " Error selecting card: %d", ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(toCard, rx->dat, rx->len);
|
||||
AddCrc14A(toCard, rx->len);
|
||||
ReaderTransmit(toCard, rx->len + 2, NULL);
|
||||
|
@ -212,9 +233,12 @@ static void become_card(void) {
|
|||
if (cardhopper_data_available()) {
|
||||
read_packet(rx);
|
||||
if (memcmp(magicRSRT, rx->dat, sizeof(magicRSRT)) == 0) {
|
||||
DbpString(_CYAN_("[@]") " Breaking from reader loop");
|
||||
DbpString(_CYAN_("[@]") " Breaking from emulation loop");
|
||||
break;
|
||||
}
|
||||
} else if (BUTTON_PRESS()) {
|
||||
DbpString(_CYAN_("[@]") " Button pressed - Breaking from emulation loop");
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -223,9 +247,13 @@ static void become_card(void) {
|
|||
if (try_use_canned_response(fromReaderDat, fromReaderLen, canned)) continue;
|
||||
|
||||
// Option 2: Reply with our cooked ATS
|
||||
bool no_reply = false;
|
||||
if (fromReaderDat[0] == ISO14443A_CMD_RATS && fromReaderLen == 4) {
|
||||
reply_with_packet(&ats);
|
||||
continue;
|
||||
|
||||
// fallthrough to still send the RATS to the card so it can learn the CID
|
||||
// but don't send the reply since we've already sent our cooked ATS
|
||||
no_reply = true;
|
||||
}
|
||||
|
||||
// Option 3: Relay the message
|
||||
|
@ -234,9 +262,11 @@ static void become_card(void) {
|
|||
write_packet(tx);
|
||||
|
||||
read_packet(rx);
|
||||
if (!no_reply && rx->len > 0) {
|
||||
reply_with_packet(rx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void prepare_emulation(uint8_t *tagType, uint16_t *flags, uint8_t *data, packet_t *ats) {
|
||||
|
@ -286,28 +316,71 @@ static void cook_ats(packet_t *ats, uint8_t fwi, uint8_t sfgi) {
|
|||
return;
|
||||
}
|
||||
|
||||
// If the ATS is too short (unusual), pad it to length with hopefully-sensible data
|
||||
// Might be better for the phone side to do this tbh
|
||||
if (ats->len == 1) {
|
||||
ats->len = 4;
|
||||
ats->dat[0] = 0x04;
|
||||
ats->dat[1] = 0x78;
|
||||
ats->dat[2] = 0x77;
|
||||
// ats->dat[3] = 0x80;
|
||||
} else if (ats->len == 2) {
|
||||
ats->len = 4;
|
||||
ats->dat[0] = 0x04;
|
||||
ats->dat[2] = 0x77;
|
||||
// ats->dat[3] = 0x80;
|
||||
} else if (ats->len == 3) {
|
||||
ats->len = 4;
|
||||
ats->dat[0] = 0x04;
|
||||
// ats->dat[3] = 0x80;
|
||||
uint8_t t0 = 0x70; // TA, TB, and TC transmitted, FSCI nibble set later
|
||||
uint8_t ta = 0x80; // only 106kbps rate supported, and must be same in both directions - PM3 doesn't support any other rates
|
||||
uint8_t tb = (fwi << 4) | sfgi; // cooked value
|
||||
uint8_t tc = 0;
|
||||
|
||||
uint8_t historical_len = 0;
|
||||
uint8_t *historical_bytes;
|
||||
if (ats->len > 1) {
|
||||
// T0 byte exists when ats length > 1
|
||||
|
||||
uint8_t orig_t0 = ats->dat[1];
|
||||
// Update FSCI in T0 from the received ATS
|
||||
t0 |= orig_t0 & 0x0F;
|
||||
|
||||
uint8_t len = ats->len - 2;
|
||||
uint8_t *orig_ats_ptr = &ats->dat[2];
|
||||
if (orig_t0 & 0x10) {
|
||||
// TA present
|
||||
if (len < 1) {
|
||||
DbpString(_RED_("[!]") " Malformed ATS - unable to cook; things may go wrong!");
|
||||
return;
|
||||
}
|
||||
orig_ats_ptr++;
|
||||
len--;
|
||||
}
|
||||
if (orig_t0 & 0x20) {
|
||||
// TB present
|
||||
if (len < 1) {
|
||||
DbpString(_RED_("[!]") " Malformed ATS - unable to cook; things may go wrong!");
|
||||
return;
|
||||
}
|
||||
orig_ats_ptr++;
|
||||
len--;
|
||||
}
|
||||
if (orig_t0 & 0x40) {
|
||||
// TC present, extract protocol parameters
|
||||
if (len < 1) {
|
||||
DbpString(_RED_("[!]") " Malformed ATS - unable to cook; things may go wrong!");
|
||||
return;
|
||||
}
|
||||
tc = *orig_ats_ptr;
|
||||
orig_ats_ptr++;
|
||||
len--;
|
||||
}
|
||||
|
||||
// Set the SFGI as well as the FWI - needed for some older readers (firmware revs?)
|
||||
uint8_t cookedTB0 = (fwi << 4) | sfgi;
|
||||
ats->dat[3] = cookedTB0;
|
||||
historical_bytes = orig_ats_ptr;
|
||||
historical_len = len;
|
||||
} else {
|
||||
// T0 byte missing, update FSCI in T0 to the default value of 2
|
||||
t0 |= 0x02;
|
||||
}
|
||||
|
||||
packet_t cooked_ats = { 0 };
|
||||
cooked_ats.len = 5 + historical_len;
|
||||
cooked_ats.dat[0] = cooked_ats.len;
|
||||
cooked_ats.dat[1] = t0;
|
||||
cooked_ats.dat[2] = ta;
|
||||
cooked_ats.dat[3] = tb;
|
||||
cooked_ats.dat[4] = tc;
|
||||
|
||||
if (historical_len > 0) {
|
||||
memcpy(cooked_ats.dat + 5, historical_bytes, historical_len);
|
||||
}
|
||||
|
||||
memcpy(ats, &cooked_ats, sizeof(packet_t));
|
||||
}
|
||||
|
||||
|
||||
|
@ -343,17 +416,18 @@ static bool try_use_canned_response(const uint8_t *dat, int len, tag_response_in
|
|||
}
|
||||
}
|
||||
|
||||
if (dat[0] == ISO14443A_CMD_PPS) {
|
||||
// high nibble of PPS is PPS CMD, low nibble of PPS is CID
|
||||
if ((dat[0] & 0xF0) == ISO14443A_CMD_PPS) {
|
||||
EmSendPrecompiledCmd(canned + RESP_INDEX_PPS);
|
||||
return true;
|
||||
}
|
||||
|
||||
// No response is expected to these 14a commands
|
||||
if ((dat[0] == 0xf2 && len == 4) || dat[0] == 0xfa) return true;
|
||||
if ((dat[0] & 0xF7) == ISO14443A_CMD_WTX) return true; // bit 0x08 indicates CID following
|
||||
if (dat[0] == ISO14443A_CMD_HALT && len == 4) return true;
|
||||
|
||||
// Ignore Apple ECP2 polling
|
||||
if (dat[0] == 0x6a) return true;
|
||||
if (dat[0] == ECP_HEADER) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -380,15 +454,38 @@ static void read_packet(packet_t *packet) {
|
|||
while (!cardhopper_data_available()) {
|
||||
WDT_HIT();
|
||||
SpinDelayUs(100);
|
||||
if (BUTTON_PRESS()) {
|
||||
DbpString(_CYAN_("[@]") " Button pressed while waiting for packet - aborting");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cardhopper_read((uint8_t *) &packet->len, 1);
|
||||
|
||||
uint32_t dataReceived = 0;
|
||||
while (dataReceived != packet->len) {
|
||||
while (!cardhopper_data_available()) WDT_HIT();
|
||||
while (!cardhopper_data_available()) {
|
||||
WDT_HIT();
|
||||
if (BUTTON_PRESS()) {
|
||||
DbpString(_CYAN_("[@]") " Button pressed while reading packet - aborting");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dataReceived += cardhopper_read(packet->dat + dataReceived, packet->len - dataReceived);
|
||||
|
||||
if (packet->len == 0x50 && dataReceived >= sizeof(PacketResponseNGPreamble) && packet->dat[0] == 0x4D && packet->dat[1] == 0x33 && packet->dat[2] == 0x61) {
|
||||
// PM3 NG packet magic
|
||||
DbpString(_CYAN_("[@]") " PM3 NG packet recieved - ignoring");
|
||||
|
||||
// clear any remaining buffered data
|
||||
while (cardhopper_data_available()) {
|
||||
cardhopper_read(packet->dat, 255);
|
||||
}
|
||||
|
||||
packet->len = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
cardhopper_write(magicACK, sizeof(magicACK));
|
||||
}
|
||||
|
@ -414,7 +511,7 @@ static bool GetIso14443aCommandFromReaderInterruptible(uint8_t *received, uint8_
|
|||
WDT_HIT();
|
||||
|
||||
if (flip == 3) {
|
||||
if (cardhopper_data_available())
|
||||
if (cardhopper_data_available() || BUTTON_PRESS())
|
||||
return false;
|
||||
|
||||
flip = 0;
|
||||
|
|
|
@ -815,14 +815,21 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
bool off;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
if (payload->on && payload->off)
|
||||
if (payload->on && payload->off) {
|
||||
reply_ng(CMD_SET_TEAROFF, PM3_EINVARG, NULL, 0);
|
||||
if (payload->on)
|
||||
}
|
||||
|
||||
if (payload->on) {
|
||||
g_tearoff_enabled = true;
|
||||
if (payload->off)
|
||||
}
|
||||
|
||||
if (payload->off) {
|
||||
g_tearoff_enabled = false;
|
||||
if (payload->delay_us > 0)
|
||||
}
|
||||
|
||||
if (payload->delay_us > 0) {
|
||||
g_tearoff_delay_us = payload->delay_us;
|
||||
}
|
||||
reply_ng(CMD_SET_TEAROFF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
|
@ -1269,11 +1276,16 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_COMMAND: {
|
||||
DirectTag15693Command(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
|
||||
iso15_raw_cmd_t *payload = (iso15_raw_cmd_t *)packet->data.asBytes;
|
||||
SendRawCommand15693(payload);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_FINDAFI: {
|
||||
BruteforceIso15693Afi(packet->oldarg[0]);
|
||||
struct p {
|
||||
uint32_t flags;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
BruteforceIso15693Afi(payload->flags);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_READER: {
|
||||
|
@ -1443,7 +1455,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
}
|
||||
case CMD_HF_ISO14443B_COMMAND: {
|
||||
iso14b_raw_cmd_t *payload = (iso14b_raw_cmd_t *)packet->data.asBytes;
|
||||
SendRawCommand14443B_Ex(payload);
|
||||
SendRawCommand14443B(payload);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_CRYPTORF_SIM : {
|
||||
|
|
|
@ -43,11 +43,6 @@ uint8_t get_pagemap(const picopass_hdr_t *hdr) {
|
|||
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
|
||||
}
|
||||
|
||||
// The length of a received command will in most cases be no more than 18 bytes.
|
||||
// we expect max 34 (32+2) bytes as tag answer (response to READ4)
|
||||
#ifndef ICLASS_BUFFER_SIZE
|
||||
#define ICLASS_BUFFER_SIZE 34 + 2
|
||||
#endif
|
||||
|
||||
#ifndef ICLASS_16KS_SIZE
|
||||
#define ICLASS_16KS_SIZE 0x100 * 8
|
||||
|
|
|
@ -36,6 +36,13 @@
|
|||
#define ICLASS_READER_TIMEOUT_UPDATE 3390 // 16000us, nominal 4-15ms
|
||||
#define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us
|
||||
|
||||
// The length of a received command will in most cases be no more than 18 bytes.
|
||||
// we expect max 34 (32+2) bytes as tag answer (response to READ4)
|
||||
#ifndef ICLASS_BUFFER_SIZE
|
||||
#define ICLASS_BUFFER_SIZE 34 + 2
|
||||
#endif
|
||||
|
||||
|
||||
#define AddCrc(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1)
|
||||
|
||||
void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "dbprint.h"
|
||||
#include "ticks.h"
|
||||
#include "iso14b.h" // defines for ETU conversions
|
||||
#include "iclass.h" // picopass buffer defines
|
||||
|
||||
/*
|
||||
* Current timing issues with ISO14443-b implementation
|
||||
|
@ -111,9 +112,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef MAX_14B_TIMEOUT
|
||||
// FWT(max) = 4949 ms or 4.95 seconds.
|
||||
// SSP_CLK = 4949000 * 3.39 = 16777120
|
||||
|
@ -195,9 +193,11 @@ static void iso14b_set_maxframesize(uint16_t size);
|
|||
static void iso14b_set_fwt(uint8_t fwt);
|
||||
|
||||
// the block number for the ISO14443-4 PCB (used with APDUs)
|
||||
static uint8_t iso14b_pcb_blocknum = 0;
|
||||
static uint8_t iso14b_fwt = 9;
|
||||
static uint32_t iso14b_timeout = FWT_TIMEOUT_14B;
|
||||
static uint8_t s_iso14b_pcb_blocknum = 0;
|
||||
static uint8_t s_iso14b_fwt = 9;
|
||||
static uint32_t s_iso14b_timeout = MAX_14B_TIMEOUT;
|
||||
|
||||
static bool s_field_on = false;
|
||||
|
||||
/*
|
||||
* ISO 14443-B communications
|
||||
|
@ -350,7 +350,6 @@ static uint32_t iso14b_timeout = FWT_TIMEOUT_14B;
|
|||
// them yet, just leaves them ready to send in ToSend[].
|
||||
//-----------------------------------------------------------------------------
|
||||
static void CodeIso14443bAsTag(const uint8_t *cmd, int len) {
|
||||
int i;
|
||||
|
||||
tosend_reset();
|
||||
|
||||
|
@ -362,6 +361,7 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) {
|
|||
// 80/fs < TR1 < 200/fs
|
||||
// 10 ETU < TR1 < 24 ETU
|
||||
|
||||
int i;
|
||||
// Send TR1.
|
||||
// 10-11 ETU * 4times samples ONES
|
||||
for (i = 0; i < 10; i++) {
|
||||
|
@ -458,15 +458,18 @@ static void iso14b_set_timeout(uint32_t timeout_etu) {
|
|||
ssp = MAX_14B_TIMEOUT;
|
||||
}
|
||||
|
||||
iso14b_timeout = ssp;
|
||||
s_iso14b_timeout = ssp;
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("ISO14443B Timeout set to %ld fwt", iso14b_timeout);
|
||||
Dbprintf("ISO14443B Timeout set to %ld fwt", s_iso14b_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
// keep track of FWT, also updates the timeout
|
||||
static void iso14b_set_fwt(uint8_t fwt) {
|
||||
iso14b_fwt = fwt;
|
||||
s_iso14b_fwt = fwt;
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("ISO14443B FWT Timeout set to %ld fwt", s_iso14b_fwt);
|
||||
}
|
||||
iso14b_set_timeout(32 << fwt);
|
||||
}
|
||||
|
||||
|
@ -1323,6 +1326,9 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, uint32_t
|
|||
|
||||
// The DMA buffer, used to stream samples from the FPGA
|
||||
dmabuf16_t *dma = get_dma16();
|
||||
if (dma == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
if (FpgaSetupSscDma((uint8_t *) dma->buf, DMA_BUFFER_SIZE) == false) {
|
||||
if (g_dbglevel > DBG_ERROR) Dbprintf("FpgaSetupSscDma failed. Exiting");
|
||||
|
@ -1407,9 +1413,10 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, uint32_t
|
|||
if (Demod.len > 0) {
|
||||
uint32_t sof_time = *eof_time - HF14_ETU_TO_SSP(
|
||||
(Demod.len * (8 + 2)) // time for byte transfers
|
||||
// + (10) // time for TR1
|
||||
+ (10 + 2) // time for SOF transfer
|
||||
+ (10)); // time for EOF transfer
|
||||
+ (10) // time for EOF transfer
|
||||
)
|
||||
;
|
||||
LogTrace(Demod.output, Demod.len, sof_time, *eof_time, NULL, false);
|
||||
}
|
||||
|
||||
|
@ -1583,7 +1590,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t
|
|||
/* Sends an APDU to the tag
|
||||
* TODO: check CRC and preamble
|
||||
*/
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, int *reponselen) {
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *response_byte, uint16_t *reponselen) {
|
||||
|
||||
uint8_t real_cmd[msg_len + 4];
|
||||
|
||||
|
@ -1596,12 +1603,12 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
|
|||
}
|
||||
|
||||
// put block number into the PCB
|
||||
real_cmd[0] |= iso14b_pcb_blocknum;
|
||||
real_cmd[0] |= s_iso14b_pcb_blocknum;
|
||||
memcpy(real_cmd + 1, msg, msg_len);
|
||||
} else {
|
||||
// R-block. ACK
|
||||
real_cmd[0] = 0xA2; // r-block + ACK
|
||||
real_cmd[0] |= iso14b_pcb_blocknum;
|
||||
real_cmd[0] |= s_iso14b_pcb_blocknum;
|
||||
}
|
||||
|
||||
AddCrc14B(real_cmd, msg_len + 1);
|
||||
|
@ -1618,26 +1625,25 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
|
|||
// SSP_CLK = 4833 µS * 3.39 = 16384
|
||||
|
||||
uint16_t len = 0;
|
||||
if (Get14443bAnswerFromTag(rxdata, rxmaxlen, iso14b_timeout, &eof_time, &len) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
int status = Get14443bAnswerFromTag(rxdata, rxmaxlen, s_iso14b_timeout, &eof_time, &len);
|
||||
if (status != PM3_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
FpgaDisableTracing();
|
||||
|
||||
uint8_t *data_bytes = (uint8_t *) rxdata;
|
||||
|
||||
if (len) {
|
||||
// S-Block WTX
|
||||
while (len && ((data_bytes[0] & 0xF2) == 0xF2)) {
|
||||
|
||||
uint32_t save_iso14b_timeout_spp = iso14b_timeout;
|
||||
uint32_t save_iso14b_timeout_spp = s_iso14b_timeout;
|
||||
|
||||
// 2 high bits mandatory set to 0b
|
||||
// byte1 - WTXM [1..59].
|
||||
uint8_t wtxm = data_bytes[1] & 0x3F;
|
||||
|
||||
// command FWT = FWT * WTXM
|
||||
uint32_t fwt_temp = iso14b_fwt * wtxm;
|
||||
uint32_t fwt_temp = (s_iso14b_fwt * wtxm);
|
||||
|
||||
// temporarily increase timeout
|
||||
iso14b_set_timeout((32 << fwt_temp));
|
||||
|
@ -1654,16 +1660,14 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
|
|||
// retrieve the result again (with increased timeout)
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
|
||||
if (Get14443bAnswerFromTag(rxdata, rxmaxlen, iso14b_timeout, &eof_time, &len) != PM3_SUCCESS) {
|
||||
FpgaDisableTracing();
|
||||
if (Get14443bAnswerFromTag(rxdata, rxmaxlen, s_iso14b_timeout, &eof_time, &len) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
data_bytes = rxdata;
|
||||
|
||||
// restore timeout
|
||||
iso14b_timeout = save_iso14b_timeout_spp;
|
||||
s_iso14b_timeout = save_iso14b_timeout_spp;
|
||||
}
|
||||
|
||||
// if we received an I- or R(ACK)-Block with a block number equal to the
|
||||
|
@ -1671,23 +1675,25 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
|
|||
|
||||
if ((len >= 3) && // PCB + CRC = 3 bytes
|
||||
(((data_bytes[0] & 0xC0) == 0) || (data_bytes[0] & 0xD0) == 0x80) && // I-Block OR R-Block with ACK bit set to 0
|
||||
((data_bytes[0] & 0x01) == iso14b_pcb_blocknum)) { // equal block numbers
|
||||
((data_bytes[0] & 0x01) == s_iso14b_pcb_blocknum)) { // equal block numbers
|
||||
|
||||
iso14b_pcb_blocknum ^= 1;
|
||||
s_iso14b_pcb_blocknum ^= 1;
|
||||
|
||||
}
|
||||
|
||||
// if we received I-block with chaining we need to send ACK and receive another block of data
|
||||
if (res) {
|
||||
*res = data_bytes[0];
|
||||
if (response_byte) {
|
||||
*response_byte = data_bytes[0];
|
||||
}
|
||||
|
||||
// crc check
|
||||
if (len >= 3 && (check_crc(CRC_14443_B, data_bytes, len) == false)) {
|
||||
return PM3_ECRC;
|
||||
}
|
||||
}
|
||||
|
||||
// cut frame byte
|
||||
if (len) {
|
||||
len -= 1;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
@ -1722,12 +1728,10 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
|
|||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
uint16_t retlen = 0;
|
||||
if (Get14443bAnswerFromTag(r, sizeof(r), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r, sizeof(r), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen != 4) {
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
@ -1745,10 +1749,9 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(cmdMSBUID, sizeof(cmdMSBUID), &start_time, &eof_time, true);
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(r, sizeof(r), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r, sizeof(r), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen != 4) {
|
||||
return PM3_ELENGTH;
|
||||
|
@ -1765,10 +1768,9 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(cmdLSBUID, sizeof(cmdLSBUID), &start_time, &eof_time, true);
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(r, sizeof(r), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r, sizeof(r), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen != 4) {
|
||||
return PM3_ELENGTH;
|
||||
|
@ -1782,9 +1784,6 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
|
|||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
out:
|
||||
FpgaDisableTracing();
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
/**
|
||||
* SRx Initialise.
|
||||
|
@ -1802,11 +1801,9 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
|||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
uint16_t retlen = 0;
|
||||
if (Get14443bAnswerFromTag(r_init, sizeof(r_init), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
FpgaDisableTracing();
|
||||
if (Get14443bAnswerFromTag(r_init, sizeof(r_init), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
// Randomly generated Chip ID
|
||||
if (card) {
|
||||
|
@ -1823,12 +1820,10 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(select_srx, sizeof(select_srx), &start_time, &eof_time, true);
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(r_select, sizeof(r_select), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r_select, sizeof(r_select), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen != 3) {
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
@ -1850,12 +1845,10 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(select_srx, 3, &start_time, &eof_time, true); // Only first three bytes for this one
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(r_papid, sizeof(r_papid), iso14b_timeout, &eof_time, & retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r_papid, sizeof(r_papid), s_iso14b_timeout, &eof_time, & retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen != 10) {
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
@ -1869,9 +1862,6 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
|||
memcpy(card->uid, r_papid, 8);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
out:
|
||||
FpgaDisableTracing();
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
// Xerox tag connect function: wup, anticoll, attrib, password
|
||||
|
@ -1907,12 +1897,11 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
for (slot = 0; slot < 4; slot++) {
|
||||
start_time = eof_time + HF14_ETU_TO_SSP(30); //(24); // next slot after 24 ETU
|
||||
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
if (retlen > 0) {
|
||||
Dbprintf("unexpected data %d", retlen);
|
||||
Dbprintf("crc %s", check_crc(CRC_14443_B, x_atqb, retlen) ? "OK" : "BAD");
|
||||
}
|
||||
goto out;
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
// tx unframed slot-marker
|
||||
|
@ -1930,8 +1919,6 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
}
|
||||
|
||||
if (4 == slot) {
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
DbpString("no answer to anticollision");
|
||||
}
|
||||
|
@ -1939,8 +1926,8 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
}
|
||||
}
|
||||
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
|
@ -1984,10 +1971,9 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(txbuf + 1, 15, &start_time, &eof_time, true);
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen < 3) {
|
||||
return PM3_ELENGTH;
|
||||
|
@ -2018,8 +2004,8 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(txbuf, 17, &start_time, &eof_time, true);
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
if (retlen < 4) {
|
||||
|
@ -2035,10 +2021,6 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
|
||||
out:
|
||||
FpgaDisableTracing();
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
/* Perform the ISO 14443 B Card Selection procedure
|
||||
|
@ -2066,12 +2048,10 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
|
|||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
uint16_t retlen = 0;
|
||||
if (Get14443bAnswerFromTag(r_pupid, sizeof(r_pupid), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r_pupid, sizeof(r_pupid), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
FpgaDisableTracing();
|
||||
|
||||
// ATQB too short?
|
||||
if (retlen < 14) {
|
||||
return PM3_ELENGTH;
|
||||
|
@ -2098,10 +2078,9 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(attrib, sizeof(attrib), &start_time, &eof_time, true);
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(r_attrib, sizeof(r_attrib), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r_attrib, sizeof(r_attrib), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
// Answer to ATTRIB too short?
|
||||
if (retlen < 3) {
|
||||
|
@ -2135,13 +2114,135 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
|
|||
}
|
||||
}
|
||||
// reset PCB block number
|
||||
iso14b_pcb_blocknum = 0;
|
||||
s_iso14b_pcb_blocknum = 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
out:
|
||||
FpgaDisableTracing();
|
||||
static int iso14443b_select_picopass_card(picopass_hdr_t *hdr) {
|
||||
|
||||
static uint8_t act_all[] = { ICLASS_CMD_ACTALL };
|
||||
static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY };
|
||||
static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 };
|
||||
uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t read_aia[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64};
|
||||
uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 };
|
||||
uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
|
||||
|
||||
uint32_t start_time = 0;
|
||||
uint32_t eof_time = 0;
|
||||
uint16_t retlen = 0;
|
||||
|
||||
// first, wake up the tag 0x0A
|
||||
CodeAndTransmit14443bAsReader(act_all, sizeof(act_all), &start_time, &eof_time, true);
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
|
||||
// 0x0C
|
||||
// start_time = eof_time + ISO14B_TR2;
|
||||
start_time = eof_time + US_TO_SSP(330); // 330ms before next cmd
|
||||
CodeAndTransmit14443bAsReader(identify, sizeof(identify), &start_time, &eof_time, true);
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
|
||||
// expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC
|
||||
if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
if (retlen != 10) {
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
||||
// copy the Anti-collision CSN to our select-packet
|
||||
memcpy(&select[1], resp, 8);
|
||||
|
||||
// select the card
|
||||
start_time = eof_time + ISO14B_TR2;
|
||||
CodeAndTransmit14443bAsReader(select, sizeof(select), &start_time, &eof_time, true);
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
|
||||
// expect a 10-byte response here, 8 byte CSN and 2 byte CRC
|
||||
if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
if (retlen != 10) {
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
||||
// save CSN
|
||||
memcpy(hdr->csn, resp, sizeof(hdr->csn));
|
||||
|
||||
// card selected, now read config (block1) (only 8 bytes no CRC)
|
||||
start_time = eof_time + ISO14B_TR2;
|
||||
CodeAndTransmit14443bAsReader(read_conf, sizeof(read_conf), &start_time, &eof_time, true);
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
|
||||
// expect a 10-byte response here, 8 bytes CONFIGURATION and 2 byte CRC)
|
||||
if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
if (retlen != 10) {
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
||||
// save CONF
|
||||
memcpy((uint8_t *)&hdr->conf, resp, sizeof(hdr->conf));
|
||||
|
||||
uint8_t pagemap = get_pagemap(hdr);
|
||||
if (pagemap != PICOPASS_NON_SECURE_PAGEMODE) {
|
||||
|
||||
// read App Issuer Area block 5
|
||||
start_time = eof_time + ISO14B_TR2;
|
||||
CodeAndTransmit14443bAsReader(read_aia, sizeof(read_aia), &start_time, &eof_time, true);
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
|
||||
// expect AIA, a 10-byte response here
|
||||
if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
if (retlen != 10) {
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
||||
memcpy(hdr->app_issuer_area, resp, sizeof(hdr->app_issuer_area));
|
||||
|
||||
// card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
|
||||
start_time = eof_time + ISO14B_TR2;
|
||||
CodeAndTransmit14443bAsReader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, true);
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
|
||||
// expect EPURSE, a 8 byte response here
|
||||
if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
if (retlen != 8) {
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
||||
memcpy(hdr->epurse, resp, sizeof(hdr->epurse));
|
||||
|
||||
} else {
|
||||
|
||||
// on NON_SECURE_PAGEMODE cards, AIA is on block2..
|
||||
|
||||
// read App Issuer Area block 2
|
||||
read_aia[1] = 0x02;
|
||||
read_aia[2] = 0x61;
|
||||
read_aia[3] = 0x10;
|
||||
|
||||
start_time = eof_time + ISO14B_TR2;
|
||||
CodeAndTransmit14443bAsReader(read_aia, sizeof(read_aia), &start_time, &eof_time, true);
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
|
||||
// expect AIA, a 10-byte response here
|
||||
if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
if (retlen != 10) {
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
||||
memcpy(hdr->epurse, resp, sizeof(hdr->epurse));
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// Set up ISO 14443 Type B communication (similar to iso14443a_setup)
|
||||
// field is setup for "Sending as Reader"
|
||||
|
@ -2180,6 +2281,8 @@ void iso14443b_setup(void) {
|
|||
// reset timeout
|
||||
iso14b_set_fwt(8);
|
||||
|
||||
s_field_on = true;
|
||||
|
||||
LED_D_ON();
|
||||
}
|
||||
|
||||
|
@ -2194,7 +2297,6 @@ void iso14443b_setup(void) {
|
|||
//-----------------------------------------------------------------------------
|
||||
static int read_14b_srx_block(uint8_t blocknr, uint8_t *block) {
|
||||
|
||||
// iceman: todo add static CRC
|
||||
uint8_t cmd[] = {ISO14443B_READ_BLK, blocknr, 0x00, 0x00};
|
||||
AddCrc14B(cmd, 2);
|
||||
|
||||
|
@ -2206,20 +2308,16 @@ static int read_14b_srx_block(uint8_t blocknr, uint8_t *block) {
|
|||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
uint16_t retlen = 0;
|
||||
if (Get14443bAnswerFromTag(r_block, sizeof(r_block), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
FpgaDisableTracing();
|
||||
if (Get14443bAnswerFromTag(r_block, sizeof(r_block), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
// Check if we got an answer from the tag
|
||||
if (retlen != 6) {
|
||||
Dbprintf("expected 6 bytes from tag, got %u", retlen);
|
||||
return PM3_EWRONGANSWER;
|
||||
}
|
||||
// The check the CRC of the answer
|
||||
if (check_crc(CRC_14443_B, r_block, retlen) == false) {
|
||||
DbpString("CRC fail");
|
||||
return PM3_ECRC;
|
||||
}
|
||||
|
||||
|
@ -2227,14 +2325,6 @@ static int read_14b_srx_block(uint8_t blocknr, uint8_t *block) {
|
|||
memcpy(block, r_block, ISO14B_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if (g_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 PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -2457,7 +2547,7 @@ static void iso14b_set_trigger(bool enable) {
|
|||
g_trigger = enable;
|
||||
}
|
||||
|
||||
void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) {
|
||||
void SendRawCommand14443B(iso14b_raw_cmd_t *p) {
|
||||
|
||||
// turn on trigger (LED_A)
|
||||
if ((p->flags & ISO14B_REQUEST_TRIGGER) == ISO14B_REQUEST_TRIGGER) {
|
||||
|
@ -2476,6 +2566,7 @@ void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) {
|
|||
clear_trace();
|
||||
BigBuf_Clear_ext(false);
|
||||
}
|
||||
|
||||
set_tracing(true);
|
||||
|
||||
// receive buffer
|
||||
|
@ -2512,51 +2603,75 @@ void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) {
|
|||
sendlen = sizeof(iso14b_cts_card_select_t);
|
||||
status = iso14443b_select_cts_card(cts);
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t *)cts, sendlen);
|
||||
if (status > PM3_SUCCESS) goto out;
|
||||
if (status != PM3_SUCCESS) goto out;
|
||||
}
|
||||
|
||||
if ((p->flags & ISO14B_SELECT_PICOPASS) == ISO14B_SELECT_PICOPASS) {
|
||||
picopass_hdr_t *hdr = (picopass_hdr_t *)buf;
|
||||
memset(hdr, 0, sizeof(picopass_hdr_t));
|
||||
sendlen = sizeof(picopass_hdr_t);
|
||||
status = iso14443b_select_picopass_card(hdr);
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t *)hdr, sendlen);
|
||||
if (status != PM3_SUCCESS) goto out;
|
||||
}
|
||||
|
||||
// if field is off...
|
||||
if (
|
||||
((p->flags & ISO14B_APDU) == ISO14B_APDU) ||
|
||||
((p->flags & ISO14B_RAW) == ISO14B_RAW)
|
||||
) {
|
||||
if (s_field_on == false) {
|
||||
DbpString("Field is off");
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, PM3_ERFTRANS, NULL, 0);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if ((p->flags & ISO14B_APDU) == ISO14B_APDU) {
|
||||
|
||||
int responselen = 0;
|
||||
uint16_t responselen = 0;
|
||||
uint8_t response_byte = 0;
|
||||
status = iso14443b_apdu(p->raw, p->rawlen, (p->flags & ISO14B_SEND_CHAINING), buf, sizeof(buf), &response_byte, &responselen);
|
||||
bool chaining = ((p->flags & ISO14B_SEND_CHAINING) == ISO14B_SEND_CHAINING);
|
||||
status = iso14443b_apdu(p->raw, p->rawlen, chaining, buf, sizeof(buf), &response_byte, &responselen);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, PM3_ETEAROFF, NULL, 0);
|
||||
} else {
|
||||
responselen = MIN(responselen, PM3_CMD_DATA_SIZE);
|
||||
|
||||
iso14b_raw_apdu_response_t *payload = (iso14b_raw_apdu_response_t *)BigBuf_calloc( sizeof(iso14b_raw_apdu_response_t) + responselen);
|
||||
uint8_t packet[responselen + 1 + 2];
|
||||
iso14b_raw_apdu_response_t *payload = (iso14b_raw_apdu_response_t *)packet;
|
||||
payload->response_byte = response_byte;
|
||||
payload->datalen = responselen;
|
||||
memcpy(payload->data, buf, payload->datalen);
|
||||
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t*)payload, sizeof(iso14b_raw_apdu_response_t) + responselen);
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, status, packet, sizeof(packet));
|
||||
}
|
||||
}
|
||||
|
||||
if ((p->flags & ISO14B_RAW) == ISO14B_RAW) {
|
||||
|
||||
uint8_t *raw = BigBuf_calloc(p->rawlen + 2);
|
||||
memcpy(raw, p->raw, p->rawlen);
|
||||
if (
|
||||
((p->flags & ISO14B_APPEND_CRC) == ISO14B_APPEND_CRC) && (p->rawlen)) {
|
||||
AddCrc14B(raw, p->rawlen);
|
||||
if (((p->flags & ISO14B_APPEND_CRC) == ISO14B_APPEND_CRC) && (p->rawlen)) {
|
||||
|
||||
// Picopass uses different CRC algo
|
||||
// it also excludes the first instruction byte
|
||||
if ((p->flags & ISO14B_SELECT_PICOPASS) == ISO14B_SELECT_PICOPASS) {
|
||||
AddCrc15(p->raw + 1, p->rawlen - 1);
|
||||
} else {
|
||||
AddCrc14B(p->raw, p->rawlen);
|
||||
}
|
||||
p->rawlen += 2;
|
||||
}
|
||||
|
||||
uint32_t start_time = 0;
|
||||
uint32_t eof_time = 0;
|
||||
CodeAndTransmit14443bAsReader(raw, p->rawlen, &start_time, &eof_time, true);
|
||||
CodeAndTransmit14443bAsReader(p->raw, p->rawlen, &start_time, &eof_time, true);
|
||||
|
||||
FpgaDisableTracing();
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, PM3_ETEAROFF, NULL, 0);
|
||||
} else {
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
|
||||
uint16_t retlen = 0;
|
||||
status = Get14443bAnswerFromTag(buf, sizeof(buf), iso14b_timeout, &eof_time, &retlen);
|
||||
status = Get14443bAnswerFromTag(buf, sizeof(buf), s_iso14b_timeout, &eof_time, &retlen);
|
||||
if (status == PM3_SUCCESS) {
|
||||
sendlen = MIN(retlen, PM3_CMD_DATA_SIZE);
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, status, Demod.output, sendlen);
|
||||
|
@ -2578,5 +2693,6 @@ out:
|
|||
switch_off(); // disconnect raw
|
||||
SpinDelay(20);
|
||||
BigBuf_free_keep_EM();
|
||||
s_field_on = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,8 +34,12 @@
|
|||
# define AddCrc14B(data, len) compute_crc(CRC_14443_B, (data), (len), (data)+(len), (data)+(len)+1)
|
||||
#endif
|
||||
|
||||
#ifndef AddCrc15
|
||||
#define AddCrc15(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1)
|
||||
#endif
|
||||
|
||||
void iso14443b_setup(void);
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, int * responselen);
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, uint16_t *responselen);
|
||||
|
||||
int iso14443b_select_card(iso14b_card_select_t *card);
|
||||
|
||||
|
@ -43,8 +47,7 @@ void SimulateIso14443bTag(const uint8_t *pupi);
|
|||
void AcquireRawAdcSamplesIso14443b(uint32_t parameter);
|
||||
void read_14b_st_block(uint8_t blocknr);
|
||||
void SniffIso14443b(void);
|
||||
void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
|
||||
void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p);
|
||||
void SendRawCommand14443B(iso14b_raw_cmd_t *p);
|
||||
|
||||
// States for 14B SIM command
|
||||
#define SIM_NOFIELD 0
|
||||
|
|
|
@ -1739,7 +1739,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
|
|||
}
|
||||
|
||||
// no need to try decoding reader data if the tag is sending
|
||||
if (!tag_is_active) {
|
||||
if (tag_is_active == false) {
|
||||
|
||||
int extra_8s = 1;
|
||||
if (Handle15693SampleFromReader((sniffdata & 0x02) >> 1, &dreader) ||
|
||||
|
@ -1756,7 +1756,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
|
|||
// sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq
|
||||
LogTrace_ISO15693(dreader.output, dreader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true);
|
||||
|
||||
if (!iclass) { // Those flags don't exist in iClass
|
||||
if (iclass == false) { // Those flags don't exist in iClass
|
||||
expect_fsk_answer = dreader.output[0] & ISO15_REQ_SUBCARRIER_TWO;
|
||||
expect_fast_answer = dreader.output[0] & ISO15_REQ_DATARATE_HIGH;
|
||||
}
|
||||
|
@ -1774,17 +1774,19 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
|
|||
}
|
||||
|
||||
// no need to try decoding tag data if the reader is currently sending or no answer expected yet
|
||||
if (!reader_is_active && expect_tag_answer) {
|
||||
if ((reader_is_active == false) && expect_tag_answer) {
|
||||
|
||||
if (!expect_fsk_answer) {
|
||||
if (expect_fsk_answer == false) {
|
||||
// single subcarrier tag response
|
||||
if (Handle15693SamplesFromTag((sniffdata >> 4) << 2, &dtag, expect_fast_answer)) {
|
||||
|
||||
// sof/eof_times are in ssp_clk, which is 13.56MHz / 4
|
||||
uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF
|
||||
|
||||
if (dtag.lastBit == SOF_PART2) {
|
||||
eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS)
|
||||
}
|
||||
|
||||
uint32_t sof_time = eof_time
|
||||
- dtag.len * 1024 // time for byte transfers (4096/fc / 4)
|
||||
- 512 // time for SOF transfer (2048/fc / 4)
|
||||
|
@ -1802,18 +1804,22 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
|
|||
} else {
|
||||
tag_is_active = (dtag.state >= STATE_TAG_RECEIVING_DATA);
|
||||
}
|
||||
|
||||
} else {
|
||||
// dual subcarrier tag response
|
||||
if (FREQ_IS_0((sniffdata >> 2) & 0x3)) // tolerate 1 00
|
||||
if (FREQ_IS_0((sniffdata >> 2) & 0x3)) { // tolerate 1 00
|
||||
sniffdata = sniffdata_prev;
|
||||
}
|
||||
|
||||
if (Handle15693FSKSamplesFromTag((sniffdata >> 2) & 0x3, &dtagfsk, expect_fast_answer)) {
|
||||
if (dtagfsk.len > 0) {
|
||||
// sof/eof_times are in ssp_clk, which is 13.56MHz / 4
|
||||
uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF
|
||||
|
||||
if (dtagfsk.lastBit == SOF) {
|
||||
eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS)
|
||||
}
|
||||
|
||||
uint32_t sof_time = eof_time
|
||||
- dtagfsk.len * 1016 // time for byte transfers (4064/fc / 4) - FSK is slightly different
|
||||
- 512 // time for SOF transfer (2048/fc / 4)
|
||||
|
@ -1937,8 +1943,8 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t
|
|||
*eof_time = start_time + 32 * ((8 * ts->max) - 4); // subtract the 4 padding bits after EOF
|
||||
LogTrace_ISO15693(send, sendlen, (start_time * 4), (*eof_time * 4), NULL, true);
|
||||
if (recv != NULL) {
|
||||
bool fsk = send[0] & ISO15_REQ_SUBCARRIER_TWO;
|
||||
bool recv_speed = send[0] & ISO15_REQ_DATARATE_HIGH;
|
||||
bool fsk = ((send[0] & ISO15_REQ_SUBCARRIER_TWO) == ISO15_REQ_SUBCARRIER_TWO);
|
||||
bool recv_speed = ((send[0] & ISO15_REQ_DATARATE_HIGH) == ISO15_REQ_DATARATE_HIGH);
|
||||
res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time, fsk, recv_speed, resp_len);
|
||||
}
|
||||
return res;
|
||||
|
@ -2087,7 +2093,7 @@ void ReaderIso15693(iso15_card_select_t *p_card) {
|
|||
reply_ng(CMD_HF_ISO15693_READER, PM3_SUCCESS, uid, sizeof(uid));
|
||||
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
Dbprintf("[+] %d octets read from IDENTIFY request:", recvlen);
|
||||
Dbprintf("[+] %d bytes read from IDENTIFY request:", recvlen);
|
||||
DbdecodeIso15693Answer(recvlen, answer);
|
||||
Dbhexdump(recvlen, answer, true);
|
||||
}
|
||||
|
@ -2360,16 +2366,20 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) {
|
|||
|
||||
// Since there is no standardized way of reading the AFI out of a tag, we will brute force it
|
||||
// (some manufactures offer a way to read the AFI, though)
|
||||
void BruteforceIso15693Afi(uint32_t speed) {
|
||||
void BruteforceIso15693Afi(uint32_t flags) {
|
||||
|
||||
clear_trace();
|
||||
|
||||
uint8_t data[7] = {0};
|
||||
uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH];
|
||||
Iso15693InitReader();
|
||||
|
||||
bool speed = ((flags & ISO15_HIGH_SPEED) == ISO15_HIGH_SPEED);
|
||||
|
||||
// first without AFI
|
||||
// Tags should respond without AFI and with AFI=0 even when AFI is active
|
||||
uint8_t data[7] = {0};
|
||||
uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH] = {0};
|
||||
|
||||
data[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
|
||||
data[0] = (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1);
|
||||
data[1] = ISO15693_INVENTORY;
|
||||
data[2] = 0; // AFI
|
||||
AddCrc15(data, 3);
|
||||
|
@ -2434,16 +2444,31 @@ void BruteforceIso15693Afi(uint32_t speed) {
|
|||
|
||||
// Allows to directly send commands to the tag via the client
|
||||
// OBS: doesn't turn off rf field afterwards.
|
||||
void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data) {
|
||||
void SendRawCommand15693(iso15_raw_cmd_t *packet) {
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
|
||||
uint16_t timeout;
|
||||
uint32_t eof_time = 0;
|
||||
uint16_t timeout = ISO15693_READER_TIMEOUT;
|
||||
if ((packet->flags & ISO15_LONG_WAIT) == ISO15_LONG_WAIT) {
|
||||
timeout = ISO15693_READER_TIMEOUT_WRITE;
|
||||
}
|
||||
|
||||
bool speed = ((packet->flags & ISO15_HIGH_SPEED) == ISO15_HIGH_SPEED);
|
||||
bool keep_field_on = ((packet->flags & ISO15_NO_DISCONNECT) == ISO15_NO_DISCONNECT);
|
||||
bool read_respone = ((packet->flags & ISO15_READ_RESPONSE) == ISO15_READ_RESPONSE);
|
||||
bool init = ((packet->flags & ISO15_CONNECT) == ISO15_CONNECT);
|
||||
|
||||
// This is part of ISO15693 protocol definitions where the following commands needs to request option.
|
||||
// note:
|
||||
// it seem like previous we just guessed and never followed the fISO145_REQ_OPTION flag if it was set / not set from client side.
|
||||
// this is a problem. Since without this the response from the tag is one byte shorter. And a lot of client side functions has been
|
||||
// hardcoded to assume for the extra byte in the response.
|
||||
|
||||
bool request_answer = false;
|
||||
|
||||
switch (data[1]) {
|
||||
switch (packet->raw[1]) {
|
||||
case ISO15693_SET_PASSWORD:
|
||||
case ISO15693_ENABLE_PRIVACY:
|
||||
case ISO15693_WRITEBLOCK:
|
||||
case ISO15693_LOCKBLOCK:
|
||||
case ISO15693_WRITE_MULTI_BLOCK:
|
||||
|
@ -2453,42 +2478,54 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint
|
|||
case ISO15693_WRITE_PASSWORD:
|
||||
case ISO15693_PASSWORD_PROTECT_EAS:
|
||||
case ISO15693_LOCK_DSFID:
|
||||
timeout = ISO15693_READER_TIMEOUT_WRITE;
|
||||
request_answer = data[0] & ISO15_REQ_OPTION;
|
||||
request_answer = ((packet->raw[0] & ISO15_REQ_OPTION) == ISO15_REQ_OPTION);
|
||||
break;
|
||||
default:
|
||||
timeout = ISO15693_READER_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t eof_time = 0;
|
||||
uint32_t start_time = 0;
|
||||
uint16_t recvlen = 0;
|
||||
int res = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), start_time, timeout, &eof_time, &recvlen);
|
||||
|
||||
uint8_t buf[ISO15693_MAX_RESPONSE_LENGTH] = {0x00};
|
||||
|
||||
int res = SendDataTag(packet->raw, packet->rawlen, init, speed, (read_respone ? buf : NULL), sizeof(buf), start_time, timeout, &eof_time, &recvlen);
|
||||
|
||||
if (res == PM3_ETEAROFF) { // tearoff occurred
|
||||
reply_ng(CMD_HF_ISO15693_COMMAND, res, NULL, 0);
|
||||
} else {
|
||||
|
||||
bool fsk = data[0] & ISO15_REQ_SUBCARRIER_TWO;
|
||||
bool recv_speed = data[0] & ISO15_REQ_DATARATE_HIGH;
|
||||
// if tag answers with an error code, it don't care about EOF packet
|
||||
if (recvlen) {
|
||||
recvlen = MIN(recvlen, ISO15693_MAX_RESPONSE_LENGTH);
|
||||
reply_ng(CMD_HF_ISO15693_COMMAND, res, buf, recvlen);
|
||||
}
|
||||
|
||||
// looking at the first byte of the RAW bytes to determine Subcarrier, datarate, request option
|
||||
bool fsk = ((packet->raw[0] & ISO15_REQ_SUBCARRIER_TWO) == ISO15_REQ_SUBCARRIER_TWO);
|
||||
bool recv_speed = ((packet->raw[0] & ISO15_REQ_DATARATE_HIGH) == ISO15_REQ_DATARATE_HIGH);
|
||||
|
||||
// send a single EOF to get the tag response
|
||||
if (request_answer) {
|
||||
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
||||
res = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT, &eof_time, fsk, recv_speed, &recvlen);
|
||||
res = SendDataTagEOF((read_respone ? buf : NULL), sizeof(buf), start_time, ISO15693_READER_TIMEOUT, &eof_time, fsk, recv_speed, &recvlen);
|
||||
}
|
||||
|
||||
if (recv) {
|
||||
if (read_respone) {
|
||||
recvlen = MIN(recvlen, ISO15693_MAX_RESPONSE_LENGTH);
|
||||
reply_ng(CMD_HF_ISO15693_COMMAND, res, recvbuf, recvlen);
|
||||
reply_ng(CMD_HF_ISO15693_COMMAND, res, buf, recvlen);
|
||||
} else {
|
||||
reply_ng(CMD_HF_ISO15693_COMMAND, PM3_SUCCESS, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (keep_field_on == false) {
|
||||
switch_off(); // disconnect raw
|
||||
SpinDelay(20);
|
||||
}
|
||||
|
||||
// note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway
|
||||
// also prevents hf 15 raw -k keep_field on ...
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LED_D_OFF();
|
||||
LED_A_OFF();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2611,10 +2648,9 @@ void LockPassSlixIso15693(uint32_t pass_id, uint32_t password) {
|
|||
void SetTag15693Uid(const uint8_t *uid) {
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
uint8_t cmd[4][9] = {
|
||||
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3e, 0x00, 0x00, 0x00, 0x00},
|
||||
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3f, 0x69, 0x96, 0x00, 0x00},
|
||||
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x8F},
|
||||
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3f, 0x69, 0x96, 0x00, 0x00, 0x8A, 0xBB},
|
||||
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x38},
|
||||
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x39}
|
||||
};
|
||||
|
@ -2631,29 +2667,31 @@ void SetTag15693Uid(const uint8_t *uid) {
|
|||
cmd[3][5] = uid[1];
|
||||
cmd[3][6] = uid[0];
|
||||
|
||||
AddCrc15(cmd[0], 7);
|
||||
AddCrc15(cmd[1], 7);
|
||||
AddCrc15(cmd[2], 7);
|
||||
AddCrc15(cmd[3], 7);
|
||||
|
||||
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
|
||||
uint8_t buf[ISO15693_MAX_RESPONSE_LENGTH] = {0x00};
|
||||
|
||||
uint32_t start_time = 0;
|
||||
uint32_t eof_time = 0;
|
||||
uint16_t recvlen = 0;
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
res = SendDataTag(
|
||||
cmd[i],
|
||||
sizeof(cmd[i]),
|
||||
(i == 0) ? true : false,
|
||||
true,
|
||||
recvbuf,
|
||||
sizeof(recvbuf),
|
||||
buf,
|
||||
sizeof(buf),
|
||||
start_time,
|
||||
ISO15693_READER_TIMEOUT_WRITE,
|
||||
&eof_time,
|
||||
&recvlen);
|
||||
&recvlen
|
||||
);
|
||||
|
||||
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,8 +48,8 @@ void AcquireRawAdcSamplesIso15693(void);
|
|||
void ReaderIso15693(iso15_card_select_t *p_card); // ISO15693 reader
|
||||
void EmlClearIso15693(void);
|
||||
void SimTagIso15693(uint8_t *uid, uint8_t block_size); // simulate an ISO15693 tag
|
||||
void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag
|
||||
void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data); // send arbitrary commands from CLI
|
||||
void BruteforceIso15693Afi(uint32_t flags); // find an AFI of a tag
|
||||
void SendRawCommand15693(iso15_raw_cmd_t *packet); // send arbitrary commands from CLI
|
||||
|
||||
void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool iclass);
|
||||
|
||||
|
|
|
@ -493,6 +493,8 @@ float brute_force_benchmark(void) {
|
|||
|
||||
if (!read_bench_data(test_candidates)) {
|
||||
PrintAndLogEx(NORMAL, "Couldn't read benchmark data. Assuming brute force rate of %1.0f states per second", DEFAULT_BRUTE_FORCE_RATE);
|
||||
free(test_candidates[0].states[ODD_STATE]);
|
||||
free(test_candidates[0].states[EVEN_STATE]);
|
||||
return DEFAULT_BRUTE_FORCE_RATE;
|
||||
}
|
||||
|
||||
|
@ -515,5 +517,3 @@ float brute_force_benchmark(void) {
|
|||
test_candidates[0].len[EVEN_STATE] = 0;
|
||||
return bf_rate;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,9 @@ author = "Adam Foster (evildaemond)"
|
|||
version = 'v0.0.1'
|
||||
desc = [[
|
||||
Convert a facility code and card number to a Mifare Classic UID, which can be used as part of a downgrade attack.
|
||||
This abuses the fact that some controllers interpret the UID for Mifare Classic cards as a CN and FN, it requires the controller to interpret the wiegand payload in this way.
|
||||
|
||||
The example of FC 146 CN 5 would be read by the reader and send as a payload like 0920005, where 9200 is dec 146 and 05 is interpreted as 5
|
||||
|
||||
Working on HID Readers with any of the following enabled
|
||||
- Generic 14333A
|
||||
|
|
|
@ -608,11 +608,14 @@ static int Cmdmandecoderaw(const char *Cmd) {
|
|||
uint64_t id = 0;
|
||||
uint32_t hi = 0;
|
||||
size_t idx = 0;
|
||||
int res = Em410xDecode(bits, &size, &idx, &hi, &id);
|
||||
size_t tmpsize = 0;
|
||||
int res = Em410xDecode(bits, &tmpsize, &idx, &hi, &id);
|
||||
if (res > 0) {
|
||||
//need to adjust to set bitstream back to manchester encoded data
|
||||
//setDemodBuff(bits, size, idx);
|
||||
printEM410x(hi, id, false, res);
|
||||
|
||||
size = tmpsize;
|
||||
}
|
||||
}
|
||||
setDemodBuff(bits, size, 0);
|
||||
|
@ -3192,7 +3195,7 @@ static int CmdDiff(const char *Cmd) {
|
|||
// dump magic card memory
|
||||
/*
|
||||
if (use_c) {
|
||||
PrintAndLogEx(WARNING, "not implemented yet, feel free to contribute!");
|
||||
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
|
||||
return PM3_ENOTIMPL;
|
||||
}
|
||||
*/
|
||||
|
@ -3200,21 +3203,41 @@ static int CmdDiff(const char *Cmd) {
|
|||
size_t biggest = (datalenA > datalenB) ? datalenA : datalenB;
|
||||
PrintAndLogEx(DEBUG, "data len: %zu A %zu B %zu", biggest, datalenA, datalenB);
|
||||
|
||||
if (inA == NULL)
|
||||
if (inA == NULL) {
|
||||
PrintAndLogEx(INFO, "inA null");
|
||||
}
|
||||
|
||||
if (inB == NULL)
|
||||
if (inB == NULL) {
|
||||
PrintAndLogEx(INFO, "inB null");
|
||||
}
|
||||
|
||||
|
||||
char hdr0[400] = {0};
|
||||
|
||||
int hdr_sln = (width * 4) + 2;
|
||||
char hdr0[300] = {0};
|
||||
int max_fn_space = (width * 4);
|
||||
|
||||
int max_fn_space = (width * 5);
|
||||
if (max_fn_space < fnlenA) {
|
||||
truncate_filename(filenameA, max_fn_space);
|
||||
fnlenA = strlen(filenameA);
|
||||
}
|
||||
|
||||
if (max_fn_space < fnlenB) {
|
||||
truncate_filename(filenameB, max_fn_space);
|
||||
fnlenB = strlen(filenameB);
|
||||
}
|
||||
|
||||
if (fnlenA && fnlenB) {
|
||||
|
||||
if (fnlenA && fnlenB && (max_fn_space > fnlenA) && (max_fn_space > fnlenB)) {
|
||||
snprintf(hdr0, sizeof(hdr0) - 1, " # | " _CYAN_("%.*s"), max_fn_space, filenameA);
|
||||
memset(hdr0 + strlen(hdr0), ' ', hdr_sln - strlen(filenameA) - 1);
|
||||
|
||||
// add space if needed
|
||||
int padding_len = (hdr_sln - fnlenA - 1);
|
||||
if (padding_len > 0) {
|
||||
memset(hdr0 + strlen(hdr0), ' ', padding_len);
|
||||
}
|
||||
snprintf(hdr0 + strlen(hdr0), sizeof(hdr0) - 1 - strlen(hdr0), "| " _CYAN_("%.*s"), max_fn_space, filenameB);
|
||||
|
||||
} else {
|
||||
strcat(hdr0, " # | " _CYAN_("a"));
|
||||
memset(hdr0 + strlen(hdr0), ' ', hdr_sln - 2);
|
||||
|
@ -3334,7 +3357,6 @@ static int CmdNumCon(const char *Cmd) {
|
|||
memset(dec, 0, sizeof(dec));
|
||||
int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)dec, sizeof(dec), &dlen);
|
||||
|
||||
|
||||
int hlen = 256;
|
||||
char hex[256];
|
||||
memset(hex, 0, sizeof(hex));
|
||||
|
@ -3363,13 +3385,13 @@ static int CmdNumCon(const char *Cmd) {
|
|||
mbedtls_mpi N;
|
||||
mbedtls_mpi_init(&N);
|
||||
|
||||
|
||||
// hex
|
||||
if (hlen > 0) {
|
||||
if (data_verify_hex((uint8_t *)hex, hlen) == false) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16, hex));
|
||||
PrintAndLogEx(INFO, "Input hex len... %d", hlen);
|
||||
}
|
||||
|
||||
// decimal
|
||||
|
@ -3382,6 +3404,7 @@ static int CmdNumCon(const char *Cmd) {
|
|||
if (blen > 0) {
|
||||
// should have bianry string check here too
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 2, bin));
|
||||
PrintAndLogEx(INFO, "Input bin len... %d", blen);
|
||||
}
|
||||
|
||||
mbedtls_mpi base;
|
||||
|
|
|
@ -205,11 +205,11 @@ static const manufactureName_t manufactureMapping[] = {
|
|||
// returns description of the best match
|
||||
const char *getTagInfo(uint8_t uid) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAYLEN(manufactureMapping); ++i)
|
||||
if (uid == manufactureMapping[i].uid)
|
||||
for (int i = 0; i < ARRAYLEN(manufactureMapping); ++i) {
|
||||
if (uid == manufactureMapping[i].uid) {
|
||||
return manufactureMapping[i].desc;
|
||||
}
|
||||
}
|
||||
|
||||
//No match, return default
|
||||
return manufactureMapping[ARRAYLEN(manufactureMapping) - 1].desc;
|
||||
|
@ -832,7 +832,7 @@ int CmdHF14ASim(const char *Cmd) {
|
|||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
PacketResponseNG resp = {0};
|
||||
|
||||
sector_t *k_sector = NULL;
|
||||
size_t k_sectors_cnt = MIFARE_4K_MAXSECTOR;
|
||||
|
@ -1254,54 +1254,59 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
|
|||
|
||||
// ISO14443-4. 7. Half-duplex block transmission protocol
|
||||
static int CmdHF14AAPDU(const char *Cmd) {
|
||||
uint8_t data[PM3_CMD_DATA_SIZE];
|
||||
int datalen = 0;
|
||||
uint8_t header[PM3_CMD_DATA_SIZE];
|
||||
int headerlen = 0;
|
||||
bool activateField = false;
|
||||
bool leaveSignalON = false;
|
||||
bool decodeTLV = false;
|
||||
bool decodeAPDU = false;
|
||||
bool makeAPDU = false;
|
||||
bool extendedAPDU = false;
|
||||
int le = 0;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14a apdu",
|
||||
"Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). works with all apdu types from ISO 7816-4:2013",
|
||||
"hf 14a apdu -st 00A404000E325041592E5359532E444446303100\n"
|
||||
"hf 14a apdu -sd 00A404000E325041592E5359532E444446303100 -> decode apdu\n"
|
||||
"hf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 -> encode standard apdu\n"
|
||||
"hf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 -> encode extended apdu\n");
|
||||
"Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL).\n"
|
||||
"Works with all APDU types from ISO 7816-4:2013\n"
|
||||
"\n"
|
||||
"note:\n"
|
||||
" `-m` and `-d` goes hand in hand\n"
|
||||
" -m <CLA INS P1 P2> -d 325041592E5359532E4444463031\n"
|
||||
"\n"
|
||||
" OR\n"
|
||||
"\n"
|
||||
" use `-d` with complete APDU data\n"
|
||||
" -d 00A404000E325041592E5359532E444446303100",
|
||||
"hf 14a apdu -st -d 00A404000E325041592E5359532E444446303100\n"
|
||||
"hf 14a apdu -sd -d 00A404000E325041592E5359532E444446303100 -> decode apdu\n"
|
||||
"hf 14a apdu -sm 00A40400 -d 325041592E5359532E4444463031 -l 256 -> encode standard apdu\n"
|
||||
"hf 14a apdu -sm 00A40400 -d 325041592E5359532E4444463031 -el 65536 -> encode extended apdu\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("s", "select", "activate field and select card"),
|
||||
arg_lit0("k", "keep", "keep signal field ON after receive"),
|
||||
arg_lit0("t", "tlv", "executes TLV decoder if it possible"),
|
||||
arg_lit0("d", "decapdu", "decode apdu request if it possible"),
|
||||
arg_str0("m", "make", "<head (CLA INS P1 P2) hex>", "make apdu with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
|
||||
arg_lit0("t", "tlv", "decode TLV"),
|
||||
arg_lit0("d", "decapdu", "decode APDU request"),
|
||||
arg_str0("m", "make", "<hex>", "APDU header, 4 bytes <CLA INS P1 P2>"),
|
||||
arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"),
|
||||
arg_int0("l", "le", "<Le (int)>", "Le apdu parameter if `m` parameter included"),
|
||||
arg_strx1(NULL, NULL, "<APDU (hex) | data (hex)>", "data if `m` parameter included"),
|
||||
arg_int0("l", "le", "<dec>", "Le APDU parameter if `m` parameter included"),
|
||||
arg_strx1("d", "data", "<hex>", "full APDU package or data if `m` parameter included"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
activateField = arg_get_lit(ctx, 1);
|
||||
leaveSignalON = arg_get_lit(ctx, 2);
|
||||
decodeTLV = arg_get_lit(ctx, 3);
|
||||
decodeAPDU = arg_get_lit(ctx, 4);
|
||||
bool activateField = arg_get_lit(ctx, 1);
|
||||
bool leaveSignalON = arg_get_lit(ctx, 2);
|
||||
bool decodeTLV = arg_get_lit(ctx, 3);
|
||||
bool decodeAPDU = arg_get_lit(ctx, 4);
|
||||
|
||||
uint8_t header[PM3_CMD_DATA_SIZE];
|
||||
int headerlen = 0;
|
||||
CLIGetHexWithReturn(ctx, 5, header, &headerlen);
|
||||
makeAPDU = headerlen > 0;
|
||||
|
||||
bool makeAPDU = (headerlen > 0);
|
||||
|
||||
if (makeAPDU && headerlen != 4) {
|
||||
PrintAndLogEx(ERR, "header length must be 4 bytes instead of %d", headerlen);
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
extendedAPDU = arg_get_lit(ctx, 6);
|
||||
le = arg_get_int_def(ctx, 7, 0);
|
||||
bool extendedAPDU = arg_get_lit(ctx, 6);
|
||||
int le = arg_get_int_def(ctx, 7, 0);
|
||||
|
||||
uint8_t data[PM3_CMD_DATA_SIZE];
|
||||
int datalen = 0;
|
||||
|
||||
if (makeAPDU) {
|
||||
uint8_t apdudata[PM3_CMD_DATA_SIZE] = {0};
|
||||
|
@ -1386,35 +1391,35 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", NULL, "active signal field ON without select"),
|
||||
arg_int0("b", NULL, "<dec>", "number of bits to send. Useful for send partial byte"),
|
||||
arg_lit0("c", NULL, "calculate and append CRC"),
|
||||
arg_lit0("k", NULL, "keep signal field ON after receive"),
|
||||
arg_lit0("a", NULL, "Active signal field ON without select"),
|
||||
arg_lit0("c", NULL, "Calculate and append CRC"),
|
||||
arg_lit0("k", NULL, "Keep signal field ON after receive"),
|
||||
arg_lit0("3", NULL, "ISO14443-3 select only (skip RATS)"),
|
||||
arg_lit0("r", NULL, "do not read response"),
|
||||
arg_lit0("s", NULL, "active signal field ON with select"),
|
||||
arg_int0("t", "timeout", "<ms>", "timeout in milliseconds"),
|
||||
arg_lit0("r", NULL, "Do not read response"),
|
||||
arg_lit0("s", NULL, "Active signal field ON with select"),
|
||||
arg_int0("t", "timeout", "<ms>", "Timeout in milliseconds"),
|
||||
arg_int0("b", NULL, "<dec>", "Number of bits to send. Useful for send partial byte"),
|
||||
arg_lit0("v", "verbose", "Verbose output"),
|
||||
arg_lit0(NULL, "topaz", "use Topaz protocol to send command"),
|
||||
arg_lit0(NULL, "ecp", "use enhanced contactless polling"),
|
||||
arg_lit0(NULL, "mag", "use Apple magsafe polling"),
|
||||
arg_strx1(NULL, NULL, "<hex>", "raw bytes to send"),
|
||||
arg_lit0(NULL, "ecp", "Use enhanced contactless polling"),
|
||||
arg_lit0(NULL, "mag", "Use Apple magsafe polling"),
|
||||
arg_lit0(NULL, "topaz", "Use Topaz protocol to send command"),
|
||||
arg_strx1(NULL, NULL, "<hex>", "Raw bytes to send"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
bool active = arg_get_lit(ctx, 1);
|
||||
uint16_t numbits = (uint16_t)arg_get_int_def(ctx, 2, 0);
|
||||
bool crc = arg_get_lit(ctx, 3);
|
||||
bool keep_field_on = arg_get_lit(ctx, 4);
|
||||
bool no_rats = arg_get_lit(ctx, 5);
|
||||
bool reply = (arg_get_lit(ctx, 6) == false);
|
||||
bool active_select = arg_get_lit(ctx, 7);
|
||||
uint32_t timeout = (uint32_t)arg_get_int_def(ctx, 8, 0);
|
||||
bool crc = arg_get_lit(ctx, 2);
|
||||
bool keep_field_on = arg_get_lit(ctx, 3);
|
||||
bool no_rats = arg_get_lit(ctx, 4);
|
||||
bool reply = (arg_get_lit(ctx, 5) == false);
|
||||
bool active_select = arg_get_lit(ctx, 6);
|
||||
uint32_t timeout = (uint32_t)arg_get_int_def(ctx, 7, 0);
|
||||
uint16_t numbits = (uint16_t)arg_get_int_def(ctx, 8, 0);
|
||||
bool verbose = arg_get_lit(ctx, 9);
|
||||
bool topazmode = arg_get_lit(ctx, 10);
|
||||
bool use_ecp = arg_get_lit(ctx, 11);
|
||||
bool use_magsafe = arg_get_lit(ctx, 12);
|
||||
bool use_ecp = arg_get_lit(ctx, 10);
|
||||
bool use_magsafe = arg_get_lit(ctx, 11);
|
||||
bool topazmode = arg_get_lit(ctx, 12);
|
||||
|
||||
int datalen = 0;
|
||||
uint8_t data[PM3_CMD_DATA_SIZE_MIX] = {0};
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
|
||||
#include "aidsearch.h"
|
||||
#include "fileutils.h" // saveFile
|
||||
#include "iclass_cmd.h" // picopass defines
|
||||
|
||||
#define MAX_14B_TIMEOUT_MS (4949U)
|
||||
|
||||
|
@ -54,9 +55,6 @@
|
|||
#define ST25_SIZE_2K 4
|
||||
#define ST25_SIZE_4K 5
|
||||
|
||||
|
||||
|
||||
|
||||
// iso14b apdu input frame length
|
||||
static uint16_t apdu_frame_length = 0;
|
||||
//static uint16_t ats_fsc[] = {16, 24, 32, 40, 48, 64, 96, 128, 256};
|
||||
|
@ -76,6 +74,17 @@ static int switch_off_field_14b(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int clear_trace_14b(void) {
|
||||
iso14b_raw_cmd_t packet = {
|
||||
.flags = ISO14B_CLEARTRACE,
|
||||
.timeout = 0,
|
||||
.rawlen = 0,
|
||||
};
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void hf14b_aid_search(bool verbose) {
|
||||
|
||||
json_t *root = AIDSearchInit(verbose);
|
||||
|
@ -258,8 +267,14 @@ static bool wait_cmd_14b(bool verbose, bool is_select, uint32_t timeout) {
|
|||
}
|
||||
|
||||
if (is_select) {
|
||||
if (resp.status == PM3_ECARDEXCHANGE) {
|
||||
PrintAndLogEx(INFO, "no response from tag");
|
||||
return false;
|
||||
}
|
||||
if (resp.status != PM3_SUCCESS) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "failed status value... %d", resp.status);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -295,226 +310,6 @@ static bool wait_cmd_14b(bool verbose, bool is_select, uint32_t timeout) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static int CmdHF14BList(const char *Cmd) {
|
||||
return CmdTraceListAlias(Cmd, "hf 14b", "14b -c");
|
||||
}
|
||||
|
||||
static int CmdHF14BSim(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sim",
|
||||
"Simulate a ISO/IEC 14443 type B tag with 4 byte UID / PUPI",
|
||||
"hf 14b sim -u 11AA33BB"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("u", "uid", "hex", "4byte UID/PUPI"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint8_t pupi[4];
|
||||
int n = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(FAILED, "failed to read pupi");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Simulate with PUPI : " _GREEN_("%s"), sprint_hex_inrow(pupi, sizeof(pupi)));
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort simulation");
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14BSniff(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sniff",
|
||||
"Sniff the communication reader and tag",
|
||||
"hf 14b sniff"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_SNIFF, NULL, 0);
|
||||
|
||||
WaitForResponse(CMD_HF_ISO14443B_SNIFF, &resp);
|
||||
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 14b list") "` to view captured tracelog");
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -h") "` to save tracelog for later analysing");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14BCmdRaw(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b raw",
|
||||
"Sends raw bytes to card",
|
||||
"hf 14b raw -cks --data 0200a40400 -> standard select, apdu 0200a4000 (7816)\n"
|
||||
"hf 14b raw -ck --sr --data 0200a40400 -> SRx select\n"
|
||||
"hf 14b raw -ck --cts --data 0200a40400 -> C-ticket select\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("k", "keep", "leave the signal field ON after receive response"),
|
||||
arg_lit0("s", "std", "activate field, use ISO14B select"),
|
||||
arg_lit0(NULL, "sr", "activate field, use SRx ST select"),
|
||||
arg_lit0(NULL, "cts", "activate field, use ASK C-ticket select"),
|
||||
arg_lit0(NULL, "xrx", "activate field, use Fuji/Xerox select"),
|
||||
arg_lit0("c", "crc", "calculate and append CRC"),
|
||||
arg_lit0("r", NULL, "do not read response from card"),
|
||||
arg_int0("t", "timeout", "<dec>", "timeout in ms"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_str0("d", "data", "<hex>", "data, bytes to send"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
bool keep_field_on = arg_get_lit(ctx, 1);
|
||||
bool select_std = arg_get_lit(ctx, 2);
|
||||
bool select_sr = arg_get_lit(ctx, 3);
|
||||
bool select_cts = arg_get_lit(ctx, 4);
|
||||
bool select_xrx = arg_get_lit(ctx, 5);
|
||||
bool add_crc = arg_get_lit(ctx, 6);
|
||||
bool read_reply = (arg_get_lit(ctx, 7) == false);
|
||||
int user_timeout = arg_get_int_def(ctx, 8, -1);
|
||||
bool verbose = arg_get_lit(ctx, 9);
|
||||
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
int datalen = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 10), data, sizeof(data), &datalen);
|
||||
if (res && verbose) {
|
||||
PrintAndLogEx(INFO, "called with no raw bytes");
|
||||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// FLAGS for device side
|
||||
uint32_t flags = ISO14B_CONNECT;
|
||||
if (add_crc) {
|
||||
flags |= ISO14B_APPEND_CRC;
|
||||
}
|
||||
|
||||
if (select_std) {
|
||||
flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using ISO14443-B select");
|
||||
}
|
||||
} else if (select_sr) {
|
||||
flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using ST/SRx select");
|
||||
}
|
||||
} else if (select_cts) {
|
||||
flags |= (ISO14B_SELECT_CTS | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using ASK/C-ticket select");
|
||||
}
|
||||
} else if (select_xrx) {
|
||||
flags |= (ISO14B_SELECT_XRX | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using Fuji/Xerox select");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t time_wait = 0;
|
||||
if (user_timeout > 0) {
|
||||
|
||||
flags |= ISO14B_SET_TIMEOUT;
|
||||
|
||||
if (user_timeout > MAX_14B_TIMEOUT_MS) {
|
||||
user_timeout = MAX_14B_TIMEOUT_MS;
|
||||
PrintAndLogEx(INFO, "set timeout to 4.9 seconds. The max we can wait for response");
|
||||
}
|
||||
|
||||
// timeout in ETUs (time to transfer 1 bit, approx. 9.4 us)
|
||||
time_wait = (uint32_t)((13560 / 128) * user_timeout);
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, " new raw timeout : %u ETU ( %u ms )", time_wait, user_timeout);
|
||||
}
|
||||
|
||||
if (keep_field_on == false) {
|
||||
flags |= ISO14B_DISCONNECT;
|
||||
}
|
||||
|
||||
if (datalen > 0) {
|
||||
flags |= ISO14B_RAW;
|
||||
}
|
||||
|
||||
// Max buffer is PM3_CMD_DATA_SIZE
|
||||
datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen;
|
||||
|
||||
|
||||
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + datalen);
|
||||
if (packet == NULL) {
|
||||
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
packet->flags = flags;
|
||||
packet->timeout = time_wait;
|
||||
packet->rawlen = datalen;
|
||||
memcpy(packet->raw, data, datalen);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen);
|
||||
free(packet);
|
||||
|
||||
if (read_reply == false) {
|
||||
clearCommandBuffer();
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
|
||||
// Select, device will send back iso14b_card_select_t, don't print it.
|
||||
if (select_std) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for standard select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_sr) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for ST/SRx select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_cts) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for ASK/C-ticket select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_xrx) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for Fuji/Xerox select");
|
||||
}
|
||||
}
|
||||
|
||||
// get back response from the raw bytes you sent.
|
||||
if (success && datalen > 0) {
|
||||
wait_cmd_14b(true, false, user_timeout);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static bool get_14b_UID(uint8_t *d, iso14b_type_t *found_type) {
|
||||
|
||||
// sanity checks
|
||||
|
@ -579,6 +374,30 @@ static bool get_14b_UID(uint8_t *d, iso14b_type_t *found_type) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/* extract uid from filename
|
||||
* filename must match '^hf-14b-[0-9A-F]{16}'
|
||||
*/
|
||||
uint8_t *get_uid_from_filename(const char *filename) {
|
||||
static uint8_t uid[8] ;
|
||||
memset(uid, 0, 8) ;
|
||||
char uidinhex[17] ;
|
||||
if (strlen(filename) < 23 || strncmp(filename, "hf-14b-", 7)) {
|
||||
PrintAndLogEx(ERR, "can't get uid from filename '%s'. Expected format is hf-14b-<uid>...", filename);
|
||||
return uid ;
|
||||
}
|
||||
// extract uid part from filename
|
||||
strncpy(uidinhex, filename + 7, 16) ;
|
||||
uidinhex[16] = '\0' ;
|
||||
int len = hex_to_bytes(uidinhex, uid, 8);
|
||||
if (len == 8)
|
||||
return SwapEndian64(uid, 8, 8);
|
||||
else {
|
||||
PrintAndLogEx(ERR, "get_uid_from_filename failed: hex_to_bytes returned %d", len);
|
||||
memset(uid, 0, 8);
|
||||
}
|
||||
return uid ;
|
||||
}
|
||||
|
||||
// print full atqb info
|
||||
// bytes
|
||||
// 0,1,2,3 = application data
|
||||
|
@ -858,6 +677,7 @@ static uint8_t get_st_cardsize(const uint8_t *uid) {
|
|||
}
|
||||
|
||||
/*
|
||||
|
||||
static uint8_t get_st25_cardsize(const uint8_t *uid) {
|
||||
uint8_t chipid = get_st25_chipid(uid);
|
||||
switch (chipid) {
|
||||
|
@ -979,6 +799,247 @@ static void print_sr_blocks(uint8_t *data, size_t len, const uint8_t *uid) {
|
|||
// 0200a404000ca000000063504b43532d313500 (resp 02 6a 82 [4b 4c])
|
||||
// 0200a4040010a000000018300301000000000000000000 (resp 02 6a 82 [4b 4c])
|
||||
|
||||
static int CmdHF14BList(const char *Cmd) {
|
||||
return CmdTraceListAlias(Cmd, "hf 14b", "14b -c");
|
||||
}
|
||||
|
||||
static int CmdHF14BSim(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sim",
|
||||
"Simulate a ISO/IEC 14443 type B tag with 4 byte UID / PUPI",
|
||||
"hf 14b sim -u 11AA33BB"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("u", "uid", "hex", "4byte UID/PUPI"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint8_t pupi[4];
|
||||
int n = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(FAILED, "failed to read pupi");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Simulate with PUPI : " _GREEN_("%s"), sprint_hex_inrow(pupi, sizeof(pupi)));
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort simulation");
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14BSniff(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sniff",
|
||||
"Sniff the communication reader and tag",
|
||||
"hf 14b sniff"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_SNIFF, NULL, 0);
|
||||
|
||||
WaitForResponse(CMD_HF_ISO14443B_SNIFF, &resp);
|
||||
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 14b list") "` to view captured tracelog");
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -h") "` to save tracelog for later analysing");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14BRaw(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b raw",
|
||||
"Sends raw bytes to card. Activates field by default",
|
||||
"hf 14b raw -cks --data 0200a40400 -> standard select, apdu 0200a4000 (7816)\n"
|
||||
"hf 14b raw -ck --sr --data 0200a40400 -> SRx select\n"
|
||||
"hf 14b raw -ck --cts --data 0200a40400 -> C-ticket select\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", NULL, "active signal field ON without select"),
|
||||
arg_lit0("c", "crc", "calculate and append CRC"),
|
||||
arg_lit0("k", "keep", "leave the signal field ON after receive response"),
|
||||
|
||||
arg_str0("d", "data", "<hex>", "data, bytes to send"),
|
||||
arg_lit0("r", NULL, "do not read response from card"),
|
||||
arg_int0("t", "timeout", "<dec>", "timeout in ms"),
|
||||
|
||||
arg_lit0("s", "std", "use ISO14B select"),
|
||||
arg_lit0(NULL, "sr", "use SRx ST select"),
|
||||
arg_lit0(NULL, "cts", "use ASK C-ticket select"),
|
||||
arg_lit0(NULL, "xrx", "use Fuji/Xerox select"),
|
||||
arg_lit0(NULL, "pico", "use Picopass select"),
|
||||
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
bool activate_field = arg_get_lit(ctx, 1);
|
||||
bool add_crc = arg_get_lit(ctx, 2);
|
||||
bool keep_field_on = arg_get_lit(ctx, 3);
|
||||
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
int datalen = 0;
|
||||
CLIParamHexToBuf(arg_get_str(ctx, 4), data, sizeof(data), &datalen);
|
||||
|
||||
bool read_reply = (arg_get_lit(ctx, 5) == false);
|
||||
int user_timeout = arg_get_int_def(ctx, 6, -1);
|
||||
bool select_std = arg_get_lit(ctx, 7);
|
||||
bool select_sr = arg_get_lit(ctx, 8);
|
||||
bool select_cts = arg_get_lit(ctx, 9);
|
||||
bool select_xrx = arg_get_lit(ctx, 10);
|
||||
bool select_pico = arg_get_lit(ctx, 11);
|
||||
bool verbose = arg_get_lit(ctx, 12);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// FLAGS for device side
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (activate_field) {
|
||||
flags |= ISO14B_CONNECT;
|
||||
}
|
||||
|
||||
if (add_crc) {
|
||||
flags |= ISO14B_APPEND_CRC;
|
||||
}
|
||||
|
||||
if (select_std) {
|
||||
flags |= (ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using ISO14443-B select");
|
||||
}
|
||||
} else if (select_sr) {
|
||||
flags |= (ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using ST/SRx select");
|
||||
}
|
||||
} else if (select_cts) {
|
||||
flags |= (ISO14B_CONNECT | ISO14B_SELECT_CTS | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using ASK/C-ticket select");
|
||||
}
|
||||
} else if (select_xrx) {
|
||||
flags |= (ISO14B_CONNECT | ISO14B_SELECT_XRX | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using Fuji/Xerox select");
|
||||
}
|
||||
} else if (select_pico) {
|
||||
flags |= (ISO14B_CONNECT | ISO14B_SELECT_PICOPASS | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using Picopass select");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t time_wait = 0;
|
||||
if (user_timeout > 0) {
|
||||
|
||||
flags |= ISO14B_SET_TIMEOUT;
|
||||
|
||||
if (user_timeout > MAX_14B_TIMEOUT_MS) {
|
||||
user_timeout = MAX_14B_TIMEOUT_MS;
|
||||
PrintAndLogEx(INFO, "set timeout to 4.9 seconds. The max we can wait for response");
|
||||
}
|
||||
|
||||
// timeout in ETUs (time to transfer 1 bit, approx. 9.4 us)
|
||||
time_wait = (uint32_t)((13560 / 128) * user_timeout);
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, " new raw timeout : %u ETU ( %u ms )", time_wait, user_timeout);
|
||||
}
|
||||
|
||||
if (keep_field_on == false) {
|
||||
flags |= ISO14B_DISCONNECT;
|
||||
}
|
||||
|
||||
if (datalen > 0) {
|
||||
flags |= ISO14B_RAW;
|
||||
}
|
||||
|
||||
// Max buffer is PM3_CMD_DATA_SIZE
|
||||
datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen;
|
||||
|
||||
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + datalen);
|
||||
if (packet == NULL) {
|
||||
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
packet->flags = flags;
|
||||
packet->timeout = time_wait;
|
||||
packet->rawlen = datalen;
|
||||
memcpy(packet->raw, data, datalen);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen);
|
||||
free(packet);
|
||||
|
||||
if (read_reply == false) {
|
||||
clearCommandBuffer();
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
|
||||
// Select, device will send back iso14b_card_select_t, don't print it.
|
||||
if (select_std) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for standard select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_sr) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for ST/SRx select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_cts) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for ASK/C-ticket select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_xrx) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for Fuji/Xerox select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_pico) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for Picopass select");
|
||||
}
|
||||
}
|
||||
|
||||
// get back response from the raw bytes you sent.
|
||||
if (success && datalen > 0) {
|
||||
wait_cmd_14b(true, false, user_timeout);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// 14b get and print Full Info (as much as we know)
|
||||
static bool HF14B_Std_Info(bool verbose, bool do_aid_search) {
|
||||
// 14b get and print UID only (general info)
|
||||
|
@ -1278,6 +1339,53 @@ static bool HF14B_ask_ct_reader(bool verbose) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool HF14B_picopass_reader(bool verbose) {
|
||||
|
||||
iso14b_raw_cmd_t packet = {
|
||||
.flags = (ISO14B_CONNECT | ISO14B_SELECT_PICOPASS | ISO14B_DISCONNECT),
|
||||
.timeout = 0,
|
||||
.rawlen = 0,
|
||||
};
|
||||
|
||||
// 14b get and print UID only (general info)
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (resp.status) {
|
||||
case PM3_SUCCESS: {
|
||||
|
||||
picopass_hdr_t *card = calloc(1, sizeof(picopass_hdr_t));
|
||||
if (card == NULL) {
|
||||
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||
return false;
|
||||
}
|
||||
memcpy(card, resp.data.asBytes, sizeof(picopass_hdr_t));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn)));
|
||||
free(card);
|
||||
return true;
|
||||
}
|
||||
case PM3_ELENGTH: {
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 wrong length");
|
||||
break;
|
||||
}
|
||||
case PM3_ECRC: {
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b Picopass select failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// test for other 14b type tags (mimic another reader - don't have tags to identify)
|
||||
static bool HF14B_other_reader(bool verbose) {
|
||||
|
||||
|
@ -1357,6 +1465,8 @@ static int CmdHF14BReader(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
clear_trace_14b();
|
||||
|
||||
return readHF14B(cm, verbose);
|
||||
}
|
||||
|
||||
|
@ -1406,7 +1516,7 @@ static int CmdHF14BSriRdBl(const char *Cmd) {
|
|||
}
|
||||
|
||||
// New command to write a SRI512/SRIX4K tag.
|
||||
static int CmdHF14BWriteSri(const char *Cmd) {
|
||||
static int CmdHF14BSriWrbl(const char *Cmd) {
|
||||
/*
|
||||
* For SRIX4K blocks 00 - 7F
|
||||
* hf 14b raw --sr -c --data [09 $srix4kwblock $srix4kwdata
|
||||
|
@ -1419,13 +1529,14 @@ static int CmdHF14BWriteSri(const char *Cmd) {
|
|||
*/
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sriwrite",
|
||||
CLIParserInit(&ctx, "hf 14b wrbl",
|
||||
"Write data to a SRI512 or SRIX4K block\n"
|
||||
"If writing to a block out-of-range, use --force to override checks",
|
||||
"hf 14b sriwrite --4k -b 100 -d 11223344\n"
|
||||
"hf 14b sriwrite --4k --sb -d 11223344 --> special block write\n"
|
||||
"hf 14b sriwrite --512 -b 15 -d 11223344\n"
|
||||
"hf 14b sriwrite --512 --sb -d 11223344 --> special block write\n"
|
||||
"If writing to a block out-of-range, use `--force` to override checks\n"
|
||||
"Special block at end denots OTP and lock bits among others",
|
||||
"hf 14b wrbl --4k -b 100 -d 11223344\n"
|
||||
"hf 14b wrbl --4k --sb -d 11223344 --> special block write\n"
|
||||
"hf 14b wrbl --512 -b 15 -d 11223344\n"
|
||||
"hf 14b wrbl --512 --sb -d 11223344 --> special block write\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -1713,16 +1824,38 @@ static uint32_t srix4kEncode(uint32_t value) {
|
|||
uint8_t block = (value & 0xFF);
|
||||
uint8_t i = 0;
|
||||
uint8_t valuebytes[] = {0, 0, 0};
|
||||
Uint3byteToMemBe(valuebytes, value >> 8);
|
||||
|
||||
num_to_bytes(value, 3, valuebytes);
|
||||
uint32_t value_x = (value >> 8);
|
||||
PrintAndLogEx(INFO, "value...... %08x %06x", value, value_x);
|
||||
PrintAndLogEx(INFO, "3b value... %s", sprint_hex_inrow(valuebytes, sizeof(valuebytes)));
|
||||
PrintAndLogEx(INFO, "block no... %02x", block);
|
||||
|
||||
// Scrambled part
|
||||
// Crumb swapping of value.
|
||||
uint8_t temp[] = {0, 0};
|
||||
temp[0] = (CRUMB(value, 22) << 4 | CRUMB(value, 14) << 2 | CRUMB(value, 6)) << 4;
|
||||
temp[0] |= CRUMB(value, 20) << 4 | CRUMB(value, 12) << 2 | CRUMB(value, 4);
|
||||
temp[1] = (CRUMB(value, 18) << 4 | CRUMB(value, 10) << 2 | CRUMB(value, 2)) << 4;
|
||||
temp[1] |= CRUMB(value, 16) << 4 | CRUMB(value, 8) << 2 | CRUMB(value, 0);
|
||||
uint32_t foo = 0;
|
||||
foo |= CRUMB(value_x, 22) << 28;
|
||||
foo |= CRUMB(value_x, 14) << 26;
|
||||
foo |= CRUMB(value_x, 6) << 24;
|
||||
|
||||
foo |= CRUMB(value_x, 20) << 20;
|
||||
foo |= CRUMB(value_x, 12) << 18;
|
||||
foo |= CRUMB(value_x, 4) << 16;
|
||||
|
||||
foo |= CRUMB(value_x, 18) << 12;
|
||||
foo |= CRUMB(value_x, 10) << 10;
|
||||
foo |= CRUMB(value_x, 2) << 8;
|
||||
|
||||
foo |= CRUMB(value_x, 16) << 4;
|
||||
foo |= CRUMB(value_x, 8) << 2;
|
||||
foo |= CRUMB(value_x, 0) << 0;
|
||||
|
||||
PrintAndLogEx(INFO, "hex........ %02x %02x %02x", CRUMB(value_x, 22), CRUMB(value_x, 14), CRUMB(value_x, 6));
|
||||
PrintAndLogEx(INFO, "hex........ %02x %02x %02x", CRUMB(value_x, 20), CRUMB(value_x, 12), CRUMB(value_x, 4));
|
||||
PrintAndLogEx(INFO, "hex........ %02x %02x %02x", CRUMB(value_x, 18), CRUMB(value_x, 10), CRUMB(value_x, 2));
|
||||
PrintAndLogEx(INFO, "hex........ %02x %02x %02x", CRUMB(value_x, 16), CRUMB(value_x, 8), CRUMB(value_x, 0));
|
||||
|
||||
PrintAndLogEx(INFO, "hex........ %08x", foo);
|
||||
|
||||
// chksum part
|
||||
uint32_t chksum = 0xFF - block;
|
||||
|
@ -1740,9 +1873,11 @@ static uint32_t srix4kEncode(uint32_t value) {
|
|||
base4[i--] = (chksum % 4 << 2);
|
||||
chksum /= 4;
|
||||
}
|
||||
PrintAndLogEx(INFO, "%s", sprint_hex_inrow(base4, sizeof(base4)));
|
||||
|
||||
// merge scambled and chksum parts
|
||||
uint32_t encvalue =
|
||||
uint32_t encvalue = 0;
|
||||
|
||||
(NIBBLE_LOW(base4[0]) << 28) |
|
||||
(NIBBLE_HIGH(temp[0]) << 24) |
|
||||
|
||||
|
@ -1758,7 +1893,14 @@ static uint32_t srix4kEncode(uint32_t value) {
|
|||
PrintAndLogEx(NORMAL, "ICE encoded | %08X -> %08X", value, encvalue);
|
||||
return encvalue;
|
||||
}
|
||||
*/
|
||||
|
||||
static uint32_t srix4k_decode_counter(uint32_t num) {
|
||||
uint32_t value = ~num;
|
||||
++value;
|
||||
return value;
|
||||
}
|
||||
/*
|
||||
static uint32_t srix4kDecode(uint32_t value) {
|
||||
switch (value) {
|
||||
case 0xC04F42C5:
|
||||
|
@ -1770,19 +1912,16 @@ static uint32_t srix4kDecode(uint32_t value) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
static uint32_t srix4kDecodeCounter(uint32_t num) {
|
||||
uint32_t value = ~num;
|
||||
++value;
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint32_t srix4kGetMagicbytes(uint64_t uid, uint32_t block6, uint32_t block18, uint32_t block19) {
|
||||
static uint32_t srix4k_get_magicbytes(uint64_t uid, uint32_t block6, uint32_t block18, uint32_t block19) {
|
||||
#define MASK 0xFFFFFFFF;
|
||||
uint32_t uid32 = uid & MASK;
|
||||
uint32_t counter = srix4kDecodeCounter(block6);
|
||||
uint32_t decodedBlock18 = srix4kDecode(block18);
|
||||
uint32_t decodedBlock19 = srix4kDecode(block19);
|
||||
uint32_t counter = srix4k_decode_counter(block6);
|
||||
uint32_t decodedBlock18 = 0;
|
||||
uint32_t decodedBlock19 = 0;
|
||||
// uint32_t decodedBlock18 = srix4kDecode(block18);
|
||||
// uint32_t decodedBlock19 = srix4kDecode(block19);
|
||||
uint32_t doubleBlock = (decodedBlock18 << 16 | decodedBlock19) + 1;
|
||||
|
||||
uint32_t result = (uid32 * doubleBlock * counter) & MASK;
|
||||
|
@ -1790,8 +1929,19 @@ static uint32_t srix4kGetMagicbytes(uint64_t uid, uint32_t block6, uint32_t bloc
|
|||
return result;
|
||||
}
|
||||
|
||||
static int srix4kValid(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
static int CmdSRIX4kValid(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b valid",
|
||||
"SRIX checksum test",
|
||||
"hf 14b valid\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint64_t uid = 0xD00202501A4532F9;
|
||||
uint32_t block6 = 0xFFFFFFFF;
|
||||
|
@ -1799,23 +1949,22 @@ static int srix4kValid(const char *Cmd) {
|
|||
uint32_t block19 = 0xC1484807;
|
||||
uint32_t block21 = 0xD1BCABA4;
|
||||
|
||||
uint32_t test_b18 = 0x00313918;
|
||||
uint32_t test_b18_enc = srix4kEncode(test_b18);
|
||||
uint32_t test_b18 = 0x001A2001; // 0x00313918;
|
||||
uint32_t test_b18_enc = 0;
|
||||
// uint32_t test_b18_enc = srix4kEncode(test_b18);
|
||||
// uint32_t test_b18_dec = srix4kDecode(test_b18_enc);
|
||||
PrintAndLogEx(SUCCESS, "ENCODE & CHECKSUM | %08X -> %08X (%s)", test_b18, test_b18_enc, "");
|
||||
|
||||
uint32_t magic = srix4kGetMagicbytes(uid, block6, block18, block19);
|
||||
uint32_t magic = srix4k_get_magicbytes(uid, block6, block18, block19);
|
||||
PrintAndLogEx(SUCCESS, "BLOCK 21 | %08X -> %08X (no XOR)", block21, magic ^ block21);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) {
|
||||
if (card) {
|
||||
memset(card, 0, sizeof(iso14b_card_select_t));
|
||||
}
|
||||
|
||||
SetAPDULogging(true);
|
||||
switch_off_field_14b();
|
||||
|
||||
iso14b_raw_cmd_t packet = {
|
||||
|
@ -1827,14 +1976,14 @@ int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) {
|
|||
PacketResponseNG resp;
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) {
|
||||
PrintAndLogEx(INFO, "Trying 14B Select SRx");
|
||||
|
||||
PrintAndLogEx(INFO, "Trying 14B Select SRx");
|
||||
// Anticollision + SELECT SR card
|
||||
packet.flags = (ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_CLEARTRACE);
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) {
|
||||
PrintAndLogEx(INFO, "Trying 14B Select CTS");
|
||||
|
||||
PrintAndLogEx(INFO, "Trying 14B Select CTS");
|
||||
// Anticollision + SELECT ASK C-Ticket card
|
||||
packet.flags = (ISO14B_CONNECT | ISO14B_SELECT_CTS | ISO14B_CLEARTRACE);
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
|
||||
|
@ -1891,7 +2040,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen,
|
|||
PrintAndLogEx(FAILED, "APDU: failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
packet->flags = (ISO14B_CONNECT | ISO14B_APDU);
|
||||
packet->flags = (ISO14B_APDU);
|
||||
packet->timeout = 0;
|
||||
packet->rawlen = 0;
|
||||
|
||||
|
@ -2020,7 +2169,6 @@ int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field,
|
|||
} while (clen < datainlen);
|
||||
|
||||
} else {
|
||||
|
||||
res = handle_14b_apdu(false, datain, datainlen, activate_field, dataout, maxdataoutlen, dataoutlen, &chaining, user_timeout);
|
||||
if (res != PM3_SUCCESS) {
|
||||
if (leave_signal_on == false) {
|
||||
|
@ -2050,18 +2198,6 @@ int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field,
|
|||
|
||||
// ISO14443-4. 7. Half-duplex block transmission protocol
|
||||
static int CmdHF14BAPDU(const char *Cmd) {
|
||||
uint8_t data[PM3_CMD_DATA_SIZE];
|
||||
int datalen = 0;
|
||||
uint8_t header[PM3_CMD_DATA_SIZE];
|
||||
int headerlen = 0;
|
||||
bool activate_field = false;
|
||||
bool leave_signal_on = false;
|
||||
bool decode_TLV = false;
|
||||
bool decode_APDU = false;
|
||||
bool make_APDU = false;
|
||||
bool extended_APDU = false;
|
||||
int le = 0;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b apdu",
|
||||
"Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL).\n"
|
||||
|
@ -2087,21 +2223,27 @@ static int CmdHF14BAPDU(const char *Cmd) {
|
|||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
activate_field = arg_get_lit(ctx, 1);
|
||||
leave_signal_on = arg_get_lit(ctx, 2);
|
||||
decode_TLV = arg_get_lit(ctx, 3);
|
||||
decode_APDU = arg_get_lit(ctx, 4);
|
||||
bool activate_field = arg_get_lit(ctx, 1);
|
||||
bool leave_signal_on = arg_get_lit(ctx, 2);
|
||||
bool decode_TLV = arg_get_lit(ctx, 3);
|
||||
bool decode_APDU = arg_get_lit(ctx, 4);
|
||||
|
||||
uint8_t header[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
int headerlen = 0;
|
||||
CLIGetHexWithReturn(ctx, 5, header, &headerlen);
|
||||
make_APDU = headerlen > 0;
|
||||
|
||||
bool make_APDU = (headerlen > 0);
|
||||
if (make_APDU && headerlen != 4) {
|
||||
PrintAndLogEx(ERR, "header length must be 4 bytes instead of %d", headerlen);
|
||||
PrintAndLogEx(ERR, "header length must be 4 bytes, got " _RED_("%d"), headerlen);
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
extended_APDU = arg_get_lit(ctx, 6);
|
||||
le = arg_get_int_def(ctx, 7, 0);
|
||||
bool extended_APDU = arg_get_lit(ctx, 6);
|
||||
int le = arg_get_int_def(ctx, 7, 0);
|
||||
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
int datalen = 0;
|
||||
|
||||
if (make_APDU) {
|
||||
uint8_t apdudata[PM3_CMD_DATA_SIZE] = {0};
|
||||
|
@ -2145,10 +2287,10 @@ static int CmdHF14BAPDU(const char *Cmd) {
|
|||
int user_timeout = arg_get_int_def(ctx, 9, -1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s",
|
||||
PrintAndLogEx(INFO, ">>>> %s%s%s >>>> " _YELLOW_("%s"),
|
||||
activate_field ? "sel" : "",
|
||||
leave_signal_on ? " keep" : "",
|
||||
decode_TLV ? " TLV" : "",
|
||||
leave_signal_on ? "| keep" : "",
|
||||
decode_TLV ? "| TLV" : "",
|
||||
sprint_hex(data, datalen)
|
||||
);
|
||||
|
||||
|
@ -2165,8 +2307,12 @@ static int CmdHF14BAPDU(const char *Cmd) {
|
|||
return res;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "<<<< %s", sprint_hex(data, datalen));
|
||||
PrintAndLogEx(SUCCESS, "APDU response: " _YELLOW_("%02x %02x") " - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1]));
|
||||
PrintAndLogEx(INFO, "<<<< %s", sprint_hex(data, datalen));
|
||||
PrintAndLogEx(SUCCESS, "APDU response: " _YELLOW_("%02x %02x") " - %s"
|
||||
, data[datalen - 2]
|
||||
, data[datalen - 1]
|
||||
, GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1])
|
||||
);
|
||||
|
||||
// TLV decoder
|
||||
if (decode_TLV && datalen > 4) {
|
||||
|
@ -2293,30 +2439,6 @@ out:
|
|||
return res;
|
||||
}
|
||||
|
||||
/* extract uid from filename
|
||||
* filename must match '^hf-14b-[0-9A-F]{16}'
|
||||
*/
|
||||
uint8_t *get_uid_from_filename(const char *filename) {
|
||||
static uint8_t uid[8] ;
|
||||
memset(uid, 0, 8) ;
|
||||
char uidinhex[17] ;
|
||||
if (strlen(filename) < 23 || strncmp(filename, "hf-14b-", 7)) {
|
||||
PrintAndLogEx(ERR, "can't get uid from filename '%s'. Expected format is hf-14b-<uid>...", filename);
|
||||
return uid ;
|
||||
}
|
||||
// extract uid part from filename
|
||||
strncpy(uidinhex, filename + 7, 16) ;
|
||||
uidinhex[16] = '\0' ;
|
||||
int len = hex_to_bytes(uidinhex, uid, 8);
|
||||
if (len == 8)
|
||||
return SwapEndian64(uid, 8, 8);
|
||||
else {
|
||||
PrintAndLogEx(ERR, "get_uid_from_filename failed: hex_to_bytes returned %d", len);
|
||||
memset(uid, 0, 8);
|
||||
}
|
||||
return uid ;
|
||||
}
|
||||
|
||||
static int CmdHF14BView(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
|
@ -2342,8 +2464,8 @@ static int CmdHF14BView(const char *Cmd) {
|
|||
|
||||
// read dump file
|
||||
uint8_t *dump = NULL;
|
||||
size_t bytes_read = 0;
|
||||
int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (ST25TB_SR_BLOCK_SIZE * 0xFF));
|
||||
size_t bytes_read = (ST25TB_SR_BLOCK_SIZE * 0x100);
|
||||
int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (ST25TB_SR_BLOCK_SIZE * 0x100));
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
@ -2351,7 +2473,6 @@ static int CmdHF14BView(const char *Cmd) {
|
|||
uint16_t block_cnt = bytes_read / ST25TB_SR_BLOCK_SIZE;
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename);
|
||||
PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, block_cnt, block_cnt);
|
||||
}
|
||||
|
||||
|
@ -2367,20 +2488,21 @@ static int CmdHF14BView(const char *Cmd) {
|
|||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHF14BList, AlwaysAvailable, "List ISO-14443-B history"},
|
||||
{"---------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("general") " -----------------------"},
|
||||
{"apdu", CmdHF14BAPDU, IfPm3Iso14443b, "Send ISO 14443-4 APDU to tag"},
|
||||
{"dump", CmdHF14BDump, IfPm3Iso14443b, "Read all memory pages of an ISO-14443-B tag, save to file"},
|
||||
{"info", CmdHF14Binfo, IfPm3Iso14443b, "Tag information"},
|
||||
{"list", CmdHF14BList, AlwaysAvailable, "List ISO-14443-B history"},
|
||||
{"ndefread", CmdHF14BNdefRead, IfPm3Iso14443b, "Read NDEF file on tag"},
|
||||
{"raw", CmdHF14BCmdRaw, IfPm3Iso14443b, "Send raw hex data to tag"},
|
||||
{"raw", CmdHF14BRaw, IfPm3Iso14443b, "Send raw hex data to tag"},
|
||||
{"rdbl", CmdHF14BSriRdBl, IfPm3Iso14443b, "Read SRI512/SRIX4 block"},
|
||||
{"reader", CmdHF14BReader, IfPm3Iso14443b, "Act as a ISO-14443-B reader to identify a tag"},
|
||||
// {"restore", CmdHF14BRestore, IfPm3Iso14443b, "Restore from file to all memory pages of an ISO-14443-B tag"},
|
||||
{"sim", CmdHF14BSim, IfPm3Iso14443b, "Fake ISO ISO-14443-B tag"},
|
||||
{"sniff", CmdHF14BSniff, IfPm3Iso14443b, "Eavesdrop ISO-14443-B"},
|
||||
{"rdbl", CmdHF14BSriRdBl, IfPm3Iso14443b, "Read SRI512/SRIX4x block"},
|
||||
{"sriwrite", CmdHF14BWriteSri, IfPm3Iso14443b, "Write data to a SRI512 or SRIX4K tag"},
|
||||
{"wrbl", CmdHF14BSriWrbl, IfPm3Iso14443b, "Write data to a SRI512/SRIX4 tag"},
|
||||
{"view", CmdHF14BView, AlwaysAvailable, "Display content from tag dump file"},
|
||||
// {"valid", srix4kValid, AlwaysAvailable, "srix4k checksum test"},
|
||||
{"valid", CmdSRIX4kValid, AlwaysAvailable, "SRIX4 checksum test"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -2432,6 +2554,13 @@ int readHF14B(bool loop, bool verbose) {
|
|||
else if (found)
|
||||
return PM3_SUCCESS;
|
||||
|
||||
// Picopass
|
||||
found |= HF14B_picopass_reader(verbose) ;
|
||||
if (found && loop)
|
||||
continue;
|
||||
else if (found)
|
||||
return PM3_SUCCESS;
|
||||
|
||||
// try ASK CT 14b
|
||||
found |= HF14B_ask_ct_reader(verbose);
|
||||
if (found && loop)
|
||||
|
|
1472
client/src/cmdhf15.c
1472
client/src/cmdhf15.c
File diff suppressed because it is too large
Load diff
|
@ -281,12 +281,12 @@ static int CmdHFCryptoRFDump(const char *Cmd) {
|
|||
bool m512 = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (m512 + m64 > 1) {
|
||||
if (m512 + m64 != 1) {
|
||||
PrintAndLogEx(INFO, "Select only one card memory size");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint16_t cardsize = 0;
|
||||
uint16_t cardsize;
|
||||
uint8_t blocks = 0;
|
||||
if (m64) {
|
||||
cardsize = (512 / 8) + 4;
|
||||
|
@ -550,4 +550,3 @@ int CmdHFCryptoRF(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
|
|
|
@ -200,9 +200,8 @@ static bool emrtd_exchange_commands(sAPDU_t apdu, bool include_le, uint16_t le,
|
|||
}
|
||||
|
||||
static int emrtd_exchange_commands_noout(sAPDU_t apdu, bool activate_field, bool keep_field_on) {
|
||||
uint8_t response[PM3_CMD_DATA_SIZE];
|
||||
uint8_t response[PM3_CMD_DATA_SIZE] = {0};
|
||||
size_t resplen = 0;
|
||||
|
||||
return emrtd_exchange_commands(apdu, false, 0, response, 0, &resplen, activate_field, keep_field_on);
|
||||
}
|
||||
|
||||
|
@ -987,7 +986,8 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA
|
|||
// Select EF_COM
|
||||
if (emrtd_select_file_by_ef(dg_table[EF_COM].fileid) == false) {
|
||||
*BAC = true;
|
||||
PrintAndLogEx(INFO, "Authentication is enforced. Will attempt external authentication.");
|
||||
PrintAndLogEx(INFO, "Authentication is enforced");
|
||||
PrintAndLogEx(INFO, "Switching to external authentication...");
|
||||
} else {
|
||||
*BAC = false;
|
||||
// Select EF_DG1
|
||||
|
@ -997,7 +997,8 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA
|
|||
uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 };
|
||||
if (emrtd_read_file(response, &resplen, NULL, NULL, NULL, false) == false) {
|
||||
*BAC = true;
|
||||
PrintAndLogEx(INFO, "Authentication is enforced. Will attempt external authentication.");
|
||||
PrintAndLogEx(INFO, "Authentication is enforced");
|
||||
PrintAndLogEx(INFO, "Switching to external authentication...");
|
||||
} else {
|
||||
*BAC = false;
|
||||
}
|
||||
|
@ -1006,9 +1007,9 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA
|
|||
// Do Basic Access Control
|
||||
if (*BAC) {
|
||||
// If BAC isn't available, exit out and warn user.
|
||||
if (!BAC_available) {
|
||||
if (BAC_available == false) {
|
||||
PrintAndLogEx(ERR, "This eMRTD enforces authentication, but you didn't supply MRZ data. Cannot proceed.");
|
||||
PrintAndLogEx(HINT, "Check out hf emrtd info/dump --help, supply data with -n -d and -e.");
|
||||
PrintAndLogEx(HINT, "Check out `hf emrtd info/dump --h`, supply data with `-n` `-d` and `-e`");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1034,19 +1035,19 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab
|
|||
}
|
||||
|
||||
// Dump EF_CardAccess (if available)
|
||||
if (!emrtd_dump_file(ks_enc, ks_mac, ssc, dg_table[EF_CardAccess].fileid, dg_table[EF_CardAccess].filename, BAC, path)) {
|
||||
if (emrtd_dump_file(ks_enc, ks_mac, ssc, dg_table[EF_CardAccess].fileid, dg_table[EF_CardAccess].filename, BAC, path) == false) {
|
||||
PrintAndLogEx(INFO, "Couldn't dump EF_CardAccess, card does not support PACE");
|
||||
PrintAndLogEx(HINT, "This is expected behavior for cards without PACE, and isn't something to be worried about");
|
||||
}
|
||||
|
||||
// Authenticate with the eMRTD
|
||||
if (!emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac)) {
|
||||
if (emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac) == false) {
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// Select EF_COM
|
||||
if (!emrtd_select_and_read(response, &resplen, dg_table[EF_COM].fileid, ks_enc, ks_mac, ssc, BAC)) {
|
||||
if (emrtd_select_and_read(response, &resplen, dg_table[EF_COM].fileid, ks_enc, ks_mac, ssc, BAC) == false) {
|
||||
PrintAndLogEx(ERR, "Failed to read EF_COM");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
@ -1884,10 +1885,10 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab
|
|||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
bool use14b = GetISODEPState() == ISODEP_NFCB;
|
||||
bool use14b = (GetISODEPState() == ISODEP_NFCB);
|
||||
|
||||
// Read EF_CardAccess
|
||||
if (!emrtd_select_and_read(response, &resplen, dg_table[EF_CardAccess].fileid, ks_enc, ks_mac, ssc, BAC)) {
|
||||
if (emrtd_select_and_read(response, &resplen, dg_table[EF_CardAccess].fileid, ks_enc, ks_mac, ssc, BAC) == false) {
|
||||
PACE_available = false;
|
||||
PrintAndLogEx(HINT, "The error above this is normal. It just means that your eMRTD lacks PACE.");
|
||||
}
|
||||
|
@ -2044,6 +2045,7 @@ int infoHF_EMRTD_offline(const char *path) {
|
|||
|
||||
// coverity scan CID 395630,
|
||||
if (data == NULL) {
|
||||
free(filepath);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
|
|
@ -263,28 +263,32 @@ static const char *felica_model_name(uint8_t rom_type, uint8_t ic_type) {
|
|||
* @param verbose prints out the response received.
|
||||
*/
|
||||
static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp, bool verbose) {
|
||||
if (WaitForResponseTimeout(CMD_ACK, resp, 2000)) {
|
||||
if (WaitForResponseTimeout(CMD_ACK, resp, 2000) == false) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff);
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, "client received %i octets", len);
|
||||
|
||||
if (len == 0 || len == 1) {
|
||||
PrintAndLogEx(ERR, "Could not receive data correctly!");
|
||||
return false;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp->data.asBytes, len));
|
||||
if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) {
|
||||
PrintAndLogEx(WARNING, "wrong or no CRC bytes");
|
||||
|
||||
PrintAndLogEx(SUCCESS, "(%u) %s", len, sprint_hex(resp->data.asBytes, len));
|
||||
|
||||
if (check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2) == false) {
|
||||
PrintAndLogEx(WARNING, "CRC ( " _RED_("fail") " )");
|
||||
}
|
||||
|
||||
if (resp->data.asBytes[0] != 0xB2 && resp->data.asBytes[1] != 0x4D) {
|
||||
PrintAndLogEx(ERR, "received incorrect frame format!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2186,13 +2190,13 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) {
|
|||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"},
|
||||
{"list", CmdHFFelicaList, AlwaysAvailable, "List ISO 18092/FeliCa history"},
|
||||
{"reader", CmdHFFelicaReader, IfPm3Felica, "Act like an ISO18092/FeliCa reader"},
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"},
|
||||
{"info", CmdHFFelicaInfo, IfPm3Felica, "Tag information"},
|
||||
{"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"},
|
||||
{"raw", CmdHFFelicaCmdRaw, IfPm3Felica, "Send raw hex data to tag"},
|
||||
{"rdbl", CmdHFFelicaReadPlain, IfPm3Felica, "read block data from authentication-not-required Service."},
|
||||
{"reader", CmdHFFelicaReader, IfPm3Felica, "Act like an ISO18092/FeliCa reader"},
|
||||
{"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"},
|
||||
{"wrbl", CmdHFFelicaWritePlain, IfPm3Felica, "write block data to an authentication-not-required Service."},
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("FeliCa Standard") " -----------------------"},
|
||||
//{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"},
|
||||
|
|
|
@ -1009,7 +1009,7 @@ int read_iclass_csn(bool loop, bool verbose, bool shallow_mod) {
|
|||
} else {
|
||||
|
||||
if (r->status == FLAG_ICLASS_NULL || resp.status == PM3_ERFTRANS) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "iCLASS / Picopass card select failed ( %d )", r->status);
|
||||
if (verbose) PrintAndLogEx(WARNING, "iCLASS / Picopass card select failed ( %d , %d)", r->status, resp.status);
|
||||
res = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
|
@ -1059,7 +1059,7 @@ static int CmdHFiClassReader(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
return read_iclass_csn(cm, true, shallow_mod);
|
||||
return read_iclass_csn(cm, false, shallow_mod);
|
||||
}
|
||||
|
||||
static int CmdHFiClassELoad(const char *Cmd) {
|
||||
|
|
|
@ -819,7 +819,6 @@ static int mfLoadKeys(uint8_t **pkeyBlock, uint32_t *pkeycnt, uint8_t *userkey,
|
|||
*pkeycnt += loaded_numKeys;
|
||||
free(keyBlock_tmp);
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%u") " keys from dictionary", loaded_numKeys);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1563,6 +1562,7 @@ out:
|
|||
free(keyB);
|
||||
PrintAndLogEx(INFO, "-----+-------------------------------------------------+----------------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(HINT, "try `" _YELLOW_("hf mf dump --ns") "` to verify");
|
||||
PrintAndLogEx(INFO, "Done!");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -1690,7 +1690,7 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
|
|||
}
|
||||
|
||||
if (acquisition_completed) {
|
||||
field_off = true; // switch off field with next SendCommandOLD and then finish
|
||||
field_off = true; // switch off field with next SendCommandMIX and then finish
|
||||
}
|
||||
|
||||
if (initialize == false) {
|
||||
|
|
|
@ -2743,7 +2743,6 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
|||
if (is_partial) {
|
||||
PrintAndLogEx(WARNING, "Partial dump created. (%d of %d blocks)", pages, card_mem_size);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -3108,7 +3107,8 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
|||
|
||||
DropField();
|
||||
free(dump);
|
||||
PrintAndLogEx(INFO, "Restore finished");
|
||||
PrintAndLogEx(HINT, "try `" _YELLOW_("hf mfu dump --ns") "` to verify");
|
||||
PrintAndLogEx(INFO, "Done!");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
//
|
||||
|
|
|
@ -5,15 +5,16 @@
|
|||
#include "cmdhfxerox.h"
|
||||
|
||||
#include "fileutils.h"
|
||||
|
||||
#include "cmdtrace.h"
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "cliparser.h"
|
||||
#include "comms.h"
|
||||
#include "iso14b.h"
|
||||
#include "crc16.h"
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
|
||||
#define TIMEOUT 2000
|
||||
|
||||
#define XEROX_BLOCK_SIZE 4
|
||||
|
||||
#define c2l(c,l) (l = ((unsigned long)(*((c)++))), \
|
||||
l |= ((unsigned long)(*((c)++))) << 8L, \
|
||||
|
@ -381,20 +382,21 @@ static int switch_off_field(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int findXerox(iso14b_card_select_t *card, bool disconnect) {
|
||||
static int xerox_select_card(iso14b_card_select_t *card) {
|
||||
|
||||
if (card == NULL) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
int8_t retry = 3;
|
||||
int8_t retry = 2;
|
||||
while (retry--) {
|
||||
|
||||
iso14b_raw_cmd_t packet = {
|
||||
.flags = (ISO14B_CONNECT | ISO14B_SELECT_XRX | (disconnect ? ISO14B_DISCONNECT : 0)),
|
||||
.flags = (ISO14B_CONNECT | ISO14B_SELECT_XRX | ISO14B_DISCONNECT),
|
||||
.timeout = 0,
|
||||
.rawlen = 0,
|
||||
};
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
|
||||
PacketResponseNG resp;
|
||||
|
@ -403,23 +405,23 @@ static int findXerox(iso14b_card_select_t *card, bool disconnect) {
|
|||
if (resp.status == PM3_SUCCESS) {
|
||||
memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
|
||||
}
|
||||
|
||||
return resp.length;
|
||||
}
|
||||
} // retry
|
||||
|
||||
// switch_off_field();
|
||||
PrintAndLogEx(FAILED, "command execution timeout");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
static uint8_t info_blocks[] = { 0x15, 0x16, 0x17, 0x18, 0x22 };
|
||||
static const char *c_type[] = { "drum", "yellow", "magenta", "cyan", "black" };
|
||||
static const char *xerox_c_type[] = { "drum", "yellow", "magenta", "cyan", "black" };
|
||||
|
||||
static inline char dec_digit(uint8_t dig) {
|
||||
return (dig <= 9) ? dig + '0' : '?';
|
||||
}
|
||||
|
||||
static void gen_pn(const uint8_t *data, char *pn) {
|
||||
static void xerox_generate_partno(const uint8_t *data, char *pn) {
|
||||
pn[0] = dec_digit(data[0] >> 4);
|
||||
pn[1] = dec_digit(data[0] & 0xF);
|
||||
pn[2] = dec_digit(data[1] >> 4);
|
||||
|
@ -438,25 +440,110 @@ static void gen_pn(const uint8_t *data, char *pn) {
|
|||
pn[12] = 0;
|
||||
}
|
||||
|
||||
static void xerox_print_hdr(void) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "block# | data | ascii");
|
||||
PrintAndLogEx(INFO, "---------+--------------+----------");
|
||||
}
|
||||
|
||||
static void xerox_print(uint8_t *data, uint16_t datalen) {
|
||||
|
||||
uint16_t blockno = datalen / XEROX_BLOCK_SIZE;
|
||||
|
||||
for (int i = 0; i < blockno; i++) {
|
||||
PrintAndLogEx(INFO,
|
||||
"%3d/0x%02X | %s | %s",
|
||||
i,
|
||||
i,
|
||||
sprint_hex(data + (i * XEROX_BLOCK_SIZE), XEROX_BLOCK_SIZE),
|
||||
sprint_ascii(data + (i * XEROX_BLOCK_SIZE), XEROX_BLOCK_SIZE)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void xerox_print_footer(void) {
|
||||
PrintAndLogEx(INFO, "---------+--------------+----------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
||||
|
||||
// structure and database for uid -> tagtype lookups
|
||||
typedef struct {
|
||||
const char *color;
|
||||
const char *partnumber;
|
||||
const char *region;
|
||||
const char *ms;
|
||||
} xerox_part_t;
|
||||
|
||||
// https://gist.github.com/JeroenSteen/4b45886b8d87fa0530af9b0364e6b277
|
||||
static const xerox_part_t xerox_part_mappings[] = {
|
||||
{"cyan", "006R01532", "DMO", "sold"},
|
||||
{"cyan", "006R01660", "DMO", "sold"},
|
||||
{"cyan", "006R01739", "DMO", "sold"},
|
||||
{"cyan", "006R01524", "WW", "metered"},
|
||||
{"cyan", "006R01528", "NA/ESG", "sold"},
|
||||
{"cyan", "006R01656", "NA/ESG", "sold"},
|
||||
{"cyan", "006R01735", "NA/ESG", "sold"},
|
||||
|
||||
{"magenta", "006R01531", "DMO", "sold"},
|
||||
{"magenta", "006R01661", "DMO", "sold"},
|
||||
{"magenta", "006R01740", "DMO", "sold"},
|
||||
{"magenta", "006R01523", "WW", "metered"},
|
||||
{"magenta", "006R01527", "NA/ESG", "sold"},
|
||||
{"magenta", "006R01657", "NA/ESG", "sold"},
|
||||
{"magenta", "006R01736", "NA/ESG", "sold"},
|
||||
|
||||
{"yellow", "006R01530", "DMO", "sold"},
|
||||
{"yellow", "006R01662", "DMO", "sold"},
|
||||
{"yellow", "006R01741", "DMO", "sold"},
|
||||
{"yellow", "006R01522", "WW", "metered"},
|
||||
{"yellow", "006R01526", "NA/ESG", "sold"},
|
||||
{"yellow", "006R01658", "NA/ESG", "sold"},
|
||||
{"yellow", "006R01737", "NA/ESG", "sold"},
|
||||
|
||||
{"black", "006R01529", "DMO", "sold"},
|
||||
{"black", "006R01659", "DMO", "sold"},
|
||||
{"black", "006R01738", "DMO", "sold"},
|
||||
{"black", "006R01521", "WW", "metered"},
|
||||
{"black", "006R01525", "NA/ESG", "sold"},
|
||||
{"black", "006R01655", "NA/ESG", "sold"},
|
||||
{"black", "006R01734", "NA/ESG", "sold"},
|
||||
{"", "", "", ""} // must be the last entry
|
||||
};
|
||||
|
||||
// get a product description based on the UID
|
||||
// returns description of the best match
|
||||
static const xerox_part_t *get_xerox_part_info(const char *pn) {
|
||||
for (int i = 0; i < ARRAYLEN(xerox_part_mappings); ++i) {
|
||||
if (str_startswith(pn, xerox_part_mappings[i].partnumber) == 0) {
|
||||
return &xerox_part_mappings[i];
|
||||
}
|
||||
}
|
||||
//No match, return default
|
||||
return &xerox_part_mappings[ARRAYLEN(xerox_part_mappings) - 1];
|
||||
}
|
||||
|
||||
int read_xerox_uid(bool loop, bool verbose) {
|
||||
|
||||
do {
|
||||
iso14b_card_select_t card;
|
||||
int status = findXerox(&card, true);
|
||||
int status = xerox_select_card(&card);
|
||||
|
||||
if (loop) {
|
||||
if (status != PM3_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
||||
PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
||||
PrintAndLogEx(SUCCESS, " UID..... %s", sprint_hex(card.uid, card.uidlen));
|
||||
PrintAndLogEx(SUCCESS, " ATQB.... %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
||||
} else {
|
||||
return PM3_ESOFT;
|
||||
if (verbose) {
|
||||
PrintAndLogEx(WARNING, "no tag found");
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
} while (loop && kbd_enter_pressed() == false);
|
||||
|
@ -464,11 +551,80 @@ int read_xerox_uid(bool loop, bool verbose) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int read_xerox_block(iso14b_card_select_t *card, uint8_t blockno, uint8_t *out) {
|
||||
|
||||
if (card == NULL || out == NULL) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t approx_len = (2 + card->uidlen + 1);
|
||||
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + approx_len);
|
||||
if (packet == NULL) {
|
||||
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
// set up the read command
|
||||
packet->flags = (ISO14B_CONNECT | ISO14B_APPEND_CRC | ISO14B_RAW);
|
||||
packet->raw[packet->rawlen++] = 0x02;
|
||||
packet->raw[packet->rawlen++] = XEROX_READ_MEM;
|
||||
|
||||
// uid
|
||||
memcpy(packet->raw + packet->rawlen, card->uid, card->uidlen);
|
||||
packet->rawlen += card->uidlen;
|
||||
|
||||
// block to read
|
||||
packet->raw[packet->rawlen++] = blockno;
|
||||
|
||||
int res = PM3_ESOFT;
|
||||
// read loop
|
||||
for (int retry = 0; retry < 2; retry++) {
|
||||
|
||||
if (retry) {
|
||||
packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW);
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen);
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// sanity checks
|
||||
if (resp.length < 7) {
|
||||
PrintAndLogEx(FAILED, "trying one more time, wrong length");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t *d = resp.data.asBytes;
|
||||
|
||||
if (check_crc(CRC_14443_B, d, 7) == false) {
|
||||
PrintAndLogEx(FAILED, "trying one more time, CRC ( " _RED_("fail") " )");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (d[0] != 2) {
|
||||
PrintAndLogEx(FAILED, "Tag returned Error %x %x", d[0], d[1]);
|
||||
res = PM3_ERFTRANS;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(out + (blockno * XEROX_BLOCK_SIZE), d + 1, XEROX_BLOCK_SIZE);
|
||||
res = PM3_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
switch_off_field();
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdHFXeroxReader(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf xerox reader",
|
||||
"Act as a 14443B reader to identify a tag",
|
||||
"Act as a 14443B reader to identify a Fuji Xerox based tag\n"
|
||||
"ISO/IEC 14443 type B based communications",
|
||||
"hf xerox reader\n"
|
||||
"hf xerox reader -@ \n"
|
||||
);
|
||||
|
@ -494,7 +650,8 @@ static int CmdHFXeroxReader(const char *Cmd) {
|
|||
static int CmdHFXeroxInfo(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf xerox info",
|
||||
"Tag information for ISO/IEC 14443 type B / XEROX based tags",
|
||||
"Tag information for Fuji Xerox based tags\n"
|
||||
"ISO/IEC 14443 type B based communications",
|
||||
"hf xerox info"
|
||||
);
|
||||
|
||||
|
@ -508,9 +665,8 @@ static int CmdHFXeroxInfo(const char *Cmd) {
|
|||
CLIParserFree(ctx);
|
||||
|
||||
iso14b_card_select_t card;
|
||||
int status = findXerox(&card, false);
|
||||
int status = xerox_select_card(&card);
|
||||
if (status != PM3_SUCCESS) {
|
||||
switch_off_field();
|
||||
if (verbose) {
|
||||
PrintAndLogEx(FAILED, "Fuji/Xerox tag select failed");
|
||||
}
|
||||
|
@ -518,86 +674,46 @@ static int CmdHFXeroxInfo(const char *Cmd) {
|
|||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
||||
PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
||||
PrintAndLogEx(SUCCESS, " UID..... %s", sprint_hex(card.uid, card.uidlen));
|
||||
PrintAndLogEx(SUCCESS, " ATQB.... %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
||||
|
||||
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + 11);
|
||||
if (packet == NULL) {
|
||||
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
int blocknum = 0;
|
||||
uint8_t data[sizeof(info_blocks) * 4] = {0};
|
||||
uint8_t data[sizeof(info_blocks) * XEROX_BLOCK_SIZE] = {0};
|
||||
|
||||
// set up the read command
|
||||
packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW);
|
||||
packet->rawlen = 11;
|
||||
packet->raw[0] = 0x02;
|
||||
packet->raw[1] = 0x20; // set command: read mem
|
||||
memcpy(packet->raw + 2, card.uid, 8); // store uid
|
||||
for (int i = 0; i < sizeof(i); i++) {
|
||||
|
||||
for (int retry = 0; (retry < 5 && blocknum < sizeof(info_blocks)); retry++) {
|
||||
|
||||
packet->raw[10] = info_blocks[blocknum];
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen);
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) {
|
||||
/*
|
||||
PrintAndLogEx(INFO, "%X %X %X %X %X %I64X %I64X %I64X %X %X %X %c",
|
||||
resp.cmd, resp.length, resp.magic, resp.status, resp.crc, resp.oldarg[0], resp.oldarg[1], resp.oldarg[2],
|
||||
resp.data.asBytes[0], resp.data.asBytes[1], resp.data.asBytes[2], resp.ng ? 't' : 'f');
|
||||
*/
|
||||
|
||||
// 14b raw command send data_len instead of status
|
||||
if (resp.length < 7) {
|
||||
PrintAndLogEx(FAILED, "retrying one more time");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t *recv = resp.data.asBytes;
|
||||
|
||||
if (check_crc(CRC_14443_B, recv, 7) == false) {
|
||||
PrintAndLogEx(FAILED, "crc fail, retrying one more time");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (recv[0] != 2) {
|
||||
PrintAndLogEx(FAILED, "Tag returned Error %x %x", recv[0], recv[1]);
|
||||
int res = read_xerox_block(&card, info_blocks[i], data + (i * XEROX_BLOCK_SIZE));
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "Fuji/Xerox tag read failed");
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(data + (blocknum * 4), resp.data.asBytes + 1, 4);
|
||||
|
||||
retry = 0;
|
||||
blocknum++;
|
||||
}
|
||||
}
|
||||
|
||||
switch_off_field();
|
||||
free(packet);
|
||||
|
||||
if (blocknum != sizeof(info_blocks)) {
|
||||
PrintAndLogEx(FAILED, "Fuji/Xerox tag read failed");
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
|
||||
char pn[13];
|
||||
gen_pn(data, pn);
|
||||
PrintAndLogEx(SUCCESS, " PartNo : %s", pn);
|
||||
PrintAndLogEx(SUCCESS, " Date : %02d.%02d.%02d", data[8], data[9], data[10]);
|
||||
PrintAndLogEx(SUCCESS, " Serial : %d", (data[14] << 16) | (data[13] << 8) | data[12]);
|
||||
PrintAndLogEx(SUCCESS, " Type : %s", (data[18] <= 4) ? c_type[data[18]] : "Unknown");
|
||||
xerox_generate_partno(data, pn);
|
||||
PrintAndLogEx(INFO, "-------- " _CYAN_("tag memory") " ---------");
|
||||
PrintAndLogEx(SUCCESS, " PartNo... %s", pn);
|
||||
PrintAndLogEx(SUCCESS, " Date..... %02d.%02d.%02d", data[8], data[9], data[10]);
|
||||
PrintAndLogEx(SUCCESS, " Serial... %d", (data[14] << 16) | (data[13] << 8) | data[12]);
|
||||
PrintAndLogEx(SUCCESS, " Type..... %s", (data[18] <= 4) ? xerox_c_type[data[18]] : "Unknown");
|
||||
|
||||
const xerox_part_t *item = get_xerox_part_info(pn);
|
||||
if (strlen(item->partnumber) > 0) {
|
||||
PrintAndLogEx(SUCCESS, "Color..... %s", item->color);
|
||||
PrintAndLogEx(SUCCESS, "Region.... %s", item->region);
|
||||
PrintAndLogEx(SUCCESS, "M/s....... %s", item->ms);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFXeroxDump(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf xerox dump",
|
||||
"Dump all memory from a Fuji/Xerox tag",
|
||||
"Dump all memory from a Fuji/Xerox tag\n"
|
||||
"ISO/IEC 14443 type B based communications",
|
||||
"hf xerox dump\n"
|
||||
);
|
||||
|
||||
|
@ -605,6 +721,8 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
arg_param_begin,
|
||||
arg_str0("f", "file", "<fn>", "filename to save dump to"),
|
||||
arg_lit0("d", "decrypt", "decrypt secret blocks"),
|
||||
arg_lit0(NULL, "ns", "no save to file"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -613,39 +731,48 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
bool decrypt = arg_get_lit(ctx, 2);
|
||||
bool nosave = arg_get_lit(ctx, 3);
|
||||
bool verbose = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + 11);
|
||||
iso14b_card_select_t card;
|
||||
int status = xerox_select_card(&card);
|
||||
if (status != PM3_SUCCESS) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(FAILED, "Fuji/Xerox tag select failed");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Reading memory from tag UID " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
|
||||
|
||||
uint8_t approx_len = (2 + 8 + 1);
|
||||
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + approx_len);
|
||||
if (packet == NULL) {
|
||||
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
iso14b_card_select_t card;
|
||||
int status = findXerox(&card, false); // remain RF on
|
||||
if (status != PM3_SUCCESS) {
|
||||
free(packet);
|
||||
switch_off_field();
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Reading memory from tag UID " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
|
||||
|
||||
int blocknum = 1; // block 0 all zeros
|
||||
uint8_t data[256 * 4] = {0};
|
||||
int blockno = 1; // block 0 all zeros
|
||||
uint8_t data[256 * XEROX_BLOCK_SIZE] = {0};
|
||||
|
||||
// set up the read command
|
||||
packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW);
|
||||
packet->rawlen = 11;
|
||||
packet->raw[0] = 0x02;
|
||||
memcpy(packet->raw + 2, card.uid, 8); // store uid
|
||||
packet->flags = (ISO14B_CONNECT | ISO14B_APPEND_CRC | ISO14B_RAW);
|
||||
packet->raw[packet->rawlen++] = 0x02;
|
||||
|
||||
// add one for command byte
|
||||
packet->rawlen++;
|
||||
|
||||
// store uid
|
||||
memcpy(packet->raw + packet->rawlen, card.uid, 8);
|
||||
packet->rawlen += 8;
|
||||
|
||||
PrintAndLogEx(INFO, "." NOLF);
|
||||
|
||||
for (int retry = 0; (retry < 5 && blocknum < 0x100); retry++) {
|
||||
for (int retry = 0; (retry < 2 && blockno < 0x100); retry++) {
|
||||
|
||||
packet->raw[1] = (blocknum < 12) ? 0x30 : 0x20; // set command: read ext mem or read mem
|
||||
packet->raw[10] = blocknum & 0xFF;
|
||||
packet->raw[1] = (blockno < 12) ? 0x30 : 0x20; // set command: read ext mem or read mem
|
||||
packet->raw[10] = blockno & 0xFF;
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
|
@ -662,23 +789,23 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
continue;
|
||||
}
|
||||
|
||||
uint8_t *recv = resp.data.asBytes;
|
||||
uint8_t *d = resp.data.asBytes;
|
||||
|
||||
if (check_crc(CRC_14443_B, recv, 7) == false) {
|
||||
PrintAndLogEx(FAILED, "crc fail, retrying one more time");
|
||||
if (check_crc(CRC_14443_B, d, 7) == false) {
|
||||
PrintAndLogEx(FAILED, "retrying one more time, CRC ( " _RED_("fail") " )");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (recv[0] != 2) {
|
||||
if (d[0] != 2) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(FAILED, "Tag returned Error %x %x", recv[0], recv[1]);
|
||||
PrintAndLogEx(FAILED, "Tag returned Error %x %x", d[0], d[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(data + (blocknum * 4), resp.data.asBytes + 1, 4);
|
||||
memcpy(data + (blockno * XEROX_BLOCK_SIZE), resp.data.asBytes + 1, XEROX_BLOCK_SIZE);
|
||||
|
||||
retry = 0;
|
||||
blocknum++;
|
||||
blockno++;
|
||||
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
fflush(stdout);
|
||||
|
@ -691,8 +818,8 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
if (blocknum != 0x100) {
|
||||
PrintAndLogEx(FAILED, "dump failed at block %d", blocknum);
|
||||
if (blockno != 0x100) {
|
||||
PrintAndLogEx(FAILED, "dump failed at block " _RED_("%d"), blockno);
|
||||
}
|
||||
|
||||
if (decrypt) {
|
||||
|
@ -705,9 +832,9 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
k1[1] = data[5];
|
||||
k1[2] = data[6];
|
||||
k1[3] = data[7];
|
||||
k1[4] = data[0x18 * 4 + 0];
|
||||
k1[5] = data[0x18 * 4 + 1];
|
||||
k1[6] = data[0x22 * 4 + 0];
|
||||
k1[4] = data[(0x18 * XEROX_BLOCK_SIZE) + 0];
|
||||
k1[5] = data[(0x18 * XEROX_BLOCK_SIZE) + 1];
|
||||
k1[6] = data[(0x22 * XEROX_BLOCK_SIZE) + 0];
|
||||
k1[7] = 0;
|
||||
|
||||
RC2_set_key(&exp_key, 8, k1, 64);
|
||||
|
@ -721,8 +848,8 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
|
||||
memcpy(k1, k2, sizeof(k1));
|
||||
|
||||
k1[2] = k2[3] ^ data[0x22 * 4 + 0];
|
||||
k1[3] = k2[4] ^ data[0x22 * 4 + 1]; // first_key[7];
|
||||
k1[2] = k2[3] ^ data[(0x22 * XEROX_BLOCK_SIZE) + 0];
|
||||
k1[3] = k2[4] ^ data[(0x22 * XEROX_BLOCK_SIZE) + 1]; // first_key[7];
|
||||
k1[5] = k2[1] ^ 0x01; // 01 = crypto method? rfid[23][2]
|
||||
|
||||
RC2_set_key(&exp_key, 8, k1, 64);
|
||||
|
@ -731,7 +858,7 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
|
||||
uint8_t dadr = var_list[n];
|
||||
|
||||
if (dadr + 1 >= blocknum) {
|
||||
if (dadr + 1 >= blockno) {
|
||||
PrintAndLogEx(INFO, "secret block %02X skipped.", dadr);
|
||||
continue;
|
||||
}
|
||||
|
@ -739,9 +866,9 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
memset(iv, 0, sizeof(iv));
|
||||
iv[0] = dadr;
|
||||
|
||||
RC2_cbc_encrypt(&data[dadr * 4], decr, 8, &exp_key, iv, RC2_DECRYPT);
|
||||
RC2_cbc_encrypt(&data[dadr * XEROX_BLOCK_SIZE], decr, 8, &exp_key, iv, RC2_DECRYPT);
|
||||
|
||||
memcpy(&data[dadr * 4], decr, 8);
|
||||
memcpy(&data[dadr * XEROX_BLOCK_SIZE], decr, 8);
|
||||
|
||||
int b;
|
||||
uint16_t cs, csd;
|
||||
|
@ -750,6 +877,7 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
for (b = 0, cs = 0; b < sizeof(decr) - 2; b += 2) {
|
||||
cs += decr[b] | (decr[b + 1] << 8);
|
||||
}
|
||||
|
||||
cs = ~cs;
|
||||
csd = (decr[7] << 8) | decr[6];
|
||||
|
||||
|
@ -759,37 +887,109 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "block# | data | ascii");
|
||||
PrintAndLogEx(INFO, "---------+--------------+----------");
|
||||
xerox_print_hdr();
|
||||
xerox_print(data, blockno * XEROX_BLOCK_SIZE);
|
||||
xerox_print_footer();
|
||||
|
||||
for (int i = 0; i < blocknum; i++) {
|
||||
PrintAndLogEx(INFO,
|
||||
"%3d/0x%02X | %s | %s",
|
||||
i,
|
||||
i,
|
||||
sprint_hex(data + (i * 4), 4),
|
||||
sprint_ascii(data + (i * 4), 4)
|
||||
);
|
||||
}
|
||||
PrintAndLogEx(INFO, "---------+--------------+----------");
|
||||
if (nosave) {
|
||||
PrintAndLogEx(INFO, "Called with no save option");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if (0 == filename[0]) { // generate filename from uid
|
||||
char *fptr = filename;
|
||||
PrintAndLogEx(INFO, "Using UID as filename");
|
||||
fptr += snprintf(fptr, sizeof(filename), "hf-xerox-");
|
||||
FillFileNameByUID(fptr, SwapEndian64(card.uid, card.uidlen, 8), decrypt ? "-dump-dec" : "-dump", card.uidlen);
|
||||
FillFileNameByUID(fptr
|
||||
, SwapEndian64(card.uid, card.uidlen, 8)
|
||||
, (decrypt) ? "-dump-dec" : "-dump"
|
||||
, card.uidlen
|
||||
);
|
||||
}
|
||||
|
||||
pm3_save_dump(filename, data, blocknum * 4, jsf14b_v2);
|
||||
pm3_save_dump(filename, data, blockno * XEROX_BLOCK_SIZE, jsf14b_v2);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFXeroxView(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf xerox view",
|
||||
"Print a Fuji/Xerox dump file (bin/eml/json)\n"
|
||||
"note:\n"
|
||||
" - command expects the filename to contain a UID\n"
|
||||
" which is needed to determine card memory type",
|
||||
"hf xerox view -f hf-xerox-0102030405060708-dump.bin"
|
||||
);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE];
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
bool verbose = arg_get_lit(ctx, 2);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// read dump file
|
||||
uint8_t *dump = NULL;
|
||||
size_t bytes_read = (XEROX_BLOCK_SIZE * 0x100);
|
||||
int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (XEROX_BLOCK_SIZE * 0x100));
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
uint16_t blockno = bytes_read / XEROX_BLOCK_SIZE;
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, blockno, blockno);
|
||||
}
|
||||
|
||||
uint8_t tmp[5 * XEROX_BLOCK_SIZE] = {0};
|
||||
for (uint8_t i = 0; i < ARRAYLEN(info_blocks); i++) {
|
||||
memcpy(tmp + (i * XEROX_BLOCK_SIZE), dump + (info_blocks[i] * XEROX_BLOCK_SIZE), XEROX_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
char pn[13];
|
||||
xerox_generate_partno(tmp, pn);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "-------- " _CYAN_("tag memory") " ---------");
|
||||
PrintAndLogEx(SUCCESS, " PartNo... %s", pn);
|
||||
PrintAndLogEx(SUCCESS, " Date..... %02d.%02d.%02d", tmp[8], tmp[9], tmp[10]);
|
||||
PrintAndLogEx(SUCCESS, " Serial... %d", (tmp[14] << 16) | (tmp[13] << 8) | tmp[12]);
|
||||
PrintAndLogEx(SUCCESS, " Type..... %s", (tmp[18] <= 4) ? xerox_c_type[tmp[18]] : "Unknown");
|
||||
|
||||
const xerox_part_t *item = get_xerox_part_info(pn);
|
||||
if (strlen(item->partnumber) > 0) {
|
||||
PrintAndLogEx(SUCCESS, "Color..... %s", item->color);
|
||||
PrintAndLogEx(SUCCESS, "Region.... %s", item->region);
|
||||
PrintAndLogEx(SUCCESS, "M/s....... %s", item->ms);
|
||||
}
|
||||
xerox_print_hdr();
|
||||
xerox_print(dump, bytes_read);
|
||||
xerox_print_footer();
|
||||
|
||||
free(dump);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFXeroxList(const char *Cmd) {
|
||||
return CmdTraceListAlias(Cmd, "hf 14b", "14b -c");
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHFXeroxList, AlwaysAvailable, "List ISO-14443B history"},
|
||||
{"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("general") " -----------------------"},
|
||||
{"info", CmdHFXeroxInfo, IfPm3Iso14443b, "Short info on Fuji/Xerox tag"},
|
||||
{"reader", CmdHFXeroxReader, IfPm3Iso14443b, "Act like a Fuji/Xerox reader"},
|
||||
{"dump", CmdHFXeroxDump, IfPm3Iso14443b, "Read all memory pages of an Fuji/Xerox tag, save to file"},
|
||||
{"reader", CmdHFXeroxReader, IfPm3Iso14443b, "Act like a Fuji/Xerox reader"},
|
||||
{"view", CmdHFXeroxView, AlwaysAvailable, "Display content from tag dump file"},
|
||||
// {"rdbl", CmdHFXeroxRdBl, IfPm3Iso14443b, "Read Fuji/Xerox block"},
|
||||
// {"wrbl", CmdHFXeroxWrBl, IfPm3Iso14443b, "Write Fuji/Xerox block"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
|
|
|
@ -292,6 +292,7 @@ int CmdLFCommandRead(const char *Cmd) {
|
|||
payload.samples = samples;
|
||||
payload.keep_field_on = keep_field_on;
|
||||
payload.verbose = verbose;
|
||||
memset(payload.symbol_extra, 0, sizeof(payload.symbol_extra));
|
||||
|
||||
if (add_crc_ht && (cmd_len <= 120)) {
|
||||
// Hitag 1, Hitag S, ZX8211
|
||||
|
@ -734,6 +735,7 @@ static int lf_read_internal(bool realtime, bool verbose, uint64_t samples) {
|
|||
int result = set_fpga_mode(FPGA_BITSTREAM_LF);
|
||||
if (result != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "failed to load LF bitstream to FPGA");
|
||||
free(realtimeBuf);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -860,6 +862,7 @@ int lf_sniff(bool realtime, bool verbose, uint64_t samples) {
|
|||
int result = set_fpga_mode(FPGA_BITSTREAM_LF);
|
||||
if (result != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "failed to load LF bitstream to FPGA");
|
||||
free(realtimeBuf);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1853,7 +1853,7 @@ static int CmdT55xxReadTrace(const char *Cmd) {
|
|||
ct = localtime_r(&now, &tm_buf);
|
||||
#endif
|
||||
|
||||
if (data.year > ct->tm_year - 110)
|
||||
if (ct != NULL && (data.year > ct->tm_year - 110))
|
||||
data.year += 2000;
|
||||
else
|
||||
data.year += 2010;
|
||||
|
@ -4419,4 +4419,3 @@ int CmdLFT55XX(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
|
|
|
@ -194,6 +194,9 @@ bool IfPm3Zx8211(void) {
|
|||
|
||||
void CmdsHelp(const command_t Commands[]) {
|
||||
if (Commands[0].Name == NULL) return;
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
int i = 0;
|
||||
while (Commands[i].Name) {
|
||||
if (Commands[i].IsAvailable()) {
|
||||
|
@ -271,6 +274,14 @@ int CmdsParse(const command_t Commands[], const char *Cmd) {
|
|||
|
||||
str_lower(cmd_name);
|
||||
|
||||
// iceman: I mistyped "list" so many times with "lsit". No more.
|
||||
char *lsit = strstr(cmd_name, "lsit");
|
||||
if (lsit) {
|
||||
lsit[1] = lsit[2] ^ lsit[1];
|
||||
lsit[2] = lsit[1] ^ lsit[2];
|
||||
lsit[1] = lsit[2] ^ lsit[1];
|
||||
}
|
||||
|
||||
// Comment
|
||||
if (cmd_name[0] == '#')
|
||||
return PM3_SUCCESS;
|
||||
|
|
|
@ -1091,6 +1091,7 @@ static int CmdSmartBruteforceSFI(const char *Cmd) {
|
|||
if (json_is_object(data) == false) {
|
||||
PrintAndLogEx(ERR, "\ndata %d is not an object\n", i + 1);
|
||||
json_decref(root);
|
||||
free(buf);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -1098,6 +1099,7 @@ static int CmdSmartBruteforceSFI(const char *Cmd) {
|
|||
if (json_is_string(jaid) == false) {
|
||||
PrintAndLogEx(ERR, "\nAID data [%d] is not a string", i + 1);
|
||||
json_decref(root);
|
||||
free(buf);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -1459,5 +1461,3 @@ bool smart_select(bool verbose, smart_card_atr_t *atr) {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -760,6 +760,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
|||
if (prev_eot)
|
||||
*prev_eot = end_of_transmission_timestamp;
|
||||
|
||||
|
||||
|
||||
// Always annotate these protocols both reader/tag messages
|
||||
switch (protocol) {
|
||||
case ISO_14443A:
|
||||
|
@ -836,6 +838,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
|||
|
||||
if (j == 0) {
|
||||
|
||||
|
||||
uint32_t time1 = hdr->timestamp - first_hdr->timestamp;
|
||||
uint32_t time2 = end_of_transmission_timestamp - first_hdr->timestamp;
|
||||
if (prev_eot) {
|
||||
|
@ -995,13 +998,14 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
|||
static int download_trace(void) {
|
||||
|
||||
if (IfPm3Present() == false) {
|
||||
PrintAndLogEx(FAILED, "You requested a trace upload in offline mode, consider using parameter '-1' for working from Tracebuffer");
|
||||
PrintAndLogEx(FAILED, "You requested a trace upload in offline mode, consider using parameter `" _YELLOW_("-1") "` for working from Tracebuffer");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// reserve some space.
|
||||
if (gs_trace)
|
||||
if (gs_trace) {
|
||||
free(gs_trace);
|
||||
}
|
||||
|
||||
gs_traceLen = 0;
|
||||
|
||||
|
@ -1011,7 +1015,7 @@ static int download_trace(void) {
|
|||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "downloading tracelog data from device");
|
||||
PrintAndLogEx(DEBUG, "downloading tracelog data from device");
|
||||
|
||||
// Query for the size of the trace, downloading PM3_CMD_DATA_SIZE
|
||||
PacketResponseNG resp;
|
||||
|
@ -1078,11 +1082,11 @@ static int CmdTraceExtract(const char *Cmd) {
|
|||
download_trace();
|
||||
} else if (gs_traceLen == 0) {
|
||||
PrintAndLogEx(FAILED, "You requested a trace list in offline mode but there is no trace.");
|
||||
PrintAndLogEx(FAILED, "Consider using " _YELLOW_("`trace load`") " or removing parameter " _YELLOW_("`-1`"));
|
||||
PrintAndLogEx(FAILED, "Consider using `" _YELLOW_("trace load") "` or removing parameter `" _YELLOW_("-1") "`");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Recorded activity (trace len = " _YELLOW_("%u") " bytes)", gs_traceLen);
|
||||
PrintAndLogEx(SUCCESS, "Recorded activity ( " _YELLOW_("%u") " bytes )", gs_traceLen);
|
||||
if (gs_traceLen == 0) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1092,10 +1096,10 @@ static int CmdTraceExtract(const char *Cmd) {
|
|||
while (tracepos < gs_traceLen) {
|
||||
tracepos = extractChallenges(tracepos, gs_traceLen, gs_trace);
|
||||
|
||||
if (kbd_enter_pressed())
|
||||
if (kbd_enter_pressed()) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1312,11 +1316,11 @@ int CmdTraceList(const char *Cmd) {
|
|||
download_trace();
|
||||
} else if (gs_traceLen == 0 || gs_trace == NULL) {
|
||||
PrintAndLogEx(FAILED, "You requested a trace list in offline mode but there is no trace.");
|
||||
PrintAndLogEx(FAILED, "Consider using " _YELLOW_("`trace load`") " or removing parameter " _YELLOW_("`-1`"));
|
||||
PrintAndLogEx(FAILED, "Consider using `" _YELLOW_("trace load") "` or removing parameter `" _YELLOW_("-1") "`");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Recorded activity (trace len = " _YELLOW_("%u") " bytes)", gs_traceLen);
|
||||
PrintAndLogEx(SUCCESS, "Recorded activity ( " _YELLOW_("%u") " bytes )", gs_traceLen);
|
||||
if (gs_traceLen == 0) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1335,9 +1339,9 @@ int CmdTraceList(const char *Cmd) {
|
|||
} else {
|
||||
|
||||
if (use_relative) {
|
||||
PrintAndLogEx(INFO, _YELLOW_("gap") " = time between transfers. " _YELLOW_("duration") " = duration of data transfer. " _YELLOW_("src") " = source of transfer");
|
||||
PrintAndLogEx(INFO, _YELLOW_("gap") " = time between transfers. " _YELLOW_("duration") " = duration of data transfer. " _YELLOW_("src") " = source of transfer.");
|
||||
} else {
|
||||
PrintAndLogEx(INFO, _YELLOW_("start") " = start of start frame " _YELLOW_("end") " = end of frame. " _YELLOW_("src") " = source of transfer");
|
||||
PrintAndLogEx(INFO, _YELLOW_("start") " = start of start frame. " _YELLOW_("end") " = end of frame. " _YELLOW_("src") " = source of transfer.");
|
||||
}
|
||||
|
||||
if (protocol == ISO_14443A || protocol == PROTO_MIFARE || protocol == MFDES || protocol == PROTO_MFPLUS || protocol == TOPAZ || protocol == LTO) {
|
||||
|
|
|
@ -145,7 +145,7 @@ int CmdWiegandDecode(const char *Cmd) {
|
|||
if (hlen) {
|
||||
res = hexstring_to_u96(&top, &mid, &bot, hex);
|
||||
if (res != hlen) {
|
||||
PrintAndLogEx(ERR, "hex string contains none hex chars");
|
||||
PrintAndLogEx(ERR, "Hex string contains none hex chars");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
} else if (blen) {
|
||||
|
@ -154,8 +154,9 @@ int CmdWiegandDecode(const char *Cmd) {
|
|||
PrintAndLogEx(ERR, "Binary string contains none <0|1> chars");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
PrintAndLogEx(INFO, "Input bin len... %d", blen);
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "empty input");
|
||||
PrintAndLogEx(ERR, "Empty input");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
|
|
@ -239,6 +239,22 @@ char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePath
|
|||
return fileName;
|
||||
}
|
||||
|
||||
// trunacate down a filename to LEN size
|
||||
void truncate_filename(char *fn, uint16_t maxlen) {
|
||||
if (fn == NULL || maxlen < 5) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the filename is already shorter than or equal to the desired length
|
||||
if (strlen(fn) <= maxlen) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If there's no extension or it's too long, just truncate the filename
|
||||
fn[maxlen - 3] = '\0';
|
||||
strcat(fn, "...");
|
||||
}
|
||||
|
||||
// --------- SAVE FILES
|
||||
int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) {
|
||||
|
||||
|
@ -1336,11 +1352,12 @@ int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen) {
|
|||
|
||||
static int load_file_sanity(char *s, uint32_t datalen, int i, size_t len) {
|
||||
if (len == 0) {
|
||||
PrintAndLogEx(WARNING, "WARNING: json %s block %d has zero-length data", s, i);
|
||||
PrintAndLogEx(INFO, "file parsing stopped");
|
||||
PrintAndLogEx(DEBUG, "WARNING: json %s block %d has zero-length data", s, i);
|
||||
PrintAndLogEx(INFO, "File parsing stopped");
|
||||
return false;
|
||||
} else if (len != datalen) {
|
||||
PrintAndLogEx(WARNING, "WARNING: json %s block %d only has %zu bytes, expected %d (will fill with zero data)", s, i, len, datalen);
|
||||
PrintAndLogEx(WARNING, "WARNING: json %s block %d only has %zu bytes", s, i, len);
|
||||
PrintAndLogEx(INFO, "Expected %d - padding with zeros", datalen);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -107,6 +107,8 @@ bool setDefaultPath(savePaths_t pathIndex, const char *path);
|
|||
|
||||
char *newfilenamemcopy(const char *preferredName, const char *suffix);
|
||||
char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePaths_t save_path);
|
||||
void truncate_filename(char *fn, uint16_t len);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility function to save data to a binary file. This method takes a preferred name, but if that
|
||||
|
|
|
@ -44,10 +44,11 @@ static isodep_state_t isodep_state = ISODEP_INACTIVE;
|
|||
void SetISODEPState(isodep_state_t state) {
|
||||
isodep_state = state;
|
||||
if (APDULogging) {
|
||||
PrintAndLogEx(SUCCESS, "Setting ISODEP -> %s%s%s"
|
||||
PrintAndLogEx(SUCCESS, "Setting ISODEP -> %s%s%s%s"
|
||||
, isodep_state == ISODEP_INACTIVE ? "inactive" : ""
|
||||
, isodep_state == ISODEP_NFCA ? _GREEN_("NFC-A") : ""
|
||||
, isodep_state == ISODEP_NFCB ? _GREEN_("NFC-B") : ""
|
||||
, isodep_state == ISODEP_NFCV ? _GREEN_("NFC-V") : ""
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +65,6 @@ int Iso7816Connect(Iso7816CommandChannel channel) {
|
|||
// select with no disconnect and set frameLength
|
||||
int res = SelectCard14443A_4(false, false, NULL);
|
||||
if (res == PM3_SUCCESS) {
|
||||
SetISODEPState(ISODEP_NFCA);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,6 @@ int Iso7816Connect(Iso7816CommandChannel channel) {
|
|||
// If not 14a, try to 14b
|
||||
res = select_card_14443b_4(false, NULL);
|
||||
if (res == PM3_SUCCESS) {
|
||||
SetISODEPState(ISODEP_NFCB);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -110,8 +109,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
return 201;
|
||||
}
|
||||
|
||||
if (APDULogging)
|
||||
if (APDULogging) {
|
||||
PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen));
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
|
||||
|
@ -125,6 +125,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
case ISODEP_NFCB:
|
||||
res = exchange_14b_apdu(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len, 4000);
|
||||
break;
|
||||
case ISODEP_NFCV:
|
||||
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
|
||||
break;
|
||||
case ISODEP_INACTIVE:
|
||||
if (activate_field == false) {
|
||||
PrintAndLogEx(FAILED, "Field currently inactive, cannot send an APDU");
|
||||
|
@ -133,11 +136,7 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
res = ExchangeAPDU14a(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len);
|
||||
if (res != PM3_SUCCESS) {
|
||||
res = exchange_14b_apdu(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len, 4000);
|
||||
if (res == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Testing ISO14443-B... ( " _GREEN_("ok") " )");
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "Testing ISO14443-B... ( " _RED_("fail") " )");
|
||||
}
|
||||
PrintAndLogEx(INFO, "Testing ISO14443-B... ( %s )", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -160,8 +159,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
}
|
||||
}
|
||||
|
||||
if (APDULogging)
|
||||
if (APDULogging) {
|
||||
PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(result, *result_len));
|
||||
}
|
||||
|
||||
if (*result_len < 2) {
|
||||
return 200;
|
||||
|
@ -177,9 +177,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
if (isw != ISO7816_OK) {
|
||||
if (APDULogging) {
|
||||
if (*sw >> 8 == 0x61) {
|
||||
PrintAndLogEx(ERR, "APDU chaining len %02x", *sw & 0xFF);
|
||||
PrintAndLogEx(ERR, "APDU chaining len " _RED_("%02x"), *sw & 0xFF);
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xFF));
|
||||
PrintAndLogEx(ERR, "APDU (%02x%02x) ERROR... " _RED_("%4X") " - %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xFF));
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ typedef enum {
|
|||
ISODEP_INACTIVE = 0,
|
||||
ISODEP_NFCA,
|
||||
ISODEP_NFCB,
|
||||
ISODEP_NFCV,
|
||||
} isodep_state_t;
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
#define NDEF_BLUEAPPL_LE "application/vnd.bluetooth.le.oob"
|
||||
#define NDEF_BLUEAPPL_SECURE_LE "application/vnd.bluetooth.secure.le.oob"
|
||||
|
||||
#define NDEF_ANDROID_PROVISION "application/com.android.managedprovisioning"
|
||||
|
||||
|
||||
static const char *TypeNameFormat_s[] = {
|
||||
"Empty Record",
|
||||
|
@ -592,7 +594,6 @@ static int ndefDecodePayloadSmartPoster(uint8_t *ndef, size_t ndeflen, bool prin
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
typedef struct ndef_wifi_type_s {
|
||||
const char *description;
|
||||
uint8_t bytes[2];
|
||||
|
@ -943,6 +944,17 @@ static int ndefDecodeMime_bt(NDEFHeader_t *ndef) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int ndefDecodeMime_android_provision(NDEFHeader_t *ndef) {
|
||||
if (ndef->PayloadLen == 0) {
|
||||
PrintAndLogEx(INFO, "no payload");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
PrintAndLogEx(INFO, _CYAN_("Android Managed Provision"));
|
||||
PrintAndLogEx(INFO, "");
|
||||
PrintAndLogEx(INFO, "%.*s", (int)ndef->PayloadLen, ndef->Payload);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// https://raw.githubusercontent.com/haldean/ndef/master/docs/NFCForum-TS-RTD_1.0.pdf
|
||||
static int ndefDecodeExternal_record(NDEFHeader_t *ndef) {
|
||||
|
||||
|
@ -1079,6 +1091,10 @@ static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) {
|
|||
ndefDecodeMime_json(ndef);
|
||||
}
|
||||
|
||||
if (str_startswith(begin, NDEF_ANDROID_PROVISION)) {
|
||||
ndefDecodeMime_android_provision(ndef);
|
||||
}
|
||||
|
||||
free(begin);
|
||||
begin = NULL;
|
||||
break;
|
||||
|
@ -1297,7 +1313,6 @@ int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int NDEFGetTotalLength(uint8_t *ndef, size_t ndeflen, size_t *outlen) {
|
||||
|
||||
size_t idx = 0;
|
||||
|
|
|
@ -157,18 +157,19 @@ const static vocabulary_t vocabulary[] = {
|
|||
{ 0, "hf 14a ndefread" },
|
||||
{ 0, "hf 14a ndefwrite" },
|
||||
{ 1, "hf 14b help" },
|
||||
{ 1, "hf 14b list" },
|
||||
{ 0, "hf 14b apdu" },
|
||||
{ 0, "hf 14b dump" },
|
||||
{ 0, "hf 14b info" },
|
||||
{ 1, "hf 14b list" },
|
||||
{ 0, "hf 14b ndefread" },
|
||||
{ 0, "hf 14b raw" },
|
||||
{ 0, "hf 14b rdbl" },
|
||||
{ 0, "hf 14b reader" },
|
||||
{ 0, "hf 14b sim" },
|
||||
{ 0, "hf 14b sniff" },
|
||||
{ 0, "hf 14b rdbl" },
|
||||
{ 0, "hf 14b sriwrite" },
|
||||
{ 0, "hf 14b wrbl" },
|
||||
{ 1, "hf 14b view" },
|
||||
{ 1, "hf 14b valid" },
|
||||
{ 1, "hf 15 help" },
|
||||
{ 1, "hf 15 list" },
|
||||
{ 1, "hf 15 demod" },
|
||||
|
@ -182,6 +183,7 @@ const static vocabulary_t vocabulary[] = {
|
|||
{ 0, "hf 15 restore" },
|
||||
{ 0, "hf 15 samples" },
|
||||
{ 1, "hf 15 view" },
|
||||
{ 0, "hf 15 wipe" },
|
||||
{ 0, "hf 15 wrbl" },
|
||||
{ 0, "hf 15 sim" },
|
||||
{ 0, "hf 15 eload" },
|
||||
|
@ -223,11 +225,11 @@ const static vocabulary_t vocabulary[] = {
|
|||
{ 1, "hf emrtd list" },
|
||||
{ 1, "hf felica help" },
|
||||
{ 1, "hf felica list" },
|
||||
{ 0, "hf felica reader" },
|
||||
{ 0, "hf felica info" },
|
||||
{ 0, "hf felica sniff" },
|
||||
{ 0, "hf felica raw" },
|
||||
{ 0, "hf felica rdbl" },
|
||||
{ 0, "hf felica reader" },
|
||||
{ 0, "hf felica sniff" },
|
||||
{ 0, "hf felica wrbl" },
|
||||
{ 0, "hf felica rqservice" },
|
||||
{ 0, "hf felica rqresponse" },
|
||||
|
@ -502,10 +504,14 @@ const static vocabulary_t vocabulary[] = {
|
|||
{ 1, "hf vas help" },
|
||||
{ 0, "hf vas reader" },
|
||||
{ 1, "hf vas decrypt" },
|
||||
{ 1, "hf waveshare help" },
|
||||
{ 1, "hf waveshare load" },
|
||||
{ 1, "hf xerox help" },
|
||||
{ 1, "hf xerox list" },
|
||||
{ 0, "hf xerox info" },
|
||||
{ 0, "hf xerox reader" },
|
||||
{ 0, "hf xerox dump" },
|
||||
{ 0, "hf xerox reader" },
|
||||
{ 1, "hf xerox view" },
|
||||
{ 1, "hw help" },
|
||||
{ 0, "hw break" },
|
||||
{ 0, "hw bootloader" },
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "cmdlfem4x05.h" // read 4305
|
||||
#include "cmdlfem4x50.h" // read 4350
|
||||
#include "em4x50.h" // 4x50 structs
|
||||
#include "iso7816/iso7816core.h" // ISODEPSTATE
|
||||
|
||||
static int returnToLuaWithError(lua_State *L, const char *fmt, ...) {
|
||||
char buffer[200];
|
||||
|
@ -1188,15 +1189,12 @@ static int l_em4x50_read(lua_State *L) {
|
|||
words[etd.addresses & 0xFF].byte[3]
|
||||
);
|
||||
lua_pushinteger(L, word);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
static int l_ndefparse(lua_State *L) {
|
||||
|
||||
size_t size;
|
||||
|
||||
//Check number of arguments
|
||||
int n = lua_gettop(L);
|
||||
if (n != 3) {
|
||||
|
@ -1212,6 +1210,7 @@ static int l_ndefparse(lua_State *L) {
|
|||
}
|
||||
|
||||
// data
|
||||
size_t size;
|
||||
const char *p_data = luaL_checklstring(L, 3, &size);
|
||||
if (size) {
|
||||
if (size > (datalen << 1))
|
||||
|
@ -1256,6 +1255,34 @@ static int l_remark(lua_State *L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_set_iso_dep_state(lua_State *L) {
|
||||
|
||||
//Check number of arguments
|
||||
int n = lua_gettop(L);
|
||||
if (n != 1) {
|
||||
return returnToLuaWithError(L, "Only one value allowed");
|
||||
}
|
||||
|
||||
size_t state = luaL_checknumber(L, 1);
|
||||
switch (state) {
|
||||
case 0:
|
||||
SetISODEPState(ISODEP_INACTIVE);
|
||||
break;
|
||||
case 1:
|
||||
SetISODEPState(ISODEP_NFCA);
|
||||
break;
|
||||
case 2:
|
||||
SetISODEPState(ISODEP_NFCB);
|
||||
break;
|
||||
case 3:
|
||||
SetISODEPState(ISODEP_NFCV);
|
||||
break;
|
||||
default:
|
||||
return returnToLuaWithError(L, "Wrong ISODEP STATE value");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 1. filename
|
||||
// 2. extension
|
||||
// output: full search path to file
|
||||
|
@ -1306,11 +1333,12 @@ static int l_cwd(lua_State *L) {
|
|||
while (GetCurrentDir(cwd, path_len) == NULL) {
|
||||
if (errno == ERANGE) { // Need bigger buffer
|
||||
path_len += 10; // if buffer was too small add 10 characters and try again
|
||||
cwd = realloc(cwd, path_len);
|
||||
if (cwd == NULL) {
|
||||
char *cwdNew = realloc(cwd, path_len);
|
||||
if (cwdNew == NULL) {
|
||||
free(cwd);
|
||||
return returnToLuaWithError(L, "Failed to allocate memory");
|
||||
}
|
||||
cwd = cwdNew;
|
||||
} else {
|
||||
free(cwd);
|
||||
return returnToLuaWithError(L, "Failed to get current working directory");
|
||||
|
@ -1402,6 +1430,7 @@ int set_pm3_libraries(lua_State *L) {
|
|||
{"em4x05_read", l_em4x05_read},
|
||||
{"em4x50_read", l_em4x50_read},
|
||||
{"ul_read_uid", l_ul_read_uid},
|
||||
{"set_isodepstate", l_set_iso_dep_state},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -85,13 +85,14 @@ static int uart_reconfigure_timeouts_polling(serial_port sp) {
|
|||
serial_port uart_open(const char *pcPortName, uint32_t speed, bool slient) {
|
||||
char acPortName[255] = {0};
|
||||
serial_port_windows_t *sp = calloc(sizeof(serial_port_windows_t), sizeof(uint8_t));
|
||||
sp->hSocket = INVALID_SOCKET; // default: serial port
|
||||
|
||||
if (sp == 0) {
|
||||
PrintAndLogEx(WARNING, "UART failed to allocate memory\n");
|
||||
return INVALID_SERIAL_PORT;
|
||||
}
|
||||
|
||||
sp->hSocket = INVALID_SOCKET; // default: serial port
|
||||
|
||||
sp->udpBuffer = NULL;
|
||||
rx_empty_counter = 0;
|
||||
g_conn.send_via_local_ip = false;
|
||||
|
|
|
@ -119,7 +119,7 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
|
|||
pathlen += strlen(subdir);
|
||||
char *tmp = realloc(path, pathlen * sizeof(char));
|
||||
if (tmp == NULL) {
|
||||
//free(path);
|
||||
free(path);
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
path = tmp;
|
||||
|
@ -156,7 +156,7 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam
|
|||
pathlen += strlen(filename);
|
||||
char *tmp = realloc(path, pathlen * sizeof(char));
|
||||
if (tmp == NULL) {
|
||||
//free(path);
|
||||
free(path);
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
|
|
|
@ -202,17 +202,22 @@ void ResetSspClk(void) {
|
|||
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
while (AT91C_BASE_TC2->TC_CV > 0);
|
||||
}
|
||||
|
||||
uint32_t RAMFUNC GetCountSspClk(void) {
|
||||
uint32_t tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV;
|
||||
if ((tmp_count & 0x0000ffff) == 0) //small chance that we may have missed an increment in TC2
|
||||
|
||||
// small chance that we may have missed an increment in TC2
|
||||
if ((tmp_count & 0x0000ffff) == 0) {
|
||||
return (AT91C_BASE_TC2->TC_CV << 16);
|
||||
}
|
||||
return tmp_count;
|
||||
}
|
||||
|
||||
uint32_t RAMFUNC GetCountSspClkDelta(uint32_t start) {
|
||||
uint32_t stop = GetCountSspClk();
|
||||
if (stop >= start)
|
||||
if (stop >= start) {
|
||||
return stop - start;
|
||||
}
|
||||
return (UINT32_MAX - start) + stop;
|
||||
}
|
||||
|
||||
|
|
1762
doc/commands.json
1762
doc/commands.json
File diff suppressed because it is too large
Load diff
|
@ -208,18 +208,19 @@ Check column "offline" for their availability.
|
|||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`hf 14b help `|Y |`This help`
|
||||
|`hf 14b list `|Y |`List ISO-14443-B history`
|
||||
|`hf 14b apdu `|N |`Send ISO 14443-4 APDU to tag`
|
||||
|`hf 14b dump `|N |`Read all memory pages of an ISO-14443-B tag, save to file`
|
||||
|`hf 14b info `|N |`Tag information`
|
||||
|`hf 14b list `|Y |`List ISO-14443-B history`
|
||||
|`hf 14b ndefread `|N |`Read NDEF file on tag`
|
||||
|`hf 14b raw `|N |`Send raw hex data to tag`
|
||||
|`hf 14b rdbl `|N |`Read SRI512/SRIX4 block`
|
||||
|`hf 14b reader `|N |`Act as a ISO-14443-B reader to identify a tag`
|
||||
|`hf 14b sim `|N |`Fake ISO ISO-14443-B tag`
|
||||
|`hf 14b sniff `|N |`Eavesdrop ISO-14443-B`
|
||||
|`hf 14b rdbl `|N |`Read SRI512/SRIX4x block`
|
||||
|`hf 14b sriwrite `|N |`Write data to a SRI512 or SRIX4K tag`
|
||||
|`hf 14b wrbl `|N |`Write data to a SRI512/SRIX4 tag`
|
||||
|`hf 14b view `|Y |`Display content from tag dump file`
|
||||
|`hf 14b valid `|Y |`SRIX4 checksum test`
|
||||
|
||||
|
||||
### hf 15
|
||||
|
@ -241,6 +242,7 @@ Check column "offline" for their availability.
|
|||
|`hf 15 restore `|N |`Restore from file to all memory pages of an ISO-15693 tag`
|
||||
|`hf 15 samples `|N |`Acquire samples as reader (enables carrier, sends inquiry)`
|
||||
|`hf 15 view `|Y |`Display content from tag dump file`
|
||||
|`hf 15 wipe `|N |`Wipe card to zeros`
|
||||
|`hf 15 wrbl `|N |`Write a block`
|
||||
|`hf 15 sim `|N |`Fake an ISO-15693 tag`
|
||||
|`hf 15 eload `|N |`Load image file into emulator to be used by 'sim' command`
|
||||
|
@ -314,11 +316,11 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`hf felica help `|Y |`This help`
|
||||
|`hf felica list `|Y |`List ISO 18092/FeliCa history`
|
||||
|`hf felica reader `|N |`Act like an ISO18092/FeliCa reader`
|
||||
|`hf felica info `|N |`Tag information`
|
||||
|`hf felica sniff `|N |`Sniff ISO 18092/FeliCa traffic`
|
||||
|`hf felica raw `|N |`Send raw hex data to tag`
|
||||
|`hf felica rdbl `|N |`read block data from authentication-not-required Service.`
|
||||
|`hf felica reader `|N |`Act like an ISO18092/FeliCa reader`
|
||||
|`hf felica sniff `|N |`Sniff ISO 18092/FeliCa traffic`
|
||||
|`hf felica wrbl `|N |`write block data to an authentication-not-required Service.`
|
||||
|`hf felica rqservice `|N |`verify the existence of Area and Service, and to acquire Key Version.`
|
||||
|`hf felica rqresponse `|N |`verify the existence of a card and its Mode.`
|
||||
|
@ -755,6 +757,16 @@ Check column "offline" for their availability.
|
|||
|`hf vas decrypt `|Y |`Decrypt a previously captured VAS cryptogram`
|
||||
|
||||
|
||||
### hf waveshare
|
||||
|
||||
{ Waveshare NFC ePaper... }
|
||||
|
||||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`hf waveshare help `|Y |`This help`
|
||||
|`hf waveshare load `|Y |`Load image file to Waveshare NFC ePaper`
|
||||
|
||||
|
||||
### hf xerox
|
||||
|
||||
{ Fuji/Xerox cartridge RFIDs... }
|
||||
|
@ -762,9 +774,11 @@ Check column "offline" for their availability.
|
|||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`hf xerox help `|Y |`This help`
|
||||
|`hf xerox list `|Y |`List ISO-14443B history`
|
||||
|`hf xerox info `|N |`Short info on Fuji/Xerox tag`
|
||||
|`hf xerox reader `|N |`Act like a Fuji/Xerox reader`
|
||||
|`hf xerox dump `|N |`Read all memory pages of an Fuji/Xerox tag, save to file`
|
||||
|`hf xerox reader `|N |`Act like a Fuji/Xerox reader`
|
||||
|`hf xerox view `|Y |`Display content from tag dump file`
|
||||
|
||||
|
||||
### hw
|
||||
|
|
|
@ -48,6 +48,7 @@ typedef enum ISO14B_COMMAND {
|
|||
ISO14B_SELECT_CTS = (1 << 10),
|
||||
ISO14B_CLEARTRACE = (1 << 11),
|
||||
ISO14B_SELECT_XRX = (1 << 12),
|
||||
ISO14B_SELECT_PICOPASS = (1 << 13),
|
||||
} iso14b_command_t;
|
||||
|
||||
typedef enum ISO14B_TYPE {
|
||||
|
|
|
@ -34,8 +34,14 @@ typedef enum ISO15_COMMAND {
|
|||
ISO15_RAW = (1 << 2),
|
||||
ISO15_APPEND_CRC = (1 << 3),
|
||||
ISO15_HIGH_SPEED = (1 << 4),
|
||||
ISO15_READ_RESPONSE = (1 << 5)
|
||||
ISO15_READ_RESPONSE = (1 << 5),
|
||||
ISO15_LONG_WAIT = (1 << 6),
|
||||
} iso15_command_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t flags; // PM3 Flags - see iso15_command_t
|
||||
uint16_t rawlen;
|
||||
uint8_t raw[]; // First byte in raw, raw[0] is ISO15693 protocol flag byte
|
||||
} PACKED iso15_raw_cmd_t;
|
||||
|
||||
#endif // _ISO15_H_
|
||||
|
|
|
@ -926,5 +926,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
|||
// 0x0A = ACK
|
||||
// 0x05 = NACK
|
||||
|
||||
// XEROX Commands
|
||||
#define XEROX_READ_MEM 0x20
|
||||
|
||||
#endif
|
||||
// PROTOCOLS_H
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue