mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
smart raw - now use NG.\nhf iclass config - added more support for keyrollning (WIP)\n
This commit is contained in:
parent
4fb28e5149
commit
8a05a4d1d7
14 changed files with 485 additions and 262 deletions
|
@ -109,7 +109,7 @@ static bool have_aa2(void) {
|
||||||
return memcmp(aa2_key, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8);
|
return memcmp(aa2_key, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t get_pagemap(const picopass_hdr *hdr) {
|
static uint8_t get_pagemap(const picopass_hdr_t *hdr) {
|
||||||
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
|
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@ static int reader_dump_mode(void) {
|
||||||
set_tracing(false);
|
set_tracing(false);
|
||||||
|
|
||||||
|
|
||||||
picopass_hdr *hdr = (picopass_hdr *)card_data;
|
picopass_hdr_t *hdr = (picopass_hdr_t *)card_data;
|
||||||
|
|
||||||
// select tag.
|
// select tag.
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
|
@ -458,7 +458,7 @@ static int dump_sim_mode(void) {
|
||||||
set_tracing(false);
|
set_tracing(false);
|
||||||
|
|
||||||
|
|
||||||
picopass_hdr *hdr = (picopass_hdr *)card_data;
|
picopass_hdr_t *hdr = (picopass_hdr_t *)card_data;
|
||||||
|
|
||||||
// select tag.
|
// select tag.
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
|
|
|
@ -1746,7 +1746,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_SMART_RAW: {
|
case CMD_SMART_RAW: {
|
||||||
SmartCardRaw(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
|
SmartCardRaw((smart_card_raw_t*)packet->data.asBytes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_SMART_UPLOAD: {
|
case CMD_SMART_UPLOAD: {
|
||||||
|
|
71
armsrc/i2c.c
71
armsrc/i2c.c
|
@ -32,15 +32,13 @@
|
||||||
|
|
||||||
#define I2C_ERROR "I2C_WaitAck Error"
|
#define I2C_ERROR "I2C_WaitAck Error"
|
||||||
|
|
||||||
//static
|
|
||||||
|
|
||||||
// Direct use the loop to delay. 6 instructions loop, Masterclock 48MHz,
|
// Direct use the loop to delay. 6 instructions loop, Masterclock 48MHz,
|
||||||
// delay=1 is about 200kbps
|
// delay=1 is about 200kbps
|
||||||
// timer.
|
// timer.
|
||||||
// I2CSpinDelayClk(4) = 12.31us
|
// I2CSpinDelayClk(4) = 12.31us
|
||||||
// I2CSpinDelayClk(1) = 3.07us
|
// I2CSpinDelayClk(1) = 3.07us
|
||||||
|
static volatile uint32_t c;
|
||||||
static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) {
|
static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) {
|
||||||
volatile uint32_t c;
|
|
||||||
for (c = delay * 2; c; c--) {};
|
for (c = delay * 2; c; c--) {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +99,7 @@ void I2C_init(void) {
|
||||||
AT91C_BASE_PIOA->PIO_PER |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
|
AT91C_BASE_PIOA->PIO_PER |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
|
||||||
|
|
||||||
bool isok = (SCL_read && SDA_read);
|
bool isok = (SCL_read && SDA_read);
|
||||||
if (!isok)
|
if (isok == false)
|
||||||
I2C_recovery();
|
I2C_recovery();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +159,7 @@ static bool WaitSCL_H_delay(uint32_t delay) {
|
||||||
// 5000 * 3.07us = 15350us. 15.35ms
|
// 5000 * 3.07us = 15350us. 15.35ms
|
||||||
// 15000 * 3.07us = 46050us. 46.05ms
|
// 15000 * 3.07us = 46050us. 46.05ms
|
||||||
static bool WaitSCL_H(void) {
|
static bool WaitSCL_H(void) {
|
||||||
return WaitSCL_H_delay(10000);
|
return WaitSCL_H_delay(15000);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool WaitSCL_L_delay(uint32_t delay) {
|
static bool WaitSCL_L_delay(uint32_t delay) {
|
||||||
|
@ -175,14 +173,14 @@ static bool WaitSCL_L_delay(uint32_t delay) {
|
||||||
}
|
}
|
||||||
// 5000 * 3.07us = 15350us. 15.35ms
|
// 5000 * 3.07us = 15350us. 15.35ms
|
||||||
static bool WaitSCL_L(void) {
|
static bool WaitSCL_L(void) {
|
||||||
return WaitSCL_L_delay(10000);
|
return WaitSCL_L_delay(15000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait max 1800ms or until SCL goes LOW.
|
// Wait max 1800ms or until SCL goes LOW.
|
||||||
// It timeout reading response from card
|
// It timeout reading response from card
|
||||||
// Which ever comes first
|
// Which ever comes first
|
||||||
static bool WaitSCL_L_timeout(void) {
|
static bool WaitSCL_L_timeout(void) {
|
||||||
volatile uint32_t delay = 1800;
|
volatile uint32_t delay = 1700;
|
||||||
while (delay--) {
|
while (delay--) {
|
||||||
// exit on SCL LOW
|
// exit on SCL LOW
|
||||||
if (!SCL_read)
|
if (!SCL_read)
|
||||||
|
@ -195,7 +193,8 @@ static bool WaitSCL_L_timeout(void) {
|
||||||
|
|
||||||
static bool I2C_Start(void) {
|
static bool I2C_Start(void) {
|
||||||
|
|
||||||
I2C_DELAY_XCLK(4);
|
I2C_DELAY_2CLK;
|
||||||
|
I2C_DELAY_2CLK;
|
||||||
SDA_H;
|
SDA_H;
|
||||||
I2C_DELAY_1CLK;
|
I2C_DELAY_1CLK;
|
||||||
SCL_H;
|
SCL_H;
|
||||||
|
@ -220,7 +219,7 @@ static bool I2C_WaitForSim(void) {
|
||||||
// 8051 speaks with smart card.
|
// 8051 speaks with smart card.
|
||||||
// 1000*50*3.07 = 153.5ms
|
// 1000*50*3.07 = 153.5ms
|
||||||
// 1byte transfer == 1ms with max frame being 256bytes
|
// 1byte transfer == 1ms with max frame being 256bytes
|
||||||
return WaitSCL_H_delay(10 * 1000 * 50);
|
return WaitSCL_H_delay(1000 * 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send i2c STOP
|
// send i2c STOP
|
||||||
|
@ -233,7 +232,10 @@ static void I2C_Stop(void) {
|
||||||
I2C_DELAY_2CLK;
|
I2C_DELAY_2CLK;
|
||||||
if (!WaitSCL_H()) return;
|
if (!WaitSCL_H()) return;
|
||||||
SDA_H;
|
SDA_H;
|
||||||
I2C_DELAY_XCLK(8);
|
I2C_DELAY_2CLK;
|
||||||
|
I2C_DELAY_2CLK;
|
||||||
|
I2C_DELAY_2CLK;
|
||||||
|
I2C_DELAY_2CLK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send i2c ACK
|
// Send i2c ACK
|
||||||
|
@ -653,7 +655,7 @@ bool sc_rx_bytes(uint8_t *dest, uint8_t *destlen) {
|
||||||
|
|
||||||
bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
|
bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
|
||||||
|
|
||||||
if (!card_ptr)
|
if (card_ptr == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
card_ptr->atr_len = 0;
|
card_ptr->atr_len = 0;
|
||||||
|
@ -710,53 +712,62 @@ void SmartCardAtr(void) {
|
||||||
set_tracing(true);
|
set_tracing(true);
|
||||||
I2C_Reset_EnterMainProgram();
|
I2C_Reset_EnterMainProgram();
|
||||||
smart_card_atr_t card;
|
smart_card_atr_t card;
|
||||||
int res = GetATR(&card, true) ? PM3_SUCCESS : PM3_ETIMEOUT;
|
if (GetATR(&card, true)) {
|
||||||
if (res == PM3_ETIMEOUT) {
|
reply_ng(CMD_SMART_ATR, PM3_SUCCESS, (uint8_t *)&card, sizeof(smart_card_atr_t));
|
||||||
I2C_Reset_EnterMainProgram();
|
} else {
|
||||||
|
reply_ng(CMD_SMART_ATR, PM3_ETIMEOUT, NULL, 0);
|
||||||
}
|
}
|
||||||
reply_ng(CMD_SMART_ATR, res, (uint8_t *)&card, sizeof(smart_card_atr_t));
|
|
||||||
set_tracing(false);
|
set_tracing(false);
|
||||||
LEDsoff();
|
LEDsoff();
|
||||||
|
// StopTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data) {
|
void SmartCardRaw(smart_card_raw_t *p) {
|
||||||
|
|
||||||
LED_D_ON();
|
LED_D_ON();
|
||||||
|
|
||||||
uint8_t len = 0;
|
uint8_t len = 0;
|
||||||
uint8_t *resp = BigBuf_malloc(ISO7618_MAX_FRAME);
|
uint8_t *resp = BigBuf_malloc(ISO7618_MAX_FRAME);
|
||||||
smartcard_command_t flags = arg0;
|
// check if alloacted...
|
||||||
|
smartcard_command_t flags = p->flags;
|
||||||
|
|
||||||
if ((flags & SC_CLEARLOG) == SC_CLEARLOG)
|
if ((flags & SC_CLEARLOG) == SC_CLEARLOG)
|
||||||
clear_trace();
|
clear_trace();
|
||||||
|
|
||||||
if ((flags & SC_LOG) == SC_LOG)
|
if ((flags & SC_LOG) == SC_LOG)
|
||||||
set_tracing(true);
|
set_tracing(true);
|
||||||
else
|
else
|
||||||
set_tracing(false);
|
set_tracing(false);
|
||||||
|
|
||||||
if ((flags & SC_CONNECT)) {
|
if ((flags & SC_CONNECT) == SC_CONNECT) {
|
||||||
|
|
||||||
I2C_Reset_EnterMainProgram();
|
I2C_Reset_EnterMainProgram();
|
||||||
|
|
||||||
if ((flags & SC_SELECT)) {
|
if ((flags & SC_SELECT) == SC_SELECT) {
|
||||||
smart_card_atr_t card;
|
smart_card_atr_t card;
|
||||||
bool gotATR = GetATR(&card, true);
|
bool gotATR = GetATR(&card, true);
|
||||||
//reply_old(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
|
//reply_old(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
|
||||||
if (!gotATR)
|
if (gotATR == false) {
|
||||||
|
reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0);
|
||||||
goto OUT;
|
goto OUT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & SC_RAW) || (flags & SC_RAW_T0)) {
|
if ((flags & SC_RAW) || (flags & SC_RAW_T0)) {
|
||||||
|
|
||||||
LogTrace(data, arg1, 0, 0, NULL, true);
|
LogTrace(p->data, p->len, 0, 0, NULL, true);
|
||||||
|
|
||||||
// Send raw bytes
|
bool res = I2C_BufferWrite(
|
||||||
// asBytes = A0 A4 00 00 02
|
p->data,
|
||||||
// arg1 = len 5
|
p->len,
|
||||||
bool res = I2C_BufferWrite(data, arg1, ((flags & SC_RAW_T0) ? I2C_DEVICE_CMD_SEND_T0 : I2C_DEVICE_CMD_SEND), I2C_DEVICE_ADDRESS_MAIN);
|
((flags & SC_RAW_T0) ? I2C_DEVICE_CMD_SEND_T0 : I2C_DEVICE_CMD_SEND),
|
||||||
if (!res && DBGLEVEL > 3) DbpString(I2C_ERROR);
|
I2C_DEVICE_ADDRESS_MAIN
|
||||||
|
);
|
||||||
|
if (res == false && DBGLEVEL > 3) {
|
||||||
|
DbpString(I2C_ERROR);
|
||||||
|
reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0);
|
||||||
|
goto OUT;
|
||||||
|
}
|
||||||
|
|
||||||
// read bytes from module
|
// read bytes from module
|
||||||
len = ISO7618_MAX_FRAME;
|
len = ISO7618_MAX_FRAME;
|
||||||
|
@ -767,8 +778,10 @@ void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data) {
|
||||||
len = 0;
|
len = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reply_ng(CMD_SMART_RAW, PM3_SUCCESS, resp, len);
|
||||||
|
|
||||||
OUT:
|
OUT:
|
||||||
reply_mix(CMD_ACK, len, 0, 0, resp, len);
|
|
||||||
BigBuf_free();
|
BigBuf_free();
|
||||||
set_tracing(false);
|
set_tracing(false);
|
||||||
LEDsoff();
|
LEDsoff();
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define __I2C_H
|
#define __I2C_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "mifare.h"
|
#include "pm3_cmd.h"
|
||||||
|
|
||||||
#define I2C_DEVICE_ADDRESS_BOOT 0xB0
|
#define I2C_DEVICE_ADDRESS_BOOT 0xB0
|
||||||
#define I2C_DEVICE_ADDRESS_MAIN 0xC0
|
#define I2C_DEVICE_ADDRESS_MAIN 0xC0
|
||||||
|
@ -39,7 +39,7 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose);
|
||||||
|
|
||||||
// generice functions
|
// generice functions
|
||||||
void SmartCardAtr(void);
|
void SmartCardAtr(void);
|
||||||
void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data);
|
void SmartCardRaw(smart_card_raw_t *packet);
|
||||||
void SmartCardUpgrade(uint64_t arg0);
|
void SmartCardUpgrade(uint64_t arg0);
|
||||||
void SmartCardSetBaud(uint64_t arg0);
|
void SmartCardSetBaud(uint64_t arg0);
|
||||||
void SmartCardSetClock(uint64_t arg0);
|
void SmartCardSetClock(uint64_t arg0);
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#include "ticks.h"
|
#include "ticks.h"
|
||||||
#include "iso15693.h"
|
#include "iso15693.h"
|
||||||
|
|
||||||
static uint8_t get_pagemap(const picopass_hdr *hdr) {
|
static uint8_t get_pagemap(const picopass_hdr_t *hdr) {
|
||||||
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
|
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_
|
||||||
|
|
||||||
//This is 'full sim' mode, where we use the emulator storage for data.
|
//This is 'full sim' mode, where we use the emulator storage for data.
|
||||||
//ie: BigBuf_get_EM_addr should be previously filled with data from the "eload" command
|
//ie: BigBuf_get_EM_addr should be previously filled with data from the "eload" command
|
||||||
picopass_hdr *hdr = (picopass_hdr *)BigBuf_get_EM_addr();
|
picopass_hdr_t *hdr = (picopass_hdr_t *)BigBuf_get_EM_addr();
|
||||||
uint8_t pagemap = get_pagemap(hdr);
|
uint8_t pagemap = get_pagemap(hdr);
|
||||||
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
|
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
|
||||||
do_iclass_simulation_nonsec();
|
do_iclass_simulation_nonsec();
|
||||||
|
@ -1275,7 +1275,7 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t *
|
||||||
* @return false = fail
|
* @return false = fail
|
||||||
* true = Got all.
|
* true = Got all.
|
||||||
*/
|
*/
|
||||||
static bool select_iclass_tag_ex(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time, uint8_t *status) {
|
static bool select_iclass_tag_ex(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, uint8_t *status) {
|
||||||
|
|
||||||
static uint8_t act_all[] = { ICLASS_CMD_ACTALL };
|
static uint8_t act_all[] = { ICLASS_CMD_ACTALL };
|
||||||
static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 };
|
static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 };
|
||||||
|
@ -1393,7 +1393,7 @@ static bool select_iclass_tag_ex(picopass_hdr *hdr, bool use_credit_key, uint32_
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time) {
|
bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time) {
|
||||||
uint8_t result = 0;
|
uint8_t result = 0;
|
||||||
return select_iclass_tag_ex(hdr, use_credit_key, eof_time, &result);
|
return select_iclass_tag_ex(hdr, use_credit_key, eof_time, &result);
|
||||||
}
|
}
|
||||||
|
@ -1402,7 +1402,7 @@ bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_tim
|
||||||
// turn off afterwards
|
// turn off afterwards
|
||||||
void ReaderIClass(uint8_t flags) {
|
void ReaderIClass(uint8_t flags) {
|
||||||
|
|
||||||
picopass_hdr hdr = {0};
|
picopass_hdr_t hdr = {0};
|
||||||
// uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
// uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
|
uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
|
||||||
memset(resp, 0xFF, sizeof(resp));
|
memset(resp, 0xFF, sizeof(resp));
|
||||||
|
@ -1470,7 +1470,7 @@ void ReaderIClass(uint8_t flags) {
|
||||||
switch_off();
|
switch_off();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out) {
|
bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out) {
|
||||||
|
|
||||||
uint8_t cmd_check[9] = { ICLASS_CMD_CHECK };
|
uint8_t cmd_check[9] = { ICLASS_CMD_CHECK };
|
||||||
uint8_t mac[4] = {0};
|
uint8_t mac[4] = {0};
|
||||||
|
@ -1538,7 +1538,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) {
|
||||||
readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK;
|
readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK;
|
||||||
|
|
||||||
// select card / e-purse
|
// select card / e-purse
|
||||||
picopass_hdr hdr = {0};
|
picopass_hdr_t hdr = {0};
|
||||||
|
|
||||||
iclass_premac_t *keys = (iclass_premac_t *)datain;
|
iclass_premac_t *keys = (iclass_premac_t *)datain;
|
||||||
|
|
||||||
|
@ -1628,7 +1628,7 @@ void iClass_ReadBlock(uint8_t *msg) {
|
||||||
|
|
||||||
// select tag.
|
// select tag.
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
picopass_hdr hdr = {0};
|
picopass_hdr_t hdr = {0};
|
||||||
bool res = select_iclass_tag(&hdr, payload->use_credit_key, &eof_time);
|
bool res = select_iclass_tag(&hdr, payload->use_credit_key, &eof_time);
|
||||||
if (res == false) {
|
if (res == false) {
|
||||||
if (payload->send_reply) {
|
if (payload->send_reply) {
|
||||||
|
@ -1701,7 +1701,7 @@ void iClass_Dump(uint8_t *msg) {
|
||||||
|
|
||||||
// select tag.
|
// select tag.
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
picopass_hdr hdr = {0};
|
picopass_hdr_t hdr = {0};
|
||||||
bool res = select_iclass_tag(&hdr, req->use_credit_key, &eof_time);
|
bool res = select_iclass_tag(&hdr, req->use_credit_key, &eof_time);
|
||||||
if (res == false) {
|
if (res == false) {
|
||||||
if (req->send_reply) {
|
if (req->send_reply) {
|
||||||
|
@ -1828,7 +1828,7 @@ void iClass_WriteBlock(uint8_t *msg) {
|
||||||
|
|
||||||
// select tag.
|
// select tag.
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
picopass_hdr hdr = {0};
|
picopass_hdr_t hdr = {0};
|
||||||
uint8_t res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time);
|
uint8_t res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time);
|
||||||
if (res == false) {
|
if (res == false) {
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1950,7 +1950,7 @@ void iClass_Restore(iclass_restore_req_t *msg) {
|
||||||
|
|
||||||
uint16_t written = 0;
|
uint16_t written = 0;
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
picopass_hdr hdr = {0};
|
picopass_hdr_t hdr = {0};
|
||||||
|
|
||||||
// select
|
// select
|
||||||
bool res = select_iclass_tag(&hdr, msg->req.use_credit_key, &eof_time);
|
bool res = select_iclass_tag(&hdr, msg->req.use_credit_key, &eof_time);
|
||||||
|
|
|
@ -34,6 +34,6 @@ bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out);
|
||||||
void iClass_ReadBlock(uint8_t *msg);
|
void iClass_ReadBlock(uint8_t *msg);
|
||||||
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time);
|
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time);
|
||||||
|
|
||||||
bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time);
|
bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time);
|
||||||
bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out);
|
bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,12 +30,18 @@
|
||||||
#include "cardhelper.h"
|
#include "cardhelper.h"
|
||||||
#include "wiegand_formats.h"
|
#include "wiegand_formats.h"
|
||||||
#include "wiegand_formatutils.h"
|
#include "wiegand_formatutils.h"
|
||||||
|
#include "cmdsmartcard.h" // smart select fct
|
||||||
|
|
||||||
#define NUM_CSNS 9
|
#define NUM_CSNS 9
|
||||||
#define ICLASS_KEYS_MAX 8
|
#define ICLASS_KEYS_MAX 8
|
||||||
#define ICLASS_AUTH_RETRY 10
|
#define ICLASS_AUTH_RETRY 10
|
||||||
#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin"
|
#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin"
|
||||||
|
|
||||||
|
static picopass_hdr_t iclass_last_known_card;
|
||||||
|
static void iclass_set_last_known_card(picopass_hdr_t *card) {
|
||||||
|
memcpy(&iclass_last_known_card, card, sizeof(picopass_hdr_t));
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
static uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
@ -129,21 +135,21 @@ uint8_t card_app2_limit[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
iclass_config_card_item_t iclass_config_types[14]= {
|
iclass_config_card_item_t iclass_config_types[14]= {
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
{"", "", ""},
|
{"", ""},
|
||||||
// must be the last entry
|
// must be the last entry
|
||||||
{"no config card info available", "", ""}
|
{"no config card info available", ""}
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool check_config_card(const iclass_config_card_item_t *o) {
|
static bool check_config_card(const iclass_config_card_item_t *o) {
|
||||||
|
@ -156,14 +162,15 @@ static bool check_config_card(const iclass_config_card_item_t *o) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int load_config_cards(void) {
|
static int load_config_cards(void) {
|
||||||
PrintAndLogEx(INFO, "Detecting cardhelper...");
|
PrintAndLogEx(INFO, "detecting cardhelper...");
|
||||||
|
if (IsCardHelperPresent(false) == false) {
|
||||||
if (IsCardHelperPresent(false) == false)
|
PrintAndLogEx(FAILED, "failed to detect cardhelper");
|
||||||
return PM3_ENODATA;
|
return PM3_ENODATA;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ARRAYLEN(iclass_config_types); ++i) {
|
for (int i = 0; i < ARRAYLEN(iclass_config_types); ++i) {
|
||||||
|
|
||||||
PrintAndLogEx(INPLACE, "loading idx %i", i);
|
PrintAndLogEx(INPLACE, "loading setting %i", i);
|
||||||
iclass_config_card_item_t *ret = &iclass_config_types[i];
|
iclass_config_card_item_t *ret = &iclass_config_types[i];
|
||||||
|
|
||||||
uint8_t desc[70] = {0};
|
uint8_t desc[70] = {0};
|
||||||
|
@ -173,8 +180,7 @@ static int load_config_cards(void) {
|
||||||
|
|
||||||
uint8_t blocks[16] = {0};
|
uint8_t blocks[16] = {0};
|
||||||
if (GetConfigCardByIdx(i, blocks) == PM3_SUCCESS) {
|
if (GetConfigCardByIdx(i, blocks) == PM3_SUCCESS) {
|
||||||
memcpy(ret->blk6, blocks, sizeof(ret->blk6));
|
memcpy(ret->data, blocks, sizeof(blocks));
|
||||||
memcpy(ret->blk7, blocks + sizeof(ret->blk6), sizeof(ret->blk7));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
@ -182,9 +188,11 @@ static int load_config_cards(void) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const iclass_config_card_item_t *get_config_card_item(uint8_t idx) {
|
static const iclass_config_card_item_t *get_config_card_item(int idx) {
|
||||||
iclass_config_card_item_t *ret = &iclass_config_types[idx];
|
if (idx < 0 && idx > 13) {
|
||||||
return ret;
|
idx = 13;
|
||||||
|
}
|
||||||
|
return &iclass_config_types[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_config_cards(void) {
|
static void print_config_cards(void) {
|
||||||
|
@ -200,15 +208,134 @@ static void print_config_cards(void) {
|
||||||
static void print_config_card(const iclass_config_card_item_t *o) {
|
static void print_config_card(const iclass_config_card_item_t *o) {
|
||||||
if (check_config_card(o)) {
|
if (check_config_card(o)) {
|
||||||
PrintAndLogEx(INFO, "description... %s", o->desc);
|
PrintAndLogEx(INFO, "description... %s", o->desc);
|
||||||
PrintAndLogEx(INFO, "block 6....... " _YELLOW_("%s"), sprint_hex_inrow(o->blk6, sizeof(o->blk6)));
|
PrintAndLogEx(INFO, "data....... " _YELLOW_("%s"), sprint_hex_inrow(o->data, sizeof(o->data)));
|
||||||
PrintAndLogEx(INFO, "block 7....... " _YELLOW_("%s"), sprint_hex_inrow(o->blk7, sizeof(o->blk7)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generate_config_card(const iclass_config_card_item_t *o) {
|
static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *key, bool got_kr) {
|
||||||
if (check_config_card(o)) {
|
if (check_config_card(o) == false) {
|
||||||
PrintAndLogEx(INFO, "to be implemented...");
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
// get header from card
|
||||||
|
//bool have = memcmp(iclass_last_known_card.csn, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
|
||||||
|
PrintAndLogEx(INFO, "trying to read a card..");
|
||||||
|
int res = read_iclass_csn(false, false);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(FAILED, "Put a card on antenna and try again...");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate dump file
|
||||||
|
uint8_t app1_limit = iclass_last_known_card.conf.app_limit;
|
||||||
|
uint8_t old_limit = app1_limit;
|
||||||
|
uint8_t tot_bytes = (app1_limit + 1) * 8;
|
||||||
|
|
||||||
|
// normal size
|
||||||
|
uint8_t *data = calloc(1, tot_bytes);
|
||||||
|
if (data == NULL) {
|
||||||
|
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
memset(data, 0xFF, tot_bytes);
|
||||||
|
|
||||||
|
// Keyrolling configuration cards are special.
|
||||||
|
if (strstr(o->desc, "Keyroll") != NULL) {
|
||||||
|
|
||||||
|
if (got_kr == false) {
|
||||||
|
PrintAndLogEx(ERR, "please specifiy KEYROLL key!");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app1_limit < 0x16) {
|
||||||
|
// if card wasn't large enough before, adapt to new size
|
||||||
|
PrintAndLogEx(WARNING, "Adapting applimit1 for KEY rolling..");
|
||||||
|
|
||||||
|
app1_limit = 0x16;
|
||||||
|
iclass_last_known_card.conf.app_limit = 0x16;
|
||||||
|
tot_bytes = (app1_limit + 1) * 8;
|
||||||
|
|
||||||
|
uint8_t *p;
|
||||||
|
p = realloc(data, tot_bytes);
|
||||||
|
if (p == NULL) {
|
||||||
|
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||||
|
free(data);
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
data = p;
|
||||||
|
memset(data, 0xFF, tot_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// need to encrypt
|
||||||
|
PrintAndLogEx(INFO, "Detecting cardhelper...");
|
||||||
|
if (IsCardHelperPresent(false) == false) {
|
||||||
|
PrintAndLogEx(FAILED, "failed to detect cardhelper");
|
||||||
|
return PM3_ENODATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ffs[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
|
||||||
|
if (Encrypt(ffs, ffs) == false) {
|
||||||
|
PrintAndLogEx(WARNING, "failed to encrypt FF");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t enckey1[8];
|
||||||
|
if (Encrypt(key, enckey1) == false) {
|
||||||
|
PrintAndLogEx(WARNING, "failed to encrypt key1");
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data, &iclass_last_known_card, sizeof(picopass_hdr_t));
|
||||||
|
memcpy(data + (6 * 8), o->data, sizeof(o->data));
|
||||||
|
|
||||||
|
// encrypted keyroll key 0D
|
||||||
|
memcpy(data + (0xD * 8), enckey1, sizeof(enckey1));
|
||||||
|
// encrypted 0xFF
|
||||||
|
for (uint8_t i = 0xe; i < 0x14; i++) {
|
||||||
|
memcpy(data + (i*8), ffs, sizeof(ffs));
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypted partial keyroll key 14
|
||||||
|
uint8_t foo[8] = {0x15};
|
||||||
|
memcpy(foo + 1, key, 7);
|
||||||
|
uint8_t enckey2[8];
|
||||||
|
if (Encrypt(foo, enckey2) == false) {
|
||||||
|
PrintAndLogEx(WARNING, "failed to encrypt partial 1");
|
||||||
|
}
|
||||||
|
memcpy(data + (0x14 * 8), enckey2, sizeof(enckey2));
|
||||||
|
|
||||||
|
// encrypted partial keyroll key 15
|
||||||
|
memset(foo, 0xFF, sizeof(foo));
|
||||||
|
foo[0] = key[7];
|
||||||
|
if (Encrypt(foo, enckey2) == false) {
|
||||||
|
PrintAndLogEx(WARNING, "failed to encrypt partial 2");
|
||||||
|
}
|
||||||
|
memcpy(data + (0x15 * 8), enckey2, sizeof(enckey2));
|
||||||
|
|
||||||
|
// encrypted 0xFF
|
||||||
|
for (uint8_t i = 0x16; i <= app1_limit; i++) {
|
||||||
|
memcpy(data + (i * 8), ffs, sizeof(ffs));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// revert potential modified app1_limit
|
||||||
|
iclass_last_known_card.conf.app_limit = old_limit;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
memcpy(data, &iclass_last_known_card, sizeof(picopass_hdr_t));
|
||||||
|
memcpy(data + (6*8), o->data, sizeof(o->data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// create filename
|
||||||
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
char *fptr = filename;
|
||||||
|
fptr += snprintf(fptr, sizeof(filename), "hf-iclass-");
|
||||||
|
FillFileNameByUID(fptr, data, "-dump", 8);
|
||||||
|
|
||||||
|
// save dump file
|
||||||
|
saveFile(filename, ".bin", data, tot_bytes);
|
||||||
|
saveFileEML(filename, data, tot_bytes, 8);
|
||||||
|
saveFileJSON(filename, jsfIclass, data, tot_bytes, NULL);
|
||||||
|
|
||||||
|
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f %s.bin") "` to view dump file", filename);
|
||||||
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t isset(uint8_t val, uint8_t mask) {
|
static uint8_t isset(uint8_t val, uint8_t mask) {
|
||||||
|
@ -219,11 +346,11 @@ static uint8_t notset(uint8_t val, uint8_t mask) {
|
||||||
return !(val & mask);
|
return !(val & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t get_pagemap(const picopass_hdr *hdr) {
|
uint8_t get_pagemap(const picopass_hdr_t *hdr) {
|
||||||
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
|
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fuse_config(const picopass_hdr *hdr) {
|
static void fuse_config(const picopass_hdr_t *hdr) {
|
||||||
|
|
||||||
uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]);
|
uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]);
|
||||||
|
|
||||||
|
@ -308,7 +435,7 @@ static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *app_areas,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t get_mem_config(const picopass_hdr *hdr) {
|
static uint8_t get_mem_config(const picopass_hdr_t *hdr) {
|
||||||
// three configuration bits that decides sizes
|
// three configuration bits that decides sizes
|
||||||
uint8_t type = (hdr->conf.chip_config & 0x10) >> 2;
|
uint8_t type = (hdr->conf.chip_config & 0x10) >> 2;
|
||||||
// 16K bit 0 == 1==
|
// 16K bit 0 == 1==
|
||||||
|
@ -320,7 +447,7 @@ static uint8_t get_mem_config(const picopass_hdr *hdr) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mem_app_config(const picopass_hdr *hdr) {
|
static void mem_app_config(const picopass_hdr_t *hdr) {
|
||||||
uint8_t mem = hdr->conf.mem_config;
|
uint8_t mem = hdr->conf.mem_config;
|
||||||
uint8_t chip = hdr->conf.chip_config;
|
uint8_t chip = hdr->conf.chip_config;
|
||||||
uint8_t kb = 2;
|
uint8_t kb = 2;
|
||||||
|
@ -365,13 +492,13 @@ static void mem_app_config(const picopass_hdr *hdr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_picopass_info(const picopass_hdr *hdr) {
|
static void print_picopass_info(const picopass_hdr_t *hdr) {
|
||||||
PrintAndLogEx(INFO, "-------------------- " _CYAN_("card configuration") " --------------------");
|
PrintAndLogEx(INFO, "-------------------- " _CYAN_("card configuration") " --------------------");
|
||||||
fuse_config(hdr);
|
fuse_config(hdr);
|
||||||
mem_app_config(hdr);
|
mem_app_config(hdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_picopass_header(const picopass_hdr *hdr) {
|
static void print_picopass_header(const picopass_hdr_t *hdr) {
|
||||||
PrintAndLogEx(INFO, "--------------------------- " _CYAN_("card") " ---------------------------");
|
PrintAndLogEx(INFO, "--------------------------- " _CYAN_("card") " ---------------------------");
|
||||||
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn)));
|
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn)));
|
||||||
PrintAndLogEx(SUCCESS, " Config: %s Card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
|
PrintAndLogEx(SUCCESS, " Config: %s Card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
|
||||||
|
@ -555,7 +682,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 -f iclass_mac_attack.bin") "` to recover elite key");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ICLASS_SIM_MODE_READER_ATTACK_KEYROLL: {
|
case ICLASS_SIM_MODE_READER_ATTACK_KEYROLL: {
|
||||||
|
@ -621,7 +748,8 @@ 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 -f iclass_mac_attack_keyroll_A.bin") "` to recover elite key");
|
||||||
|
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -f iclass_mac_attack_keyroll_B.bin") "` to recover elite key");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ICLASS_SIM_MODE_CSN:
|
case ICLASS_SIM_MODE_CSN:
|
||||||
|
@ -683,9 +811,16 @@ int read_iclass_csn(bool loop, bool verbose) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
picopass_hdr *hdr = (picopass_hdr *)resp.data.asBytes;
|
picopass_hdr_t *card = calloc(1, sizeof(picopass_hdr_t));
|
||||||
PrintAndLogEx(NORMAL, "");
|
if (card) {
|
||||||
PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(hdr->csn, sizeof(hdr->csn)));
|
memcpy(card, (picopass_hdr_t *)resp.data.asBytes, sizeof(picopass_hdr_t));
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn)));
|
||||||
|
iclass_set_last_known_card(card);
|
||||||
|
free(card);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (loop && kbd_enter_pressed() == false);
|
} while (loop && kbd_enter_pressed() == false);
|
||||||
|
|
||||||
|
@ -800,8 +935,8 @@ static int CmdHFiClassELoad(const char *Cmd) {
|
||||||
dump = newdump;
|
dump = newdump;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_picopass_header((picopass_hdr *) dump);
|
print_picopass_header((picopass_hdr_t *) dump);
|
||||||
print_picopass_info((picopass_hdr *) dump);
|
print_picopass_info((picopass_hdr_t *) dump);
|
||||||
|
|
||||||
// fast push mode
|
// fast push mode
|
||||||
conn.block_after_ACK = true;
|
conn.block_after_ACK = true;
|
||||||
|
@ -882,7 +1017,7 @@ static int CmdHFiClassESave(const char *Cmd) {
|
||||||
saveFileJSON(filename, jsfIclass, dump, bytes, NULL);
|
saveFileJSON(filename, jsfIclass, dump, bytes, NULL);
|
||||||
free(dump);
|
free(dump);
|
||||||
|
|
||||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view") "` to view dump file");
|
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f %s.bin") "` to view dump file", filename);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -935,8 +1070,8 @@ static int CmdHFiClassEView(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
print_picopass_header((picopass_hdr *) dump);
|
print_picopass_header((picopass_hdr_t *) dump);
|
||||||
print_picopass_info((picopass_hdr *) dump);
|
print_picopass_info((picopass_hdr_t *) dump);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
@ -1056,7 +1191,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||||
|
|
||||||
if (have_file) {
|
if (have_file) {
|
||||||
|
|
||||||
picopass_hdr *hdr = (picopass_hdr *)decrypted;
|
picopass_hdr_t *hdr = (picopass_hdr_t *)decrypted;
|
||||||
|
|
||||||
uint8_t mem = hdr->conf.mem_config;
|
uint8_t mem = hdr->conf.mem_config;
|
||||||
uint8_t chip = hdr->conf.chip_config;
|
uint8_t chip = hdr->conf.chip_config;
|
||||||
|
@ -1291,7 +1426,7 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
picopass_hdr *hdr = (picopass_hdr *)resp.data.asBytes;
|
picopass_hdr_t *hdr = (picopass_hdr_t *)resp.data.asBytes;
|
||||||
|
|
||||||
if (CSN != NULL)
|
if (CSN != NULL)
|
||||||
memcpy(CSN, hdr->csn, 8);
|
memcpy(CSN, hdr->csn, 8);
|
||||||
|
@ -1436,7 +1571,7 @@ static int CmdHFiClassDump(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
uint8_t readStatus = resp.oldarg[0] & 0xff;
|
uint8_t readStatus = resp.oldarg[0] & 0xff;
|
||||||
picopass_hdr *hdr = (picopass_hdr *)resp.data.asBytes;
|
picopass_hdr_t *hdr = (picopass_hdr_t *)resp.data.asBytes;
|
||||||
|
|
||||||
if (readStatus == 0) {
|
if (readStatus == 0) {
|
||||||
PrintAndLogEx(FAILED, "no tag found");
|
PrintAndLogEx(FAILED, "no tag found");
|
||||||
|
@ -1645,8 +1780,8 @@ write_dump:
|
||||||
saveFileEML(filename, tag_data, bytes_got, 8);
|
saveFileEML(filename, tag_data, bytes_got, 8);
|
||||||
saveFileJSON(filename, jsfIclass, tag_data, bytes_got, NULL);
|
saveFileJSON(filename, jsfIclass, tag_data, bytes_got, NULL);
|
||||||
|
|
||||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass decrypt") "` to decrypt dump file");
|
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass decrypt -f %s.bin") "` to decrypt dump file", filename);
|
||||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view") "` to view dump file");
|
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f %s.bin") "` to view dump file", filename);
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -1941,7 +2076,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
|
||||||
|
|
||||||
if (resp.status == PM3_SUCCESS) {
|
if (resp.status == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(SUCCESS, "iCLASS restore " _GREEN_("successful"));
|
PrintAndLogEx(SUCCESS, "iCLASS restore " _GREEN_("successful"));
|
||||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass rdbl ") "` to verify data on card");
|
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass rdbl") "` to verify data on card");
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "iCLASS restore " _RED_("failed"));
|
PrintAndLogEx(WARNING, "iCLASS restore " _RED_("failed"));
|
||||||
}
|
}
|
||||||
|
@ -2201,8 +2336,8 @@ static int CmdHFiClass_loclass(const char *Cmd) {
|
||||||
|
|
||||||
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) {
|
||||||
|
|
||||||
picopass_hdr *hdr = (picopass_hdr *)iclass_dump;
|
picopass_hdr_t *hdr = (picopass_hdr_t *)iclass_dump;
|
||||||
// picopass_ns_hdr *ns_hdr = (picopass_ns_hdr *)iclass_dump;
|
// picopass_ns_hdr_t *ns_hdr = (picopass_ns_hdr_t *)iclass_dump;
|
||||||
// uint8_t pagemap = get_pagemap(hdr);
|
// uint8_t pagemap = get_pagemap(hdr);
|
||||||
// if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { }
|
// if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { }
|
||||||
|
|
||||||
|
@ -2357,8 +2492,8 @@ static int CmdHFiClassView(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
print_picopass_header((picopass_hdr *) dump);
|
print_picopass_header((picopass_hdr_t *) dump);
|
||||||
print_picopass_info((picopass_hdr *) dump);
|
print_picopass_info((picopass_hdr_t *) dump);
|
||||||
printIclassDumpContents(dump, startblock, endblock, bytes_read);
|
printIclassDumpContents(dump, startblock, endblock, bytes_read);
|
||||||
free(dump);
|
free(dump);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -2700,7 +2835,7 @@ static void add_key(uint8_t *key) {
|
||||||
if (i == ICLASS_KEYS_MAX) {
|
if (i == ICLASS_KEYS_MAX) {
|
||||||
PrintAndLogEx(INFO, "Couldn't find an empty keyslot");
|
PrintAndLogEx(INFO, "Couldn't find an empty keyslot");
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf iclass managekeys -p`") " to view keys");
|
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass managekeys -p") "` to view keys");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3578,14 +3713,17 @@ static int CmdHFiClassConfigCard(const char * Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf iclass configcard",
|
CLIParserInit(&ctx, "hf iclass configcard",
|
||||||
"Manage reader configuration card via Cardhelper",
|
"Manage reader configuration card via Cardhelper",
|
||||||
"hf iclass configcard -l --> download config cards "
|
"hf iclass configcard -l --> download config cards\n"
|
||||||
"hf iclass configcard -p --> print config card"
|
"hf iclass configcard -p --> print config card\n"
|
||||||
"hf iclass configcard -g --ki 1 --> generate config dump file based on idx 1"
|
"hf iclass configcard --ci 1 --> use config card in slot 1\n"
|
||||||
|
"hf iclass configcard -g --ci 0 --> generate config file from slot 0"
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_int0(NULL, "ki", "<dec>", "select index in list"),
|
arg_int0(NULL, "ci", "<dec>", "use config slot at index"),
|
||||||
|
arg_int0(NULL, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
|
||||||
arg_lit0("g", NULL, "generate card dump file"),
|
arg_lit0("g", NULL, "generate card dump file"),
|
||||||
arg_lit0("l", NULL, "load available cards"),
|
arg_lit0("l", NULL, "load available cards"),
|
||||||
arg_lit0("p", NULL, "print available cards"),
|
arg_lit0("p", NULL, "print available cards"),
|
||||||
|
@ -3593,12 +3731,26 @@ static int CmdHFiClassConfigCard(const char * Cmd) {
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
int idx = arg_get_int_def(ctx, 1, -1);
|
int ccidx = arg_get_int_def(ctx, 1, -1);
|
||||||
bool generate = arg_get_lit(ctx, 2);
|
int kidx = arg_get_int_def(ctx, 2, -1);
|
||||||
bool load = arg_get_lit(ctx, 3);
|
bool generate = arg_get_lit(ctx, 3);
|
||||||
bool print = arg_get_lit(ctx, 4);
|
bool load = arg_get_lit(ctx, 4);
|
||||||
|
bool print = arg_get_lit(ctx, 5);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
bool got_kr = false;
|
||||||
|
uint8_t key[8] = {0};
|
||||||
|
if (kidx >= 0) {
|
||||||
|
if (kidx < ICLASS_KEYS_MAX) {
|
||||||
|
got_kr = true;
|
||||||
|
memcpy(key, iClass_Key_Table[kidx], 8);
|
||||||
|
PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), kidx, sprint_hex(iClass_Key_Table[kidx], 8));
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(ERR, "--ki number is invalid");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (load) {
|
if (load) {
|
||||||
if (load_config_cards() != PM3_SUCCESS) {
|
if (load_config_cards() != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(INFO, "failed to load, check your cardhelper");
|
PrintAndLogEx(INFO, "failed to load, check your cardhelper");
|
||||||
|
@ -3609,14 +3761,20 @@ static int CmdHFiClassConfigCard(const char * Cmd) {
|
||||||
print_config_cards();
|
print_config_cards();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx > -1 && idx < 14) {
|
if (ccidx > -1 && ccidx < 14) {
|
||||||
const iclass_config_card_item_t *item = get_config_card_item(idx);
|
const iclass_config_card_item_t *item = get_config_card_item(ccidx);
|
||||||
print_config_card(item);
|
print_config_card(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (generate) {
|
if (generate) {
|
||||||
const iclass_config_card_item_t *item = get_config_card_item(idx);
|
const iclass_config_card_item_t *item = get_config_card_item(ccidx);
|
||||||
generate_config_card(item);
|
if (strstr(item->desc, "Keyroll") != NULL) {
|
||||||
|
if (got_kr == false) {
|
||||||
|
PrintAndLogEx(ERR, "please specifiy KEYROLL key!");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generate_config_card(item, key, got_kr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -3700,8 +3858,8 @@ int info_iclass(void) {
|
||||||
return PM3_EOPABORTED;
|
return PM3_EOPABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
picopass_hdr *hdr = (picopass_hdr *)resp.data.asBytes;
|
picopass_hdr_t *hdr = (picopass_hdr_t *)resp.data.asBytes;
|
||||||
picopass_ns_hdr *ns_hdr = (picopass_ns_hdr *)resp.data.asBytes;
|
picopass_ns_hdr_t *ns_hdr = (picopass_ns_hdr_t *)resp.data.asBytes;
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--------------------- " _CYAN_("Tag Information") " ----------------------");
|
PrintAndLogEx(INFO, "--------------------- " _CYAN_("Tag Information") " ----------------------");
|
||||||
|
|
|
@ -30,8 +30,7 @@ typedef struct iclass_prekey {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char desc[70];
|
char desc[70];
|
||||||
uint8_t blk6[8];
|
uint8_t data[16];
|
||||||
uint8_t blk7[8];
|
|
||||||
} iclass_config_card_item_t;
|
} iclass_config_card_item_t;
|
||||||
|
|
||||||
int CmdHFiClass(const char *Cmd);
|
int CmdHFiClass(const char *Cmd);
|
||||||
|
@ -46,6 +45,6 @@ void GenerateMacKeyFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elit
|
||||||
void PrintPreCalcMac(uint8_t *keys, uint32_t keycnt, iclass_premac_t *pre_list);
|
void PrintPreCalcMac(uint8_t *keys, uint32_t keycnt, iclass_premac_t *pre_list);
|
||||||
void PrintPreCalc(iclass_prekey_t *list, uint32_t itemcnt);
|
void PrintPreCalc(iclass_prekey_t *list, uint32_t itemcnt);
|
||||||
|
|
||||||
uint8_t get_pagemap(const picopass_hdr *hdr);
|
uint8_t get_pagemap(const picopass_hdr_t *hdr);
|
||||||
bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t *tmac, uint8_t *key);
|
bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t *tmac, uint8_t *key);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -255,28 +255,44 @@ static void PrintATR(uint8_t *atr, size_t atrlen) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smart_wait(uint8_t *data, bool verbose) {
|
static int smart_wait(uint8_t *out, int maxoutlen, bool verbose) {
|
||||||
int i = 5;
|
int i = 4;
|
||||||
uint32_t len = 0;
|
uint32_t len = 0;
|
||||||
do {
|
do {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
if (WaitForResponseTimeout(CMD_SMART_RAW, &resp, 1000)) {
|
||||||
|
|
||||||
|
if (resp.status != PM3_SUCCESS) {
|
||||||
|
if (verbose) PrintAndLogEx(WARNING, "smart card response status failed");
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
len = resp.oldarg[0];
|
len = resp.length;
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
if (verbose) PrintAndLogEx(WARNING, "smart card response failed");
|
if (verbose) PrintAndLogEx(WARNING, "smart card response failed");
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(data, resp.data.asBytes, len);
|
if (len > maxoutlen) {
|
||||||
|
if (verbose) PrintAndLogEx(ERR, "Response too large. Got %u, expected %d", len, maxoutlen);
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(out, resp.data.asBytes, len);
|
||||||
if (len >= 2) {
|
if (len >= 2) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(SUCCESS, "%02X%02X | %s", data[len - 2], data[len - 1], GetAPDUCodeDescription(data[len - 2], data[len - 1]));
|
|
||||||
|
|
||||||
|
if (out[len - 2] == 0x90 && out[len - 1] == 0x00) {
|
||||||
|
PrintAndLogEx(SUCCESS, _GREEN_("%02X%02X") " | %s", out[len - 2], out[len - 1], GetAPDUCodeDescription(out[len - 2], out[len - 1]));
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(SUCCESS, "%02X%02X | %s", out[len - 2], out[len - 1], GetAPDUCodeDescription(out[len - 2], out[len - 1]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 8));
|
PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(out, len, 8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
|
@ -289,29 +305,35 @@ static int smart_wait(uint8_t *data, bool verbose) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smart_responseEx(uint8_t *data, bool verbose) {
|
static int smart_responseEx(uint8_t *out, int maxoutlen, bool verbose) {
|
||||||
|
|
||||||
int datalen = smart_wait(data, verbose);
|
int datalen = smart_wait(out, maxoutlen, verbose);
|
||||||
bool needGetData = false;
|
bool needGetData = false;
|
||||||
|
|
||||||
if (datalen < 2) {
|
if (datalen < 2) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data[datalen - 2] == 0x61 || data[datalen - 2] == 0x9F) {
|
if (out[datalen - 2] == 0x61 || out[datalen - 2] == 0x9F) {
|
||||||
needGetData = true;
|
needGetData = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needGetData) {
|
if (needGetData) {
|
||||||
int len = data[datalen - 1];
|
int len = out[datalen - 1];
|
||||||
|
|
||||||
if (verbose) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len);
|
if (verbose) PrintAndLogEx(INFO, "Requesting " _YELLOW_("0x%02X") " bytes response", len);
|
||||||
|
|
||||||
|
uint8_t cmd_getresp[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len};
|
||||||
|
smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(cmd_getresp));
|
||||||
|
payload->flags = SC_RAW | SC_LOG;
|
||||||
|
payload->len = sizeof(cmd_getresp);
|
||||||
|
memcpy(payload->data, cmd_getresp, sizeof(cmd_getresp));
|
||||||
|
|
||||||
uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len};
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_SMART_RAW, SC_RAW, sizeof(getstatus), 0, getstatus, sizeof(getstatus));
|
SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + sizeof(cmd_getresp));
|
||||||
|
free(payload);
|
||||||
|
|
||||||
datalen = smart_wait(data, verbose);
|
datalen = smart_wait(out, maxoutlen, verbose);
|
||||||
|
|
||||||
if (datalen < 2) {
|
if (datalen < 2) {
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -321,16 +343,16 @@ static int smart_responseEx(uint8_t *data, bool verbose) {
|
||||||
if (datalen != len + 2) {
|
if (datalen != len + 2) {
|
||||||
// data with ACK
|
// data with ACK
|
||||||
if (datalen == len + 2 + 1) { // 2 - response, 1 - ACK
|
if (datalen == len + 2 + 1) { // 2 - response, 1 - ACK
|
||||||
if (data[0] != ISO7816_GET_RESPONSE) {
|
if (out[0] != ISO7816_GET_RESPONSE) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(ERR, "GetResponse ACK error. len 0x%x | data[0] %02X", len, data[0]);
|
PrintAndLogEx(ERR, "GetResponse ACK error. len 0x%x | data[0] %02X", len, out[0]);
|
||||||
}
|
}
|
||||||
datalen = 0;
|
datalen = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
datalen--;
|
datalen--;
|
||||||
memmove(data, &data[1], datalen);
|
memmove(out, &out[1], datalen);
|
||||||
} else {
|
} else {
|
||||||
// wrong length
|
// wrong length
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
@ -344,8 +366,8 @@ out:
|
||||||
return datalen;
|
return datalen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smart_response(uint8_t *data) {
|
static int smart_response(uint8_t *out, int maxoutlen) {
|
||||||
return smart_responseEx(data, true);
|
return smart_responseEx(out, maxoutlen, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdSmartRaw(const char *Cmd) {
|
static int CmdSmartRaw(const char *Cmd) {
|
||||||
|
@ -386,61 +408,76 @@ static int CmdSmartRaw(const char *Cmd) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t flags = SC_LOG;
|
smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + dlen);
|
||||||
|
if (payload == NULL) {
|
||||||
|
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
payload->len = dlen;
|
||||||
|
memcpy(payload->data, data, dlen);
|
||||||
|
|
||||||
|
payload->flags = SC_LOG;
|
||||||
if (active || active_select) {
|
if (active || active_select) {
|
||||||
|
|
||||||
flags |= (SC_CONNECT | SC_CLEARLOG);
|
payload->flags |= (SC_CONNECT | SC_CLEARLOG);
|
||||||
if (active_select)
|
if (active_select)
|
||||||
flags |= SC_SELECT;
|
payload->flags |= SC_SELECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dlen > 0) {
|
if (dlen > 0) {
|
||||||
if (use_t0)
|
if (use_t0)
|
||||||
flags |= SC_RAW_T0;
|
payload->flags |= SC_RAW_T0;
|
||||||
else
|
else
|
||||||
flags |= SC_RAW;
|
payload->flags |= SC_RAW;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *buf = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
|
||||||
|
if (buf == NULL) {
|
||||||
|
PrintAndLogEx(DEBUG, "failed to allocate memory");
|
||||||
|
return PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_SMART_RAW, flags, dlen, 0, data, dlen);
|
SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + dlen);
|
||||||
|
|
||||||
|
if (reply == false) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
// reading response from smart card
|
// reading response from smart card
|
||||||
if (reply) {
|
int len = smart_response(buf, PM3_CMD_DATA_SIZE);
|
||||||
|
if (len < 0) {
|
||||||
uint8_t *buf = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
|
|
||||||
if (!buf)
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
|
|
||||||
int len = smart_response(buf);
|
|
||||||
if (len < 0) {
|
|
||||||
free(buf);
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf[0] == 0x6C) {
|
|
||||||
data[4] = buf[1];
|
|
||||||
|
|
||||||
clearCommandBuffer();
|
|
||||||
SendCommandMIX(CMD_SMART_RAW, 0, dlen, 0, data, dlen);
|
|
||||||
len = smart_response(buf);
|
|
||||||
|
|
||||||
data[4] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decode_tlv && len > 4)
|
|
||||||
TLVPrintFromBuffer(buf, len - 2);
|
|
||||||
else {
|
|
||||||
if (len > 16) {
|
|
||||||
for (int i = 0; i < len; i += 16) {
|
|
||||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex_ascii(buf + i, 16)) ;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex_ascii(buf, len)) ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buf[0] == 0x6C) {
|
||||||
|
|
||||||
|
// request more bytes to download
|
||||||
|
data[4] = buf[1];
|
||||||
|
memcpy(payload->data, data, dlen);
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + dlen);
|
||||||
|
|
||||||
|
len = smart_response(buf, PM3_CMD_DATA_SIZE);
|
||||||
|
|
||||||
|
data[4] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decode_tlv && len > 4)
|
||||||
|
TLVPrintFromBuffer(buf, len - 2);
|
||||||
|
else {
|
||||||
|
if (len > 2) {
|
||||||
|
PrintAndLogEx(INFO, "Response data:");
|
||||||
|
PrintAndLogEx(INFO, " # | bytes | ascii");
|
||||||
|
PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
|
||||||
|
print_hex_break(buf, len, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
out:
|
||||||
|
free(payload);
|
||||||
|
free(buf);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,7 +669,7 @@ static int CmdSmartInfo(const char *Cmd) {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_SMART_ATR, NULL, 0);
|
SendCommandNG(CMD_SMART_ATR, NULL, 0);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500)) {
|
if (WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500) == false) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(WARNING, "smart card timeout");
|
PrintAndLogEx(WARNING, "smart card timeout");
|
||||||
}
|
}
|
||||||
|
@ -683,7 +720,6 @@ static int CmdSmartInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdSmartReader(const char *Cmd) {
|
static int CmdSmartReader(const char *Cmd) {
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "smart reader",
|
CLIParserInit(&ctx, "smart reader",
|
||||||
"Act as a smart card reader.",
|
"Act as a smart card reader.",
|
||||||
|
@ -702,7 +738,7 @@ static int CmdSmartReader(const char *Cmd) {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_SMART_ATR, NULL, 0);
|
SendCommandNG(CMD_SMART_ATR, NULL, 0);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500)) {
|
if (WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500) == false) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(WARNING, "smart card select failed");
|
PrintAndLogEx(WARNING, "smart card select failed");
|
||||||
}
|
}
|
||||||
|
@ -715,10 +751,8 @@ static int CmdSmartReader(const char *Cmd) {
|
||||||
}
|
}
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
smart_card_atr_t card;
|
smart_card_atr_t *card = (smart_card_atr_t *)resp.data.asBytes;
|
||||||
memcpy(&card, (smart_card_atr_t *)resp.data.asBytes, sizeof(smart_card_atr_t));
|
PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card->atr, card->atr_len));
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -816,17 +850,18 @@ static void smart_brute_prim(void) {
|
||||||
|
|
||||||
for (int i = 0; i < ARRAYLEN(get_card_data); i += 5) {
|
for (int i = 0; i < ARRAYLEN(get_card_data); i += 5) {
|
||||||
|
|
||||||
|
smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + 5);
|
||||||
|
payload->flags = SC_RAW_T0;
|
||||||
|
payload->len = 5;
|
||||||
|
memcpy(payload->data, get_card_data + i, 5);
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, 5, 0, get_card_data + i, 5);
|
SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + 5);
|
||||||
|
free(payload);
|
||||||
int len = smart_responseEx(buf, false);
|
|
||||||
|
|
||||||
|
int len = smart_responseEx(buf, PM3_CMD_DATA_SIZE, false);
|
||||||
if (len > 2) {
|
if (len > 2) {
|
||||||
// if ( decodeTLV ) {
|
|
||||||
// if (!TLVPrintFromBuffer(buf, len-2)) {
|
|
||||||
PrintAndLogEx(SUCCESS, "\tHEX %d |: %s", len, sprint_hex(buf, len));
|
PrintAndLogEx(SUCCESS, "\tHEX %d |: %s", len, sprint_hex(buf, len));
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(buf);
|
free(buf);
|
||||||
|
@ -858,21 +893,29 @@ static int smart_brute_sfi(bool decodeTLV) {
|
||||||
READ_RECORD[2] = rec;
|
READ_RECORD[2] = rec;
|
||||||
READ_RECORD[3] = (sfi << 3) | 4;
|
READ_RECORD[3] = (sfi << 3) | 4;
|
||||||
|
|
||||||
clearCommandBuffer();
|
smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(READ_RECORD));
|
||||||
SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, sizeof(READ_RECORD), 0, READ_RECORD, sizeof(READ_RECORD));
|
payload->flags = SC_RAW_T0;
|
||||||
|
payload->len = sizeof(READ_RECORD);
|
||||||
|
memcpy(payload->data, READ_RECORD, sizeof(READ_RECORD));
|
||||||
|
|
||||||
len = smart_responseEx(buf, false);
|
clearCommandBuffer();
|
||||||
|
SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + sizeof(READ_RECORD));
|
||||||
|
|
||||||
|
len = smart_responseEx(buf, PM3_CMD_DATA_SIZE, false);
|
||||||
|
|
||||||
if (buf[0] == 0x6C) {
|
if (buf[0] == 0x6C) {
|
||||||
READ_RECORD[4] = buf[1];
|
READ_RECORD[4] = buf[1];
|
||||||
|
|
||||||
|
memcpy(payload->data, READ_RECORD, sizeof(READ_RECORD));
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, sizeof(READ_RECORD), 0, READ_RECORD, sizeof(READ_RECORD));
|
SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + sizeof(READ_RECORD));
|
||||||
len = smart_responseEx(buf, false);
|
len = smart_responseEx(buf, PM3_CMD_DATA_SIZE, false);
|
||||||
|
|
||||||
READ_RECORD[4] = 0;
|
READ_RECORD[4] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(payload);
|
||||||
|
|
||||||
if (len > 4) {
|
if (len > 4) {
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "\n\t file %02d, record %02d found", sfi, rec);
|
PrintAndLogEx(SUCCESS, "\n\t file %02d, record %02d found", sfi, rec);
|
||||||
|
@ -898,13 +941,19 @@ static void smart_brute_options(bool decodeTLV) {
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Get processing options command
|
||||||
uint8_t GET_PROCESSING_OPTIONS[] = {0x80, 0xA8, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00};
|
uint8_t GET_PROCESSING_OPTIONS[] = {0x80, 0xA8, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00};
|
||||||
|
|
||||||
// Get processing options command
|
smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(GET_PROCESSING_OPTIONS));
|
||||||
clearCommandBuffer();
|
payload->flags = SC_RAW_T0;
|
||||||
SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, sizeof(GET_PROCESSING_OPTIONS), 0, GET_PROCESSING_OPTIONS, sizeof(GET_PROCESSING_OPTIONS));
|
payload->len = sizeof(GET_PROCESSING_OPTIONS);
|
||||||
|
memcpy(payload->data, GET_PROCESSING_OPTIONS, sizeof(GET_PROCESSING_OPTIONS));
|
||||||
|
|
||||||
int len = smart_responseEx(buf, false);
|
clearCommandBuffer();
|
||||||
|
SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + sizeof(GET_PROCESSING_OPTIONS));
|
||||||
|
free(payload);
|
||||||
|
|
||||||
|
int len = smart_responseEx(buf, PM3_CMD_DATA_SIZE, false);
|
||||||
if (len > 4) {
|
if (len > 4) {
|
||||||
PrintAndLogEx(SUCCESS, "Got processing options");
|
PrintAndLogEx(SUCCESS, "Got processing options");
|
||||||
if (decodeTLV) {
|
if (decodeTLV) {
|
||||||
|
@ -997,10 +1046,16 @@ static int CmdSmartBruteforceSFI(const char *Cmd) {
|
||||||
if (res)
|
if (res)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
clearCommandBuffer();
|
smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + hexlen);
|
||||||
SendCommandOLD(CMD_SMART_RAW, SC_RAW_T0, hexlen, 0, cmddata, hexlen);
|
payload->flags = SC_RAW_T0;
|
||||||
|
payload->len = hexlen;
|
||||||
|
|
||||||
int len = smart_responseEx(buf, false);
|
memcpy(payload->data, cmddata, hexlen);
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + hexlen);
|
||||||
|
free(payload);
|
||||||
|
|
||||||
|
int len = smart_responseEx(buf, PM3_CMD_DATA_SIZE, false);
|
||||||
if (len < 3)
|
if (len < 3)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1072,43 +1127,38 @@ int ExchangeAPDUSC(bool verbose, uint8_t *datain, int datainlen, bool activateCa
|
||||||
|
|
||||||
*dataoutlen = 0;
|
*dataoutlen = 0;
|
||||||
|
|
||||||
|
smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + datainlen);
|
||||||
|
payload->flags = (SC_RAW_T0 | SC_LOG);
|
||||||
if (activateCard) {
|
if (activateCard) {
|
||||||
if (smart_select(false, NULL) == false) {
|
payload->flags |= (SC_SELECT | SC_CONNECT);
|
||||||
PrintAndLogEx(DEBUG, "APDU SC - select card failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(DEBUG, "APDU SC");
|
|
||||||
|
|
||||||
uint8_t flags = SC_RAW_T0;
|
|
||||||
if (activateCard) {
|
|
||||||
flags |= SC_SELECT | SC_CONNECT;
|
|
||||||
}
|
}
|
||||||
|
payload->len = datainlen;
|
||||||
|
memcpy(payload->data, datain, datainlen);
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_SMART_RAW, flags, datainlen, 0, datain, datainlen);
|
SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + datainlen);
|
||||||
|
|
||||||
int len = smart_responseEx(dataout, verbose);
|
int len = smart_responseEx(dataout, maxdataoutlen, verbose);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// retry
|
// retry
|
||||||
if (len > 1 && dataout[len - 2] == 0x6c && datainlen > 4) {
|
if (len > 1 && dataout[len - 2] == 0x6c && datainlen > 4) {
|
||||||
uint8_t data [5];
|
|
||||||
memcpy(data, datain, 5);
|
|
||||||
|
|
||||||
|
payload->flags = SC_RAW_T0;
|
||||||
|
payload->len = 5;
|
||||||
// transfer length via T=0
|
// transfer length via T=0
|
||||||
data[4] = dataout[len - 1];
|
datain[4] = dataout[len - 1];
|
||||||
|
memcpy(payload->data, datain, 5);
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
// something fishy: we have only 5 bytes but we put datainlen in arg1?
|
SendCommandNG(CMD_SMART_RAW, (uint8_t*)payload, sizeof(smart_card_raw_t) + 5);
|
||||||
SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, datainlen, 0, data, sizeof(data));
|
datain[4] = 0;
|
||||||
|
len = smart_responseEx(dataout, maxdataoutlen, verbose);
|
||||||
len = smart_responseEx(dataout, verbose);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(payload);
|
||||||
|
|
||||||
*dataoutlen = len;
|
*dataoutlen = len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1120,9 +1170,8 @@ bool smart_select(bool verbose, smart_card_atr_t *atr) {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_SMART_ATR, NULL, 0);
|
SendCommandNG(CMD_SMART_ATR, NULL, 0);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500)) {
|
if (WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500) == false) {
|
||||||
|
if (verbose) PrintAndLogEx(WARNING, "smart card select timeouted");
|
||||||
if (verbose) PrintAndLogEx(WARNING, "smart card select failed");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#define CMDSMARTCARD_H__
|
#define CMDSMARTCARD_H__
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "mifare.h" // structs
|
#include "pm3_cmd.h" // structs
|
||||||
|
|
||||||
int CmdSmartcard(const char *Cmd);
|
int CmdSmartcard(const char *Cmd);
|
||||||
|
|
||||||
|
|
|
@ -466,13 +466,13 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
|
||||||
case jsfIclass: {
|
case jsfIclass: {
|
||||||
JsonSaveStr(root, "FileType", "iclass");
|
JsonSaveStr(root, "FileType", "iclass");
|
||||||
|
|
||||||
picopass_hdr *hdr = (picopass_hdr *)data;
|
picopass_hdr_t *hdr = (picopass_hdr_t *)data;
|
||||||
JsonSaveBufAsHexCompact(root, "$.Card.CSN", hdr->csn, sizeof(hdr->csn));
|
JsonSaveBufAsHexCompact(root, "$.Card.CSN", hdr->csn, sizeof(hdr->csn));
|
||||||
JsonSaveBufAsHexCompact(root, "$.Card.Configuration", (uint8_t *)&hdr->conf, sizeof(hdr->conf));
|
JsonSaveBufAsHexCompact(root, "$.Card.Configuration", (uint8_t *)&hdr->conf, sizeof(hdr->conf));
|
||||||
|
|
||||||
uint8_t pagemap = get_pagemap(hdr);
|
uint8_t pagemap = get_pagemap(hdr);
|
||||||
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
|
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
|
||||||
picopass_ns_hdr *ns_hdr = (picopass_ns_hdr *)data;
|
picopass_ns_hdr_t *ns_hdr = (picopass_ns_hdr_t *)data;
|
||||||
JsonSaveBufAsHexCompact(root, "$.Card.AIA", ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area));
|
JsonSaveBufAsHexCompact(root, "$.Card.AIA", ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area));
|
||||||
} else {
|
} else {
|
||||||
JsonSaveBufAsHexCompact(root, "$.Card.Epurse", hdr->epurse, sizeof(hdr->epurse));
|
JsonSaveBufAsHexCompact(root, "$.Card.Epurse", hdr->epurse, sizeof(hdr->epurse));
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#define CARD_INS_PINSIZE 0x08
|
#define CARD_INS_PINSIZE 0x08
|
||||||
#define CARD_INS_CC 0x81
|
#define CARD_INS_CC 0x81
|
||||||
#define CARD_INS_CC_DESC 0x82
|
#define CARD_INS_CC_DESC 0x82
|
||||||
static uint8_t cmd[] = {0x96, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
||||||
|
|
||||||
// look for CardHelper
|
// look for CardHelper
|
||||||
bool IsCardHelperPresent(bool verbose) {
|
bool IsCardHelperPresent(bool verbose) {
|
||||||
|
@ -31,7 +30,7 @@ bool IsCardHelperPresent(bool verbose) {
|
||||||
if (IfPm3Smartcard()) {
|
if (IfPm3Smartcard()) {
|
||||||
int resp_len = 0;
|
int resp_len = 0;
|
||||||
uint8_t version[] = {0x96, 0x69, 0x00, 0x00, 0x00};
|
uint8_t version[] = {0x96, 0x69, 0x00, 0x00, 0x00};
|
||||||
uint8_t resp[20] = {0};
|
uint8_t resp[30] = {0};
|
||||||
ExchangeAPDUSC(verbose, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len);
|
ExchangeAPDUSC(verbose, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len);
|
||||||
|
|
||||||
if (resp_len < 8) {
|
if (resp_len < 8) {
|
||||||
|
@ -49,14 +48,12 @@ bool IsCardHelperPresent(bool verbose) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool executeCrypto(uint8_t ins, uint8_t *src, uint8_t *dest) {
|
static bool executeCrypto(uint8_t ins, uint8_t *src, uint8_t *dest) {
|
||||||
int resp_len = 0;
|
uint8_t cmd[] = {0x96, ins, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t dec[11] = {0};
|
|
||||||
|
|
||||||
cmd[1] = ins;
|
|
||||||
memcpy(cmd + 5, src, 8);
|
memcpy(cmd + 5, src, 8);
|
||||||
|
|
||||||
ExchangeAPDUSC(false, cmd, sizeof(cmd), false, false, dec, sizeof(dec), &resp_len);
|
int resp_len = 0;
|
||||||
|
uint8_t dec[11] = {0};
|
||||||
|
ExchangeAPDUSC(false, cmd, sizeof(cmd), false, true, dec, sizeof(dec), &resp_len);
|
||||||
if (resp_len == 10) {
|
if (resp_len == 10) {
|
||||||
memcpy(dest, dec, 8);
|
memcpy(dest, dec, 8);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -121,23 +121,5 @@ typedef struct {
|
||||||
} state;
|
} state;
|
||||||
} PACKED nonces_t;
|
} PACKED nonces_t;
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// ISO 7618 Smart Card
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
typedef struct {
|
|
||||||
uint8_t atr_len;
|
|
||||||
uint8_t atr[50];
|
|
||||||
} PACKED smart_card_atr_t;
|
|
||||||
|
|
||||||
typedef enum SMARTCARD_COMMAND {
|
|
||||||
SC_CONNECT = (1 << 0),
|
|
||||||
SC_NO_DISCONNECT = (1 << 1),
|
|
||||||
SC_RAW = (1 << 2),
|
|
||||||
SC_SELECT = (1 << 3),
|
|
||||||
SC_RAW_T0 = (1 << 4),
|
|
||||||
SC_CLEARLOG = (1 << 5),
|
|
||||||
SC_LOG = (1 << 6),
|
|
||||||
} smartcard_command_t;
|
|
||||||
|
|
||||||
|
|
||||||
#endif // _MIFARE_H_
|
#endif // _MIFARE_H_
|
||||||
|
|
|
@ -368,14 +368,14 @@ typedef struct {
|
||||||
uint8_t key_d[8];
|
uint8_t key_d[8];
|
||||||
uint8_t key_c[8];
|
uint8_t key_c[8];
|
||||||
uint8_t app_issuer_area[8];
|
uint8_t app_issuer_area[8];
|
||||||
} PACKED picopass_hdr;
|
} PACKED picopass_hdr_t;
|
||||||
|
|
||||||
// iCLASS non-secure mode memory mapping
|
// iCLASS non-secure mode memory mapping
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t csn[8];
|
uint8_t csn[8];
|
||||||
picopass_conf_block_t conf;
|
picopass_conf_block_t conf;
|
||||||
uint8_t app_issuer_area[8];
|
uint8_t app_issuer_area[8];
|
||||||
} PACKED picopass_ns_hdr;
|
} PACKED picopass_ns_hdr_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -393,6 +393,31 @@ typedef struct {
|
||||||
uint8_t data[];
|
uint8_t data[];
|
||||||
} PACKED flashmem_write_t;
|
} PACKED flashmem_write_t;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// ISO 7618 Smart Card
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
typedef struct {
|
||||||
|
uint8_t atr_len;
|
||||||
|
uint8_t atr[50];
|
||||||
|
} PACKED smart_card_atr_t;
|
||||||
|
|
||||||
|
typedef enum SMARTCARD_COMMAND {
|
||||||
|
SC_CONNECT = (1 << 0),
|
||||||
|
SC_NO_DISCONNECT = (1 << 1),
|
||||||
|
SC_RAW = (1 << 2),
|
||||||
|
SC_SELECT = (1 << 3),
|
||||||
|
SC_RAW_T0 = (1 << 4),
|
||||||
|
SC_CLEARLOG = (1 << 5),
|
||||||
|
SC_LOG = (1 << 6),
|
||||||
|
} smartcard_command_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t flags;
|
||||||
|
uint16_t len;
|
||||||
|
uint8_t data[];
|
||||||
|
} PACKED smart_card_raw_t;
|
||||||
|
|
||||||
|
|
||||||
// For the bootloader
|
// For the bootloader
|
||||||
#define CMD_DEVICE_INFO 0x0000
|
#define CMD_DEVICE_INFO 0x0000
|
||||||
//#define CMD_SETUP_WRITE 0x0001
|
//#define CMD_SETUP_WRITE 0x0001
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue