Merge branch 'master' into allin

update 201110
This commit is contained in:
tharexde 2020-11-10 00:47:13 +01:00
commit 8a1558757c
62 changed files with 2074 additions and 1149 deletions

View file

@ -3,8 +3,11 @@ 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... 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] ## [unreleased][unreleased]
- Fix 'hf iclass wrbl' - dealing with tags in unsecured vs secured pagemode now is correct (@iceman1001)
- Change many commands to cliparser (@iceman1001, @tcprst, @mwalker33,...) - Change many commands to cliparser (@iceman1001, @tcprst, @mwalker33,...)
- ... - ...
- Added compilation options for 256k Proxmark versions, see doc (@doegox)
- Added support for 10b UID in `hf 14a sim` (@doegox)
- Added `HF_TCPRST` standalone mode which read and emulate IKEA Rothult cards (@tcprst) - Added `HF_TCPRST` standalone mode which read and emulate IKEA Rothult cards (@tcprst)
- Add Gallagher key checking/KDF on MIFARE Desfire (@NZSmartie) - Add Gallagher key checking/KDF on MIFARE Desfire (@NZSmartie)
- Add dictionaries with common words of proper size (@will-caruana) - Add dictionaries with common words of proper size (@will-caruana)

View file

@ -129,6 +129,16 @@ uint8_t *BigBuf_malloc(uint16_t chunksize) {
return (uint8_t *)BigBuf + s_bigbuf_hi; return (uint8_t *)BigBuf + s_bigbuf_hi;
} }
// allocate a chunk of memory from BigBuf, and returns a pointer to it.
// sets the memory to zero
uint8_t *BigBuf_calloc(uint16_t chunksize) {
uint8_t *mem = BigBuf_malloc(chunksize);
if (mem != NULL) {
memset(mem, 0x00, chunksize);
}
return mem;
}
// free ALL allocated chunks. The whole BigBuf is available for traces or samples again. // free ALL allocated chunks. The whole BigBuf is available for traces or samples again.
void BigBuf_free(void) { void BigBuf_free(void) {
s_bigbuf_hi = s_bigbuf_size; s_bigbuf_hi = s_bigbuf_size;

View file

@ -34,6 +34,7 @@ void BigBuf_Clear_ext(bool verbose);
void BigBuf_Clear_keep_EM(void); void BigBuf_Clear_keep_EM(void);
void BigBuf_Clear_EM(void); void BigBuf_Clear_EM(void);
uint8_t *BigBuf_malloc(uint16_t); uint8_t *BigBuf_malloc(uint16_t);
uint8_t *BigBuf_calloc(uint16_t);
void BigBuf_free(void); void BigBuf_free(void);
void BigBuf_free_keep_EM(void); void BigBuf_free_keep_EM(void);
void BigBuf_print_status(void); void BigBuf_print_status(void);
@ -46,10 +47,8 @@ bool get_tracing(void);
bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, uint32_t ts_end, uint8_t *parity, bool reader2tag); bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, uint32_t ts_end, uint8_t *parity, bool reader2tag);
uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length); uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length);
typedef struct { typedef struct {
int max; int max;
int bit; int bit;

View file

@ -132,7 +132,7 @@ static void download_instructions(uint8_t t) {
DbpString("The collected data was saved to SPIFFS. The file names below may differ"); DbpString("The collected data was saved to SPIFFS. The file names below may differ");
DbpString("1. " _YELLOW_("mem spiffs tree")); DbpString("1. " _YELLOW_("mem spiffs tree"));
DbpString("2. " _YELLOW_("mem spiffs dump o " HF_ICLASS_ATTACK_BIN " f " HF_ICLASS_ATTACK_BIN)); DbpString("2. " _YELLOW_("mem spiffs dump o " HF_ICLASS_ATTACK_BIN " f " HF_ICLASS_ATTACK_BIN));
DbpString("3. " _YELLOW_("hf iclass loclass f " HF_ICLASS_ATTACK_BIN)); DbpString("3. " _YELLOW_("hf iclass loclass -f " HF_ICLASS_ATTACK_BIN));
break; break;
} }
case ICE_STATE_READER: { case ICE_STATE_READER: {

View file

@ -90,15 +90,6 @@ void RunMod(void) {
// Did we get the NDEF file contents from the card // Did we get the NDEF file contents from the card
bool gotndef = false; bool gotndef = false;
//For emulation steps
#define ATQA 0
#define UIDC1 1
#define UIDC2 2
#define SAKC1 3
#define SAKC2 4
#define RATS 5
#define SIGNATURE 7
#define PPS 8
//ST25TA Rothult values //ST25TA Rothult values
#define SAK 0x20 #define SAK 0x20
@ -232,23 +223,23 @@ void RunMod(void) {
if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST
odd_reply = !odd_reply; odd_reply = !odd_reply;
if (odd_reply) if (odd_reply)
p_response = &responses[ATQA]; p_response = &responses[RESP_INDEX_ATQA];
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { // Received a HALT } else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { // Received a HALT
p_response = NULL; p_response = NULL;
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP } else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP
p_response = &responses[ATQA]; p_response = &responses[RESP_INDEX_ATQA];
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1) } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1)
p_response = &responses[UIDC1]; p_response = &responses[RESP_INDEX_UIDC1];
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2) } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2)
p_response = &responses[UIDC2]; p_response = &responses[RESP_INDEX_UIDC2];
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1) } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1)
p_response = &responses[SAKC1]; p_response = &responses[RESP_INDEX_SAKC1];
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2) } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2)
p_response = &responses[SAKC2]; p_response = &responses[RESP_INDEX_SAKC2];
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request } else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
p_response = &responses[RATS]; p_response = &responses[RESP_INDEX_RATS];
} else if (receivedCmd[0] == ISO14443A_CMD_PPS) { } else if (receivedCmd[0] == ISO14443A_CMD_PPS) {
p_response = &responses[PPS]; p_response = &responses[RESP_INDEX_PPS];
} else { } else {
DbpString(_YELLOW_("[ ") "Card reader command" _YELLOW_(" ]")); DbpString(_YELLOW_("[ ") "Card reader command" _YELLOW_(" ]"));
Dbhexdump(len, receivedCmd, false); Dbhexdump(len, receivedCmd, false);
@ -413,23 +404,23 @@ void RunMod(void) {
if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST
odd_reply = !odd_reply; odd_reply = !odd_reply;
if (odd_reply) if (odd_reply)
p_response = &responses[ATQA]; p_response = &responses[RESP_INDEX_ATQA];
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { // Received a HALT } else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { // Received a HALT
p_response = NULL; p_response = NULL;
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP } else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP
p_response = &responses[ATQA]; p_response = &responses[RESP_INDEX_ATQA];
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1) } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1)
p_response = &responses[UIDC1]; p_response = &responses[RESP_INDEX_UIDC1];
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2) } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2)
p_response = &responses[UIDC2]; p_response = &responses[RESP_INDEX_UIDC2];
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1) } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1)
p_response = &responses[SAKC1]; p_response = &responses[RESP_INDEX_SAKC1];
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2) } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2)
p_response = &responses[SAKC2]; p_response = &responses[RESP_INDEX_SAKC2];
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request } else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
p_response = &responses[RATS]; p_response = &responses[RESP_INDEX_RATS];
} else if (receivedCmd[0] == ISO14443A_CMD_PPS) { } else if (receivedCmd[0] == ISO14443A_CMD_PPS) {
p_response = &responses[PPS]; p_response = &responses[RESP_INDEX_PPS];
} else { } else {
DbpString(_YELLOW_("[ ") "Card reader command" _YELLOW_(" ]")); DbpString(_YELLOW_("[ ") "Card reader command" _YELLOW_(" ]"));
Dbhexdump(len, receivedCmd, false); Dbhexdump(len, receivedCmd, false);

View file

@ -65,6 +65,9 @@
#include "spiffs.h" #include "spiffs.h"
#endif #endif
int DBGLEVEL = DBG_ERROR;
uint8_t g_trigger = 0;
bool g_hf_field_active = false;
extern uint32_t _stack_start, _stack_end; extern uint32_t _stack_start, _stack_end;
struct common_area common_area __attribute__((section(".commonarea"))); struct common_area common_area __attribute__((section(".commonarea")));
static int button_status = BUTTON_NO_CLICK; static int button_status = BUTTON_NO_CLICK;
@ -88,6 +91,12 @@ int tearoff_hook(void) {
} }
} }
void hf_field_off(void) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
g_hf_field_active = false;
}
void send_wtx(uint16_t wtx) { void send_wtx(uint16_t wtx) {
if (allow_send_wtx) { if (allow_send_wtx) {
reply_ng(CMD_WTX, PM3_SUCCESS, (uint8_t *)&wtx, sizeof(wtx)); reply_ng(CMD_WTX, PM3_SUCCESS, (uint8_t *)&wtx, sizeof(wtx));
@ -1545,9 +1554,10 @@ static void PacketReceived(PacketCommandNG *packet) {
struct p { struct p {
uint8_t counter; uint8_t counter;
uint32_t tearoff_time; uint32_t tearoff_time;
uint8_t value[4];
} PACKED; } PACKED;
struct p *payload = (struct p *) packet->data.asBytes; struct p *payload = (struct p *) packet->data.asBytes;
MifareU_Counter_Tearoff(payload->counter, payload->tearoff_time); MifareU_Counter_Tearoff(payload->counter, payload->tearoff_time, payload->value);
break; break;
} }
case CMD_HF_MIFARE_STATIC_NONCE: { case CMD_HF_MIFARE_STATIC_NONCE: {
@ -2341,14 +2351,6 @@ void __attribute__((noreturn)) AppMain(void) {
*p = 0xdeadbeef; *p = 0xdeadbeef;
} }
if (common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) {
/* Initialize common area */
memset(&common_area, 0, sizeof(common_area));
common_area.magic = COMMON_AREA_MAGIC;
common_area.version = 1;
}
common_area.flags.osimage_present = 1;
LEDsoff(); LEDsoff();
// The FPGA gets its clock from us from PCK0 output, so set that up. // The FPGA gets its clock from us from PCK0 output, so set that up.

View file

@ -13,9 +13,9 @@
#include "common.h" #include "common.h"
extern int g_rsamples; // = 0;
extern uint8_t g_trigger; extern uint8_t g_trigger;
extern bool g_hf_field_active;
void hf_field_off(void);
int tearoff_hook(void); int tearoff_hook(void);
// ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV // ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV

View file

@ -22,10 +22,12 @@
#include "commonutil.h" #include "commonutil.h"
#include "ticks.h" #include "ticks.h"
#ifdef WITH_ISO14443a
// Protocol and Parameter Selection Request for ISO 14443 type A cards // Protocol and Parameter Selection Request for ISO 14443 type A cards
// use regular (1x) speed in both directions // use regular (1x) speed in both directions
// CRC is already included // CRC is already included
static const uint8_t pps[] = {0xD0, 0x11, 0x00, 0x52, 0xA6}; static const uint8_t pps[] = {0xD0, 0x11, 0x00, 0x52, 0xA6};
#endif
// APDUs for communication with German Identification Card // APDUs for communication with German Identification Card
@ -116,9 +118,25 @@ static char iso_type = 0;
static int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response, uint16_t respmaxlen) { static int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response, uint16_t respmaxlen) {
switch (iso_type) { switch (iso_type) {
case 'a': case 'a':
#ifdef WITH_ISO14443a
return iso14_apdu(apdu, (uint16_t) length, false, response, NULL); return iso14_apdu(apdu, (uint16_t) length, false, response, NULL);
#else
(void) apdu;
(void) length;
(void) response;
(void) respmaxlen;
return PM3_ENOTIMPL;
#endif
case 'b': case 'b':
#ifdef WITH_ISO14443b
return iso14443b_apdu(apdu, length, false, response, respmaxlen, NULL); return iso14443b_apdu(apdu, length, false, response, respmaxlen, NULL);
#else
(void) apdu;
(void) length;
(void) response;
(void) respmaxlen;
return PM3_ENOTIMPL;
#endif
default: default:
return 0; return 0;
} }
@ -522,7 +540,10 @@ void EPA_PACE_Replay(PacketCommandNG *c) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
int EPA_Setup(void) { int EPA_Setup(void) {
#ifdef WITH_ISO14443a
{
// first, look for type A cards // first, look for type A cards
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// power up the field // power up the field
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
iso14a_card_select_t card_a_info; iso14a_card_select_t card_a_info;
@ -541,20 +562,24 @@ int EPA_Setup(void) {
iso_type = 'a'; iso_type = 'a';
return 0; return 0;
} }
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); #endif
#ifdef WITH_ISO14443b
{
// if we're here, there is no type A card, so we look for type B // if we're here, there is no type A card, so we look for type B
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// power up the field // power up the field
iso14443b_setup(); iso14443b_setup();
iso14b_card_select_t card_b_info; iso14b_card_select_t card_b_info;
return_code = iso14443b_select_card(&card_b_info); int return_code = iso14443b_select_card(&card_b_info);
if (return_code == 0) { if (return_code == 0) {
Dbprintf("ISO 14443 Type B"); Dbprintf("ISO 14443 Type B");
iso_type = 'b'; iso_type = 'b';
return 0; return 0;
} }
}
#endif
Dbprintf("No card found"); Dbprintf("No card found");
return 1; return 1;
} }

View file

@ -103,8 +103,6 @@ static bool end = false;
#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 #define HITAG_T_TAG_CAPTURE_THREE_HALF 41
#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 #define HITAG_T_TAG_CAPTURE_FOUR_HALF 57
#define DBGLEVEL 0
/* /*
* Implementation of the crc8 calculation from Hitag S * Implementation of the crc8 calculation from Hitag S
* from http://www.proxmark.org/files/Documents/125%20kHz%20-%20Hitag/HitagS.V11.pdf * from http://www.proxmark.org/files/Documents/125%20kHz%20-%20Hitag/HitagS.V11.pdf

View file

@ -1776,13 +1776,19 @@ void iClass_Dump(uint8_t *msg) {
BigBuf_free(); BigBuf_free();
} }
static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac) { static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac, bool use_mac) {
// write command: cmd, 1 blockno, 8 data, 4 mac // write command: cmd, 1 blockno, 8 data, 4 mac
uint8_t write[16] = { 0x80 | ICLASS_CMD_UPDATE, blockno }; uint8_t write[14] = { 0x80 | ICLASS_CMD_UPDATE, blockno };
uint8_t write_len = 14;
memcpy(write + 2, data, 8); memcpy(write + 2, data, 8);
if (use_mac) {
memcpy(write + 10, mac, 4); memcpy(write + 10, mac, 4);
AddCrc(write + 1, 13); } else {
AddCrc(write + 1, 9);
write_len -= 2;
}
uint8_t resp[10] = {0}; uint8_t resp[10] = {0};
uint32_t eof_time = 0, start_time = 0; uint32_t eof_time = 0, start_time = 0;
@ -1819,7 +1825,8 @@ void iClass_WriteBlock(uint8_t *msg) {
iclass_writeblock_req_t *payload = (iclass_writeblock_req_t *)msg; iclass_writeblock_req_t *payload = (iclass_writeblock_req_t *)msg;
uint8_t write[16] = { 0x80 | ICLASS_CMD_UPDATE, payload->req.blockno }; uint8_t write[14] = { 0x80 | ICLASS_CMD_UPDATE, payload->req.blockno };
uint8_t write_len = 14;
Iso15693InitReader(); Iso15693InitReader();
@ -1844,23 +1851,30 @@ void iClass_WriteBlock(uint8_t *msg) {
} }
} }
// calc new mac for write // new block data
memcpy(write + 2, payload->data, 8);
uint8_t pagemap = get_pagemap(&hdr);
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
// Unsecured tags uses CRC16, but don't include the UPDATE operation code
// byte0 = update op
// byte1 = block no
// byte2..9 = new block data
AddCrc(write + 1, 9);
write_len -= 2;
} else {
// Secure tags uses MAC
uint8_t wb[9]; uint8_t wb[9];
wb[0] = payload->req.blockno; wb[0] = payload->req.blockno;
memcpy(wb + 1, payload->data, 8); memcpy(wb + 1, payload->data, 8);
if (payload->req.use_replay) {
doMAC_N(wb, sizeof(wb), payload->req.key + 4, mac);
} else {
if (payload->req.use_credit_key) if (payload->req.use_credit_key)
doMAC_N(wb, sizeof(wb), hdr.key_c, mac); doMAC_N(wb, sizeof(wb), hdr.key_c, mac);
else else
doMAC_N(wb, sizeof(wb), hdr.key_d, mac); doMAC_N(wb, sizeof(wb), hdr.key_d, mac);
}
memcpy(write + 2, payload->data, 8); // data memcpy(write + 10, mac, sizeof(mac));
memcpy(write + 10, mac, sizeof(mac)); // mac }
AddCrc(write + 1, 13);
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
@ -1869,7 +1883,7 @@ void iClass_WriteBlock(uint8_t *msg) {
uint8_t tries = 3; uint8_t tries = 3;
while (tries-- > 0) { while (tries-- > 0) {
iclass_send_as_reader(write, sizeof(write), &start_time, &eof_time); iclass_send_as_reader(write, write_len, &start_time, &eof_time);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
res = false; res = false;
@ -1961,11 +1975,18 @@ void iClass_Restore(iclass_restore_req_t *msg) {
} }
// main loop // main loop
bool use_mac;
for (uint8_t i = 0; i < msg->item_cnt; i++) { for (uint8_t i = 0; i < msg->item_cnt; i++) {
iclass_restore_item_t item = msg->blocks[i]; iclass_restore_item_t item = msg->blocks[i];
// calc new mac for data, using 1b blockno, 8b data, uint8_t pagemap = get_pagemap(&hdr);
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
// Unsecured tags uses CRC16
use_mac = false;
} else {
// Secure tags uses MAC
use_mac = true;
uint8_t wb[9] = {0}; uint8_t wb[9] = {0};
wb[0] = item.blockno; wb[0] = item.blockno;
memcpy(wb + 1, item.data, 8); memcpy(wb + 1, item.data, 8);
@ -1974,9 +1995,10 @@ void iClass_Restore(iclass_restore_req_t *msg) {
doMAC_N(wb, sizeof(wb), hdr.key_c, mac); doMAC_N(wb, sizeof(wb), hdr.key_c, mac);
else else
doMAC_N(wb, sizeof(wb), hdr.key_d, mac); doMAC_N(wb, sizeof(wb), hdr.key_d, mac);
}
// data + mac // data + mac
if (iclass_writeblock_ext(item.blockno, item.data, mac)) { if (iclass_writeblock_ext(item.blockno, item.data, mac, use_mac)) {
Dbprintf("Write block [%02x] " _GREEN_("successful"), item.blockno); Dbprintf("Write block [%02x] " _GREEN_("successful"), item.blockno);
written++; written++;
} else { } else {

View file

@ -28,12 +28,9 @@
#define MAX_ISO14A_TIMEOUT 524288 #define MAX_ISO14A_TIMEOUT 524288
static uint32_t iso14a_timeout; static uint32_t iso14a_timeout;
// if iso14443a not active - transmit/receive dont try to execute
static bool hf_field_active = false;
static uint8_t colpos = 0; static uint8_t colpos = 0;
int g_rsamples = 0;
uint8_t g_trigger = 0;
// the block number for the ISO14443-4 PCB // the block number for the ISO14443-4 PCB
static uint8_t iso14_pcb_blocknum = 0; static uint8_t iso14_pcb_blocknum = 0;
@ -161,7 +158,7 @@ void printHf14aConfig(void) {
); );
Dbprintf(" [r] RATS override.......%i %s%s%s", Dbprintf(" [r] RATS override.......%i %s%s%s",
hf14aconfig.forcerats, hf14aconfig.forcerats,
(hf14aconfig.forcerats == 0) ? "( " _GREEN_("No") " q follow standard " : "", (hf14aconfig.forcerats == 0) ? "( " _GREEN_("No") " ) follow standard " : "",
(hf14aconfig.forcerats == 1) ? "( " _RED_("Yes") " ) always do RATS" : "", (hf14aconfig.forcerats == 1) ? "( " _RED_("Yes") " ) always do RATS" : "",
(hf14aconfig.forcerats == 2) ? "( " _RED_("Yes") " ) always skip RATS" : "" (hf14aconfig.forcerats == 2) ? "( " _RED_("Yes") " ) always skip RATS" : ""
); );
@ -1005,10 +1002,14 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
static uint8_t rUIDc1[5] = { 0x00 }; static uint8_t rUIDc1[5] = { 0x00 };
// For UID size 7, // For UID size 7,
static uint8_t rUIDc2[5] = { 0x00 }; static uint8_t rUIDc2[5] = { 0x00 };
// Prepare the mandatory SAK (for 4 and 7 byte UID) // For UID size 10,
static uint8_t rUIDc3[5] = { 0x00 };
// Prepare the mandatory SAK (for 4, 7 and 10 byte UID)
static uint8_t rSAKc1[3] = { 0x00 }; static uint8_t rSAKc1[3] = { 0x00 };
// Prepare the optional second SAK (for 7 byte UID), drop the cascade bit // Prepare the optional second SAK (for 7 and 10 byte UID), drop the cascade bit for 7b
static uint8_t rSAKc2[3] = { 0x00 }; static uint8_t rSAKc2[3] = { 0x00 };
// Prepare the optional third SAK (for 10 byte UID), drop the cascade bit
static uint8_t rSAKc3[3] = { 0x00 };
// dummy ATS (pseudo-ATR), answer to RATS // dummy ATS (pseudo-ATR), answer to RATS
// static uint8_t rRATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 }; // static uint8_t rRATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 };
static uint8_t rRATS[] = { 0x05, 0x75, 0x80, 0x60, 0x02, 0x00, 0x00 }; static uint8_t rRATS[] = { 0x05, 0x75, 0x80, 0x60, 0x02, 0x00, 0x00 };
@ -1017,7 +1018,7 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
static uint8_t rVERSION[10] = { 0x00 }; static uint8_t rVERSION[10] = { 0x00 };
// READ_SIG response for EV1/NTAG // READ_SIG response for EV1/NTAG
static uint8_t rSIGN[34] = { 0x00 }; static uint8_t rSIGN[34] = { 0x00 };
// PPS respoonse // PPS response
static uint8_t rPPS[3] = { 0xD0 }; static uint8_t rPPS[3] = { 0xD0 };
switch (tagType) { switch (tagType) {
@ -1101,7 +1102,7 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
case 10: { // ST25TA IKEA Rothult case 10: { // ST25TA IKEA Rothult
rATQA[0] = 0x42; rATQA[0] = 0x42;
rATQA[1] = 0x00; rATQA[1] = 0x00;
sak = 0x00; sak = 0x20;
} }
break; break;
@ -1127,11 +1128,25 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
} }
} }
if ((flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA) { if ((flags & FLAG_4B_UID_IN_DATA) == FLAG_4B_UID_IN_DATA) {
rUIDc1[0] = data[0];
rUIDc1[1] = data[1];
rUIDc1[2] = data[2];
rUIDc1[3] = data[3];
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
// Configure the ATQA and SAK accordingly
rATQA[0] &= 0xBF;
rSAKc1[0] = sak & 0xFB;
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
*cuid = bytes_to_num(data, 4);
} else if ((flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA) {
rUIDc1[0] = 0x88; // Cascade Tag marker rUIDc1[0] = 0x88; // Cascade Tag marker
rUIDc1[1] = data[0]; rUIDc1[1] = data[0];
rUIDc1[2] = data[1]; rUIDc1[2] = data[1];
rUIDc1[3] = data[2]; rUIDc1[3] = data[2];
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
rUIDc2[0] = data[3]; rUIDc2[0] = data[3];
rUIDc2[1] = data[4]; rUIDc2[1] = data[4];
@ -1140,37 +1155,49 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
rUIDc2[4] = rUIDc2[0] ^ rUIDc2[1] ^ rUIDc2[2] ^ rUIDc2[3]; rUIDc2[4] = rUIDc2[0] ^ rUIDc2[1] ^ rUIDc2[2] ^ rUIDc2[3];
// Configure the ATQA and SAK accordingly // Configure the ATQA and SAK accordingly
rATQA[0] &= 0xBF;
rATQA[0] |= 0x40; rATQA[0] |= 0x40;
sak |= 0x04; rSAKc1[0] = 0x04;
rSAKc2[0] = sak & 0xFB;
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
AddCrc14A(rSAKc2, sizeof(rSAKc2) - 2);
*cuid = bytes_to_num(data + 3, 4); *cuid = bytes_to_num(data + 3, 4);
} else if ((flags & FLAG_4B_UID_IN_DATA) == FLAG_4B_UID_IN_DATA) { } else if ((flags & FLAG_10B_UID_IN_DATA) == FLAG_10B_UID_IN_DATA) {
memcpy(rUIDc1, data, 4); rUIDc1[0] = 0x88; // Cascade Tag marker
rUIDc1[1] = data[0];
rUIDc1[2] = data[1];
rUIDc1[3] = data[2];
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
rUIDc2[0] = 0x88; // Cascade Tag marker
rUIDc2[1] = data[3];
rUIDc2[2] = data[4];
rUIDc2[3] = data[5];
rUIDc2[4] = rUIDc2[0] ^ rUIDc2[1] ^ rUIDc2[2] ^ rUIDc2[3];
rUIDc3[0] = data[6];
rUIDc3[1] = data[7];
rUIDc3[2] = data[8];
rUIDc3[3] = data[9];
rUIDc3[4] = rUIDc3[0] ^ rUIDc3[1] ^ rUIDc3[2] ^ rUIDc3[3];
// Configure the ATQA and SAK accordingly // Configure the ATQA and SAK accordingly
rATQA[0] &= 0xBF; rATQA[0] &= 0xBF;
sak &= 0xFB; rATQA[0] |= 0x80;
*cuid = bytes_to_num(data, 4); rSAKc1[0] = 0x04;
rSAKc2[0] = 0x04;
rSAKc3[0] = sak & 0xFB;
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
AddCrc14A(rSAKc2, sizeof(rSAKc2) - 2);
AddCrc14A(rSAKc3, sizeof(rSAKc3) - 2);
*cuid = bytes_to_num(data + 3 + 3, 4);
} else { } else {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("[-] ERROR: UID size not defined"); if (DBGLEVEL >= DBG_ERROR) Dbprintf("[-] ERROR: UID size not defined");
return false; return false;
} }
// Calculate BCC for the first 4 bytes of the UID.
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
if (tagType == 10) {
rSAKc1[0] = 0x04;
rSAKc2[0] = 0x20;
} else {
rSAKc1[0] = sak;
rSAKc2[0] = sak & 0xFB;
}
// crc
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
AddCrc14A(rSAKc2, sizeof(rSAKc2) - 2);
// Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present, // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present,
// TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1 // TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1
// TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us) // TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us)
@ -1179,24 +1206,25 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
AddCrc14A(rPPS, sizeof(rPPS) - 2); AddCrc14A(rPPS, sizeof(rPPS) - 2);
#define TAG_RESPONSE_COUNT 9 static tag_response_info_t responses_init[] = {
static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = {
{ .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type { .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type
{ .response = rUIDc1, .response_n = sizeof(rUIDc1) }, // Anticollision cascade1 - respond with uid { .response = rUIDc1, .response_n = sizeof(rUIDc1) }, // Anticollision cascade1 - respond with uid
{ .response = rUIDc2, .response_n = sizeof(rUIDc2) }, // Anticollision cascade2 - respond with 2nd half of uid if asked { .response = rUIDc2, .response_n = sizeof(rUIDc2) }, // Anticollision cascade2 - respond with 2nd half of uid if asked
{ .response = rUIDc3, .response_n = sizeof(rUIDc3) }, // Anticollision cascade3 - respond with 3rd half of uid if asked
{ .response = rSAKc1, .response_n = sizeof(rSAKc1) }, // Acknowledge select - cascade 1 { .response = rSAKc1, .response_n = sizeof(rSAKc1) }, // Acknowledge select - cascade 1
{ .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2 { .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2
{ .response = rSAKc3, .response_n = sizeof(rSAKc3) }, // Acknowledge select - cascade 3
{ .response = rRATS, .response_n = sizeof(rRATS) }, // dummy ATS (pseudo-ATR), answer to RATS { .response = rRATS, .response_n = sizeof(rRATS) }, // dummy ATS (pseudo-ATR), answer to RATS
{ .response = rVERSION, .response_n = sizeof(rVERSION) }, // EV1/NTAG GET_VERSION response { .response = rVERSION, .response_n = sizeof(rVERSION) }, // EV1/NTAG GET_VERSION response
{ .response = rSIGN, .response_n = sizeof(rSIGN) }, // EV1/NTAG READ_SIG response { .response = rSIGN, .response_n = sizeof(rSIGN) }, // EV1/NTAG READ_SIG response
{ .response = rPPS, .response_n = sizeof(rPPS) } // PPS response { .response = rPPS, .response_n = sizeof(rPPS) } // PPS response
}; };
// "precompile" responses. There are 9 predefined responses with a total of 72 bytes data to transmit. // "precompile" responses. There are 11 predefined responses with a total of 80 bytes data to transmit.
// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) // Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
// 72 * 8 data bits, 72 * 1 parity bits, 9 start bits, 9 stop bits, 9 correction bits -- 677 bytes buffer // 80 * 8 data bits, 80 * 1 parity bits, 11 start bits, 11 stop bits, 11 correction bits
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 675 // 80 * 8 + 80 + 11 + 11 + 11 == 753
// 576 + 72 + 9 + 9 + 9 == 675 #define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 753
uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE); uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE);
// modulation buffer pointer and current buffer free space size // modulation buffer pointer and current buffer free space size
@ -1205,7 +1233,7 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
// Prepare the responses of the anticollision phase // Prepare the responses of the anticollision phase
// there will be not enough time to do this at the moment the reader sends it REQA // there will be not enough time to do this at the moment the reader sends it REQA
for (size_t i = 0; i < TAG_RESPONSE_COUNT; i++) { for (size_t i = 0; i < ARRAYLEN(responses_init); i++) {
if (prepare_allocated_tag_modulation(&responses_init[i], &free_buffer_pointer, &free_buffer_size) == false) { if (prepare_allocated_tag_modulation(&responses_init[i], &free_buffer_pointer, &free_buffer_size) == false) {
BigBuf_free_keep_EM(); BigBuf_free_keep_EM();
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Not enough modulation buffer size, exit after %d elements", i); if (DBGLEVEL >= DBG_ERROR) Dbprintf("Not enough modulation buffer size, exit after %d elements", i);
@ -1215,16 +1243,6 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
*responses = responses_init; *responses = responses_init;
// indices into responses array:
#define ATQA 0
#define UIDC1 1
#define UIDC2 2
#define SAKC1 3
#define SAKC2 4
#define RATS 5
#define VERSION 6
#define SIGNATURE 7
#define PPS 8
return true; return true;
} }
@ -1289,16 +1307,18 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
// To control where we are in the protocol // To control where we are in the protocol
#define ORDER_NONE 0 #define ORDER_NONE 0
#define ORDER_REQA 1 //#define ORDER_REQA 1
#define ORDER_SELECT_ALL_CL1 2 //#define ORDER_SELECT_ALL_CL1 2
#define ORDER_SELECT_CL1 3 //#define ORDER_SELECT_CL1 3
#define ORDER_HALTED 5 #define ORDER_HALTED 5
#define ORDER_WUPA 6 #define ORDER_WUPA 6
#define ORDER_AUTH 7 #define ORDER_AUTH 7
#define ORDER_SELECT_ALL_CL2 20 //#define ORDER_SELECT_ALL_CL2 20
#define ORDER_SELECT_CL2 30 //#define ORDER_SELECT_CL2 25
//#define ORDER_SELECT_ALL_CL3 30
//#define ORDER_SELECT_CL3 35
#define ORDER_EV1_COMP_WRITE 40 #define ORDER_EV1_COMP_WRITE 40
#define ORDER_RATS 70 //#define ORDER_RATS 70
uint8_t order = ORDER_NONE; uint8_t order = ORDER_NONE;
int retval = PM3_SUCCESS; int retval = PM3_SUCCESS;
@ -1416,19 +1436,23 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
} else if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST, but in HALTED, skip } else if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST, but in HALTED, skip
odd_reply = !odd_reply; odd_reply = !odd_reply;
if (odd_reply) if (odd_reply)
p_response = &responses[ATQA]; p_response = &responses[RESP_INDEX_ATQA];
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP } else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP
p_response = &responses[ATQA]; p_response = &responses[RESP_INDEX_ATQA];
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1) } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1)
p_response = &responses[UIDC1]; p_response = &responses[RESP_INDEX_UIDC1];
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2) } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2)
p_response = &responses[UIDC2]; p_response = &responses[RESP_INDEX_UIDC2];
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && len == 2) { // Received request for UID (cascade 3)
p_response = &responses[RESP_INDEX_UIDC3];
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1) } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1)
p_response = &responses[SAKC1]; p_response = &responses[RESP_INDEX_SAKC1];
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2) } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2)
p_response = &responses[SAKC2]; p_response = &responses[RESP_INDEX_SAKC2];
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && len == 9) { // Received a SELECT (cascade 3)
p_response = &responses[RESP_INDEX_SAKC3];
} else if (receivedCmd[0] == ISO14443A_CMD_PPS) { } else if (receivedCmd[0] == ISO14443A_CMD_PPS) {
p_response = &responses[PPS]; p_response = &responses[RESP_INDEX_PPS];
} else if (receivedCmd[0] == ISO14443A_CMD_READBLOCK && len == 4) { // Received a (plain) READ } else if (receivedCmd[0] == ISO14443A_CMD_READBLOCK && len == 4) { // Received a (plain) READ
uint8_t block = receivedCmd[1]; uint8_t block = receivedCmd[1];
// if Ultralight or NTAG (4 byte blocks) // if Ultralight or NTAG (4 byte blocks)
@ -1450,7 +1474,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
// FM11005SH. 16blocks, 4bytes / block. // FM11005SH. 16blocks, 4bytes / block.
// block0 = 2byte Customer ID (CID), 2byte Manufacture ID (MID) // block0 = 2byte Customer ID (CID), 2byte Manufacture ID (MID)
// block1 = 4byte UID. // block1 = 4byte UID.
p_response = &responses[UIDC1]; p_response = &responses[RESP_INDEX_UIDC1];
} else { // all other tags (16 byte block tags) } else { // all other tags (16 byte block tags)
uint8_t emdata[MAX_MIFARE_FRAME_SIZE]; uint8_t emdata[MAX_MIFARE_FRAME_SIZE];
emlGetMemBt(emdata, block, 16); emlGetMemBt(emdata, block, 16);
@ -1512,7 +1536,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
} }
p_response = NULL; p_response = NULL;
} else if (receivedCmd[0] == MIFARE_ULEV1_READSIG && len == 4 && tagType == 7) { // Received a READ SIGNATURE -- } else if (receivedCmd[0] == MIFARE_ULEV1_READSIG && len == 4 && tagType == 7) { // Received a READ SIGNATURE --
p_response = &responses[SIGNATURE]; p_response = &responses[RESP_INDEX_SIGNATURE];
} else if (receivedCmd[0] == MIFARE_ULEV1_READ_CNT && len == 4 && tagType == 7) { // Received a READ COUNTER -- } else if (receivedCmd[0] == MIFARE_ULEV1_READ_CNT && len == 4 && tagType == 7) { // Received a READ COUNTER --
uint8_t index = receivedCmd[1]; uint8_t index = receivedCmd[1];
if (index > 2) { if (index > 2) {
@ -1561,7 +1585,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
p_response = NULL; p_response = NULL;
order = ORDER_HALTED; order = ORDER_HALTED;
} else if (receivedCmd[0] == MIFARE_ULEV1_VERSION && len == 3 && (tagType == 2 || tagType == 7)) { } else if (receivedCmd[0] == MIFARE_ULEV1_VERSION && len == 3 && (tagType == 2 || tagType == 7)) {
p_response = &responses[VERSION]; p_response = &responses[RESP_INDEX_VERSION];
} else if ((receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) && len == 4 && tagType != 2 && tagType != 7) { // Received an authentication request } else if ((receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) && len == 4 && tagType != 2 && tagType != 7) { // Received an authentication request
cardAUTHKEY = receivedCmd[0] - 0x60; cardAUTHKEY = receivedCmd[0] - 0x60;
cardAUTHSC = receivedCmd[1] / 4; // received block num cardAUTHSC = receivedCmd[1] / 4; // received block num
@ -1579,7 +1603,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
EmSend4bit(CARD_NACK_NA); EmSend4bit(CARD_NACK_NA);
p_response = NULL; p_response = NULL;
} else { } else {
p_response = &responses[RATS]; p_response = &responses[RESP_INDEX_RATS];
} }
} else if (receivedCmd[0] == MIFARE_ULC_AUTH_1) { // ULC authentication, or Desfire Authentication } else if (receivedCmd[0] == MIFARE_ULC_AUTH_1) { // ULC authentication, or Desfire Authentication
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
@ -1787,7 +1811,7 @@ static void PrepareDelayedTransfer(uint16_t delay) {
//------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------
static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing) { static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing) {
if (!hf_field_active) { if (!g_hf_field_active) {
Dbprintf("Warning: HF field is off, ignoring TransmitFor14443a command"); Dbprintf("Warning: HF field is off, ignoring TransmitFor14443a command");
return; return;
} }
@ -2187,7 +2211,7 @@ bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_Start
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool GetIso14443aAnswerFromTag_Thinfilm(uint8_t *receivedResponse, uint8_t *received_len) { bool GetIso14443aAnswerFromTag_Thinfilm(uint8_t *receivedResponse, uint8_t *received_len) {
if (!hf_field_active) { if (!g_hf_field_active) {
Dbprintf("Warning: HF field is off, ignoring GetIso14443aAnswerFromTag_Thinfilm command"); Dbprintf("Warning: HF field is off, ignoring GetIso14443aAnswerFromTag_Thinfilm command");
return false; return false;
} }
@ -2237,7 +2261,7 @@ bool GetIso14443aAnswerFromTag_Thinfilm(uint8_t *receivedResponse, uint8_t *rec
static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receivedResponsePar, uint16_t offset) { static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receivedResponsePar, uint16_t offset) {
uint32_t c = 0; uint32_t c = 0;
if (!hf_field_active) if (!g_hf_field_active)
return false; return false;
// Set FPGA mode to "reader listen mode", no modulation (listen // Set FPGA mode to "reader listen mode", no modulation (listen
@ -2731,13 +2755,7 @@ void iso14443a_setup(uint8_t fpga_minor_mode) {
NextTransferTime = 2 * DELAY_ARM2AIR_AS_READER; NextTransferTime = 2 * DELAY_ARM2AIR_AS_READER;
iso14a_set_timeout(1060); // 106 * 10ms default iso14a_set_timeout(1060); // 106 * 10ms default
hf_field_active = true; g_hf_field_active = true;
}
void hf_field_off(void) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
hf_field_active = false;
} }
/* Peter Fillmore 2015 /* Peter Fillmore 2015

View file

@ -84,6 +84,21 @@ typedef struct {
uint8_t *parity; uint8_t *parity;
} tUart14a; } tUart14a;
// indices into responses array:
typedef enum {
RESP_INDEX_ATQA,
RESP_INDEX_UIDC1,
RESP_INDEX_UIDC2,
RESP_INDEX_UIDC3,
RESP_INDEX_SAKC1,
RESP_INDEX_SAKC2,
RESP_INDEX_SAKC3,
RESP_INDEX_RATS,
RESP_INDEX_VERSION,
RESP_INDEX_SIGNATURE,
RESP_INDEX_PPS
} resp_index_t;
#ifndef AddCrc14A #ifndef AddCrc14A
# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1) # define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1)
#endif #endif
@ -129,7 +144,6 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u
int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats); int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats);
int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades); int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades);
void iso14a_set_trigger(bool enable); void iso14a_set_trigger(bool enable);
void hf_field_off(void);
int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen); int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen);
int EmSend4bit(uint8_t resp); int EmSend4bit(uint8_t resp);

View file

@ -717,6 +717,211 @@ void SimulateIso14443bTag(uint8_t *pupi) {
switch_off(); //simulate switch_off(); //simulate
} }
/*
void Simulate_iso14443b_srx_tag(uint8_t *uid) {
LED_A_ON();
/ SRI512
> initiate 06 00 ISO14443B_INITIATE
< xx crc crc
> select 0e xx ISO14443B_SELECT
< xx nn nn
> readblock 08 blck_no ISO14443B_READ_BLK
< d0 d1 d2 d3 2byte crc
> get uid ISO14443B_GET_UID
< 81 93 99 20 92 11 02 (8byte UID in MSB D002 199220 999381)
#define ISO14443B_REQB 0x05
#define ISO14443B_ATTRIB 0x1D
#define ISO14443B_HALT 0x50
#define ISO14443B_INITIATE 0x06
#define ISO14443B_SELECT 0x0E
#define ISO14443B_GET_UID 0x0B
#define ISO14443B_READ_BLK 0x08
#define ISO14443B_WRITE_BLK 0x09
#define ISO14443B_RESET 0x0C
#define ISO14443B_COMPLETION 0x0F
#define ISO14443B_AUTHENTICATE 0x0A
#define ISO14443B_PING 0xBA
#define ISO14443B_PONG 0xAB
static const uint8_t resp_init_srx[] = { 0x73, 0x64, 0xb1 };
uint8_t resp_select_srx[] = { 0x73, 0x64, 0xb1 };
// a default uid, or user supplied
uint8_t resp_getuid_srx[10] = {
0x81, 0x93, 0x99, 0x20, 0x92, 0x11, 0x02, 0xD0, 0x00, 0x00
};
// ...UID supplied from user. Adjust ATQB response accordingly
if (memcmp("\x00\x00\x00\x00\x00\x00\x00\x00", uid, 8) != 0) {
memcpy(resp_getuid_srx, uid, 8);
AddCrc14B(resp_getuid_srx, 8);
}
// response to HLTB and ATTRIB
static const uint8_t respOK[] = {0x00, 0x78, 0xF0};
// setup device.
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Set up the synchronous serial port
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
// allocate command receive buffer
BigBuf_free();
BigBuf_Clear_ext(false);
clear_trace();
set_tracing(true);
uint16_t len, cmdsReceived = 0;
int cardSTATE = SIM_NOFIELD;
int vHf = 0; // in mV
tosend_t *ts = get_tosend();
uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
// prepare "ATQB" tag answer (encoded):
CodeIso14443bAsTag(respATQB, sizeof(respATQB));
uint8_t *encodedATQB = BigBuf_malloc(ts->max);
uint16_t encodedATQBLen = ts->max;
memcpy(encodedATQB, ts->buf, ts->max);
// prepare "OK" tag answer (encoded):
CodeIso14443bAsTag(respOK, sizeof(respOK));
uint8_t *encodedOK = BigBuf_malloc(ts->max);
uint16_t encodedOKLen = ts->max;
memcpy(encodedOK, ts->buf, ts->max);
// Simulation loop
while (BUTTON_PRESS() == false) {
WDT_HIT();
//iceman: limit with 2000 times..
if (data_available()) {
break;
}
// find reader field
if (cardSTATE == SIM_NOFIELD) {
#if defined RDV4
vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc(ADC_CHAN_HF_RDV40, 32)) >> 15;
#else
vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
#endif
if (vHf > MF_MINFIELDV) {
cardSTATE = SIM_IDLE;
LED_A_ON();
}
}
if (cardSTATE == SIM_NOFIELD) continue;
// Get reader command
if (!GetIso14443bCommandFromReader(receivedCmd, &len)) {
Dbprintf("button pressed, received %d commands", cmdsReceived);
break;
}
// ISO14443-B protocol states:
// REQ or WUP request in ANY state
// WUP in HALTED state
if (len == 5) {
if ((receivedCmd[0] == ISO14443B_REQB && (receivedCmd[2] & 0x8) == 0x8 && cardSTATE == SIM_HALTED) ||
receivedCmd[0] == ISO14443B_REQB) {
LogTrace(receivedCmd, len, 0, 0, NULL, true);
cardSTATE = SIM_SELECTING;
}
}
/
* How should this flow go?
* REQB or WUPB
* send response ( waiting for Attrib)
* ATTRIB
* send response ( waiting for commands 7816)
* HALT
send halt response ( waiting for wupb )
/
switch (cardSTATE) {
//case SIM_NOFIELD:
case SIM_HALTED:
case SIM_IDLE: {
LogTrace(receivedCmd, len, 0, 0, NULL, true);
break;
}
case SIM_SELECTING: {
TransmitFor14443b_AsTag(encodedATQB, encodedATQBLen);
LogTrace(respATQB, sizeof(respATQB), 0, 0, NULL, false);
cardSTATE = SIM_WORK;
break;
}
case SIM_HALTING: {
TransmitFor14443b_AsTag(encodedOK, encodedOKLen);
LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false);
cardSTATE = SIM_HALTED;
break;
}
case SIM_ACKNOWLEDGE: {
TransmitFor14443b_AsTag(encodedOK, encodedOKLen);
LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false);
cardSTATE = SIM_IDLE;
break;
}
case SIM_WORK: {
if (len == 7 && receivedCmd[0] == ISO14443B_HALT) {
cardSTATE = SIM_HALTED;
} else if (len == 11 && receivedCmd[0] == ISO14443B_ATTRIB) {
cardSTATE = SIM_ACKNOWLEDGE;
} else {
// Todo:
// - SLOT MARKER
// - ISO7816
// - emulate with a memory dump
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsReceived);
// CRC Check
if (len >= 3) { // if crc exists
if (!check_crc(CRC_14443_B, receivedCmd, len)) {
if (DBGLEVEL >= DBG_DEBUG) {
DbpString("CRC fail");
}
}
} else {
if (DBGLEVEL >= DBG_DEBUG) {
DbpString("CRC passed");
}
}
cardSTATE = SIM_IDLE;
}
break;
}
default:
break;
}
++cmdsReceived;
}
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen());
switch_off(); //simulate
}
*/
//============================================================================= //=============================================================================
// An ISO 14443 Type B reader. We take layer two commands, code them // An ISO 14443 Type B reader. We take layer two commands, code them
// appropriately, and then send them to the tag. We then listen for the // appropriately, and then send them to the tag. We then listen for the
@ -1160,6 +1365,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t
tosend_t *ts = get_tosend(); tosend_t *ts = get_tosend();
CodeIso14443bAsReader(cmd, len); CodeIso14443bAsReader(cmd, len);
TransmitFor14443b_AsReader(start_time); TransmitFor14443b_AsReader(start_time);
if (g_trigger) LED_A_ON();
*eof_time = *start_time + (10 * ts->max) + 10 + 2 + 10; *eof_time = *start_time + (10 * ts->max) + 10 + 2 + 10;
LogTrace(cmd, len, *start_time, *eof_time, NULL, true); LogTrace(cmd, len, *start_time, *eof_time, NULL, true);
} }

View file

@ -450,7 +450,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
// 2 = use 0x1B authentication. // 2 = use 0x1B authentication.
// datain : 4 first bytes is data to be written. // datain : 4 first bytes is data to be written.
// : 4/16 next bytes is authentication key. // : 4/16 next bytes is authentication key.
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { static void MifareUWriteBlockEx(uint8_t arg0, uint8_t arg1, uint8_t *datain, bool reply) {
uint8_t blockNo = arg0; uint8_t blockNo = arg0;
bool useKey = (arg1 == 1); //UL_C bool useKey = (arg1 == 1); //UL_C
bool usePwd = (arg1 == 2); //UL_EV1/NTAG bool usePwd = (arg1 == 2); //UL_EV1/NTAG
@ -507,12 +507,17 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
if (DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); if (DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
if (reply)
reply_mix(CMD_ACK, 1, 0, 0, 0, 0); reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff(); LEDsoff();
set_tracing(false); set_tracing(false);
} }
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
MifareUWriteBlockEx(arg0, arg1, datain, true);
}
// Arg0 : Block to write to. // Arg0 : Block to write to.
// Arg1 : 0 = use no authentication. // Arg1 : 0 = use no authentication.
// 1 = use 0x1A authentication. // 1 = use 0x1A authentication.
@ -2376,6 +2381,9 @@ void MifareHasStaticNonce(void) {
int retval = PM3_SUCCESS; int retval = PM3_SUCCESS;
uint32_t nt = 0; uint32_t nt = 0;
uint8_t *uid = BigBuf_malloc(10); uint8_t *uid = BigBuf_malloc(10);
memset(uid, 0x00, 10);
uint8_t data[1] = { NONCE_FAIL }; uint8_t data[1] = { NONCE_FAIL };
struct Crypto1State mpcs = {0, 0}; struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs; struct Crypto1State *pcs;
@ -2392,7 +2400,7 @@ void MifareHasStaticNonce(void) {
goto OUT; goto OUT;
} }
uint8_t rec[1] = {0x00}; uint8_t rec[4] = {0x00};
uint8_t recpar[1] = {0x00}; uint8_t recpar[1] = {0x00};
// Transmit MIFARE_CLASSIC_AUTH 0x60, block 0 // Transmit MIFARE_CLASSIC_AUTH 0x60, block 0
int len = mifare_sendcmd_short(pcs, false, MIFARE_AUTH_KEYA, 0, rec, recpar, NULL); int len = mifare_sendcmd_short(pcs, false, MIFARE_AUTH_KEYA, 0, rec, recpar, NULL);
@ -2412,6 +2420,8 @@ void MifareHasStaticNonce(void) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff(); LEDsoff();
CHK_TIMEOUT(); CHK_TIMEOUT();
memset(rec, 0x00, sizeof(rec));
} }
if (counter) { if (counter) {
@ -2715,7 +2725,8 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t tearoff_time, uint8_t *datain) {
if (tearoff_time > 43000) if (tearoff_time > 43000)
tearoff_time = 43000; tearoff_time = 43000;
MifareUWriteBlock(blockNo, 0, data_fullwrite); MifareUWriteBlockEx(blockNo, 0, data_fullwrite, false);
LEDsoff(); LEDsoff();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
@ -2724,13 +2735,18 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t tearoff_time, uint8_t *datain) {
// write cmd to send, include CRC // write cmd to send, include CRC
// 1b write, 1b block, 4b data, 2 crc // 1b write, 1b block, 4b data, 2 crc
uint8_t cmd[] = {MIFARE_ULC_WRITE, blockNo, data_testwrite[0], data_testwrite[1], data_testwrite[2], data_testwrite[3], 0, 0}; uint8_t cmd[] = {
MIFARE_ULC_WRITE, blockNo,
data_testwrite[0], data_testwrite[1], data_testwrite[2], data_testwrite[3],
0, 0
};
AddCrc14A(cmd, sizeof(cmd) - 2); AddCrc14A(cmd, sizeof(cmd) - 2);
// anticollision / select card // anticollision / select card
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
OnError(1); OnError(1);
reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_EFAILED, NULL, 0);
return; return;
}; };
// send // send
@ -2748,7 +2764,7 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t tearoff_time, uint8_t *datain) {
// //
// Tear-off attack against MFU counter // Tear-off attack against MFU counter
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) { void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time, uint8_t *datain) {
if (tearoff_time > 43000) if (tearoff_time > 43000)
tearoff_time = 43000; tearoff_time = 43000;
@ -2762,10 +2778,10 @@ void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) {
uint8_t cmd[] = { uint8_t cmd[] = {
MIFARE_ULEV1_INCR_CNT, MIFARE_ULEV1_INCR_CNT,
counter, counter,
0, // lsb datain[0], // lsb
0, datain[1],
0, // msb datain[2], // msb
0, // rfu datain[3], // rfu
0, 0,
0, 0,
}; };

View file

@ -64,5 +64,5 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
// Tear-off test for MFU // Tear-off test for MFU
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain); void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain);
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time); void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time, uint8_t *datain);
#endif #endif

View file

@ -20,8 +20,6 @@
#include "protocols.h" #include "protocols.h"
#include "desfire_crypto.h" #include "desfire_crypto.h"
int DBGLEVEL = DBG_ERROR;
// crypto1 helpers // crypto1 helpers
void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out) { void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out) {
if (len != 1) { if (len != 1) {

View file

@ -18,14 +18,13 @@
#include "BigBuf.h" #include "BigBuf.h"
#include "string.h" #include "string.h"
static uint8_t *next_free_memory;
extern struct common_area common_area; extern struct common_area common_area;
extern char __data_src_start__, __data_start__, __data_end__, __bss_start__, __bss_end__; extern char __data_src_start__, __data_start__, __data_end__, __bss_start__, __bss_end__;
static void uncompress_data_section(void) { static void uncompress_data_section(void) {
next_free_memory = BigBuf_get_addr();
int avail_in; int avail_in;
memcpy(&avail_in, &__data_start__, sizeof(int)); memcpy(&avail_in, &__data_src_start__, sizeof(int));
int avail_out = &__data_end__ - &__data_start__; // uncompressed size. Correct. int avail_out = &__data_end__ - &__data_start__; // uncompressed size. Correct.
// uncompress data segment to RAM // uncompress data segment to RAM
uintptr_t p = (uintptr_t)&__data_src_start__; uintptr_t p = (uintptr_t)&__data_src_start__;
@ -34,13 +33,21 @@ static void uncompress_data_section(void) {
if (res < 0) if (res < 0)
return; return;
// save the size of the compressed data section // save the size of the compressed data section
common_area.arg1 = res; common_area.arg1 = avail_in;
} }
void __attribute__((section(".startos"))) Vector(void); void __attribute__((section(".startos"))) Vector(void);
void Vector(void) { void Vector(void) {
/* Stack should have been set up by the bootloader */ /* Stack should have been set up by the bootloader */
if (common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) {
/* Initialize common area */
memset(&common_area, 0, sizeof(common_area));
common_area.magic = COMMON_AREA_MAGIC;
common_area.version = 1;
}
common_area.flags.osimage_present = 1;
uncompress_data_section(); uncompress_data_section();
/* Set up (that is: clear) BSS. */ /* Set up (that is: clear) BSS. */

View file

@ -216,6 +216,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/uart/uart_posix.c ${PM3_ROOT}/client/src/uart/uart_posix.c
${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/uart/uart_win32.c
${PM3_ROOT}/client/src/ui/overlays.ui ${PM3_ROOT}/client/src/ui/overlays.ui
${PM3_ROOT}/client/src/aiddesfire.c
${PM3_ROOT}/client/src/aidsearch.c ${PM3_ROOT}/client/src/aidsearch.c
${PM3_ROOT}/client/src/cmdanalyse.c ${PM3_ROOT}/client/src/cmdanalyse.c
${PM3_ROOT}/client/src/cmdcrc.c ${PM3_ROOT}/client/src/cmdcrc.c

View file

@ -29,26 +29,31 @@ endif
AMIIBOLIBPATH = ./deps/amiitool AMIIBOLIBPATH = ./deps/amiitool
AMIIBOLIBINC = -I$(AMIIBOLIBPATH) AMIIBOLIBINC = -I$(AMIIBOLIBPATH)
AMIIBOLIB = $(AMIIBOLIBPATH)/libamiibo.a AMIIBOLIB = $(AMIIBOLIBPATH)/libamiibo.a
AMIIBOLIBLD =
## Cliparser / Argtable3 ## Cliparser / Argtable3
CLIPARSERLIBPATH = ./deps/cliparser CLIPARSERLIBPATH = ./deps/cliparser
CLIPARSERLIBINC = -I$(CLIPARSERLIBPATH) CLIPARSERLIBINC = -I$(CLIPARSERLIBPATH)
CLIPARSERLIB = $(CLIPARSERLIBPATH)/libcliparser.a CLIPARSERLIB = $(CLIPARSERLIBPATH)/libcliparser.a
CLIPARSERLIBLD =
## Hardnested ## Hardnested
HARDNESTEDLIBPATH = ./deps/hardnested HARDNESTEDLIBPATH = ./deps/hardnested
HARDNESTEDLIBINC = -I$(HARDNESTEDLIBPATH) HARDNESTEDLIBINC = -I$(HARDNESTEDLIBPATH)
HARDNESTEDLIB = $(HARDNESTEDLIBPATH)/libhardnested.a HARDNESTEDLIB = $(HARDNESTEDLIBPATH)/libhardnested.a
HARDNESTEDLIBLD =
## Jansson ## Jansson
JANSSONLIBPATH = ./deps/jansson JANSSONLIBPATH = ./deps/jansson
JANSSONLIBINC = -I$(JANSSONLIBPATH) JANSSONLIBINC = -I$(JANSSONLIBPATH)
JANSSONLIB = $(JANSSONLIBPATH)/libjansson.a JANSSONLIB = $(JANSSONLIBPATH)/libjansson.a
JANSSONLIBLD =
## Lua ## Lua
LUALIBPATH = ./deps/liblua LUALIBPATH = ./deps/liblua
LUALIBINC = -I$(LUALIBPATH) LUALIBINC = -I$(LUALIBPATH)
LUALIB = $(LUALIBPATH)/liblua.a LUALIB = $(LUALIBPATH)/liblua.a
LUALIBLD =
LUAPLATFORM = generic LUAPLATFORM = generic
ifneq (,$(findstring MINGW,$(platform))) ifneq (,$(findstring MINGW,$(platform)))
LUAPLATFORM = mingw LUAPLATFORM = mingw
@ -56,7 +61,7 @@ else
ifeq ($(platform),Darwin) ifeq ($(platform),Darwin)
LUAPLATFORM = macosx LUAPLATFORM = macosx
else else
LUALIB += -ldl LUALIBLD += -ldl
LUAPLATFORM = linux LUAPLATFORM = linux
endif endif
endif endif
@ -65,16 +70,19 @@ endif
REVENGLIBPATH = ./deps/reveng REVENGLIBPATH = ./deps/reveng
REVENGLIBINC = -I$(REVENGLIBPATH) REVENGLIBINC = -I$(REVENGLIBPATH)
REVENGLIB = $(REVENGLIBPATH)/libreveng.a REVENGLIB = $(REVENGLIBPATH)/libreveng.a
REVENGLIBLD =
## Tinycbor ## Tinycbor
TINYCBORLIBPATH = ./deps/tinycbor TINYCBORLIBPATH = ./deps/tinycbor
TINYCBORLIBINC = -I$(TINYCBORLIBPATH) TINYCBORLIBINC = -I$(TINYCBORLIBPATH)
TINYCBORLIB = $(TINYCBORLIBPATH)/tinycbor.a TINYCBORLIB = $(TINYCBORLIBPATH)/tinycbor.a
TINYCBORLIBLD =
## Whereami ## Whereami
WHEREAMILIBPATH = ./deps/whereami WHEREAMILIBPATH = ./deps/whereami
WHEREAMILIBINC = -I$(WHEREAMILIBPATH) WHEREAMILIBINC = -I$(WHEREAMILIBPATH)
WHEREAMILIB = $(WHEREAMILIBPATH)/libwhereami.a WHEREAMILIB = $(WHEREAMILIBPATH)/libwhereami.a
WHEREAMILIBLD =
########################## ##########################
# common local libraries # # common local libraries #
@ -91,17 +99,20 @@ MBEDTLSLIB = $(OBJDIR)/libmbedtls.a
## Amiibo ## Amiibo
# not distributed as system library # not distributed as system library
LDLIBS += $(AMIIBOLIB) STATICLIBS += $(AMIIBOLIB)
LDLIBS += $(AMIIBOLIBLD)
INCLUDES += $(AMIIBOLIBINC) INCLUDES += $(AMIIBOLIBINC)
## Cliparser / Argtable3 ## Cliparser / Argtable3
# not distributed as system library # not distributed as system library
LDLIBS += $(CLIPARSERLIB) STATICLIBS += $(CLIPARSERLIB)
LDLIBS += $(CLIPARSERLIBLD)
INCLUDES += $(CLIPARSERLIBINC) INCLUDES += $(CLIPARSERLIBINC)
## Hardnested ## Hardnested
# not distributed as system library # not distributed as system library
LDLIBS += $(HARDNESTEDLIB) STATICLIBS += $(HARDNESTEDLIB)
LDLIBS +=$(HARDNESTEDLIBLD)
INCLUDES += $(HARDNESTEDLIBINC) INCLUDES += $(HARDNESTEDLIBINC)
## Jansson ## Jansson
@ -109,12 +120,14 @@ ifneq ($(SKIPJANSSONSYSTEM),1)
JANSSONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags jansson 2>/dev/null) JANSSONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags jansson 2>/dev/null)
JANSSONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs jansson 2>/dev/null) JANSSONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs jansson 2>/dev/null)
ifneq ($(JANSSONLDLIBS),) ifneq ($(JANSSONLDLIBS),)
JANSSONLIB = $(JANSSONLDLIBS) JANSSONLIB =
JANSSONLIBLD = $(JANSSONLDLIBS)
JANSSONLIBINC = $(JANSSONINCLUDES) JANSSONLIBINC = $(JANSSONINCLUDES)
JANSSON_FOUND = 1 JANSSON_FOUND = 1
endif endif
endif endif
LDLIBS += $(JANSSONLIB) STATICLIBS += $(JANSSONLIB)
LDLIBS += $(JANSSONLIBLD)
INCLUDES += $(JANSSONLIBINC) INCLUDES += $(JANSSONLIBINC)
## Lua ## Lua
@ -122,38 +135,45 @@ ifneq ($(SKIPLUASYSTEM),1)
LUAINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags lua5.2 2>/dev/null) LUAINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags lua5.2 2>/dev/null)
LUALDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs lua5.2 2>/dev/null) LUALDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs lua5.2 2>/dev/null)
ifneq ($(LUALDLIBS),) ifneq ($(LUALDLIBS),)
LUALIB = $(LUALDLIBS) LUALIB =
LUALIBLD = $(LUALDLIBS)
LUALIBINC = $(LUAINCLUDES) LUALIBINC = $(LUAINCLUDES)
LUA_FOUND = 1 LUA_FOUND = 1
endif endif
endif endif
LDLIBS += $(LUALIB) STATICLIBS += $(LUALIB)
LDLIBS += $(LUALIBLD)
INCLUDES += $(LUALIBINC) INCLUDES += $(LUALIBINC)
## mbed TLS ## mbed TLS
# system library cannot be used because it is compiled by default without CMAC support # system library cannot be used because it is compiled by default without CMAC support
LDLIBS +=$(MBEDTLSLIB) STATICLIBS += $(MBEDTLSLIB)
LDLIBS += $(MBEDTLSLIBLD)
INCLUDES += $(MBEDTLSLIBINC) INCLUDES += $(MBEDTLSLIBINC)
## Reveng ## Reveng
# not distributed as system library # not distributed as system library
LDLIBS += $(REVENGLIB) STATICLIBS += $(REVENGLIB)
LDLIBS += $(REVENGLIBLD)
INCLUDES += $(REVENGLIBINC) INCLUDES += $(REVENGLIBINC)
## Tinycbor ## Tinycbor
# not distributed as system library # not distributed as system library
LDLIBS += $(TINYCBORLIB) STATICLIBS += $(TINYCBORLIB)
LDLIBS += $(TINYCBORLIBLD)
INCLUDES += $(TINYCBORLIBINC) INCLUDES += $(TINYCBORLIBINC)
## Whereami ## Whereami
ifneq ($(SKIPWHEREAMISYSTEM),1) ifneq ($(SKIPWHEREAMISYSTEM),1)
ifneq (,$(wildcard /usr/include/whereami.h)) ifneq (,$(wildcard /usr/include/whereami.h))
WHEREAMILIB = -lwhereami WHEREAMILIB =
WHEREAMILIBLD = -lwhereami
WHEREAMILIBINC = WHEREAMILIBINC =
WHEREAMI_FOUND = 1 WHEREAMI_FOUND = 1
endif endif
endif endif
LDLIBS += $(WHEREAMILIB) STATICLIBS += $(WHEREAMILIB)
LDLIBS += $(WHEREAMILIBLD)
INCLUDES += $(WHEREAMILIBINC) INCLUDES += $(WHEREAMILIBINC)
#################### ####################
@ -176,12 +196,12 @@ ifneq ($(SKIPBT),1)
BTINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags bluez 2>/dev/null) BTINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags bluez 2>/dev/null)
BTLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs bluez 2>/dev/null) BTLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs bluez 2>/dev/null)
ifneq ($(BTLDLIBS),) ifneq ($(BTLDLIBS),)
BTLIB = $(BTLDLIBS) BTLIBLD = $(BTLDLIBS)
BTLIBINC = $(BTINCLUDES) BTLIBINC = $(BTINCLUDES)
BT_FOUND = 1 BT_FOUND = 1
endif endif
endif endif
LDLIBS += $(BTLIB) LDLIBS += $(BTLIBLD)
INCLUDES += $(BTLIBINC) INCLUDES += $(BTLIBINC)
## Math ## Math
@ -198,7 +218,7 @@ ifneq ($(SKIPPYTHON),1)
PYTHONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags python3 2>/dev/null) PYTHONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags python3 2>/dev/null)
PYTHONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs python3 2>/dev/null) PYTHONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs python3 2>/dev/null)
ifneq ($(PYTHONLDLIBS),) ifneq ($(PYTHONLDLIBS),)
PYTHONLIB = $(PYTHONLDLIBS) PYTHONLIBLD = $(PYTHONLDLIBS)
PYTHONLIBINC = $(PYTHONINCLUDES) PYTHONLIBINC = $(PYTHONINCLUDES)
PYTHON_FOUND = 1 PYTHON_FOUND = 1
else else
@ -206,13 +226,13 @@ ifneq ($(SKIPPYTHON),1)
PYTHONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags python3-embed 2>/dev/null) PYTHONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags python3-embed 2>/dev/null)
PYTHONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs python3-embed 2>/dev/null) PYTHONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs python3-embed 2>/dev/null)
ifneq ($(PYTHONLDLIBS),) ifneq ($(PYTHONLDLIBS),)
PYTHONLIB = $(PYTHONLDLIBS) PYTHONLIBLD = $(PYTHONLDLIBS)
PYTHONLIBINC = $(PYTHONINCLUDES) PYTHONLIBINC = $(PYTHONINCLUDES)
PYTHON_FOUND = 1 PYTHON_FOUND = 1
endif endif
endif endif
endif endif
LDLIBS += $(PYTHONLIB) LDLIBS += $(PYTHONLIBLD)
INCLUDES += $(PYTHONLIBINC) INCLUDES += $(PYTHONLIBINC)
## QT5 (or QT4 fallback) (optional) ## QT5 (or QT4 fallback) (optional)
@ -410,7 +430,8 @@ POSTCOMPILE = $(MV) -f $(OBJDIR)/$*.Td $(OBJDIR)/$*.d && $(TOUCH) $@
# enumerations # # enumerations #
################ ################
SRCS = aidsearch.c \ SRCS = aiddesfire.c \
aidsearch.c \
cmdanalyse.c \ cmdanalyse.c \
cmdcrc.c \ cmdcrc.c \
cmddata.c \ cmddata.c \
@ -583,9 +604,9 @@ all: $(BINS)
all-static: LDLIBS:=-static $(LDLIBS) all-static: LDLIBS:=-static $(LDLIBS)
all-static: $(BINS) all-static: $(BINS)
proxmark3: $(OBJS) amiibo cliparser jansson hardnested lua mbedtls reveng tinycbor whereami lualibs/pm3_cmd.lua lualibs/mfc_default_keys.lua proxmark3: $(OBJS) $(STATICLIBS) lualibs/pm3_cmd.lua lualibs/mfc_default_keys.lua
$(info [=] LD $@) $(info [=] LD $@)
$(Q)$(LD) $(PM3LDFLAGS) $(OBJS) $(LDLIBS) -o $@ $(Q)$(LD) $(PM3LDFLAGS) $(OBJS) $(STATICLIBS) $(LDLIBS) -o $@
src/proxgui.cpp: src/ui/ui_overlays.h src/proxgui.cpp: src/ui/ui_overlays.h
@ -648,44 +669,43 @@ tarbin: $(BINS)
########################### ###########################
# local libraries targets # # local libraries targets #
########################### ###########################
$(AMIIBOLIB): .FORCE
amiibo:
$(info [*] MAKE $@) $(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C $(AMIIBOLIBPATH) all $(Q)$(MAKE) --no-print-directory -C $(AMIIBOLIBPATH) all
cliparser: $(CLIPARSERLIB): .FORCE
$(info [*] MAKE $@) $(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C $(CLIPARSERLIBPATH) all $(Q)$(MAKE) --no-print-directory -C $(CLIPARSERLIBPATH) all
hardnested: $(HARDNESTEDLIB): .FORCE
$(info [*] MAKE $@) $(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C $(HARDNESTEDLIBPATH) all $(Q)$(MAKE) --no-print-directory -C $(HARDNESTEDLIBPATH) all
jansson: $(JANSSONLIB): .FORCE
ifneq ($(JANSSON_FOUND),1) ifneq ($(JANSSON_FOUND),1)
$(info [*] MAKE $@) $(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C $(JANSSONLIBPATH) all $(Q)$(MAKE) --no-print-directory -C $(JANSSONLIBPATH) all
endif endif
lua: $(LUALIB): .FORCE
ifneq ($(LUA_FOUND),1) ifneq ($(LUA_FOUND),1)
$(info [*] MAKE $@ for $(LUAPLATFORM)) $(info [*] MAKE $@ for $(LUAPLATFORM))
$(Q)$(MAKE) --no-print-directory -C $(LUALIBPATH) $(LUAPLATFORM) $(Q)$(MAKE) --no-print-directory -C $(LUALIBPATH) $(LUAPLATFORM)
endif endif
mbedtls: $(MBEDTLSLIB): .FORCE
$(info [*] MAKE $@) $(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C $(MBEDTLSLIBPATH) OBJDIR=$(ROOT_DIR)$(OBJDIR) BINDIR=$(ROOT_DIR)$(OBJDIR) all $(Q)$(MAKE) --no-print-directory -C $(MBEDTLSLIBPATH) OBJDIR=$(ROOT_DIR)$(OBJDIR) BINDIR=$(ROOT_DIR)$(OBJDIR) all
reveng: $(REVENGLIB): .FORCE
$(info [*] MAKE $@) $(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C $(REVENGLIBPATH) all $(Q)$(MAKE) --no-print-directory -C $(REVENGLIBPATH) all
tinycbor: $(TINYCBORLIB): .FORCE
$(info [*] MAKE $@) $(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C $(TINYCBORLIBPATH) all $(Q)$(MAKE) --no-print-directory -C $(TINYCBORLIBPATH) all
whereami: $(WHEREAMILIB): .FORCE
ifneq ($(WHEREAMI_FOUND),1) ifneq ($(WHEREAMI_FOUND),1)
$(info [*] MAKE $@) $(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C $(WHEREAMILIBPATH) all $(Q)$(MAKE) --no-print-directory -C $(WHEREAMILIBPATH) all
@ -695,7 +715,7 @@ endif
# misc # # misc #
######## ########
.PHONY: all clean install uninstall tarbin amiibo cliparser hardnested jansson lua mbedtls reveng tinycbor whereami .PHONY: all clean install uninstall tarbin .FORCE
# version.c should be remade on every compilation # version.c should be remade on every compilation
src/version.c: default_version.c src/version.c: default_version.c

View file

@ -94,6 +94,7 @@ add_library(pm3rrg_rdv4 SHARED
${PM3_ROOT}/client/src/uart/uart_posix.c ${PM3_ROOT}/client/src/uart/uart_posix.c
${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/uart/uart_win32.c
${PM3_ROOT}/client/src/ui/overlays.ui ${PM3_ROOT}/client/src/ui/overlays.ui
${PM3_ROOT}/client/src/aiddesfire.c
${PM3_ROOT}/client/src/aidsearch.c ${PM3_ROOT}/client/src/aidsearch.c
${PM3_ROOT}/client/src/cmdanalyse.c ${PM3_ROOT}/client/src/cmdanalyse.c
${PM3_ROOT}/client/src/cmdcrc.c ${PM3_ROOT}/client/src/cmdcrc.c

View file

@ -132,8 +132,7 @@
"Vendor": "Clipper", "Vendor": "Clipper",
"Country": "US", "Country": "US",
"Name": "Clipper Card/San Francisco Bay Area ", "Name": "Clipper Card/San Francisco Bay Area ",
"Description": "(FIDs 02: current balance; 04: Refill History; 08: Card Information; 0E: Trip History) "Description": "(FIDs 02: current balance; 04: Refill History; 08: Card Information; 0E: Trip History)\\nFFFFFF General Issuer Information (FIDs 00: MAD Version; 01: Card Holder; 02: Card Publisher)",
FFFFFF General Issuer Information (FIDs 00: MAD Version; 01: Card Holder; 02: Card Publisher)",
"Type": "transport" "Type": "transport"
}, },
{ {

133
client/src/aiddesfire.c Normal file
View file

@ -0,0 +1,133 @@
//-----------------------------------------------------------------------------
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// AID DESFire functions
//-----------------------------------------------------------------------------
#include "aiddesfire.h"
#include "pm3_cmd.h"
#include "fileutils.h"
#include "jansson.h"
static json_t *df_known_aids = NULL;
static int open_aiddf_file(json_t **root, bool verbose) {
char *path;
int res = searchFile(&path, RESOURCES_SUBDIR, "aid_desfire", ".json", true);
if (res != PM3_SUCCESS) {
return PM3_EFILE;
}
int retval = PM3_SUCCESS;
json_error_t error;
*root = json_load_file(path, 0, &error);
if (!*root) {
PrintAndLogEx(ERR, "json (%s) error on line %d: %s", path, error.line, error.text);
retval = PM3_ESOFT;
goto out;
}
if (!json_is_array(*root)) {
PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", path);
retval = PM3_ESOFT;
goto out;
}
if (verbose)
PrintAndLogEx(SUCCESS, "Loaded file " _YELLOW_("`%s`") " (%s) %zu records.", path, _GREEN_("ok"), json_array_size(*root));
out:
free(path);
return retval;
}
static int close_aiddf_file(json_t *root) {
json_decref(root);
return PM3_SUCCESS;
}
static const char *aiddf_json_get_str(json_t *data, const char *name) {
json_t *jstr = json_object_get(data, name);
if (jstr == NULL)
return NULL;
if (!json_is_string(jstr)) {
PrintAndLogEx(WARNING, _YELLOW_("`%s`") " is not a string", name);
return NULL;
}
const char *cstr = json_string_value(jstr);
if (strlen(cstr) == 0)
return NULL;
return cstr;
}
static int print_aiddf_description(json_t *root, uint8_t aid[3], char *fmt, bool verbose) {
char laid[7] = {0};
sprintf(laid, "%02x%02x%02x", aid[2], aid[1], aid[0]); // must be lowercase
json_t *elm = NULL;
for (uint32_t idx = 0; idx < json_array_size(root); idx++) {
json_t *data = json_array_get(root, idx);
if (!json_is_object(data)) {
PrintAndLogEx(ERR, "data [%d] is not an object\n", idx);
continue;
}
const char *faid = aiddf_json_get_str(data, "AID");
char lfaid[strlen(faid) + 1];
strcpy(lfaid, faid);
str_lower(lfaid);
if (strcmp(laid, lfaid) == 0) {
elm = data;
break;
}
}
if (elm == NULL) {
PrintAndLogEx(INFO, fmt, " (unknown)");
return PM3_ENODATA;
}
const char *vaid = aiddf_json_get_str(elm, "AID");
const char *vendor = aiddf_json_get_str(elm, "Vendor");
const char *country = aiddf_json_get_str(elm, "Country");
const char *name = aiddf_json_get_str(elm, "Name");
const char *description = aiddf_json_get_str(elm, "Description");
const char *type = aiddf_json_get_str(elm, "Type");
if (name && vendor) {
char result[4 + strlen(name) + strlen(vendor)];
sprintf(result, " %s [%s]", name, vendor);
PrintAndLogEx(INFO, fmt, result);
}
if (verbose) {
PrintAndLogEx(SUCCESS, " AID: %s", vaid);
if (name)
PrintAndLogEx(SUCCESS, " Name: %s", name);
if (description)
PrintAndLogEx(SUCCESS, " Description: %s", description);
if (type)
PrintAndLogEx(SUCCESS, " Type: %s", type);
if (vendor)
PrintAndLogEx(SUCCESS, " Vendor: %s", vendor);
if (country)
PrintAndLogEx(SUCCESS, " Country: %s", country);
}
return PM3_SUCCESS;
}
int AIDDFDecodeAndPrint(uint8_t aid[3]) {
open_aiddf_file(&df_known_aids, false);
char fmt[50];
sprintf(fmt, " DF AID Function %02X%02X%02X :" _YELLOW_("%s"), aid[2], aid[1], aid[0], "%s");
print_aiddf_description(df_known_aids, aid, fmt, false);
close_aiddf_file(df_known_aids);
return PM3_SUCCESS;
}

16
client/src/aiddesfire.h Normal file
View file

@ -0,0 +1,16 @@
//-----------------------------------------------------------------------------
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// AID DESFire functions
//-----------------------------------------------------------------------------
#ifndef _AIDDESFIRE_H_
#define _AIDDESFIRE_H_
#include "common.h"
int AIDDFDecodeAndPrint(uint8_t aid[3]);
#endif // _AIDDESFIRE_H_

View file

@ -398,19 +398,64 @@ static int CmdSetDebugMode(const char *Cmd) {
//by marshmellow //by marshmellow
// max output to 512 bits if we have more // max output to 512 bits if we have more
// doesn't take inconsideration where the demod offset or bitlen found. // doesn't take inconsideration where the demod offset or bitlen found.
void printDemodBuff(void) { int printDemodBuff(uint8_t offset, bool strip_leading, bool invert, bool print_hex) {
int len = DemodBufferLen; size_t len = DemodBufferLen;
if (len < 1) { if (len == 0) {
PrintAndLogEx(INFO, "(printDemodBuff) no bits found in demod buffer"); PrintAndLogEx(WARNING, "Demodbuffer is empty");
return; return PM3_EINVARG;
} }
if (len > 512) len = 512;
PrintAndLogEx(NORMAL, "%s", sprint_bin_break(DemodBuffer, len, 32)); uint8_t *buf = NULL;
if (strip_leading) {
buf = (DemodBuffer + offset);
if (len > (DemodBufferLen - offset))
len = (DemodBufferLen - offset);
size_t i;
for (i = 0; i < len; i++) {
if (buf[i] == 1) break;
}
offset += i;
}
if (len > (DemodBufferLen - offset)) {
len = (DemodBufferLen - offset);
}
if (len > 512) {
len = 512;
}
if (invert) {
buf = (DemodBuffer + offset);
for (size_t i = 0; i < len; i++) {
if (buf[i] == 1)
buf[i] = 0;
else {
if (buf[i] == 0)
buf[i] = 1;
}
}
}
if (print_hex) {
buf = (DemodBuffer + offset);
char hex[512] = {0x00};
int num_bits = binarraytohex(hex, sizeof(hex), (char *)buf, len);
if (num_bits == 0) {
return PM3_ESOFT;
}
PrintAndLogEx(SUCCESS, "DemodBuffer: %s", hex);
} else {
PrintAndLogEx(SUCCESS, "DemodBuffer:\n%s", sprint_bin_break(DemodBuffer + offset, len, 32));
}
return PM3_SUCCESS;
} }
int CmdPrintDemodBuff(const char *Cmd) { int CmdPrintDemodBuff(const char *Cmd) {
bool hexMode = false; bool print_hex = false;
bool errors = false; bool errors = false;
bool lstrip = false; bool lstrip = false;
bool invert = false; bool invert = false;
@ -422,7 +467,7 @@ int CmdPrintDemodBuff(const char *Cmd) {
case 'h': case 'h':
return usage_data_printdemodbuf(); return usage_data_printdemodbuf();
case 'x': case 'x':
hexMode = true; print_hex = true;
cmdp++; cmdp++;
break; break;
case 'o': case 'o':
@ -452,45 +497,7 @@ int CmdPrintDemodBuff(const char *Cmd) {
//Validations //Validations
if (errors) return usage_data_printdemodbuf(); if (errors) return usage_data_printdemodbuf();
if (DemodBufferLen == 0) { return printDemodBuff(offset, lstrip, invert, print_hex);
PrintAndLogEx(WARNING, "Demodbuffer is empty");
return PM3_ESOFT;
}
if (lstrip) {
char *buf = (char *)(DemodBuffer + offset);
length = (length > (DemodBufferLen - offset)) ? DemodBufferLen - offset : length;
uint32_t i;
for (i = 0; i < length; i++) {
if (buf[i] == 1) break;
}
offset += i;
}
length = (length > (DemodBufferLen - offset)) ? DemodBufferLen - offset : length;
if (invert) {
char *buf = (char *)(DemodBuffer + offset);
for (uint32_t i = 0; i < length; i++) {
if (buf[i] == 1)
buf[i] = 0;
else {
if (buf[i] == 0)
buf[i] = 1;
}
}
}
if (hexMode) {
char *buf = (char *)(DemodBuffer + offset);
char hex[512] = {0x00};
int numBits = binarraytohex(hex, sizeof(hex), buf, length);
if (numBits == 0) {
return PM3_ESOFT;
}
PrintAndLogEx(SUCCESS, "DemodBuffer: %s", hex);
} else {
PrintAndLogEx(SUCCESS, "DemodBuffer:\n%s", sprint_bin_break(DemodBuffer + offset, length, 32));
}
return PM3_SUCCESS;
} }
//by marshmellow //by marshmellow
@ -596,7 +603,7 @@ int ASKDemod_ext(int clk, int invert, int maxErr, size_t maxLen, bool amplify, b
else else
PrintAndLogEx(DEBUG, "ASK/Raw - Clock: %d - Decoded bitstream:", clk); PrintAndLogEx(DEBUG, "ASK/Raw - Clock: %d - Decoded bitstream:", clk);
printDemodBuff(); printDemodBuff(0, false, false, false);
} }
uint64_t lo = 0; uint64_t lo = 0;
uint32_t hi = 0; uint32_t hi = 0;
@ -792,7 +799,7 @@ int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose) {
setClockGrid(clk, startIdx + clk * offset / 2); setClockGrid(clk, startIdx + clk * offset / 2);
if (g_debugMode || verbose) { if (g_debugMode || verbose) {
PrintAndLogEx(DEBUG, "Biphase Decoded using offset %d | clock %d | #errors %d | start index %d\ndata\n", offset, clk, errCnt, (startIdx + clk * offset / 2)); PrintAndLogEx(DEBUG, "Biphase Decoded using offset %d | clock %d | #errors %d | start index %d\ndata\n", offset, clk, errCnt, (startIdx + clk * offset / 2));
printDemodBuff(); printDemodBuff(offset, false, false, false);
} }
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1204,7 +1211,7 @@ int FSKrawDemod(uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow, bo
if (verbose || g_debugMode) { if (verbose || g_debugMode) {
PrintAndLogEx(DEBUG, "DEBUG: (FSKrawDemod) Using Clock:%u, invert:%u, fchigh:%u, fclow:%u", rfLen, invert, fchigh, fclow); PrintAndLogEx(DEBUG, "DEBUG: (FSKrawDemod) Using Clock:%u, invert:%u, fchigh:%u, fclow:%u", rfLen, invert, fchigh, fclow);
PrintAndLogEx(NORMAL, "%s decoded bitstream:", GetFSKType(fchigh, fclow, invert)); PrintAndLogEx(NORMAL, "%s decoded bitstream:", GetFSKType(fchigh, fclow, invert));
printDemodBuff(); printDemodBuff(0, false, invert, false);
} }
goto out; goto out;
} else { } else {
@ -1327,7 +1334,7 @@ int NRZrawDemod(int clk, int invert, int maxErr, bool verbose) {
if (verbose || g_debugMode) { if (verbose || g_debugMode) {
PrintAndLogEx(NORMAL, "NRZ demoded bitstream:"); PrintAndLogEx(NORMAL, "NRZ demoded bitstream:");
// Now output the bitstream to the scrollback by line of 16 bits // Now output the bitstream to the scrollback by line of 16 bits
printDemodBuff(); printDemodBuff(0, false, invert, false);
} }
free(bits); free(bits);
@ -1352,14 +1359,14 @@ static int CmdNRZrawDemod(const char *Cmd) {
} }
// by marshmellow // by marshmellow
// takes 3 arguments - clock, invert, maxErr as integers // takes 3 arguments - clock, invert, max_err as integers
// attempts to demodulate psk only // attempts to demodulate psk only
// prints binary found and saves in demodbuffer for further commands // prints binary found and saves in demodbuffer for further commands
int CmdPSK1rawDemod(const char *Cmd) { int CmdPSK1rawDemod(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0)); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_p1(); if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_p1();
int clk = 0, invert = 0, maxErr = 100; int clk = 0, invert = 0, max_err = 100;
sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr); sscanf(Cmd, "%i %i %i", &clk, &invert, &max_err);
if (clk == 1) { if (clk == 1) {
invert = 1; invert = 1;
clk = 0; clk = 0;
@ -1368,7 +1375,7 @@ int CmdPSK1rawDemod(const char *Cmd) {
PrintAndLogEx(WARNING, "Invalid value for invert: %i", invert); PrintAndLogEx(WARNING, "Invalid value for invert: %i", invert);
return PM3_EINVARG; return PM3_EINVARG;
} }
int ans = PSKDemod(clk, invert, maxErr, true); int ans = PSKDemod(clk, invert, max_err, true);
//output //output
if (ans != PM3_SUCCESS) { if (ans != PM3_SUCCESS) {
if (g_debugMode) PrintAndLogEx(ERR, "Error demoding: %d", ans); if (g_debugMode) PrintAndLogEx(ERR, "Error demoding: %d", ans);
@ -1376,7 +1383,7 @@ int CmdPSK1rawDemod(const char *Cmd) {
} }
PrintAndLogEx(NORMAL, "PSK1 demoded bitstream:"); PrintAndLogEx(NORMAL, "PSK1 demoded bitstream:");
// Now output the bitstream to the scrollback by line of 16 bits // Now output the bitstream to the scrollback by line of 16 bits
printDemodBuff(); printDemodBuff(0, false, invert, false);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1385,8 +1392,8 @@ int CmdPSK1rawDemod(const char *Cmd) {
static int CmdPSK2rawDemod(const char *Cmd) { static int CmdPSK2rawDemod(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0)); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_p2(); if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_p2();
int clk = 0, invert = 0, maxErr = 100; int clk = 0, invert = 0, max_err = 100;
sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr); sscanf(Cmd, "%i %i %i", &clk, &invert, &max_err);
if (clk == 1) { if (clk == 1) {
invert = 1; invert = 1;
clk = 0; clk = 0;
@ -1395,7 +1402,7 @@ static int CmdPSK2rawDemod(const char *Cmd) {
PrintAndLogEx(WARNING, "Invalid value for invert: %i", invert); PrintAndLogEx(WARNING, "Invalid value for invert: %i", invert);
return PM3_EINVARG; return PM3_EINVARG;
} }
int ans = PSKDemod(clk, invert, maxErr, true); int ans = PSKDemod(clk, invert, max_err, true);
if (ans != PM3_SUCCESS) { if (ans != PM3_SUCCESS) {
if (g_debugMode) PrintAndLogEx(ERR, "Error demoding: %d", ans); if (g_debugMode) PrintAndLogEx(ERR, "Error demoding: %d", ans);
return PM3_ESOFT; return PM3_ESOFT;
@ -1403,7 +1410,7 @@ static int CmdPSK2rawDemod(const char *Cmd) {
psk1TOpsk2(DemodBuffer, DemodBufferLen); psk1TOpsk2(DemodBuffer, DemodBufferLen);
PrintAndLogEx(NORMAL, "PSK2 demoded bitstream:"); PrintAndLogEx(NORMAL, "PSK2 demoded bitstream:");
// Now output the bitstream to the scrollback by line of 16 bits // Now output the bitstream to the scrollback by line of 16 bits
printDemodBuff(); printDemodBuff(0, false, invert, false);
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -68,7 +68,8 @@ int PSKDemod(int clk, int invert, int maxErr, bool verbose);
int NRZrawDemod(int clk, int invert, int maxErr, bool verbose); // used by cmd lf pac, lf t55xx int NRZrawDemod(int clk, int invert, int maxErr, bool verbose); // used by cmd lf pac, lf t55xx
void printDemodBuff(void); int printDemodBuff(uint8_t offset, bool strip_leading, bool invert, bool print_hex);
void setDemodBuff(uint8_t *buff, size_t size, size_t start_idx); void setDemodBuff(uint8_t *buff, size_t size, size_t start_idx);
bool getDemodBuff(uint8_t *buff, size_t *size); bool getDemodBuff(uint8_t *buff, size_t *size);
void save_restoreDB(uint8_t saveOpt);// option '1' to save DemodBuffer any other to restore void save_restoreDB(uint8_t saveOpt);// option '1' to save DemodBuffer any other to restore

View file

@ -29,6 +29,7 @@
#include "aidsearch.h" #include "aidsearch.h"
#include "cmdhf.h" // handle HF plot #include "cmdhf.h" // handle HF plot
#include "protocols.h" // MAGIC_GEN_1A #include "protocols.h" // MAGIC_GEN_1A
#include "emv/dump.h" // dump_buffer
bool APDUInFramingEnable = true; bool APDUInFramingEnable = true;
@ -210,8 +211,7 @@ static int usage_hf_14a_config(void) {
} }
static int usage_hf_14a_sim(void) { static int usage_hf_14a_sim(void) {
// PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"); PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n");
PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 byte UID\n");
PrintAndLogEx(NORMAL, "Usage: hf 14a sim [h] t <type> u <uid> [x] [e] [v]"); PrintAndLogEx(NORMAL, "Usage: hf 14a sim [h] t <type> u <uid> [x] [e] [v]");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " h : This help");
@ -225,8 +225,7 @@ static int usage_hf_14a_sim(void) {
PrintAndLogEx(NORMAL, " 8 = MIFARE Classic 4k"); PrintAndLogEx(NORMAL, " 8 = MIFARE Classic 4k");
PrintAndLogEx(NORMAL, " 9 = FM11RF005SH Shanghai Metro"); PrintAndLogEx(NORMAL, " 9 = FM11RF005SH Shanghai Metro");
PrintAndLogEx(NORMAL, " 10 = JCOP 31/41 Rothult"); PrintAndLogEx(NORMAL, " 10 = JCOP 31/41 Rothult");
// PrintAndLogEx(NORMAL, " u : 4, 7 or 10 byte UID"); PrintAndLogEx(NORMAL, " u : 4, 7 or 10 byte UID");
PrintAndLogEx(NORMAL, " u : 4, 7 byte UID");
PrintAndLogEx(NORMAL, " x : (Optional) Performs the 'reader attack', nr/ar attack against a reader"); PrintAndLogEx(NORMAL, " x : (Optional) Performs the 'reader attack', nr/ar attack against a reader");
PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys"); PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys");
PrintAndLogEx(NORMAL, " v : (Optional) Verbose"); PrintAndLogEx(NORMAL, " v : (Optional) Verbose");
@ -234,7 +233,7 @@ static int usage_hf_14a_sim(void) {
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344 x")); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344 x"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344")); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344556677")); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344556677"));
// PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223445566778899AA\n"); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 112233445566778899AA"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_14a_sniff(void) { static int usage_hf_14a_sniff(void) {
@ -552,8 +551,8 @@ static int CmdHF14AReader(const char *Cmd) {
res = PM3_ESOFT; res = PM3_ESOFT;
goto plot; goto plot;
} }
if (!(silent && continuous)) {
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
if (!(silent && continuous)) {
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02x %02x"), card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02x %02x"), card.atqa[1], card.atqa[0]);
PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02x [%" PRIu64 "]"), card.sak, resp.oldarg[0]); PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02x [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
@ -689,7 +688,9 @@ int CmdHF14ASim(const char *Cmd) {
param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen); param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen);
uidlen >>= 1; uidlen >>= 1;
switch (uidlen) { switch (uidlen) {
//case 10: flags |= FLAG_10B_UID_IN_DATA; break; case 10:
flags |= FLAG_10B_UID_IN_DATA;
break;
case 7: case 7:
flags |= FLAG_7B_UID_IN_DATA; flags |= FLAG_7B_UID_IN_DATA;
break; break;
@ -1838,34 +1839,38 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} }
if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
PrintAndLogEx(INFO, "-------------------------- " _CYAN_("ATS") " --------------------------");
bool ta1 = 0, tb1 = 0, tc1 = 0; bool ta1 = 0, tb1 = 0, tc1 = 0;
int pos;
if (select_status == 2) { if (select_status == 2) {
PrintAndLogEx(INFO, "SAK incorrectly claims that card doesn't support RATS"); PrintAndLogEx(INFO, "--> SAK incorrectly claims that card doesn't support RATS <--");
} }
PrintAndLogEx(SUCCESS, " ATS: %s", sprint_hex(card.ats, card.ats_len));
PrintAndLogEx(SUCCESS, " - TL : length is %d bytes", card.ats[0]);
if (card.ats[0] != card.ats_len - 2) { if (card.ats[0] != card.ats_len - 2) {
PrintAndLogEx(SUCCESS, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len); PrintAndLogEx(WARNING, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len);
} }
PrintAndLogEx(SUCCESS, "ATS: " _YELLOW_("%s")"[ %02x %02x ]", sprint_hex(card.ats, card.ats_len - 2), card.ats[card.ats_len - 1], card.ats[card.ats_len]);
PrintAndLogEx(INFO, " " _YELLOW_("%02x") "............... TL length is " _GREEN_("%d") " bytes", card.ats[0], card.ats[0]);
if (card.ats[0] > 1) { // there is a format byte (T0) if (card.ats[0] > 1) { // there is a format byte (T0)
ta1 = (card.ats[1] & 0x10) == 0x10; ta1 = (card.ats[1] & 0x10) == 0x10;
tb1 = (card.ats[1] & 0x20) == 0x20; tb1 = (card.ats[1] & 0x20) == 0x20;
tc1 = (card.ats[1] & 0x40) == 0x40; tc1 = (card.ats[1] & 0x40) == 0x40;
int16_t fsci = card.ats[1] & 0x0f; int16_t fsci = card.ats[1] & 0x0f;
PrintAndLogEx(SUCCESS, " - T0 : TA1 is%s present, TB1 is%s present, " PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ T0 TA1 is%s present, TB1 is%s present, "
"TC1 is%s present, FSCI is %d (FSC = %d)", "TC1 is%s present, FSCI is %d (FSC = %d)",
(ta1 ? "" : " NOT"), card.ats[1],
(tb1 ? "" : " NOT"), (ta1 ? "" : _RED_(" NOT")),
(tc1 ? "" : " NOT"), (tb1 ? "" : _RED_(" NOT")),
(tc1 ? "" : _RED_(" NOT")),
fsci, fsci,
fsci < ARRAYLEN(atsFSC) ? atsFSC[fsci] : -1 fsci < ARRAYLEN(atsFSC) ? atsFSC[fsci] : -1
); );
} }
pos = 2; int pos = 2;
if (ta1) { if (ta1) {
char dr[16], ds[16]; char dr[16], ds[16];
dr[0] = ds[0] = '\0'; dr[0] = ds[0] = '\0';
@ -1877,19 +1882,23 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if (card.ats[pos] & 0x04) strcat(dr, "8, "); if (card.ats[pos] & 0x04) strcat(dr, "8, ");
if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0'; if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0';
if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0'; if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0';
PrintAndLogEx(SUCCESS, " - TA1 : different divisors are%s supported, " PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... TA1 different divisors are%s supported, "
"DR: [%s], DS: [%s]", "DR: [%s], DS: [%s]",
((card.ats[pos] & 0x80) ? " NOT" : ""), card.ats[pos],
((card.ats[pos] & 0x80) ? _RED_(" NOT") : ""),
dr, dr,
ds ds
); );
pos++; pos++;
} }
if (tb1) { if (tb1) {
uint32_t sfgi = card.ats[pos] & 0x0F; uint32_t sfgi = card.ats[pos] & 0x0F;
uint32_t fwi = card.ats[pos] >> 4; uint32_t fwi = card.ats[pos] >> 4;
PrintAndLogEx(SUCCESS, " - TB1 : SFGI = %d (SFGT = %s%d/fc), FWI = %d (FWT = %d/fc)",
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... TB1 SFGI = %d (SFGT = %s%d/fc), FWI = " _YELLOW_("%d") " (FWT = %d/fc)",
card.ats[pos],
(sfgi), (sfgi),
sfgi ? "" : "(not needed) ", sfgi ? "" : "(not needed) ",
sfgi ? (1 << 12) << sfgi : 0, sfgi ? (1 << 12) << sfgi : 0,
@ -1900,31 +1909,39 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} }
if (tc1) { if (tc1) {
PrintAndLogEx(SUCCESS, " - TC1 : NAD is%s supported, CID is%s supported", PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... TC1 NAD is%s supported, CID is%s supported",
(card.ats[pos] & 0x01) ? "" : " NOT", card.ats[pos],
(card.ats[pos] & 0x02) ? "" : " NOT"); (card.ats[pos] & 0x01) ? "" : _RED_(" NOT"),
(card.ats[pos] & 0x02) ? "" : _RED_(" NOT")
);
pos++; pos++;
} }
if (card.ats[0] > pos && card.ats[0] < card.ats_len - 2) { // ATS - Historial bytes and identify based on it
const char *tip = ""; if (card.ats[0] > pos && card.ats[0] <= card.ats_len - 2) {
char tip[60];
tip[0] = '\0';
if (card.ats[0] - pos >= 7) { if (card.ats[0] - pos >= 7) {
snprintf(tip, sizeof(tip), " ");
if ((card.sak & 0x70) == 0x40) { // and no GetVersion().. if ((card.sak & 0x70) == 0x40) { // and no GetVersion()..
if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
tip = "-> MIFARE Plus X 2K/4K (SL3)"; snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus X 2K/4K (SL3)");
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
if ((card.atqa[0] & 0x02) == 0x02) if ((card.atqa[0] & 0x02) == 0x02)
tip = "-> MIFARE Plus S 2K (SL3)"; snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus S 2K (SL3)");
else if ((card.atqa[0] & 0x04) == 0x04) else if ((card.atqa[0] & 0x04) == 0x04)
tip = "-> MIFARE Plus S 4K (SL3)"; snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus S 4K (SL3)");
} else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) { } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) {
tip = "-> MIFARE Plus SE 1K (17pF)"; snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus SE 1K (17pF)");
} else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) { } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) {
tip = "-> MIFARE Plus SE 1K (70pF)"; snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus SE 1K (70pF)");
} }
} else { //SAK B4,5,6 } else { //SAK B4,5,6
@ -1933,37 +1950,41 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
tip = "-> MIFARE Plus X 2K (SL1)"; snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus X 2K (SL1)");
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
tip = "-> MIFARE Plus S 2K (SL1)"; snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus S 2K (SL1)");
} else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) { } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) {
tip = "-> MIFARE Plus SE 1K (17pF)"; snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus SE 1K (17pF)");
} else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) { } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) {
tip = "-> MIFARE Plus SE 1K (70pF)"; snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus SE 1K (70pF)");
} }
} else { } else {
if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
tip = "-> MIFARE Plus X 4K (SL1)"; snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus X 4K (SL1)");
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
tip = "-> MIFARE Plus S 4K (SL1)"; snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus S 4K (SL1)");
}
} }
} }
} }
} uint8_t calen = card.ats[0] - pos;
PrintAndLogEx(SUCCESS, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "-------------------- " _CYAN_("Historical bytes") " --------------------");
if (card.ats[pos] == 0xC1) { if (card.ats[pos] == 0xC1) {
PrintAndLogEx(SUCCESS, " c1 -> Mifare or (multiple) virtual cards of various type"); PrintAndLogEx(INFO, " %s%s", sprint_hex(card.ats + pos, calen), tip);
PrintAndLogEx(SUCCESS, " %02x -> Length is %d bytes", card.ats[pos + 1], card.ats[pos + 1]); PrintAndLogEx(SUCCESS, " C1..................... Mifare or (multiple) virtual cards of various type");
PrintAndLogEx(SUCCESS, " %02x.................. length is " _YELLOW_("%d") " bytes", card.ats[pos + 1], card.ats[pos + 1]);
switch (card.ats[pos + 2] & 0xf0) { switch (card.ats[pos + 2] & 0xf0) {
case 0x10: case 0x10:
PrintAndLogEx(SUCCESS, " 1x -> MIFARE DESFire"); PrintAndLogEx(SUCCESS, " 1x............... MIFARE DESFire");
isMifareDESFire = true; isMifareDESFire = true;
isMifareClassic = false; isMifareClassic = false;
isMifarePlus = false; isMifarePlus = false;
break; break;
case 0x20: case 0x20:
PrintAndLogEx(SUCCESS, " 2x -> MIFARE Plus"); PrintAndLogEx(SUCCESS, " 2x............... MIFARE Plus");
isMifarePlus = true; isMifarePlus = true;
isMifareDESFire = false; isMifareDESFire = false;
isMifareClassic = false; isMifareClassic = false;
@ -1971,51 +1992,53 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} }
switch (card.ats[pos + 2] & 0x0f) { switch (card.ats[pos + 2] & 0x0f) {
case 0x00: case 0x00:
PrintAndLogEx(SUCCESS, " x0 -> <1 kByte"); PrintAndLogEx(SUCCESS, " x0............... < 1 kByte");
break; break;
case 0x01: case 0x01:
PrintAndLogEx(SUCCESS, " x1 -> 1 kByte"); PrintAndLogEx(SUCCESS, " x1............... 1 kByte");
break; break;
case 0x02: case 0x02:
PrintAndLogEx(SUCCESS, " x2 -> 2 kByte"); PrintAndLogEx(SUCCESS, " x2............... 2 kByte");
break; break;
case 0x03: case 0x03:
PrintAndLogEx(SUCCESS, " x3 -> 4 kByte"); PrintAndLogEx(SUCCESS, " x3............... 4 kByte");
break; break;
case 0x04: case 0x04:
PrintAndLogEx(SUCCESS, " x4 -> 8 kByte"); PrintAndLogEx(SUCCESS, " x4............... 8 kByte");
break; break;
} }
switch (card.ats[pos + 3] & 0xf0) { switch (card.ats[pos + 3] & 0xf0) {
case 0x00: case 0x00:
PrintAndLogEx(SUCCESS, " 0x -> Engineering sample"); PrintAndLogEx(SUCCESS, " 0x............ Engineering sample");
break; break;
case 0x20: case 0x20:
PrintAndLogEx(SUCCESS, " 2x -> Released"); PrintAndLogEx(SUCCESS, " 2x............ Released");
break; break;
} }
switch (card.ats[pos + 3] & 0x0f) { switch (card.ats[pos + 3] & 0x0f) {
case 0x00: case 0x00:
PrintAndLogEx(SUCCESS, " x0 -> Generation 1"); PrintAndLogEx(SUCCESS, " x0............ Generation 1");
break; break;
case 0x01: case 0x01:
PrintAndLogEx(SUCCESS, " x1 -> Generation 2"); PrintAndLogEx(SUCCESS, " x1............ Generation 2");
break; break;
case 0x02: case 0x02:
PrintAndLogEx(SUCCESS, " x2 -> Generation 3"); PrintAndLogEx(SUCCESS, " x2............ Generation 3");
break; break;
} }
switch (card.ats[pos + 4] & 0x0f) { switch (card.ats[pos + 4] & 0x0f) {
case 0x00: case 0x00:
PrintAndLogEx(SUCCESS, " x0 -> Only VCSL supported"); PrintAndLogEx(SUCCESS, " x0......... Only VCSL supported");
break; break;
case 0x01: case 0x01:
PrintAndLogEx(SUCCESS, " x1 -> VCS, VCSL, and SVC supported"); PrintAndLogEx(SUCCESS, " x1......... VCS, VCSL, and SVC supported");
break; break;
case 0x0E: case 0x0E:
PrintAndLogEx(SUCCESS, " xE -> no VCS command supported"); PrintAndLogEx(SUCCESS, " xE......... no VCS command supported");
break; break;
} }
} else {
dump_buffer(&card.ats[pos], calen, NULL, 1);
} }
} }
@ -2087,7 +2110,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} else { } else {
PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported"); PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported");
if ((card.sak & 0x20) == 0x20) { if ((card.sak & 0x20) == 0x20) {
PrintAndLogEx(INFO, "SAK incorrectly claims that card supports RATS"); PrintAndLogEx(INFO, "--> SAK incorrectly claims that card supports RATS <--");
} }
} }
@ -2134,6 +2157,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if (isST) if (isST)
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf st info`")); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf st info`"));
PrintAndLogEx(NORMAL, "");
DropField(); DropField();
return select_status; return select_status;
} }

View file

@ -66,22 +66,12 @@ static int usage_hf_iclass_sim(void) {
PrintAndLogEx(NORMAL, " -- execute loclass attack online part"); PrintAndLogEx(NORMAL, " -- execute loclass attack online part");
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass sim 2")); PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass sim 2"));
PrintAndLogEx(NORMAL, " -- simulate full iCLASS 2k tag"); PrintAndLogEx(NORMAL, " -- simulate full iCLASS 2k tag");
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass eload f hf-iclass-AA162D30F8FF12F1-dump.bin")); PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass eload -f hf-iclass-AA162D30F8FF12F1-dump.bin"));
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass sim 3")); PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass sim 3"));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_iclass_eload(void) {
PrintAndLogEx(NORMAL, "Loads iCLASS tag dump into emulator memory on device\n");
PrintAndLogEx(NORMAL, "Usage: hf iclass eload [h] f <filename>\n");
PrintAndLogEx(NORMAL, "Options");
PrintAndLogEx(NORMAL, " h : Show this help");
PrintAndLogEx(NORMAL, " f <filename> : filename of dump");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass eload f hf-iclass-AA162D30F8FF12F1-dump.bin"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
static int usage_hf_iclass_esave(void) { static int usage_hf_iclass_esave(void) {
PrintAndLogEx(NORMAL, "Save emulator memory to file."); PrintAndLogEx(NORMAL, "Save emulator memory to file.");
PrintAndLogEx(NORMAL, "if not filename is supplied, CSN will be used."); PrintAndLogEx(NORMAL, "if not filename is supplied, CSN will be used.");
@ -272,27 +262,6 @@ static int usage_hf_iclass_managekeys(void) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_iclass_loclass(void) {
PrintAndLogEx(NORMAL, "Execute the offline part of loclass attack");
PrintAndLogEx(NORMAL, " An iclass dumpfile is assumed to consist of an arbitrary number of");
PrintAndLogEx(NORMAL, " malicious CSNs, and their protocol responses");
PrintAndLogEx(NORMAL, " The binary format of the file is expected to be as follows: ");
PrintAndLogEx(NORMAL, " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
PrintAndLogEx(NORMAL, " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
PrintAndLogEx(NORMAL, " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
PrintAndLogEx(NORMAL, " ... totalling N*24 bytes\n");
PrintAndLogEx(NORMAL, "Usage: hf iclass loclass [h] [t [l]] [f <filename>]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h Show this help");
PrintAndLogEx(NORMAL, " t Perform self-test");
PrintAndLogEx(NORMAL, " t l Perform self-test, including long ones");
PrintAndLogEx(NORMAL, " f <filename> Bruteforce iclass dumpfile");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass loclass f iclass-dump.bin"));
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass loclass t"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
static int usage_hf_iclass_chk(void) { static int usage_hf_iclass_chk(void) {
PrintAndLogEx(NORMAL, "Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag\n"); PrintAndLogEx(NORMAL, "Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag\n");
PrintAndLogEx(NORMAL, "Usage: hf iclass chk [h|e|r] [f (*.dic)]\n"); PrintAndLogEx(NORMAL, "Usage: hf iclass chk [h|e|r] [f (*.dic)]\n");
@ -730,7 +699,7 @@ static int CmdHFiClassSim(const char *Cmd) {
saveFile("iclass_mac_attack", ".bin", dump, datalen); saveFile("iclass_mac_attack", ".bin", dump, datalen);
free(dump); free(dump);
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass h") "` to recover elite key"); PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -h") "` to recover elite key");
break; break;
} }
case ICLASS_SIM_MODE_READER_ATTACK_KEYROLL: { case ICLASS_SIM_MODE_READER_ATTACK_KEYROLL: {
@ -796,7 +765,7 @@ static int CmdHFiClassSim(const char *Cmd) {
saveFile("iclass_mac_attack_keyroll_B", ".bin", dump, datalen); saveFile("iclass_mac_attack_keyroll_B", ".bin", dump, datalen);
free(dump); free(dump);
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass h") "` to recover elite key"); PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -h") "` to recover elite key");
break; break;
} }
case ICLASS_SIM_MODE_CSN: case ICLASS_SIM_MODE_CSN:
@ -884,50 +853,54 @@ static int CmdHFiClassReader(const char *Cmd) {
} }
static int CmdHFiClassELoad(const char *Cmd) { static int CmdHFiClassELoad(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf iclass eload",
"Loads iCLASS tag dump into emulator memory on device",
"hf iclass eload -f hf-iclass-AA162D30F8FF12F1-dump.bin\n");
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<filename>", "filename of dump"),
arg_lit0(NULL, "json", "load JSON type dump"),
arg_lit0(NULL, "eml", "load EML type dump"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
if (strlen(filename) == 0) {
PrintAndLogEx(ERR, "Error: Please specify a filename");
CLIParserFree(ctx);
return PM3_EINVARG;
}
DumpFileType_t dftype = BIN; DumpFileType_t dftype = BIN;
char filename[FILE_PATH_SIZE] = {0};
bool errors = false; bool use_json = arg_get_lit(ctx, 2);
uint8_t cmdp = 0; bool use_eml = arg_get_lit(ctx, 3);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { CLIParserFree(ctx);
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': if (use_json && use_eml) {
return usage_hf_iclass_eload(); PrintAndLogEx(ERR, "Error: can't specify both JSON & EML");
case 'f': return PM3_EINVARG;
if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) {
PrintAndLogEx(FAILED, "Filename too long");
errors = true;
break;
} }
cmdp += 2;
break; if (use_json) {
case 'j':
dftype = JSON; dftype = JSON;
cmdp++; } else if (use_eml) {
break;
case 'e':
dftype = EML; dftype = EML;
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
//Validations
if (errors || cmdp == 0) {
return usage_hf_iclass_eload();
} }
size_t bytes_read = 2048;
uint8_t *dump = calloc(2048, sizeof(uint8_t)); uint8_t *dump = calloc(2048, sizeof(uint8_t));
if (!dump) { if (!dump) {
PrintAndLogEx(ERR, "error, cannot allocate memory "); PrintAndLogEx(ERR, "error, cannot allocate memory ");
return PM3_EMALLOC; return PM3_EMALLOC;
} }
size_t bytes_read = 2048;
int res = 0; int res = 0;
switch (dftype) { switch (dftype) {
@ -943,10 +916,10 @@ static int CmdHFiClassELoad(const char *Cmd) {
res = loadFileJSON(filename, dump, 2048, &bytes_read, NULL); res = loadFileJSON(filename, dump, 2048, &bytes_read, NULL);
break; break;
} }
case DICTIONARY: case DICTIONARY: {
PrintAndLogEx(ERR, "No dictionary loaded"); PrintAndLogEx(ERR, "Error: Only BIN/JSON/EML formats allowed");
free(dump); return PM3_EINVARG;
return PM3_ESOFT; }
} }
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
@ -1787,7 +1760,7 @@ write_dump:
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool replay, bool verbose) { static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool replay, bool verbose, bool use_secure_pagemode) {
iclass_writeblock_req_t payload = { iclass_writeblock_req_t payload = {
.req.use_raw = rawkey, .req.use_raw = rawkey,
@ -1796,7 +1769,7 @@ static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bo
.req.use_replay = replay, .req.use_replay = replay,
.req.blockno = blockno, .req.blockno = blockno,
.req.send_reply = true, .req.send_reply = true,
.req.do_auth = true, .req.do_auth = use_secure_pagemode,
}; };
memcpy(payload.req.key, KEY, 8); memcpy(payload.req.key, KEY, 8);
memcpy(payload.data, bldata, sizeof(payload.data)); memcpy(payload.data, bldata, sizeof(payload.data));
@ -1831,6 +1804,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
bool use_replay = false; bool use_replay = false;
bool errors = false; bool errors = false;
bool verbose = false; bool verbose = false;
bool use_secure_pagemode = false;
uint8_t cmdp = 0; uint8_t cmdp = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) { switch (tolower(param_getchar(Cmd, cmdp))) {
@ -1875,6 +1849,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
PrintAndLogEx(WARNING, "\nERROR: Credit Key is incorrect length\n"); PrintAndLogEx(WARNING, "\nERROR: Credit Key is incorrect length\n");
errors = true; errors = true;
} }
use_secure_pagemode = true;
cmdp += 2; cmdp += 2;
break; break;
case 'r': case 'r':
@ -1907,9 +1882,9 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
errors = true; errors = true;
} }
if (errors || cmdp < 6) return usage_hf_iclass_writeblock(); if (errors || cmdp < 4) return usage_hf_iclass_writeblock();
int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, use_replay, verbose); int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, use_replay, verbose, use_secure_pagemode);
switch (isok) { switch (isok) {
case PM3_SUCCESS: case PM3_SUCCESS:
PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno); PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno);
@ -2325,26 +2300,42 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
} }
static int CmdHFiClass_loclass(const char *Cmd) { static int CmdHFiClass_loclass(const char *Cmd) {
char opt = tolower(param_getchar(Cmd, 0)); CLIParserContext *ctx;
CLIParserInit(&ctx, "hf iclass loclass",
"Execute the offline part of loclass attack\n"
" An iclass dumpfile is assumed to consist of an arbitrary number of\n"
" malicious CSNs, and their protocol responses\n"
" The binary format of the file is expected to be as follows: \n"
" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>\n"
" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>\n"
" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>\n"
" ... totalling N*24 bytes",
"hf iclass loclass -f iclass-dump.bin\n"
"hf iclass loclass --test");
if (strlen(Cmd) < 1 || opt == 'h') void *argtable[] = {
return usage_hf_iclass_loclass(); arg_param_begin,
arg_str0("f", "file", "<filename>", "filename of Bruteforce iclass dumpfile"),
arg_lit0(NULL, "test", "Perform self-test"),
arg_lit0(NULL, "long", "Perform self-test, including long ones"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
if (opt == 'f') { int fnlen = 0;
char fileName[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
if (param_getstr(Cmd, 1, fileName, sizeof(fileName)) > 0) { CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
return bruteforceFileNoKeys(fileName);
} else {
PrintAndLogEx(WARNING, "You must specify a filename");
return PM3_EFILE;
}
} else if (opt == 't') {
char opt2 = tolower(param_getchar(Cmd, 1));
bool test = arg_get_lit(ctx, 2);
bool longtest = arg_get_lit(ctx, 3);
CLIParserFree(ctx);
if (test || longtest) {
int errors = testCipherUtils(); int errors = testCipherUtils();
errors += testMAC(); errors += testMAC();
errors += doKeyTests(); errors += doKeyTests();
errors += testElite(opt2 == 'l'); errors += testElite(longtest);
if (errors != PM3_SUCCESS) if (errors != PM3_SUCCESS)
PrintAndLogEx(ERR, "There were errors!!!"); PrintAndLogEx(ERR, "There were errors!!!");
@ -2352,7 +2343,7 @@ static int CmdHFiClass_loclass(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
} }
return usage_hf_iclass_loclass(); return bruteforceFileNoKeys(filename);
} }
void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize) { void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize) {
@ -3576,10 +3567,11 @@ int info_iclass(void) {
PrintAndLogEx(INFO, "------------------------ " _CYAN_("Fingerprint") " -----------------------"); PrintAndLogEx(INFO, "------------------------ " _CYAN_("Fingerprint") " -----------------------");
uint8_t aia[8]; uint8_t aia[8];
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
memcpy(aia, ns_hdr->app_issuer_area, sizeof(aia)); memcpy(aia, ns_hdr->app_issuer_area, sizeof(aia));
else } else {
memcpy(aia, hdr->app_issuer_area, sizeof(aia)); memcpy(aia, hdr->app_issuer_area, sizeof(aia));
}
// if CSN ends with FF12E0, it's inside HID CSN range. // if CSN ends with FF12E0, it's inside HID CSN range.
bool isHidRange = (memcmp(hdr->csn + 5, "\xFF\x12\xE0", 3) == 0); bool isHidRange = (memcmp(hdr->csn + 5, "\xFF\x12\xE0", 3) == 0);
@ -3594,11 +3586,13 @@ int info_iclass(void) {
if (se_enabled) if (se_enabled)
PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS SE")); PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS SE"));
} else { } else {
PrintAndLogEx(SUCCESS, " CSN..-....... " _YELLOW_("outside HID range")); PrintAndLogEx(SUCCESS, " CSN.......... " _YELLOW_("outside HID range"));
} }
uint8_t cardtype = get_mem_config(hdr); uint8_t cardtype = get_mem_config(hdr);
PrintAndLogEx(SUCCESS, " Card type.... " _GREEN_("%s"), card_types[cardtype]); PrintAndLogEx(SUCCESS, " Card type.... " _GREEN_("%s"), card_types[cardtype]);
} }
DropField(); DropField();

View file

@ -198,10 +198,12 @@ static const char* lto_print_size(uint8_t ti) {
switch (ti) { switch (ti) {
case 1: case 1:
return "101 blocks / 3232 bytes"; return "101 blocks / 3232 bytes";
case 2:
return "95 blocks / 3040 bytes";
case 3: case 3:
return "255 blocks / 8160 bytes"; return "255 blocks / 8160 bytes";
default : default :
return ""; return "unknown";
} }
} }
@ -222,6 +224,9 @@ int infoLTO(bool verbose) {
PrintAndLogEx(SUCCESS, "UID......... " _YELLOW_("%s"), sprint_hex_inrow(serial_number, sizeof(serial_number))); PrintAndLogEx(SUCCESS, "UID......... " _YELLOW_("%s"), sprint_hex_inrow(serial_number, sizeof(serial_number)));
PrintAndLogEx(SUCCESS, "Type info... " _YELLOW_("%s"), sprint_hex_inrow(type_info, sizeof(type_info))); PrintAndLogEx(SUCCESS, "Type info... " _YELLOW_("%s"), sprint_hex_inrow(type_info, sizeof(type_info)));
PrintAndLogEx(SUCCESS, "Memory...... " _YELLOW_("%s"), lto_print_size(type_info[1])); PrintAndLogEx(SUCCESS, "Memory...... " _YELLOW_("%s"), lto_print_size(type_info[1]));
if (type_info[1] > 3) {
PrintAndLogEx(INFO, "Unknown LTO tag, report to @iceman!");
}
} }
return ret_val; return ret_val;
@ -464,10 +469,13 @@ int dumpLTO(uint8_t *dump, bool verbose) {
return ret_val; return ret_val;
} }
// 0003 == 255 blocks x 32 = 8160 bytes // 0003 == 255 blocks x 32 = 8160 bytes
// 0002 == 95 blocks x 32 = 3040 bytes
// 0001 == 101 blocks x 32 = 3232 bytes // 0001 == 101 blocks x 32 = 3232 bytes
uint8_t blocks = 0xFF; uint8_t blocks = 0xFF;
if (type_info[1] == 0x01) { if (type_info[1] == 0x01) {
blocks = 0x65; blocks = 0x65;
} else if (type_info[1] == 0x02) {
blocks = 0x5F;
} }
PrintAndLogEx(SUCCESS, "Found LTO tag w " _YELLOW_("%s") " memory", lto_print_size(type_info[1])); PrintAndLogEx(SUCCESS, "Found LTO tag w " _YELLOW_("%s") " memory", lto_print_size(type_info[1]));

View file

@ -34,6 +34,7 @@
#include "mifare/ndef.h" // NDEF #include "mifare/ndef.h" // NDEF
#include "mifare/mad.h" #include "mifare/mad.h"
#include "generator.h" #include "generator.h"
#include "aiddesfire.h"
#define MAX_KEY_LEN 24 #define MAX_KEY_LEN 24
#define MAX_KEYS_LIST_LEN 1024 #define MAX_KEYS_LIST_LEN 1024
@ -59,7 +60,7 @@ uint8_t k3kdefaultkeys[1][24] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
struct desfire_tag mf_state = {.session_key = NULL, .authentication_scheme = AS_LEGACY, .authenticated_key_no = NOT_YET_AUTHENTICATED, .crypto_buffer = NULL, .crypto_buffer_size = 0, .selected_application = 0}; struct desfire_tag mf_state = {.session_key = NULL, .authentication_scheme = AS_LEGACY, .authenticated_key_no = NOT_YET_AUTHENTICATED, .crypto_buffer = NULL, .crypto_buffer_size = 0, .selected_application = 0};
static desfiretag_t tag = &mf_state; static desfiretag_t tag = &mf_state;
typedef struct { typedef struct mfdes_authinput {
uint8_t mode; uint8_t mode;
uint8_t algo; uint8_t algo;
uint8_t keyno; uint8_t keyno;
@ -93,7 +94,6 @@ typedef struct {
uint8_t details[14]; uint8_t details[14];
} PACKED mfdes_info_res_t; } PACKED mfdes_info_res_t;
typedef struct mfdes_value { typedef struct mfdes_value {
uint8_t fileno; //01 uint8_t fileno; //01
uint8_t value[16]; uint8_t value[16];
@ -339,14 +339,36 @@ typedef enum {
NTAG413DNA, NTAG413DNA,
} nxp_cardtype_t; } nxp_cardtype_t;
typedef struct { typedef struct dfname {
uint8_t aid[3]; uint8_t aid[3];
uint8_t fid[2]; uint8_t fid[2];
uint8_t name[16]; uint8_t name[16];
} dfname_t; } PACKED dfname_t;
typedef struct aidhdr {
uint8_t aid[3];
uint8_t keysetting1;
uint8_t keysetting2;
uint8_t fid[2];
uint8_t name[16];
} PACKED aidhdr_t;
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static const char *getEncryptionAlgoStr(uint8_t algo) {
switch (algo) {
case MFDES_ALGO_AES :
return "AES";
case MFDES_ALGO_3DES :
return "3DES";
case MFDES_ALGO_DES :
return "DES";
case MFDES_ALGO_3K3DES :
return "3K3DES";
default :
return "";
}
}
/* /*
The 7 MSBits (= n) code the storage size itself based on 2^n, The 7 MSBits (= n) code the storage size itself based on 2^n,
the LSBit is set to '0' if the size is exactly 2^n the LSBit is set to '0' if the size is exactly 2^n
@ -1113,6 +1135,12 @@ static int handler_desfire_freemem(uint32_t *free_mem) {
} }
static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t new_algo, uint8_t *old_key, uint8_t old_algo, uint8_t aes_version) { static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t new_algo, uint8_t *old_key, uint8_t old_algo, uint8_t aes_version) {
if (new_key == NULL || old_key == NULL) {
return PM3_EINVARG;
}
// AID == 000000 6bits LSB needs to be 0
key_no &= 0x0F; key_no &= 0x0F;
/* /*
@ -1120,24 +1148,34 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
* changing the card master key to one of them require a key_no tweak. * changing the card master key to one of them require a key_no tweak.
*/ */
if (0x000000 == tag->selected_application) { if (0x000000 == tag->selected_application) {
// PICC master key, 6bits LSB needs to be 0
key_no = 0x00;
// PICC master key, keyalgo specific 2bit MSB
switch (new_algo) { switch (new_algo) {
case MFDES_ALGO_DES: case MFDES_ALGO_DES:
break; case MFDES_ALGO_3DES:
break; // 00xx xxx
case MFDES_ALGO_3K3DES: case MFDES_ALGO_3K3DES:
key_no |= 0x40; key_no |= 0x40; // 01xx xxx
break; break;
case MFDES_ALGO_AES: case MFDES_ALGO_AES:
key_no |= 0x80; key_no |= 0x80; // 10xx xxx
break; break;
} }
} }
uint8_t data[24 * 4] = {key_no}; // Variable length ciphered key data 26-42 bytes plus padding..
uint8_t data[64] = {key_no};
sAPDU apdu = {0x90, MFDES_CHANGE_KEY, 0x00, 0x00, 0x01, data}; // 0xC4 sAPDU apdu = {0x90, MFDES_CHANGE_KEY, 0x00, 0x00, 0x01, data}; // 0xC4
uint8_t new_key_length = 16; uint8_t new_key_length = 16;
switch (new_algo) { switch (new_algo) {
case MFDES_ALGO_DES: case MFDES_ALGO_DES:
new_key_length = 8;
break;
case MFDES_ALGO_3DES:
case MFDES_ALGO_AES: case MFDES_ALGO_AES:
new_key_length = 16; new_key_length = 16;
break; break;
@ -1222,7 +1260,7 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
tag->session_key = NULL; tag->session_key = NULL;
} }
return 0; return PM3_SUCCESS;
} }
// --- GET SIGNATURE // --- GET SIGNATURE
@ -1247,7 +1285,7 @@ static int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signat
{"DESFire EV3", "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743"}, {"DESFire EV3", "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743"},
{"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"}, {"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"},
{"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"}, {"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"},
{"Mifare Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"} {"MIFARE Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}
}; };
@ -1513,9 +1551,14 @@ static int handler_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) {
static int handler_desfire_select_application(uint8_t *aid) { static int handler_desfire_select_application(uint8_t *aid) {
if (g_debugMode > 1) { if (g_debugMode > 1) {
if (aid == NULL) PrintAndLogEx(ERR, "AID=NULL"); if (aid == NULL) {
PrintAndLogEx(ERR, "AID=NULL");
} }
if (aid == NULL) return PM3_EINVARG; }
if (aid == NULL) {
return PM3_EINVARG;
}
sAPDU apdu = {0x90, MFDES_SELECT_APPLICATION, 0x00, 0x00, 0x03, aid}; //0x5a sAPDU apdu = {0x90, MFDES_SELECT_APPLICATION, 0x00, 0x00, 0x03, aid}; //0x5a
uint32_t recv_len = 0; uint32_t recv_len = 0;
uint16_t sw = 0; uint16_t sw = 0;
@ -1589,48 +1632,49 @@ static int handler_desfire_filesettings(uint8_t file_id, uint8_t *dest, uint32_t
return res; return res;
} }
typedef struct {
uint8_t aid[3];
uint8_t keysetting1;
uint8_t keysetting2;
uint8_t fid[2];
uint8_t name[16];
} aidhdr_t;
static int handler_desfire_createapp(aidhdr_t *aidhdr, bool usename, bool usefid) { static int handler_desfire_createapp(aidhdr_t *aidhdr, bool usename, bool usefid) {
if (aidhdr == NULL) return PM3_EINVARG; if (aidhdr == NULL) return PM3_EINVARG;
sAPDU apdu = {0x90, MFDES_CREATE_APPLICATION, 0x00, 0x00, sizeof(aidhdr_t), (uint8_t *)aidhdr}; // 0xCA sAPDU apdu = {0x90, MFDES_CREATE_APPLICATION, 0x00, 0x00, sizeof(aidhdr_t), (uint8_t *)aidhdr}; // 0xCA
if (!usename) { if (usename == false) {
apdu.Lc = apdu.Lc - 16; apdu.Lc = apdu.Lc - sizeof(aidhdr->name);
} }
if (!usefid) { if (usefid == false) {
apdu.Lc = apdu.Lc - 2; apdu.Lc = apdu.Lc - sizeof(aidhdr->fid);
} }
uint8_t *data = NULL; uint8_t *data = NULL;
if (!usefid && usename) {
data = (uint8_t *)malloc(apdu.Lc); // skip over FID if not used.
if (usefid == false && usename) {
data = calloc(apdu.Lc, sizeof(uint8_t));
apdu.data = data; apdu.data = data;
memcpy(data, aidhdr, apdu.Lc);
memcpy(&data[3 + 1 + 1], aidhdr->name, 16); memcpy(data, aidhdr->aid, sizeof(aidhdr->aid));
data[3] = aidhdr->keysetting1;
data[4] = aidhdr->keysetting2;
memcpy(data + 5, aidhdr->name, sizeof(aidhdr->name));
PrintAndLogEx(INFO, "new data: %s", sprint_hex_inrow(data, apdu.Lc));
} }
uint16_t sw = 0; uint16_t sw = 0;
uint32_t recvlen = 0; uint32_t recvlen = 0;
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (data != NULL) free(data); if (data != NULL) {
free(data);
}
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't create aid -> %s"), GetErrorString(res, &sw)); PrintAndLogEx(WARNING, _RED_(" Can't create aid -> %s"), GetErrorString(res, &sw));
DropField(); DropField();
return res;
} }
return res; return res;
} }
static int handler_desfire_deleteapp(const uint8_t *aid) { static int handler_desfire_deleteapp(const uint8_t *aid) {
if (aid == NULL) return PM3_EINVARG; if (aid == NULL) {
return PM3_EINVARG;
}
sAPDU apdu = {0x90, MFDES_DELETE_APPLICATION, 0x00, 0x00, 3, (uint8_t *)aid}; // 0xDA sAPDU apdu = {0x90, MFDES_DELETE_APPLICATION, 0x00, 0x00, 3, (uint8_t *)aid}; // 0xDA
uint16_t sw = 0; uint16_t sw = 0;
uint32_t recvlen = 0; uint32_t recvlen = 0;
@ -1638,7 +1682,6 @@ static int handler_desfire_deleteapp(const uint8_t *aid) {
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't delete aid -> %s"), GetErrorString(res, &sw)); PrintAndLogEx(WARNING, _RED_(" Can't delete aid -> %s"), GetErrorString(res, &sw));
DropField(); DropField();
return res;
} }
return res; return res;
} }
@ -2115,19 +2158,20 @@ static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid,
PrintAndLogEx(FAILED, "KDF AN10922 algo requires an input of length 1-31 bytes."); PrintAndLogEx(FAILED, "KDF AN10922 algo requires an input of length 1-31 bytes.");
return PM3_EINVARG; return PM3_EINVARG;
} }
break;
case MFDES_KDF_ALGO_GALLAGHER: case MFDES_KDF_ALGO_GALLAGHER:
// TODO: 2TDEA and 3TDEA keys use an input length of 1-15 bytes // TODO: 2TDEA and 3TDEA keys use an input length of 1-15 bytes
if (cmdAuthAlgo != MFDES_ALGO_AES) { if (cmdAuthAlgo != MFDES_ALGO_AES) {
PrintAndLogEx(FAILED, "Crypto algo not valid for the KDF AN10922 algo."); PrintAndLogEx(FAILED, "Crypto algo not valid for the KDF AN10922 algo.");
return PM3_EINVARG; return PM3_EINVARG;
} }
break;
// KDF input arg is ignored as it'll be generated. // KDF input arg is ignored as it'll be generated.
case MFDES_KDF_ALGO_NONE: case MFDES_KDF_ALGO_NONE:
break; break;
default: default:
PrintAndLogEx(WARNING, "KDF algo %d is not supported.", cmdKdfAlgo); PrintAndLogEx(WARNING, "KDF algo %d is not supported.", cmdKdfAlgo);
return PM3_EINVARG; return PM3_EINVARG;
break;
} }
// KEY // KEY
@ -2198,12 +2242,12 @@ static int CmdHF14ADesSelectApp(const char *Cmd) {
} }
int res = handler_desfire_select_application(aid); int res = handler_desfire_select_application(aid);
if (res != PM3_SUCCESS) {
DropField(); DropField();
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error on selecting aid."); PrintAndLogEx(ERR, "Error on selecting aid.");
return res; } else {
}
PrintAndLogEx(SUCCESS, "Successfully selected aid."); PrintAndLogEx(SUCCESS, "Successfully selected aid.");
}
return res; return res;
} }
@ -2211,7 +2255,7 @@ static int CmdHF14ADesCreateApp(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes createaid", CLIParserInit(&ctx, "hf mfdes createaid",
"Create Application ID", "Create Application ID",
"hf mfdes createaid -a 123456 -f 1111 -k 0E -l 2E -n Test" "hf mfdes createaid -a 123456 -f 1111 -k 0E -l 2E --name Test"
); );
void *argtable[] = { void *argtable[] = {
@ -2220,7 +2264,7 @@ static int CmdHF14ADesCreateApp(const char *Cmd) {
arg_strx0("f", "fid", "<fid>", "File ID to create (optional)"), arg_strx0("f", "fid", "<fid>", "File ID to create (optional)"),
arg_strx0("k", "ks1", "<keysetting1>", "Key Setting 1 (Application Master Key Settings)"), arg_strx0("k", "ks1", "<keysetting1>", "Key Setting 1 (Application Master Key Settings)"),
arg_strx0("l", "ks2", "<keysetting2>", "Key Setting 2"), arg_strx0("l", "ks2", "<keysetting2>", "Key Setting 2"),
arg_str0("n", "name", "<name>", "App ISO-4 Name (optional)"), arg_str0(NULL, "name", "<name>", "App ISO-4 Name (optional)"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -2318,9 +2362,20 @@ static int CmdHF14ADesCreateApp(const char *Cmd) {
aidhdr.keysetting1 = keysetting1[0]; aidhdr.keysetting1 = keysetting1[0];
aidhdr.keysetting2 = keysetting2[0]; aidhdr.keysetting2 = keysetting2[0];
if (usefid) memcpy(aidhdr.fid, fid, sizeof(fid)); if (usefid)
memcpy(aidhdr.fid, fid, sizeof(aidhdr.fid));
if (usename) memcpy(aidhdr.name, name, sizeof(name)); if (usename)
memcpy(aidhdr.name, name, sizeof(aidhdr.name));
PrintAndLogEx(INFO, "Creating AID using:");
PrintAndLogEx(INFO, "AID %s", sprint_hex_inrow(aidhdr.aid, sizeof(aidhdr.aid)));
PrintAndLogEx(INFO, "Key set1 0x%02X", aidhdr.keysetting1);
PrintAndLogEx(INFO, "Key Set2 0x%02X", aidhdr.keysetting2);
if (usefid)
PrintAndLogEx(INFO, "FID %s", sprint_hex_inrow(aidhdr.fid, sizeof(aidhdr.fid)));
if (usename)
PrintAndLogEx(INFO, "DF Name %s", aidhdr.name);
uint8_t rootaid[3] = {0x00, 0x00, 0x00}; uint8_t rootaid[3] = {0x00, 0x00, 0x00};
int res = handler_desfire_select_application(rootaid); int res = handler_desfire_select_application(rootaid);
@ -2331,7 +2386,9 @@ static int CmdHF14ADesCreateApp(const char *Cmd) {
res = handler_desfire_createapp(&aidhdr, usename, usefid); res = handler_desfire_createapp(&aidhdr, usename, usefid);
DropField(); DropField();
if (res == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "Successfully created aid."); PrintAndLogEx(SUCCESS, "Successfully created aid.");
}
return res; return res;
} }
@ -2366,10 +2423,15 @@ static int CmdHF14ADesDeleteApp(const char *Cmd) {
uint8_t rootaid[3] = {0x00, 0x00, 0x00}; uint8_t rootaid[3] = {0x00, 0x00, 0x00};
int res = handler_desfire_select_application(rootaid); int res = handler_desfire_select_application(rootaid);
if (res != PM3_SUCCESS) { DropField(); return res;} if (res != PM3_SUCCESS) {
DropField();
return res;
}
res = handler_desfire_deleteapp(aid); res = handler_desfire_deleteapp(aid);
DropField(); DropField();
if (res == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "Successfully deleted aid."); PrintAndLogEx(SUCCESS, "Successfully deleted aid.");
}
return res; return res;
} }
@ -3571,6 +3633,20 @@ static int DecodeFileSettings(uint8_t *src, int src_len, int maclen) {
} }
static int CmdHF14ADesDump(const char *Cmd) { static int CmdHF14ADesDump(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes dump",
"Tries to dump all files on a DESFire tag",
"hf mfdes dump");
void *argtable[] = {
arg_param_begin,
// arg_strx0("a", "aid", "<aid>", "Use specific AID (3 hex bytes, big endian)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
DropField(); DropField();
@ -3597,7 +3673,7 @@ static int CmdHF14ADesDump(const char *Cmd) {
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "-- Mifare DESFire Dump ----------------------"); PrintAndLogEx(INFO, "-- " _CYAN_("MIFARE DESFire Dump") " ----------------------");
PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
for (uint32_t i = 0; i < app_ids_len; i += 3) { for (uint32_t i = 0; i < app_ids_len; i += 3) {
@ -3612,6 +3688,8 @@ static int CmdHF14ADesDump(const char *Cmd) {
PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid); PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid);
PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8)); PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8));
MADDFDecodeAndPrint(short_aid); MADDFDecodeAndPrint(short_aid);
} else {
AIDDFDecodeAndPrint(aid);
} }
for (uint8_t m = 0; m < dfname_count; m++) { for (uint8_t m = 0; m < dfname_count; m++) {
if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) { if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) {
@ -3757,7 +3835,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "-- Mifare DESFire Enumerate applications --------------------"); PrintAndLogEx(INFO, "-- MIFARE DESFire Enumerate applications --------------------");
PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(SUCCESS, " Tag report " _GREEN_("%d") " application%c", app_ids_len / 3, (app_ids_len == 3) ? ' ' : 's'); PrintAndLogEx(SUCCESS, " Tag report " _GREEN_("%d") " application%c", app_ids_len / 3, (app_ids_len == 3) ? ' ' : 's');
@ -3782,6 +3860,8 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid); PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid);
PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8)); PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8));
MADDFDecodeAndPrint(short_aid); MADDFDecodeAndPrint(short_aid);
} else {
AIDDFDecodeAndPrint(aid);
} }
for (uint8_t m = 0; m < dfname_count; m++) { for (uint8_t m = 0; m < dfname_count; m++) {
if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) { if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) {
@ -3832,7 +3912,7 @@ static int CmdHF14ADesChangeKey(const char *Cmd) {
uint8_t newkeylength = 8; uint8_t newkeylength = 8;
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes changekey", CLIParserInit(&ctx, "hf mfdes changekey",
"Changes Mifare DESFire Key\n" "Changes MIFARE DESFire Key\n"
"Make sure to select aid or authenticate aid before running this command.", "Make sure to select aid or authenticate aid before running this command.",
"hf mfdes changekey -n 0 -t 1 -k 0000000000000000 -u 1 -j 0102030405060708 -> DES,keynumber 0" "hf mfdes changekey -n 0 -t 1 -k 0000000000000000 -u 1 -j 0102030405060708 -> DES,keynumber 0"
); );
@ -3903,6 +3983,10 @@ static int CmdHF14ADesChangeKey(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
PrintAndLogEx(INFO, "changing key number 0x%02x", cmdKeyNo);
PrintAndLogEx(INFO, "old key: %s (%s)", sprint_hex_inrow(key, keylen), getEncryptionAlgoStr(cmdAuthAlgo));
PrintAndLogEx(INFO, "new key: %s (%s)", sprint_hex_inrow(newkey, newkeylen), getEncryptionAlgoStr(newcmdAuthAlgo));
int error = mifare_desfire_change_key(cmdKeyNo, newkey, newcmdAuthAlgo, key, cmdAuthAlgo, aesversion); int error = mifare_desfire_change_key(cmdKeyNo, newkey, newcmdAuthAlgo, key, cmdAuthAlgo, aesversion);
if (error == PM3_SUCCESS) { if (error == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, " Successfully changed key."); PrintAndLogEx(SUCCESS, " Successfully changed key.");
@ -3929,7 +4013,7 @@ static int CmdHF14ADesAuth(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes auth", CLIParserInit(&ctx, "hf mfdes auth",
"Authenticates Mifare DESFire using Key", "Authenticates MIFARE DESFire using Key",
"hf mfdes auth -m 3 -t 4 -a 808301 -n 0 -k 00000000000000000000000000000000 -> AES,keynumber 0, aid 0x803201\n" "hf mfdes auth -m 3 -t 4 -a 808301 -n 0 -k 00000000000000000000000000000000 -> AES,keynumber 0, aid 0x803201\n"
"hf mfdes auth -m 2 -t 2 -a 000000 -n 1 -k 00000000000000000000000000000000 -> 3DES,keynumber 1, aid 0x000000\n" "hf mfdes auth -m 2 -t 2 -a 000000 -n 1 -k 00000000000000000000000000000000 -> 3DES,keynumber 1, aid 0x000000\n"
"hf mfdes auth -m 1 -t 1 -a 000000 -n 2 -k 0000000000000000 -> DES,keynumber 2, aid 0x000000\n" "hf mfdes auth -m 1 -t 1 -a 000000 -n 2 -k 0000000000000000 -> DES,keynumber 2, aid 0x000000\n"
@ -4308,7 +4392,7 @@ static int CmdHF14aDesChk(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes chk", CLIParserInit(&ctx, "hf mfdes chk",
"Checks keys with Mifare Desfire card.", "Checks keys with MIFARE DESFire card.",
"hf mfdes chk -a 123456 -k 000102030405060708090a0b0c0d0e0f -> check key on aid 0x123456\n" "hf mfdes chk -a 123456 -k 000102030405060708090a0b0c0d0e0f -> check key on aid 0x123456\n"
"hf mfdes chk -d mfdes_default_keys -> check keys from dictionary against all existing aid on card\n" "hf mfdes chk -d mfdes_default_keys -> check keys from dictionary against all existing aid on card\n"
"hf mfdes chk -d mfdes_default_keys -a 123456 -> check keys from dictionary against aid 0x123456\n" "hf mfdes chk -d mfdes_default_keys -a 123456 -> check keys from dictionary against aid 0x123456\n"
@ -4470,7 +4554,7 @@ static int CmdHF14aDesChk(const char *Cmd) {
PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " k3kdes keys", k3kkeyListLen); PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " k3kdes keys", k3kkeyListLen);
} }
if (!verbose) if (verbose == false)
PrintAndLogEx(INFO, "Search keys:"); PrintAndLogEx(INFO, "Search keys:");
bool result = false; bool result = false;
@ -4520,7 +4604,7 @@ static int CmdHF14aDesChk(const char *Cmd) {
continue; continue;
} }
if (dict_filenamelen && endFilePosition) { if (dict_filenamelen) {
if (verbose == false) if (verbose == false)
PrintAndLogEx(NORMAL, "d" NOLF); PrintAndLogEx(NORMAL, "d" NOLF);
@ -4547,7 +4631,7 @@ static int CmdHF14aDesChk(const char *Cmd) {
// save keys to json // save keys to json
if ((jsonnamelen > 0) && result) { if ((jsonnamelen > 0) && result) {
// Mifare Desfire info // MIFARE DESFire info
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
PacketResponseNG resp; PacketResponseNG resp;
@ -4604,7 +4688,6 @@ static int CmdHF14aDesNDEF(const char *Cmd) {
arg_litn("v", "verbose", 0, 2, "show technical data"), arg_litn("v", "verbose", 0, 2, "show technical data"),
arg_str0("", "aid", "<aid>", "replace default aid for NDEF"), arg_str0("", "aid", "<aid>", "replace default aid for NDEF"),
arg_str0("k", "key", "<key>", "replace default key for NDEF"), arg_str0("k", "key", "<key>", "replace default key for NDEF"),
arg_lit0("b", "keyb", "use key B for access sectors (by default: key A)"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -4617,20 +4700,24 @@ static int CmdHF14aDesNDEF(const char *Cmd) {
uint8_t key[16] = {0}; uint8_t key[16] = {0};
int keylen; int keylen;
CLIGetHexWithReturn(ctx, 3, key, &keylen); CLIGetHexWithReturn(ctx, 3, key, &keylen);
bool keyB = arg_get_lit(ctx, 4);
uint16_t ndefAID = 0xe103; CLIParserFree(ctx);
if (aidlen == 2)
ndefAID = (aid[0] << 8) + aid[1];
uint32_t ndefAID = 0xEEEE10;
if (aidlen == 2) {
ndefAID = (aid[0] << 16) | (aid[1] << 8) | aid[2];
}
// set default NDEF key
uint8_t ndefkey[16] = {0}; uint8_t ndefkey[16] = {0};
memcpy(ndefkey, g_mifarep_ndef_key, 16); memcpy(ndefkey, g_mifarep_ndef_key, 16);
// user supplied key
if (keylen == 16) { if (keylen == 16) {
memcpy(ndefkey, key, 16); memcpy(ndefkey, key, 16);
} }
uint8_t data[4096] = {0}; int file_ids_len = 0;
int datalen = 0;
for (int j = (int)file_ids_len - 1; j >= 0; j--) { for (int j = (int)file_ids_len - 1; j >= 0; j--) {
PrintAndLogEx(SUCCESS, "\n\n Fileid %d (0x%02x)", file_ids[j], file_ids[j]); PrintAndLogEx(SUCCESS, "\n\n Fileid %d (0x%02x)", file_ids[j], file_ids[j]);
@ -4638,7 +4725,7 @@ static int CmdHF14aDesNDEF(const char *Cmd) {
uint8_t filesettings[20] = {0}; uint8_t filesettings[20] = {0};
uint32_t fileset_len = 0; uint32_t fileset_len = 0;
res = handler_desfire_filesettings(file_ids[j], filesettings, &fileset_len); int res = handler_desfire_filesettings(file_ids[j], filesettings, &fileset_len);
if (res != PM3_SUCCESS) continue; if (res != PM3_SUCCESS) continue;
int maclen = 0; // To be implemented int maclen = 0; // To be implemented
@ -4657,7 +4744,7 @@ static int CmdHF14aDesNDEF(const char *Cmd) {
} }
fdata.data = data; fdata.data = data;
int res = handler_desfire_readdata(&fdata, MFDES_DATA_FILE, filesettings[1]); res = handler_desfire_readdata(&fdata, MFDES_DATA_FILE, filesettings[1]);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
uint32_t len = le24toh(fdata.length); uint32_t len = le24toh(fdata.length);
NDEFDecodeAndPrint(data, datalen, verbose); NDEFDecodeAndPrint(data, datalen, verbose);
@ -4670,6 +4757,7 @@ static int CmdHF14aDesNDEF(const char *Cmd) {
free(data); free(data);
} }
}
// PrintAndLogEx(INFO, "reading data from tag"); // PrintAndLogEx(INFO, "reading data from tag");
@ -4680,13 +4768,40 @@ static int CmdHF14aDesNDEF(const char *Cmd) {
if (verbose2) { if (verbose2) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("DESfire NDEF raw") " ----------------"); PrintAndLogEx(INFO, "--- " _CYAN_("DESFire NDEF raw") " ----------------");
dump_buffer(data, datalen, stdout, 1); dump_buffer(data, datalen, stdout, 1);
} }
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfdes ndef -vv`") " for more details"); PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfdes ndef -vv`") " for more details");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
*/ */
/*
static int CmdHF14aDesMAD(const char *Cmd) {
DropField();
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes mad",
"Prints MIFARE Application directory (MAD)",
"hf mfdes mad -> shows MAD data\n"
"hf mfdes mad -v -> shows MAD parsed and raw data\n"
"hf mfdes mad -a e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows MAD data with custom AID and key");
void *argtable[] = {
arg_param_begin,
arg_litn("v", "verbose", 0, 2, "show technical data"),
arg_str0("", "aid", "<aid>", "replace default aid for MAD"),
arg_str0("k", "key", "<key>", "replace default key for MAD"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfdes mad -v`") " for more details");
return PM3_SUCCESS;
}
*/
/*static int CmdTest(const char *Cmd) { /*static int CmdTest(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
@ -4714,28 +4829,32 @@ static int CmdHF14aDesNDEF(const char *Cmd) {
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("general") " -----------------------"},
{"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "Tries a MIFARE DesFire Authentication"},
{"changekey", CmdHF14ADesChangeKey, IfPm3Iso14443a, "Change Key"},
{"chk", CmdHF14aDesChk, IfPm3Iso14443a, "Check keys"},
{"enum", CmdHF14ADesEnumApplications, IfPm3Iso14443a, "Tries enumerate all applications"},
{"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"},
{"getuid", CmdHF14ADesGetUID, IfPm3Iso14443a, "Get random uid"},
{"info", CmdHF14ADesInfo, IfPm3Iso14443a, "Tag information"}, {"info", CmdHF14ADesInfo, IfPm3Iso14443a, "Tag information"},
{"list", CmdHF14ADesList, AlwaysAvailable, "List DESFire (ISO 14443A) history"}, {"list", CmdHF14ADesList, AlwaysAvailable, "List DESFire (ISO 14443A) history"},
{"enum", CmdHF14ADesEnumApplications, IfPm3Iso14443a, "Tries enumerate all applications"}, // {"ndef", CmdHF14aDesNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
{"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "Tries a MIFARE DesFire Authentication"}, // {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records from card"},
{"getuid", CmdHF14ADesGetUID, IfPm3Iso14443a, "Get random uid"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("AID") " -----------------------"},
{"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"},
{"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"}, {"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"},
{"deleteaid", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application ID"}, {"deleteaid", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application ID"},
{"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("Files") " -----------------------"},
{"changevalue", CmdHF14ADesChangeValue, IfPm3Iso14443a, "Write value of a value file (credit/debit/clear)"},
{"clearfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"},
{"createfile", CmdHF14ADesCreateFile, IfPm3Iso14443a, "Create Standard/Backup File"}, {"createfile", CmdHF14ADesCreateFile, IfPm3Iso14443a, "Create Standard/Backup File"},
{"createvaluefile", CmdHF14ADesCreateValueFile, IfPm3Iso14443a, "Create Value File"}, {"createvaluefile", CmdHF14ADesCreateValueFile, IfPm3Iso14443a, "Create Value File"},
{"createrecordfile", CmdHF14ADesCreateRecordFile, IfPm3Iso14443a, "Create Linear/Cyclic Record File"}, {"createrecordfile", CmdHF14ADesCreateRecordFile, IfPm3Iso14443a, "Create Linear/Cyclic Record File"},
{"deletefile", CmdHF14ADesDeleteFile, IfPm3Iso14443a, "Create Delete File"}, {"deletefile", CmdHF14ADesDeleteFile, IfPm3Iso14443a, "Create Delete File"},
{"clearfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"}, {"dump", CmdHF14ADesDump, IfPm3Iso14443a, "Dump all files"},
{"getvalue", CmdHF14ADesGetValueData, IfPm3Iso14443a, "Get value of file"},
{"readdata", CmdHF14ADesReadData, IfPm3Iso14443a, "Read data from standard/backup/record file"}, {"readdata", CmdHF14ADesReadData, IfPm3Iso14443a, "Read data from standard/backup/record file"},
{"writedata", CmdHF14ADesWriteData, IfPm3Iso14443a, "Write data to standard/backup/record file"}, {"writedata", CmdHF14ADesWriteData, IfPm3Iso14443a, "Write data to standard/backup/record file"},
{"getvalue", CmdHF14ADesGetValueData, IfPm3Iso14443a, "Get value of file"},
{"changevalue", CmdHF14ADesChangeValue, IfPm3Iso14443a, "Write value of a value file (credit/debit/clear)"},
{"changekey", CmdHF14ADesChangeKey, IfPm3Iso14443a, "Change Key"},
{"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"},
{"dump", CmdHF14ADesDump, IfPm3Iso14443a, "Dump all files"},
{"chk", CmdHF14aDesChk, IfPm3Iso14443a, "Check keys"},
// {"ndef", CmdHF14aDesNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -330,8 +330,10 @@ int demodAWID(bool verbose) {
free(bits); free(bits);
PrintAndLogEx(DEBUG, "DEBUG: AWID idx: %d, Len: %zu Printing Demod Buffer:", idx, size); PrintAndLogEx(DEBUG, "DEBUG: AWID idx: %d, Len: %zu Printing Demod Buffer:", idx, size);
if (g_debugMode) if (g_debugMode) {
printDemodBuff(); printDemodBuff(0, false, false, true);
printDemodBuff(0, false, false, false);
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -318,8 +318,9 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo) {
setClockGrid(g_DemodClock, g_DemodStartIdx + ((idx + 1)*g_DemodClock)); setClockGrid(g_DemodClock, g_DemodStartIdx + ((idx + 1)*g_DemodClock));
PrintAndLogEx(DEBUG, "DEBUG: Em410x idx: %zu, Len: %zu, Printing Demod Buffer:", idx, size); PrintAndLogEx(DEBUG, "DEBUG: Em410x idx: %zu, Len: %zu, Printing Demod Buffer:", idx, size);
if (g_debugMode) if (g_debugMode) {
printDemodBuff(); printDemodBuff(0, false, false, true);
}
if (verbose) if (verbose)
printEM410x(*hi, *lo); printEM410x(*hi, *lo);

View file

@ -1932,10 +1932,12 @@ int CmdEM4x05Sniff(const char *Cmd) {
sampleData = !arg_get_lit(ctx, 1); sampleData = !arg_get_lit(ctx, 1);
fwd = arg_get_lit(ctx, 2); fwd = arg_get_lit(ctx, 2);
CLIParserFree(ctx);
// setup and sample data from Proxmark // setup and sample data from Proxmark
// if not directed to existing sample/graphbuffer // if not directed to existing sample/graphbuffer
if (sampleData) { if (sampleData) {
if (!IfPm3Lf()) { if (IfPm3Lf() == false) {
PrintAndLogEx(WARNING, "Only offline mode is available"); PrintAndLogEx(WARNING, "Only offline mode is available");
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -1993,7 +1995,7 @@ int CmdEM4x05Sniff(const char *Cmd) {
((strncmp(bits, "01001", 5) == 0) && (bitidx == 12)) || ((strncmp(bits, "01001", 5) == 0) && (bitidx == 12)) ||
((strncmp(bits, "01100", 5) == 0) && (bitidx == 50)) || ((strncmp(bits, "01100", 5) == 0) && (bitidx == 50)) ||
((strncmp(bits, "01010", 5) == 0) && (bitidx == 50))) { ((strncmp(bits, "01010", 5) == 0) && (bitidx == 50))) {
memcpy (bits,&bits[1],bitidx-1); memmove(bits, &bits[1], bitidx - 1);
bitidx--; bitidx--;
printf("Trim leading 0\n"); printf("Trim leading 0\n");
} }
@ -2066,9 +2068,9 @@ int CmdEM4x05Sniff(const char *Cmd) {
// Print results // Print results
if (haveData) { //&& (minWidth > 1) && (maxWidth > minWidth)){ if (haveData) { //&& (minWidth > 1) && (maxWidth > minWidth)){
if (pwd) if (pwd)
PrintAndLogEx(SUCCESS, "%6llu | %-10s | "_YELLOW_("%8s")" | "_YELLOW_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits); PrintAndLogEx(SUCCESS, "%6zu | %-10s | "_YELLOW_("%8s")" | "_YELLOW_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits);
else else
PrintAndLogEx(SUCCESS, "%6llu | %-10s | "_GREEN_("%8s")" | "_GREEN_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits); PrintAndLogEx(SUCCESS, "%6zu | %-10s | "_GREEN_("%8s")" | "_GREEN_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits);
} }
} }

View file

@ -137,11 +137,17 @@ int demodHID(bool verbose) {
} }
wiegand_message_t packed = initialize_message_object(hi2, hi, lo); wiegand_message_t packed = initialize_message_object(hi2, hi, lo);
HIDTryUnpack(&packed, false); if (HIDTryUnpack(&packed, false) == false) {
PrintAndLogEx(INFO, "raw: " _GREEN_("%08x%08x%08x"), hi2, hi, lo);
printDemodBuff(0, false, false, true);
}
PrintAndLogEx(DEBUG, "DEBUG: HID idx: %d, Len: %zu, Printing Demod Buffer: ", idx, size); PrintAndLogEx(DEBUG, "DEBUG: HID idx: %d, Len: %zu, Printing Demod Buffer: ", idx, size);
if (g_debugMode) if (g_debugMode) {
printDemodBuff(); PrintAndLogEx(DEBUG, "raw: " _GREEN_("%08x%08x%08x"), hi2, hi, lo);
printDemodBuff(0, false, false, false);
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -268,7 +268,7 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) {
if (g_debugMode) { if (g_debugMode) {
PrintAndLogEx(DEBUG, "DEBUG: Indala - printing demodbuffer"); PrintAndLogEx(DEBUG, "DEBUG: Indala - printing demodbuffer");
printDemodBuff(); printDemodBuff(0, false, false, false);
} }
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -185,7 +185,8 @@ int demodIOProx(bool verbose) {
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox crc failed"); PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox crc failed");
PrintAndLogEx(DEBUG, "DEBUG: IO prox idx: %d, Len: %zu, Printing demod buffer:", idx, size); PrintAndLogEx(DEBUG, "DEBUG: IO prox idx: %d, Len: %zu, Printing demod buffer:", idx, size);
printDemodBuff(); printDemodBuff(0, false, false, true);
printDemodBuff(0, false, false, false);
} }
return retval; return retval;
} }

View file

@ -192,8 +192,9 @@ int demodParadox(bool verbose) {
); );
PrintAndLogEx(DEBUG, "DEBUG: Paradox idx: %d, len: %zu, Printing Demod Buffer:", idx, size); PrintAndLogEx(DEBUG, "DEBUG: Paradox idx: %d, len: %zu, Printing Demod Buffer:", idx, size);
if (g_debugMode) if (g_debugMode) {
printDemodBuff(); printDemodBuff(0, false, false, false);
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -203,8 +203,9 @@ int demodPyramid(bool verbose) {
); );
PrintAndLogEx(DEBUG, "DEBUG: Pyramid: idx: %d, Len: %d, Printing Demod Buffer:", idx, 128); PrintAndLogEx(DEBUG, "DEBUG: Pyramid: idx: %d, Len: %d, Printing Demod Buffer:", idx, 128);
if (g_debugMode) if (g_debugMode) {
printDemodBuff(); printDemodBuff(0, false, false, false);
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -1024,6 +1024,9 @@ static void T55xx_Print_DownlinkMode(uint8_t downlink_mode) {
PrintAndLogEx(NORMAL, msg); PrintAndLogEx(NORMAL, msg);
} }
// Define prototype to call from within detect.
static int CmdT55xxWakeUp (const char *Cmd);
static int CmdT55xxDetect(const char *Cmd) { static int CmdT55xxDetect(const char *Cmd) {
bool errors = false; bool errors = false;
@ -1032,9 +1035,16 @@ static int CmdT55xxDetect(const char *Cmd) {
bool try_with_pwd = false; bool try_with_pwd = false;
bool try_all_dl_modes = true; bool try_all_dl_modes = true;
bool found = false; bool found = false;
bool usewake = false;
uint64_t password = -1; uint64_t password = -1;
uint8_t cmdp = 0; uint8_t cmdp = 0;
uint8_t downlink_mode = 0; uint8_t downlink_mode = 0;
char wakecmd[20] = { 0x00 };
struct timespec sleepperiod;
// Setup the 90ms time value to sleep for after the wake, to allow delay init to complete (~70ms)
sleepperiod.tv_sec = 0;
sleepperiod.tv_nsec = 90000000;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) { switch (tolower(param_getchar(Cmd, cmdp))) {
@ -1042,6 +1052,7 @@ static int CmdT55xxDetect(const char *Cmd) {
return usage_t55xx_detect(); return usage_t55xx_detect();
case 'p': case 'p':
password = param_get32ex(Cmd, cmdp + 1, 0, 16); password = param_get32ex(Cmd, cmdp + 1, 0, 16);
sprintf (wakecmd,"p %08x q",(uint32_t)(password & 0xFFFFFFFF));
usepwd = true; usepwd = true;
cmdp += 2; cmdp += 2;
break; break;
@ -1064,6 +1075,7 @@ static int CmdT55xxDetect(const char *Cmd) {
} }
if (errors) return usage_t55xx_detect(); if (errors) return usage_t55xx_detect();
// detect called so clear data blocks // detect called so clear data blocks
T55x7_ClearAllBlockData(); T55x7_ClearAllBlockData();
@ -1072,11 +1084,22 @@ static int CmdT55xxDetect(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
if (useGB == false) { if (useGB == false) {
// do ... while not found and not yet tried with wake (for AOR or Init Delay)
do {
// do ... while to check without password then loop back if password supplied // do ... while to check without password then loop back if password supplied
do { do {
if (try_all_dl_modes) { if (try_all_dl_modes) {
for (uint8_t m = downlink_mode; m < 4; m++) { for (uint8_t m = downlink_mode; m < 4; m++) {
if (usewake) {
// call wake
if (try_with_pwd)
CmdT55xxWakeUp (wakecmd);
else
CmdT55xxWakeUp ("q");
// sleep 90 ms
nanosleep (&sleepperiod, &sleepperiod);
}
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, (try_with_pwd && usepwd), password, m) == false) if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, (try_with_pwd && usepwd), password, m) == false)
continue; continue;
@ -1089,6 +1112,16 @@ static int CmdT55xxDetect(const char *Cmd) {
break; break;
} }
} else { } else {
if (usewake) {
// call wake
if (try_with_pwd)
CmdT55xxWakeUp (wakecmd);
else
CmdT55xxWakeUp ("q");
// sleep 90 ms
nanosleep (&sleepperiod, &sleepperiod);
}
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) { if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) {
found = t55xxTryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, (usepwd) ? password : -1); found = t55xxTryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, (usepwd) ? password : -1);
} }
@ -1103,7 +1136,9 @@ static int CmdT55xxDetect(const char *Cmd) {
try_with_pwd = false; try_with_pwd = false;
} while (try_with_pwd); } while (try_with_pwd);
// Toggle so we loop back and try with wakeup.
usewake = !usewake;
} while (!found && usewake);
} else { } else {
found = t55xxTryDetectModulation(downlink_mode, T55XX_PrintConfig); found = t55xxTryDetectModulation(downlink_mode, T55XX_PrintConfig);
} }
@ -1619,6 +1654,7 @@ static int CmdT55xxWakeUp(const char *Cmd) {
uint8_t cmdp = 0; uint8_t cmdp = 0;
bool errors = false; bool errors = false;
uint8_t downlink_mode = config.downlink_mode; uint8_t downlink_mode = config.downlink_mode;
bool quiet = false;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) { switch (tolower(param_getchar(Cmd, cmdp))) {
@ -1635,6 +1671,10 @@ static int CmdT55xxWakeUp(const char *Cmd) {
cmdp += 2; cmdp += 2;
break; break;
case 'q':
quiet = true;
cmdp++;
break;
default: default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true; errors = true;
@ -1659,7 +1699,9 @@ static int CmdT55xxWakeUp(const char *Cmd) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
if (!quiet)
PrintAndLogEx(SUCCESS, "Wake up command sent. Try read now"); PrintAndLogEx(SUCCESS, "Wake up command sent. Try read now");
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -262,16 +262,16 @@ static command_t CommandTable[] = {
{"hf", CmdHF, AlwaysAvailable, "{ High frequency commands... }"}, {"hf", CmdHF, AlwaysAvailable, "{ High frequency commands... }"},
{"hw", CmdHW, AlwaysAvailable, "{ Hardware commands... }"}, {"hw", CmdHW, AlwaysAvailable, "{ Hardware commands... }"},
{"lf", CmdLF, AlwaysAvailable, "{ Low frequency commands... }"}, {"lf", CmdLF, AlwaysAvailable, "{ Low frequency commands... }"},
{"mem", CmdFlashMem, IfPm3Flash, "{ Flash Memory manipulation... }"}, {"mem", CmdFlashMem, IfPm3Flash, "{ Flash memory manipulation... }"},
{"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software }"}, {"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software... }"},
{"smart", CmdSmartcard, AlwaysAvailable, "{ Smart card ISO-7816 commands... }"}, {"smart", CmdSmartcard, AlwaysAvailable, "{ Smart card ISO-7816 commands... }"},
{"script", CmdScript, AlwaysAvailable, "{ Scripting commands }"}, {"script", CmdScript, AlwaysAvailable, "{ Scripting commands... }"},
{"trace", CmdTrace, AlwaysAvailable, "{ Trace manipulation... }"}, {"trace", CmdTrace, AlwaysAvailable, "{ Trace manipulation... }"},
{"usart", CmdUsart, IfPm3FpcUsartFromUsb, "{ USART commands... }"}, {"usart", CmdUsart, IfPm3FpcUsartFromUsb, "{ USART commands... }"},
{"wiegand", CmdWiegand, AlwaysAvailable, "{ Wiegand format manipulation... }"}, {"wiegand", CmdWiegand, AlwaysAvailable, "{ Wiegand format manipulation... }"},
{"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"}, {"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"},
{"auto", CmdAuto, IfPm3Present, "Automated detection process for unknown tags"}, {"auto", CmdAuto, IfPm3Present, "Automated detection process for unknown tags"},
{"clear", CmdClear, AlwaysAvailable, "clear screen"}, {"clear", CmdClear, AlwaysAvailable, "Clear screen"},
{"help", CmdHelp, AlwaysAvailable, "This help. Use " _YELLOW_("'<command> help'") " for details of a particular command."}, {"help", CmdHelp, AlwaysAvailable, "This help. Use " _YELLOW_("'<command> help'") " for details of a particular command."},
{"hints", CmdHints, AlwaysAvailable, "Turn hints on / off"}, {"hints", CmdHints, AlwaysAvailable, "Turn hints on / off"},
{"msleep", CmdMsleep, AlwaysAvailable, "Add a pause in milliseconds"}, {"msleep", CmdMsleep, AlwaysAvailable, "Add a pause in milliseconds"},

View file

@ -312,7 +312,7 @@ static void PrintATR(uint8_t *atr, size_t atrlen) {
PrintAndLogEx(WARNING, "Invalid ATR length. len: %zu, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K); PrintAndLogEx(WARNING, "Invalid ATR length. len: %zu, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K);
if (K > 0) if (K > 0)
PrintAndLogEx(INFO, "Historical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]); PrintAndLogEx(INFO, "Historical bytes | len %02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]);
if (K > 1) { if (K > 1) {
PrintAndLogEx(INFO, "\tHistorical bytes"); PrintAndLogEx(INFO, "\tHistorical bytes");

View file

@ -606,8 +606,8 @@ int CmdTraceList(const char *Cmd) {
"trace list -t hitags -> interpret as " _YELLOW_("HitagS") " communications\n" "trace list -t hitags -> interpret as " _YELLOW_("HitagS") " communications\n"
"trace list -t lto -> interpret as " _YELLOW_("LTO-CM") " communications\n" "trace list -t lto -> interpret as " _YELLOW_("LTO-CM") " communications\n"
"trace list -t cryptorf -> interpret as " _YELLOW_("CryptoRF") " communitcations\n" "trace list -t cryptorf -> interpret as " _YELLOW_("CryptoRF") " communitcations\n"
"trace list -t 14a f -> show frame delay times\n" "trace list -t 14a -f -> show frame delay times\n"
"trace list -t 14a 1 -> use trace buffer " "trace list -t 14a -1 -> use trace buffer "
); );
void *argtable[] = { void *argtable[] = {

View file

@ -517,3 +517,21 @@ void APDUPrintEx(APDUStruct apdu, size_t maxdatalen) {
if (maxdatalen > 0) if (maxdatalen > 0)
PrintAndLogEx(INFO, "data: %s%s", sprint_hex(apdu.data, MIN(apdu.lc, maxdatalen)), apdu.lc > maxdatalen ? "..." : ""); PrintAndLogEx(INFO, "data: %s%s", sprint_hex(apdu.data, MIN(apdu.lc, maxdatalen)), apdu.lc > maxdatalen ? "..." : "");
} }
void SAPDUPrint(sAPDU apdu, size_t maxdatalen) {
PrintAndLogEx(INFO, "APDU: CLA 0x%02x, INS 0x%02x, P1 0x%02x, P2 0x%02x, Lc 0x%02x(%d)",
apdu.CLA,
apdu.INS,
apdu.P1,
apdu.P2,
apdu.Lc,
apdu.Lc
);
size_t len = apdu.Lc;
if (maxdatalen > 0)
len = MIN(apdu.Lc, maxdatalen);
PrintAndLogEx(INFO, "data { %s%s }", sprint_hex(apdu.data, len), apdu.Lc > len ? "..." : "");
}

View file

@ -63,4 +63,5 @@ extern int APDUEncodeS(sAPDU *sapdu, bool extended, uint16_t le, uint8_t *data,
extern void APDUPrint(APDUStruct apdu); extern void APDUPrint(APDUStruct apdu);
extern void APDUPrintEx(APDUStruct apdu, size_t maxdatalen); extern void APDUPrintEx(APDUStruct apdu, size_t maxdatalen);
void SAPDUPrint(sAPDU apdu, size_t maxdatalen);
#endif #endif

View file

@ -122,6 +122,9 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs,
} }
if (paddr < FLASH_START || (paddr + filesz) > flash_end) { if (paddr < FLASH_START || (paddr + filesz) > flash_end) {
PrintAndLogEx(ERR, "Error: PHDR is not contained in Flash"); PrintAndLogEx(ERR, "Error: PHDR is not contained in Flash");
if ((paddr + filesz) > flash_end) {
PrintAndLogEx(ERR, "Firmware probably too big for your device");
}
return PM3_EFILE; return PM3_EFILE;
} }
if (vaddr >= FLASH_START && vaddr < flash_end && (flags & PF_W)) { if (vaddr >= FLASH_START && vaddr < flash_end && (flags & PF_W)) {

View file

@ -189,6 +189,29 @@ static bool Unpack_Kastle(wiegand_message_t *packed, wiegand_card_t *card) {
return true; return true;
} }
static bool Pack_Kantech(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 32;
set_linear_field(packed, card->FacilityCode, 7, 8);
set_linear_field(packed, card->CardNumber, 15, 16);
return add_HID_header(packed);
}
static bool Unpack_Kantech(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 32) return false; // Wrong length? Stop here.
card->FacilityCode = get_linear_field(packed, 7, 8);
card->CardNumber = get_linear_field(packed, 15, 16);
return true;
}
static bool Pack_D10202(wiegand_card_t *card, wiegand_message_t *packed) { static bool Pack_D10202(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t)); memset(packed, 0, sizeof(wiegand_message_t));
@ -489,11 +512,12 @@ static bool Pack_H10304(wiegand_card_t *card, wiegand_message_t *packed) {
if (card->OEM > 0) return false; // Not used in this format if (card->OEM > 0) return false; // Not used in this format
packed->Length = 37; // Set number of bits packed->Length = 37; // Set number of bits
packed->Bot |= (card->CardNumber & 0x0007FFFF) << 1;
packed->Bot |= (card->FacilityCode & 0x00000FFF) << 20; set_linear_field(packed, card->FacilityCode, 1, 16);
packed->Mid |= (card->FacilityCode & 0x0000F000) >> 12; set_linear_field(packed, card->CardNumber, 17, 19);
packed->Mid |= (evenparity32((packed->Mid & 0x0000000F) ^ (packed->Bot & 0xFFFC0000)) & 1) << 4;
packed->Bot |= (oddparity32(packed->Bot & 0x0007FFFE) & 1); set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0);
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36);
return add_HID_header(packed); return add_HID_header(packed);
} }
@ -502,11 +526,97 @@ static bool Unpack_H10304(wiegand_message_t *packed, wiegand_card_t *card) {
if (packed->Length != 37) return false; // Wrong length? Stop here. if (packed->Length != 37) return false; // Wrong length? Stop here.
card->CardNumber = (packed->Bot >> 1) & 0x0007FFFF; card->FacilityCode = get_linear_field(packed, 1, 16);
card->FacilityCode = ((packed->Mid & 0xF) << 12) | ((packed->Bot >> 20)); card->CardNumber = get_linear_field(packed, 17, 19);
card->ParityValid = card->ParityValid =
(evenparity32((packed->Mid & 0x0000000F) ^ (packed->Bot & 0xFFFC0000)) == ((packed->Mid >> 4) & 1)) && (get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 18))) &&
(oddparity32(packed->Bot & 0x0007FFFE) == (packed->Bot & 1)); (get_bit_by_position(packed, 36) == oddparity32(get_linear_field(packed, 18, 18)));
return true;
}
static bool Pack_HGeneric37(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0) return false; // Not used in this format
if (card->CardNumber > 0x0007FFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 37; // Set number of bits
set_linear_field(packed, card->CardNumber, 4, 32);
set_bit_by_position(packed, 1, 36); // Always 1
// even1
set_bit_by_position(packed,
evenparity32(
get_nonlinear_field(packed, 8, (uint8_t[]) {4, 8, 12, 16, 20, 24, 28, 32})
)
, 0
);
// odd1
set_bit_by_position(packed,
oddparity32(
get_nonlinear_field(packed, 8, (uint8_t[]) {6, 10, 14, 18, 22, 26, 30, 34})
)
, 2
);
// even2
set_bit_by_position(packed,
evenparity32(
get_nonlinear_field(packed, 8, (uint8_t[]) {7, 11, 15, 19, 23, 27, 31, 35})
)
, 3
);
return add_HID_header(packed);
}
static bool Unpack_HGeneric37(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 37) return false; // Wrong length? Stop here.
if (get_bit_by_position(packed, 36) != 1) return false; // Always 1 in this format
card->CardNumber = get_linear_field(packed, 4, 32);
card->ParityValid =
(get_bit_by_position(packed, 0) == evenparity32(get_nonlinear_field(packed, 8, (uint8_t[]) {4, 8, 12, 16, 20, 24, 28, 32}))) &&
(get_bit_by_position(packed, 2) == oddparity32(get_nonlinear_field(packed, 8, (uint8_t[]) {6, 10, 14, 18, 22, 28, 30, 34}))) &&
(get_bit_by_position(packed, 3) == evenparity32(get_nonlinear_field(packed, 8, (uint8_t[]) {7, 11, 15, 19, 23, 27, 31, 35})))
;
return true;
}
static bool Pack_MDI37(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0x0000F) return false; // Can't encode FC.
if (card->CardNumber > 0x1FFFFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 37; // Set number of bits
set_linear_field(packed, card->FacilityCode, 3, 4);
set_linear_field(packed, card->CardNumber, 7, 29);
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0);
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36);
return add_HID_header(packed);
}
static bool Unpack_MDI37(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 37) return false; // Wrong length? Stop here.
card->FacilityCode = get_linear_field(packed, 3, 4);;
card->CardNumber = get_linear_field(packed, 7, 29);
card->ParityValid =
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 18))) &&
(get_bit_by_position(packed, 36) == oddparity32(get_linear_field(packed, 18, 18)))
;
return true; return true;
} }
@ -705,6 +815,8 @@ static const cardformat_t FormatTable[] = {
{"ATSW30", Pack_ATSW30, Unpack_ATSW30, "ATS Wiegand 30-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au {"ATSW30", Pack_ATSW30, Unpack_ATSW30, "ATS Wiegand 30-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"ADT31", Pack_ADT31, Unpack_ADT31, "HID ADT 31-bit", {1, 1, 0, 0, 0}}, // from cardinfo.barkweb.com.au {"ADT31", Pack_ADT31, Unpack_ADT31, "HID ADT 31-bit", {1, 1, 0, 0, 0}}, // from cardinfo.barkweb.com.au
{"Kastle", Pack_Kastle, Unpack_Kastle, "Kastle 32-bit", {1, 1, 1, 0, 1}}, // from @xilni; PR #23 on RfidResearchGroup/proxmark3 {"Kastle", Pack_Kastle, Unpack_Kastle, "Kastle 32-bit", {1, 1, 1, 0, 1}}, // from @xilni; PR #23 on RfidResearchGroup/proxmark3
{"Kantech", Pack_Kantech, Unpack_Kantech, "Indala/Kantech KFS 32-bit", {1, 1, 0, 0, 0}}, // from cardinfo.barkweb.com.au
{"D10202", Pack_D10202, Unpack_D10202, "HID D10202 33-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au {"D10202", Pack_D10202, Unpack_D10202, "HID D10202 33-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"H10306", Pack_H10306, Unpack_H10306, "HID H10306 34-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack {"H10306", Pack_H10306, Unpack_H10306, "HID H10306 34-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
{"N10002", Pack_N10002, Unpack_N10002, "HID N10002 34-bit", {1, 1, 0, 0, 0}}, // from cardinfo.barkweb.com.au {"N10002", Pack_N10002, Unpack_N10002, "HID N10002 34-bit", {1, 1, 0, 0, 0}}, // from cardinfo.barkweb.com.au
@ -717,7 +829,9 @@ static const cardformat_t FormatTable[] = {
{"Sie36", Pack_Sie36, Unpack_Sie36, "HID 36-bit Siemens", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au {"Sie36", Pack_Sie36, Unpack_Sie36, "HID 36-bit Siemens", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"H10320", Pack_H10320, Unpack_H10320, "HID H10320 36-bit BCD", {1, 0, 0, 0, 1}}, // from Proxmark forums {"H10320", Pack_H10320, Unpack_H10320, "HID H10320 36-bit BCD", {1, 0, 0, 0, 1}}, // from Proxmark forums
{"H10302", Pack_H10302, Unpack_H10302, "HID H10302 37-bit huge ID", {1, 0, 0, 0, 1}}, // from Proxmark forums {"H10302", Pack_H10302, Unpack_H10302, "HID H10302 37-bit huge ID", {1, 0, 0, 0, 1}}, // from Proxmark forums
{"H10304", Pack_H10304, Unpack_H10304, "HID H10304 37-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack {"H10304", Pack_H10304, Unpack_H10304, "HID H10304 37-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"HGeneric37", Pack_HGeneric37, Unpack_HGeneric37, "HID Generic 37-bit", {1, 0, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"MDI37", Pack_MDI37, Unpack_MDI37, "PointGuard MDI 37-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"P10001", Pack_P10001, Unpack_P10001, "HID P10001 Honeywell 40-bit", {1, 1, 0, 1, 0}}, // from cardinfo.barkweb.com.au {"P10001", Pack_P10001, Unpack_P10001, "HID P10001 Honeywell 40-bit", {1, 1, 0, 1, 0}}, // from cardinfo.barkweb.com.au
{"Casi40", Pack_CasiRusco40, Unpack_CasiRusco40, "Casi-Rusco 40-bit", {1, 0, 0, 0, 0}}, // from cardinfo.barkweb.com.au {"Casi40", Pack_CasiRusco40, Unpack_CasiRusco40, "Casi-Rusco 40-bit", {1, 0, 0, 0, 0}}, // from cardinfo.barkweb.com.au
{"C1k48s", Pack_C1k48s, Unpack_C1k48s, "HID Corporate 1000 48-bit standard layout", {1, 1, 0, 0, 1}}, // imported from old pack/unpack {"C1k48s", Pack_C1k48s, Unpack_C1k48s, "HID Corporate 1000 48-bit standard layout", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
@ -831,7 +945,8 @@ bool HIDTryUnpack(wiegand_message_t *packed, bool ignore_parity) {
++i; ++i;
} }
if (result == false && packed->Length) { if (result == false && packed->Length) {
PrintAndLogEx(SUCCESS, "Unknown. Bit len %d", packed->Length); PrintAndLogEx(SUCCESS, "(wiegand unpack) unknown bit len %d", packed->Length);
PrintAndLogEx(HINT, "Try 0xFFFF's http://cardinfo.barkweb.com.au/");
} }
return result; return result;

View file

@ -1586,7 +1586,7 @@ int LZ4_compress_fast_continue(LZ4_stream_t *LZ4_stream,
* cost to copy the dictionary's tables into the active context, * cost to copy the dictionary's tables into the active context,
* so that the compression loop is only looking into one table. * so that the compression loop is only looking into one table.
*/ */
LZ4_memcpy(streamPtr, streamPtr->dictCtx, sizeof(LZ4_stream_t)); LZ4_memcpy(streamPtr, streamPtr->dictCtx, sizeof(*streamPtr));
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration); result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);
} else { } else {
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration); result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration);

View file

@ -45,6 +45,23 @@ PLATFORM_EXTRAS=BTADDON
Default standalone mode is $(DEFAULT_STANDALONE). Default standalone mode is $(DEFAULT_STANDALONE).
To disable standalone modes, set explicitly an empty STANDALONE: To disable standalone modes, set explicitly an empty STANDALONE:
STANDALONE= STANDALONE=
For Proxmarks with only 256k, you can define
PLATFORM_SIZE=256
to be warned if the image is too big for your device
and you can specify which parts to skip in order to reduce the size:
SKIP_LF=1
SKIP_HITAG=1
SKIP_EM4x50=1
SKIP_ISO15693=1
SKIP_LEGICRF=1
SKIP_ISO14443b=1
SKIP_ISO14443a=1
SKIP_ICLASS=1
SKIP_FELICA=1
SKIP_NFCBARCODE=1
SKIP_HFSNIFF=1
SKIP_HFPLOT=1
endef endef
define KNOWN_DEFINITIONS define KNOWN_DEFINITIONS
@ -79,21 +96,44 @@ ifneq (,$(PLATFORM_EXTRAS_TMP))
endif endif
# common LF support # common LF support
ifneq ($(SKIP_LF),1)
PLATFORM_DEFS += -DWITH_LF PLATFORM_DEFS += -DWITH_LF
endif
ifneq ($(SKIP_HITAG),1)
PLATFORM_DEFS += -DWITH_HITAG PLATFORM_DEFS += -DWITH_HITAG
endif
ifneq ($(SKIP_EM4x50),1)
PLATFORM_DEFS += -DWITH_EM4x50 PLATFORM_DEFS += -DWITH_EM4x50
endif
# common HF support # common HF support
ifneq ($(SKIP_ISO15693),1)
PLATFORM_DEFS += -DWITH_ISO15693 PLATFORM_DEFS += -DWITH_ISO15693
endif
ifneq ($(SKIP_LEGICRF),1)
PLATFORM_DEFS += -DWITH_LEGICRF PLATFORM_DEFS += -DWITH_LEGICRF
endif
ifneq ($(SKIP_ISO14443b),1)
PLATFORM_DEFS += -DWITH_ISO14443b PLATFORM_DEFS += -DWITH_ISO14443b
endif
ifneq ($(SKIP_ISO14443a),1)
PLATFORM_DEFS += -DWITH_ISO14443a PLATFORM_DEFS += -DWITH_ISO14443a
endif
ifneq ($(SKIP_ICLASS),1)
PLATFORM_DEFS += -DWITH_ICLASS PLATFORM_DEFS += -DWITH_ICLASS
endif
ifneq ($(SKIP_FELICA),1)
PLATFORM_DEFS += -DWITH_FELICA PLATFORM_DEFS += -DWITH_FELICA
endif
ifneq ($(SKIP_NFCBARCODE),1)
PLATFORM_DEFS += -DWITH_NFCBARCODE PLATFORM_DEFS += -DWITH_NFCBARCODE
endif
ifneq ($(SKIP_HFSNIFF),1)
PLATFORM_DEFS += -DWITH_HFSNIFF PLATFORM_DEFS += -DWITH_HFSNIFF
endif
ifneq ($(SKIP_HFPLOT),1)
PLATFORM_DEFS += -DWITH_HFPLOT PLATFORM_DEFS += -DWITH_HFPLOT
endif
# Standalone mode # Standalone mode
ifneq ($(strip $(filter $(PLATFORM_DEFS),$(STANDALONE_REQ_DEFS))),$(strip $(STANDALONE_REQ_DEFS))) ifneq ($(strip $(filter $(PLATFORM_DEFS),$(STANDALONE_REQ_DEFS))),$(strip $(STANDALONE_REQ_DEFS)))
@ -133,6 +173,10 @@ ifeq (,$(PLATFORM_DEFS_INFO_STANDALONE))
PLATFORM_DEFS_INFO_STANDALONE = No standalone mode selected PLATFORM_DEFS_INFO_STANDALONE = No standalone mode selected
endif endif
ifeq ($(PLATFORM_SIZE),)
PLATFORM_SIZE=512
endif
PLATFORM_CHANGED=false PLATFORM_CHANGED=false
ifneq ($(PLATFORM), $(CACHED_PLATFORM)) ifneq ($(PLATFORM), $(CACHED_PLATFORM))
PLATFORM_CHANGED=true PLATFORM_CHANGED=true
@ -145,6 +189,7 @@ endif
export PLATFORM export PLATFORM
export PLATFORM_EXTRAS export PLATFORM_EXTRAS
export PLATFORM_EXTRAS_INFO export PLATFORM_EXTRAS_INFO
export PLATFORM_SIZE
export PLTNAME export PLTNAME
export PLATFORM_DEFS export PLATFORM_DEFS
export PLATFORM_DEFS_INFO export PLATFORM_DEFS_INFO
@ -154,6 +199,7 @@ export PLATFORM_CHANGED
$(info ===================================================================) $(info ===================================================================)
$(info Platform name: $(PLTNAME)) $(info Platform name: $(PLTNAME))
$(info PLATFORM: $(PLATFORM)) $(info PLATFORM: $(PLATFORM))
$(info PLATFORM_SIZE: $(PLATFORM_SIZE))
$(info Platform extras: $(PLATFORM_EXTRAS_INFO)) $(info Platform extras: $(PLATFORM_EXTRAS_INFO))
$(info Included options: $(PLATFORM_DEFS_INFO)) $(info Included options: $(PLATFORM_DEFS_INFO))
$(info Standalone mode: $(PLATFORM_DEFS_INFO_STANDALONE)) $(info Standalone mode: $(PLATFORM_DEFS_INFO_STANDALONE))

View file

@ -135,7 +135,7 @@ Options
--- ---
f <filename> : load iCLASS tag-dump filename f <filename> : load iCLASS tag-dump filename
pm3 --> hf iclass eload f hf-iclass-db883702f8ff12e0.bin pm3 --> hf iclass eload -f hf-iclass-db883702f8ff12e0.bin
``` ```
Clone iCLASS Legacy Sequence Clone iCLASS Legacy Sequence
@ -160,7 +160,7 @@ pm3 --> hf iclass sim 3
Simulate iCLASS Sequence Simulate iCLASS Sequence
``` ```
pm3 --> hf iclass dump k 0 pm3 --> hf iclass dump k 0
pm3 --> hf iclass eload f hf-iclass-db883702f8ff12e0.bin pm3 --> hf iclass eload -f hf-iclass-db883702f8ff12e0.bin
pm3 --> hf iclass sim 3 pm3 --> hf iclass sim 3
``` ```
@ -173,7 +173,7 @@ k <key> : Access Key as 16 hex symbols or 1 hex to select key from memory
e : If 'e' is specified, elite computations applied to key e : If 'e' is specified, elite computations applied to key
pm3 --> hf iclass sim 2 pm3 --> hf iclass sim 2
pm3 --> hf iclass loclass f iclass_mac_attack.bin pm3 --> hf iclass loclass -f iclass_mac_attack.bin
pm3 --> hf iclass managekeys n 7 k <Kcus> pm3 --> hf iclass managekeys n 7 k <Kcus>
pm3 --> hf iclass dump k 7 e pm3 --> hf iclass dump k 7 e
``` ```

View file

@ -160,7 +160,7 @@ Check column "offline" for their availability.
|`hf 14b reader `|N |`Act as a 14443B reader to identify a tag` |`hf 14b reader `|N |`Act as a 14443B reader to identify a tag`
|`hf 14b sim `|N |`Fake ISO 14443B tag` |`hf 14b sim `|N |`Fake ISO 14443B tag`
|`hf 14b sniff `|N |`Eavesdrop ISO 14443B` |`hf 14b sniff `|N |`Eavesdrop ISO 14443B`
|`hf 14b sriread `|N |`Read contents of a SRI512 | SRIX4K tag` |`hf 14b rdbl `|N |`Read SRI512/SRIX4x block`
|`hf 14b sriwrite `|N |`Write data to a SRI512 | SRIX4K tag` |`hf 14b sriwrite `|N |`Write data to a SRI512 | SRIX4K tag`
@ -203,7 +203,7 @@ Check column "offline" for their availability.
### hf felica ### hf felica
{ ISO18092 / Felica RFIDs... } { ISO18092 / FeliCa RFIDs... }
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
@ -325,6 +325,7 @@ Check column "offline" for their availability.
|`hf mf chk `|N |`Check keys` |`hf mf chk `|N |`Check keys`
|`hf mf fchk `|N |`Check keys fast, targets all keys on card` |`hf mf fchk `|N |`Check keys fast, targets all keys on card`
|`hf mf decrypt `|Y |`[nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace` |`hf mf decrypt `|Y |`[nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace`
|`hf mf supercard `|N |`Extract info from a `super card``
|`hf mf auth4 `|N |`ISO14443-4 AES authentication` |`hf mf auth4 `|N |`ISO14443-4 AES authentication`
|`hf mf dump `|N |`Dump MIFARE Classic tag to binary file` |`hf mf dump `|N |`Dump MIFARE Classic tag to binary file`
|`hf mf mad `|N |`Checks and prints MAD` |`hf mf mad `|N |`Checks and prints MAD`
@ -409,27 +410,27 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`hf mfdes help `|Y |`This help` |`hf mfdes help `|Y |`This help`
|`hf mfdes auth `|N |`Tries a MIFARE DesFire Authentication`
|`hf mfdes changekey `|N |`Change Key`
|`hf mfdes chk `|N |`Check keys`
|`hf mfdes enum `|N |`Tries enumerate all applications`
|`hf mfdes formatpicc `|N |`Format PICC`
|`hf mfdes getuid `|N |`Get random uid`
|`hf mfdes info `|N |`Tag information` |`hf mfdes info `|N |`Tag information`
|`hf mfdes list `|Y |`List DESFire (ISO 14443A) history` |`hf mfdes list `|Y |`List DESFire (ISO 14443A) history`
|`hf mfdes enum `|N |`Tries enumerate all applications`
|`hf mfdes auth `|N |`Tries a MIFARE DesFire Authentication`
|`hf mfdes getuid `|N |`Get random uid`
|`hf mfdes selectaid `|N |`Select Application ID`
|`hf mfdes createaid `|N |`Create Application ID` |`hf mfdes createaid `|N |`Create Application ID`
|`hf mfdes deleteaid `|N |`Delete Application ID` |`hf mfdes deleteaid `|N |`Delete Application ID`
|`hf mfdes selectaid `|N |`Select Application ID`
|`hf mfdes changevalue `|N |`Write value of a value file (credit/debit/clear)`
|`hf mfdes clearfile `|N |`Clear record File`
|`hf mfdes createfile `|N |`Create Standard/Backup File` |`hf mfdes createfile `|N |`Create Standard/Backup File`
|`hf mfdes createvaluefile`|N |`Create Value File` |`hf mfdes createvaluefile`|N |`Create Value File`
|`hf mfdes createrecordfile`|N |`Create Linear/Cyclic Record File` |`hf mfdes createrecordfile`|N |`Create Linear/Cyclic Record File`
|`hf mfdes deletefile `|N |`Create Delete File` |`hf mfdes deletefile `|N |`Create Delete File`
|`hf mfdes clearfile `|N |`Clear record File` |`hf mfdes dump `|N |`Dump all files`
|`hf mfdes getvalue `|N |`Get value of file`
|`hf mfdes readdata `|N |`Read data from standard/backup/record file` |`hf mfdes readdata `|N |`Read data from standard/backup/record file`
|`hf mfdes writedata `|N |`Write data to standard/backup/record file` |`hf mfdes writedata `|N |`Write data to standard/backup/record file`
|`hf mfdes getvalue `|N |`Get value of file`
|`hf mfdes changevalue `|N |`Write value of a value file (credit/debit/clear)`
|`hf mfdes changekey `|N |`Change Key`
|`hf mfdes formatpicc `|N |`Format PICC`
|`hf mfdes dump `|N |`Dump all files`
|`hf mfdes chk `|N |`Check keys`
### hf st ### hf st
@ -591,10 +592,12 @@ Check column "offline" for their availability.
|`lf em 4x05_read `|N |`read word data from EM4x05/EM4x69` |`lf em 4x05_read `|N |`read word data from EM4x05/EM4x69`
|`lf em 4x05_write `|N |`write word data to EM4x05/EM4x69` |`lf em 4x05_write `|N |`write word data to EM4x05/EM4x69`
|`lf em 4x05_unlock `|N |`execute tear off against EM4x05/EM4x69` |`lf em 4x05_unlock `|N |`execute tear off against EM4x05/EM4x69`
|`lf em 4x05_sniff `|Y |`Attempt to recover em4x05 commands from sample buffer`
|`lf em 4x05_brute `|N |`Bruteforce password`
|`lf em 4x50_dump `|N |`dump EM4x50 tag` |`lf em 4x50_dump `|N |`dump EM4x50 tag`
|`lf em 4x50_info `|N |`tag information EM4x50` |`lf em 4x50_info `|N |`tag information EM4x50`
|`lf em 4x50_write `|N |`write word data to EM4x50` |`lf em 4x50_write `|N |`write word data to EM4x50`
|`lf em 4x50_write_password`|N |`change passwword of EM4x50 tag` |`lf em 4x50_write_password`|N |`change password of EM4x50 tag`
|`lf em 4x50_read `|N |`read word data from EM4x50` |`lf em 4x50_read `|N |`read word data from EM4x50`
|`lf em 4x50_wipe `|N |`wipe data from EM4x50` |`lf em 4x50_wipe `|N |`wipe data from EM4x50`

View file

@ -8,15 +8,15 @@ LOCLASS, is a two part attack. First is the online part where you gather needed
The second part is offline, where the information gathered from the first step is used in a series of DES operations to figure out the used The second part is offline, where the information gathered from the first step is used in a series of DES operations to figure out the used
masterkey. masterkey.
run `hf iclass loclass f abc.bin` run `hf iclass loclass -f abc.bin`
If you don't have access to a iClass SE reader configured in Elite mode there is a test file which you can use. If you don't have access to a iClass SE reader configured in Elite mode there is a test file which you can use.
`hf iclass loclass f iclass_dump.bin` `hf iclass loclass -f iclass_dump.bin`
# Unit testing # Unit testing
In order to verify that loclass is actually working, there is a "unit" test mode. In order to verify that loclass is actually working, there is a "unit" test mode.
run `hf iclass loclass t`. run `hf iclass loclass --test`.
This test mode uses two files. This test mode uses two files.

View file

@ -32,9 +32,7 @@ make SKIPBT=1
By default, the firmware is of course tuned for the Proxmark3 Rdv4.0 device, which has built-in support for 256kb onboard flash SPI memory, Sim module (smart card support), FPC connector. By default, the firmware is of course tuned for the Proxmark3 Rdv4.0 device, which has built-in support for 256kb onboard flash SPI memory, Sim module (smart card support), FPC connector.
These features make it very different from all other devices, there is non other like this one. These features make it very different from all other devices, there is non other like this one.
**Recommendation**: if you don't have a RDV4, we strongly recommend your device to have at least a 512kb arm chip, since this repo is on the very edge of 256kb limit. **Recommendation**: if you don't have a RDV4, we strongly recommend your device to have at least a 512kb arm chip, since this repo is crossing 256kb limit. There is still a way to skip parts to make it fit on a 256kb device, see below.
A firmware built for the RDV4 can still run on the other platforms as it will auto-detect during boot that external SPI and Sim are not present, still it will boot faster if it's tuned to the platform, which solves USB enumeration issues on some OSes.
If you need to tune things and save the configuration, create a file `Makefile.platform` in the root directory of the repository, see `Makefile.platform.sample`. If you need to tune things and save the configuration, create a file `Makefile.platform` in the root directory of the repository, see `Makefile.platform.sample`.
For an up-to-date exhaustive list of options, you can run `make PLATFORM=`. For an up-to-date exhaustive list of options, you can run `make PLATFORM=`.
@ -96,10 +94,55 @@ Here are the supported values you can assign to `STANDALONE` in `Makefile.platfo
| HF_LEGIC | HF Legic Prime standalone - uhei | HF_LEGIC | HF Legic Prime standalone - uhei
| HF_MATTYRUN | Mifare sniff/clone - Matías A. Ré Medina | HF_MATTYRUN | Mifare sniff/clone - Matías A. Ré Medina
| HF_MSDSAL (def)| EMV Read and emulation - Salvador Mendoza | HF_MSDSAL (def)| EMV Read and emulation - Salvador Mendoza
| HF_TCPRST | IKEA Rothult ST25TA, Standalone Master Key Dump/Emulation - Nick Draffen
| HF_YOUNG | Mifare sniff/simulation - Craig Young | HF_YOUNG | Mifare sniff/simulation - Craig Young
By default `STANDALONE=HF_MSDSAL`. By default `STANDALONE=HF_MSDSAL`.
## 256kb versions
If you own a Proxmark3 Easy with only 256kb, you can use a few definitions to help you getting a smaller firmware.
First thing is of course to use the `PLATFORM=PM3OTHER`.
Adding `PLATFORM_SIZE=256` will provoke an error during compilation of the recovery image if your image is too big, so you can detect the problem before trying to flash the Proxmark3, e.g.
```
[=] GEN proxmark3_recovery.bin
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ERROR: Firmware image too large for your platform! 262768 > 262144
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
```
You can skip the standalone support by indicating `STANDALONE=` and
a series of `SKIP_*` allow to skip some of the functionalities and to get a smaller image.
| Definitions | Rough estimation of the saved space |
|---------------------|-------------------------------------|
|STANDALONE= | 3.6kb
|SKIP_LF=1 | 25.8kb
|SKIP_HITAG=1 | 24.2kb
|SKIP_EM4x50=1 | 2.9kb
|SKIP_ISO15693=1 | 3.2kb
|SKIP_LEGICRF=1 | 3.9kb
|SKIP_ISO14443b=1 | 3.7kb
|SKIP_ISO14443a=1 | 63.0kb
|SKIP_ICLASS=1 | 10.5kb
|SKIP_FELICA=1 | 4.0kb
|SKIP_NFCBARCODE=1 | 1.4kb
|SKIP_HFSNIFF=1 | 0.5kb
|SKIP_HFPLOT=1 | 0.3kb
So for example, at the time of writing, this is a valid `Makefile.platform` compiling an image for 256k:
```
PLATFORM=PM3OTHER
PLATFORM_SIZE=256
STANDALONE=
SKIP_LEGICRF=1
SKIP_FELICA=1
```
Situation might change when the firmware is growing of course, requiring to skip more elements.
Last note: if you skip a tech, be careful not to use a standalone mode which requires that same tech, else the firmware size reduction won't be much.
## Next step ## Next step
See [Compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md) See [Compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)

View file

@ -6,10 +6,18 @@ ifneq (,$(FWTAG))
else else
INSTALLFWTAG = $(notdir $(INSTALLFW)) INSTALLFWTAG = $(notdir $(INSTALLFW))
endif endif
FWMAXSIZE = $(shell echo $$(($(PLATFORM_SIZE)*1024)))
BINS = bootrom.bin fullimage.bin $(INSTALLFW) BINS = bootrom.bin fullimage.bin $(INSTALLFW)
all: $(BINS) all: $(BINS)
@FWSIZE=$$(stat -c "%s" $(INSTALLFW));\
if [ $$FWSIZE -gt $(FWMAXSIZE) ]; then \
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; \
echo "ERROR: Firmware image too large for your platform! $$FWSIZE > $(FWMAXSIZE)"; \
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; \
exit 1; \
fi
bootrom.bin: ../bootrom/obj/bootrom.elf bootrom.bin: ../bootrom/obj/bootrom.elf
$(info [=] GEN $@) $(info [=] GEN $@)

View file

@ -450,10 +450,10 @@ while true; do
echo -e "\n${C_BLUE}Testing HF:${C_NC}" echo -e "\n${C_BLUE}Testing HF:${C_NC}"
if ! CheckExecute "hf mf offline text" "$CLIENTBIN -c 'hf mf'" "at_enc"; then break; fi if ! CheckExecute "hf mf offline text" "$CLIENTBIN -c 'hf mf'" "at_enc"; then break; fi
if ! CheckExecute slow retry ignore "hf mf hardnested long test" "$CLIENTBIN -c 'hf mf hardnested t 1 000000000000'" "found:"; then break; fi if ! CheckExecute slow retry ignore "hf mf hardnested long test" "$CLIENTBIN -c 'hf mf hardnested t 1 000000000000'" "found:"; then break; fi
if ! CheckExecute slow "hf iclass long test" "$CLIENTBIN -c 'hf iclass loclass t l'" "verified ok"; then break; fi if ! CheckExecute slow "hf iclass long test" "$CLIENTBIN -c 'hf iclass loclass --long'" "verified ok"; then break; fi
if ! CheckExecute slow "emv long test" "$CLIENTBIN -c 'emv test -l'" "Test(s) \[ ok"; then break; fi if ! CheckExecute slow "emv long test" "$CLIENTBIN -c 'emv test -l'" "Test(s) \[ ok"; then break; fi
if ! $SLOWTESTS; then if ! $SLOWTESTS; then
if ! CheckExecute "hf iclass test" "$CLIENTBIN -c 'hf iclass loclass t'" "key diversification (ok)"; then break; fi if ! CheckExecute "hf iclass test" "$CLIENTBIN -c 'hf iclass loclass --test'" "key diversification (ok)"; then break; fi
if ! CheckExecute "emv test" "$CLIENTBIN -c 'emv test'" "Test(s) \[ ok"; then break; fi if ! CheckExecute "emv test" "$CLIENTBIN -c 'emv test'" "Test(s) \[ ok"; then break; fi
fi fi
fi fi