mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-07-30 03:28:32 -07:00
Add Smartcard functions (RDV4.0) (#646)
* allow common makefile options-defines * remove non-existing file references * Uncomment lcd option (still) not enabled by default use Makefile_Enabled_Options.common to enable lcd if desired. * Add Smartcard Functions * add smartcard to menu + make get atr work sc is now functioning as far as my limited knowledge takes me * sc cleanup - add init to all sc commands... because cmds won't work until the first init happens. (multiple inits don't appear to affect it negatively) * default options to exclude Smartcard for main repo * update changelog
This commit is contained in:
parent
f684231796
commit
43591e6464
14 changed files with 1661 additions and 22 deletions
|
@ -24,6 +24,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi)
|
||||
|
||||
### Added
|
||||
- Added `sc` smartcard (contact card) commands - reader, info, raw, upgrade, setclock, list (hardware version RDV4.0 only) must turn option on in makefile options (Willok, Iceman, marshmellow)
|
||||
- Added a bitbang mode to `lf cmdread` if delay is 0 the cmd bits turn off and on the antenna with 0 and 1 respectively (marshmellow)
|
||||
- Added PAC/Stanley detection to lf search (marshmellow)
|
||||
- Added lf pac demod and lf pac read - extracts the raw blocks from a PAC/Stanley tag (marshmellow)
|
||||
|
|
|
@ -15,18 +15,22 @@ APP_CFLAGS = -DON_DEVICE \
|
|||
|
||||
include ../common/Makefile_Enabled_Options.common
|
||||
|
||||
ifneq (,$(findstring LCD,$(APP_CFLAGS)))
|
||||
ifneq (,$(findstring WITH_LCD,$(APP_CFLAGS)))
|
||||
SRC_LCD = fonts.c LCD.c
|
||||
else
|
||||
SRC_LCD =
|
||||
endif
|
||||
#SRC_LCD = fonts.c LCD.c
|
||||
SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c protocols.c
|
||||
SRC_ISO15693 = iso15693.c iso15693tools.c
|
||||
SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c mifaresim.c
|
||||
SRC_ISO14443b = iso14443b.c
|
||||
SRC_CRAPTO1 = crypto1.c des.c
|
||||
SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c parity.c
|
||||
ifneq (,$(findstring WITH_SMARTCARD,$(APP_CFLAGS)))
|
||||
SRC_SMARTCARD = i2c.c
|
||||
else
|
||||
SRC_SMARTCARD =
|
||||
endif
|
||||
#the FPGA bitstream files. Note: order matters!
|
||||
FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit
|
||||
|
||||
|
@ -44,6 +48,7 @@ THUMBSRC = start.c \
|
|||
$(SRC_ISO15693) \
|
||||
$(SRC_LF) \
|
||||
$(SRC_ZLIB) \
|
||||
$(SRC_SMARTCARD) \
|
||||
appmain.c \
|
||||
printf.c \
|
||||
util.c \
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
#ifdef WITH_LCD
|
||||
#include "LCD.h"
|
||||
#endif
|
||||
#ifdef WITH_SMARTCARD
|
||||
#include "i2c.h"
|
||||
#endif
|
||||
|
||||
|
||||
// Craig Young - 14a stand-alone code
|
||||
#ifdef WITH_ISO14443a
|
||||
|
@ -357,12 +361,15 @@ void SendStatus(void)
|
|||
{
|
||||
BigBuf_print_status();
|
||||
Fpga_print_status();
|
||||
#ifdef WITH_SMARTCARD
|
||||
I2C_print_status();
|
||||
#endif
|
||||
printConfig(); //LF Sampling config
|
||||
printUSBSpeed();
|
||||
Dbprintf("Various");
|
||||
Dbprintf(" MF_DBGLEVEL......%d", MF_DBGLEVEL);
|
||||
Dbprintf(" ToSendMax........%d",ToSendMax);
|
||||
Dbprintf(" ToSendBit........%d",ToSendBit);
|
||||
Dbprintf(" MF_DBGLEVEL........%d", MF_DBGLEVEL);
|
||||
Dbprintf(" ToSendMax..........%d", ToSendMax);
|
||||
Dbprintf(" ToSendBit..........%d", ToSendBit);
|
||||
|
||||
cmd_send(CMD_ACK,1,0,0,0,0);
|
||||
}
|
||||
|
@ -1253,6 +1260,31 @@ void UsbPacketReceived(uint8_t *packet, int len)
|
|||
HfSnoop(c->arg[0], c->arg[1]);
|
||||
break;
|
||||
#endif
|
||||
#ifdef WITH_SMARTCARD
|
||||
case CMD_SMART_ATR: {
|
||||
SmartCardAtr();
|
||||
break;
|
||||
}
|
||||
case CMD_SMART_SETCLOCK:{
|
||||
SmartCardSetClock(c->arg[0]);
|
||||
break;
|
||||
}
|
||||
case CMD_SMART_RAW: {
|
||||
SmartCardRaw(c->arg[0], c->arg[1], c->d.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_SMART_UPLOAD: {
|
||||
// upload file from client
|
||||
uint8_t *mem = BigBuf_get_addr();
|
||||
memcpy( mem + c->arg[0], c->d.asBytes, USB_CMD_DATA_SIZE);
|
||||
cmd_send(CMD_ACK,1,0,0,0,0);
|
||||
break;
|
||||
}
|
||||
case CMD_SMART_UPGRADE: {
|
||||
SmartCardUpgrade(c->arg[0]);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case CMD_BUFF_CLEAR:
|
||||
BigBuf_Clear();
|
||||
|
|
720
armsrc/i2c.c
Normal file
720
armsrc/i2c.c
Normal file
|
@ -0,0 +1,720 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Willok, June 2018
|
||||
// Edits by Iceman, July 2018
|
||||
//
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
// The main i2c code, for communications with smart card module
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "i2c.h"
|
||||
#include "mifareutil.h" //for mf_dbglevel
|
||||
#include "string.h" //for memset memcmp
|
||||
|
||||
// 定义连接引脚
|
||||
#define GPIO_RST AT91C_PIO_PA1
|
||||
#define GPIO_SCL AT91C_PIO_PA5
|
||||
#define GPIO_SDA AT91C_PIO_PA7
|
||||
|
||||
#define SCL_H HIGH(GPIO_SCL)
|
||||
#define SCL_L LOW(GPIO_SCL)
|
||||
#define SDA_H HIGH(GPIO_SDA)
|
||||
#define SDA_L LOW(GPIO_SDA)
|
||||
|
||||
#define SCL_read (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SCL)
|
||||
#define SDA_read (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SDA)
|
||||
|
||||
#define I2C_ERROR "I2C_WaitAck Error"
|
||||
|
||||
volatile unsigned long c;
|
||||
|
||||
// 直接使用循环来延时,一个循环 6 条指令,48M, Delay=1 大概为 200kbps
|
||||
// timer.
|
||||
// I2CSpinDelayClk(4) = 12.31us
|
||||
// I2CSpinDelayClk(1) = 3.07us
|
||||
void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) {
|
||||
for (c = delay * 2; c; c--) {};
|
||||
}
|
||||
|
||||
// 通讯延迟函数 communication delay function
|
||||
#define I2C_DELAY_1CLK I2CSpinDelayClk(1)
|
||||
#define I2C_DELAY_2CLK I2CSpinDelayClk(2)
|
||||
#define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x))
|
||||
|
||||
|
||||
#define ISO7618_MAX_FRAME 255
|
||||
|
||||
void I2C_init(void) {
|
||||
// 配置复位引脚,关闭上拉,推挽输出,默认高
|
||||
// Configure reset pin, close up pull up, push-pull output, default high
|
||||
AT91C_BASE_PIOA->PIO_PPUDR = GPIO_RST;
|
||||
AT91C_BASE_PIOA->PIO_MDDR = GPIO_RST;
|
||||
|
||||
// 配置 I2C 引脚,开启上拉,开漏输出
|
||||
// Configure I2C pin, open up, open leakage
|
||||
AT91C_BASE_PIOA->PIO_PPUER |= (GPIO_SCL | GPIO_SDA); // 打开上拉 Open up the pull up
|
||||
AT91C_BASE_PIOA->PIO_MDER |= (GPIO_SCL | GPIO_SDA);
|
||||
|
||||
// 默认三根线全部拉高
|
||||
// default three lines all pull up
|
||||
AT91C_BASE_PIOA->PIO_SODR |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
|
||||
|
||||
// 允许输出
|
||||
// allow output
|
||||
AT91C_BASE_PIOA->PIO_OER |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
|
||||
AT91C_BASE_PIOA->PIO_PER |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
|
||||
}
|
||||
|
||||
|
||||
// 设置复位状态
|
||||
// set the reset state
|
||||
void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA) {
|
||||
if (LineRST)
|
||||
HIGH(GPIO_RST);
|
||||
else
|
||||
LOW(GPIO_RST);
|
||||
|
||||
if (LineSCK)
|
||||
HIGH(GPIO_SCL);
|
||||
else
|
||||
LOW(GPIO_SCL);
|
||||
|
||||
if (LineSDA)
|
||||
HIGH(GPIO_SDA);
|
||||
else
|
||||
LOW(GPIO_SDA);
|
||||
}
|
||||
|
||||
// 复位进入主程序
|
||||
// Reset the SIM_Adapter, then enter the main program
|
||||
// Note: the SIM_Adapter will not enter the main program after power up. Please run this function before use SIM_Adapter.
|
||||
void I2C_Reset_EnterMainProgram(void) {
|
||||
I2C_SetResetStatus(0, 0, 0); // 拉低复位线
|
||||
SpinDelay(30);
|
||||
I2C_SetResetStatus(1, 0, 0); // 解除复位
|
||||
SpinDelay(30);
|
||||
I2C_SetResetStatus(1, 1, 1); // 拉高数据线
|
||||
SpinDelay(10);
|
||||
}
|
||||
|
||||
// 复位进入引导模式
|
||||
// Reset the SIM_Adapter, then enter the bootloader program
|
||||
// Reserve:For firmware update.
|
||||
void I2C_Reset_EnterBootloader(void) {
|
||||
I2C_SetResetStatus(0, 1, 1); // 拉低复位线
|
||||
SpinDelay(100);
|
||||
I2C_SetResetStatus(1, 1, 1); // 解除复位
|
||||
SpinDelay(10);
|
||||
}
|
||||
|
||||
// 等待时钟变高
|
||||
// Wait for the clock to go High.
|
||||
bool WaitSCL_H_delay(uint32_t delay) {
|
||||
while (delay--) {
|
||||
if (SCL_read) {
|
||||
return true;
|
||||
}
|
||||
I2C_DELAY_1CLK;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5000 * 3.07us = 15350us. 15.35ms
|
||||
bool WaitSCL_H(void) {
|
||||
return WaitSCL_H_delay(5000);
|
||||
}
|
||||
|
||||
// Wait max 300ms or until SCL goes LOW.
|
||||
// Which ever comes first
|
||||
bool WaitSCL_L_300ms(void) {
|
||||
volatile uint16_t delay = 300;
|
||||
while ( delay-- ) {
|
||||
// exit on SCL LOW
|
||||
if (!SCL_read)
|
||||
return true;
|
||||
|
||||
SpinDelay(1);
|
||||
}
|
||||
return (delay == 0);
|
||||
}
|
||||
|
||||
bool I2C_Start(void) {
|
||||
|
||||
I2C_DELAY_XCLK(4);
|
||||
SDA_H; I2C_DELAY_1CLK;
|
||||
SCL_H;
|
||||
if (!WaitSCL_H()) return false;
|
||||
|
||||
I2C_DELAY_2CLK;
|
||||
|
||||
if (!SCL_read) return false;
|
||||
if (!SDA_read) return false;
|
||||
|
||||
SDA_L; I2C_DELAY_2CLK;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool I2C_WaitForSim() {
|
||||
// variable delay here.
|
||||
if (!WaitSCL_L_300ms())
|
||||
return false;
|
||||
|
||||
// 8051 speaks with smart card.
|
||||
// 1000*50*3.07 = 153.5ms
|
||||
// 1byte transfer == 1ms
|
||||
if (!WaitSCL_H_delay(2000*50) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// send i2c STOP
|
||||
void I2C_Stop(void) {
|
||||
SCL_L; I2C_DELAY_2CLK;
|
||||
SDA_L; I2C_DELAY_2CLK;
|
||||
SCL_H; I2C_DELAY_2CLK;
|
||||
if (!WaitSCL_H()) return;
|
||||
SDA_H;
|
||||
I2C_DELAY_XCLK(8);
|
||||
}
|
||||
|
||||
// Send i2c ACK
|
||||
void I2C_Ack(void) {
|
||||
SCL_L; I2C_DELAY_2CLK;
|
||||
SDA_L; I2C_DELAY_2CLK;
|
||||
SCL_H; I2C_DELAY_2CLK;
|
||||
SCL_L; I2C_DELAY_2CLK;
|
||||
}
|
||||
|
||||
// Send i2c NACK
|
||||
void I2C_NoAck(void) {
|
||||
SCL_L; I2C_DELAY_2CLK;
|
||||
SDA_H; I2C_DELAY_2CLK;
|
||||
SCL_H; I2C_DELAY_2CLK;
|
||||
SCL_L; I2C_DELAY_2CLK;
|
||||
}
|
||||
|
||||
bool I2C_WaitAck(void) {
|
||||
SCL_L; I2C_DELAY_1CLK;
|
||||
SDA_H; I2C_DELAY_1CLK;
|
||||
SCL_H;
|
||||
if (!WaitSCL_H())
|
||||
return false;
|
||||
|
||||
I2C_DELAY_2CLK;
|
||||
if (SDA_read) {
|
||||
SCL_L;
|
||||
return false;
|
||||
}
|
||||
SCL_L;
|
||||
return true;
|
||||
}
|
||||
|
||||
void I2C_SendByte(uint8_t data) {
|
||||
uint8_t i = 8;
|
||||
|
||||
while (i--) {
|
||||
SCL_L; I2C_DELAY_1CLK;
|
||||
|
||||
if (data & 0x80)
|
||||
SDA_H;
|
||||
else
|
||||
SDA_L;
|
||||
|
||||
data <<= 1;
|
||||
I2C_DELAY_1CLK;
|
||||
|
||||
SCL_H;
|
||||
if (!WaitSCL_H())
|
||||
return;
|
||||
|
||||
I2C_DELAY_2CLK;
|
||||
}
|
||||
SCL_L;
|
||||
}
|
||||
|
||||
uint8_t I2C_ReadByte(void) {
|
||||
uint8_t i = 8, b = 0;
|
||||
|
||||
SDA_H;
|
||||
while (i--) {
|
||||
b <<= 1;
|
||||
SCL_L; I2C_DELAY_2CLK;
|
||||
SCL_H;
|
||||
if (!WaitSCL_H())
|
||||
return 0;
|
||||
|
||||
I2C_DELAY_2CLK;
|
||||
if (SDA_read)
|
||||
b |= 0x01;
|
||||
}
|
||||
SCL_L;
|
||||
return b;
|
||||
}
|
||||
|
||||
// Sends one byte ( command to be written, SlaveDevice address)
|
||||
bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address) {
|
||||
bool bBreak = true;
|
||||
do {
|
||||
if (!I2C_Start())
|
||||
return false;
|
||||
//[C0]
|
||||
I2C_SendByte(device_address & 0xFE);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
I2C_SendByte(device_cmd);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
bBreak = false;
|
||||
} while (false);
|
||||
|
||||
I2C_Stop();
|
||||
if (bBreak) {
|
||||
if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 写入1字节数据 (待写入数据,待写入地址,器件类型)
|
||||
// Sends 1 byte data (Data to be written, command to be written , SlaveDevice address ).
|
||||
bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address) {
|
||||
bool bBreak = true;
|
||||
do {
|
||||
if (!I2C_Start())
|
||||
return false;
|
||||
|
||||
I2C_SendByte(device_address & 0xFE);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
I2C_SendByte(device_cmd);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
I2C_SendByte(data);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
bBreak = false;
|
||||
} while (false);
|
||||
|
||||
I2C_Stop();
|
||||
if (bBreak) {
|
||||
if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 写入1串数据(待写入数组地址,待写入长度,待写入地址,器件类型)
|
||||
//Sends a string of data (Array, length, command to be written , SlaveDevice address ).
|
||||
// len = uint8 (max buffer to write 256bytes)
|
||||
bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) {
|
||||
bool bBreak = true;
|
||||
do {
|
||||
if (!I2C_Start())
|
||||
return false;
|
||||
|
||||
I2C_SendByte(device_address & 0xFE);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
I2C_SendByte(device_cmd);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
while (len) {
|
||||
|
||||
I2C_SendByte(*data);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
len--;
|
||||
data++;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
bBreak = false;
|
||||
} while (false);
|
||||
|
||||
I2C_Stop();
|
||||
if (bBreak) {
|
||||
if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 读出1串数据(存放读出数据,待读出长度,带读出地址,器件类型)
|
||||
// read 1 strings of data (Data array, Readout length, command to be written , SlaveDevice address ).
|
||||
// len = uint8 (max buffer to read 256bytes)
|
||||
uint8_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) {
|
||||
|
||||
if ( !data || len == 0 )
|
||||
return 0;
|
||||
|
||||
// extra wait 500us (514us measured)
|
||||
// 200us (xx measured)
|
||||
SpinDelayUs(200);
|
||||
bool bBreak = true;
|
||||
uint8_t readcount = 0;
|
||||
|
||||
do {
|
||||
if (!I2C_Start())
|
||||
return 0;
|
||||
|
||||
// 0xB0 / 0xC0 == i2c write
|
||||
I2C_SendByte(device_address & 0xFE);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
I2C_SendByte(device_cmd);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
// 0xB1 / 0xC1 == i2c read
|
||||
I2C_Start();
|
||||
I2C_SendByte(device_address | 1);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
bBreak = false;
|
||||
} while (false);
|
||||
|
||||
if (bBreak) {
|
||||
I2C_Stop();
|
||||
if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// reading
|
||||
while (len) {
|
||||
|
||||
*data = I2C_ReadByte();
|
||||
|
||||
len--;
|
||||
|
||||
// 读取的第一个字节为后续长度
|
||||
// The first byte in response is the message length
|
||||
if (!readcount && (len > *data)) {
|
||||
len = *data;
|
||||
} else {
|
||||
data++;
|
||||
}
|
||||
readcount++;
|
||||
|
||||
// acknowledgements. After last byte send NACK.
|
||||
if (len == 0)
|
||||
I2C_NoAck();
|
||||
else
|
||||
I2C_Ack();
|
||||
}
|
||||
|
||||
I2C_Stop();
|
||||
// return bytecount - first byte (which is length byte)
|
||||
return (readcount) ? --readcount : 0;
|
||||
}
|
||||
|
||||
uint8_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) {
|
||||
//START, 0xB0, 0x00, 0x00, START, 0xB1, xx, yy, zz, ......, STOP
|
||||
bool bBreak = true;
|
||||
uint8_t readcount = 0;
|
||||
|
||||
// sending
|
||||
do {
|
||||
if (!I2C_Start())
|
||||
return 0;
|
||||
|
||||
// 0xB0 / 0xC0 i2c write
|
||||
I2C_SendByte(device_address & 0xFE);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
// msb
|
||||
I2C_SendByte(msb);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
// lsb
|
||||
I2C_SendByte(lsb);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
// 0xB1 / 0xC1 i2c read
|
||||
I2C_Start();
|
||||
I2C_SendByte(device_address | 1);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
bBreak = false;
|
||||
} while (false);
|
||||
|
||||
if (bBreak) {
|
||||
I2C_Stop();
|
||||
if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// reading
|
||||
while (len) {
|
||||
*data = I2C_ReadByte();
|
||||
|
||||
data++;
|
||||
readcount++;
|
||||
len--;
|
||||
|
||||
// acknowledgements. After last byte send NACK.
|
||||
if (len == 0)
|
||||
I2C_NoAck();
|
||||
else
|
||||
I2C_Ack();
|
||||
}
|
||||
|
||||
I2C_Stop();
|
||||
return readcount;
|
||||
}
|
||||
|
||||
bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) {
|
||||
//START, 0xB0, 0x00, 0x00, xx, yy, zz, ......, STOP
|
||||
bool bBreak = true;
|
||||
|
||||
do {
|
||||
if (!I2C_Start())
|
||||
return false;
|
||||
|
||||
// 0xB0 == i2c write
|
||||
I2C_SendByte(device_address & 0xFE);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
// msb
|
||||
I2C_SendByte(msb);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
// lsb
|
||||
I2C_SendByte(lsb);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
while (len) {
|
||||
I2C_SendByte(*data);
|
||||
if (!I2C_WaitAck())
|
||||
break;
|
||||
|
||||
len--;
|
||||
data++;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
bBreak = false;
|
||||
} while (false);
|
||||
|
||||
I2C_Stop();
|
||||
if (bBreak) {
|
||||
if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void I2C_print_status(void) {
|
||||
DbpString("Smart card module (ISO 7816)");
|
||||
uint8_t resp[] = {0,0,0,0};
|
||||
I2C_init();
|
||||
I2C_Reset_EnterMainProgram();
|
||||
uint8_t len = I2C_BufferRead(resp, sizeof(resp), I2C_DEVICE_CMD_GETVERSION, I2C_DEVICE_ADDRESS_MAIN);
|
||||
if ( len > 0 )
|
||||
Dbprintf(" version.................v%x.%02x", resp[0], resp[1]);
|
||||
else
|
||||
DbpString(" version.................FAILED");
|
||||
}
|
||||
|
||||
bool GetATR(smart_card_atr_t *card_ptr) {
|
||||
|
||||
// clear
|
||||
if ( card_ptr ) {
|
||||
card_ptr->atr_len = 0;
|
||||
memset(card_ptr->atr, 0, sizeof(card_ptr->atr));
|
||||
}
|
||||
|
||||
// Send ATR
|
||||
// start [C0 01] stop start C1 len aa bb cc stop]
|
||||
I2C_WriteCmd(I2C_DEVICE_CMD_GENERATE_ATR, I2C_DEVICE_ADDRESS_MAIN);
|
||||
uint8_t cmd[1] = {1};
|
||||
LogTrace(cmd, 1, 0, 0, NULL, true);
|
||||
|
||||
//wait for sim card to answer.
|
||||
if (!I2C_WaitForSim())
|
||||
return false;
|
||||
|
||||
// read answer
|
||||
uint8_t len = I2C_BufferRead(card_ptr->atr, sizeof(card_ptr->atr), I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN);
|
||||
|
||||
if ( len == 0 )
|
||||
return false;
|
||||
|
||||
// for some reason we only get first byte of atr, if that is so, send dummy command to retrieve the rest of the atr
|
||||
if (len == 1) {
|
||||
|
||||
uint8_t data[1] = {0};
|
||||
I2C_BufferWrite(data, len, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN);
|
||||
|
||||
if ( !I2C_WaitForSim() )
|
||||
return false;
|
||||
|
||||
uint8_t len2 = I2C_BufferRead(card_ptr->atr + len, sizeof(card_ptr->atr) - len, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN);
|
||||
len = len + len2;
|
||||
}
|
||||
|
||||
if ( card_ptr ) {
|
||||
card_ptr->atr_len = len;
|
||||
LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SmartCardAtr(void) {
|
||||
smart_card_atr_t card;
|
||||
LED_D_ON();
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
I2C_init();
|
||||
I2C_Reset_EnterMainProgram();
|
||||
bool isOK = GetATR( &card );
|
||||
cmd_send(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
|
||||
set_tracing(false);
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
void SmartCardRaw( uint64_t arg0, uint64_t arg1, uint8_t *data ) {
|
||||
|
||||
LED_D_ON();
|
||||
|
||||
uint8_t len = 0;
|
||||
uint8_t *resp = BigBuf_malloc(ISO7618_MAX_FRAME);
|
||||
smartcard_command_t flags = arg0;
|
||||
|
||||
if ((flags & SC_CONNECT))
|
||||
clear_trace();
|
||||
|
||||
set_tracing(true);
|
||||
|
||||
if ((flags & SC_CONNECT)) {
|
||||
|
||||
I2C_init();
|
||||
I2C_Reset_EnterMainProgram();
|
||||
|
||||
if ( !(flags & SC_NO_SELECT) ) {
|
||||
smart_card_atr_t card;
|
||||
bool gotATR = GetATR( &card );
|
||||
//cmd_send(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
|
||||
if ( !gotATR )
|
||||
goto OUT;
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & SC_RAW)) {
|
||||
|
||||
LogTrace(data, arg1, 0, 0, NULL, true);
|
||||
|
||||
// Send raw bytes
|
||||
// asBytes = A0 A4 00 00 02
|
||||
// arg1 = len 5
|
||||
I2C_BufferWrite(data, arg1, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN);
|
||||
|
||||
if ( !I2C_WaitForSim() )
|
||||
goto OUT;
|
||||
|
||||
len = I2C_BufferRead(resp, ISO7618_MAX_FRAME, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN);
|
||||
LogTrace(resp, len, 0, 0, NULL, false);
|
||||
}
|
||||
OUT:
|
||||
cmd_send(CMD_ACK, len, 0, 0, resp, len);
|
||||
set_tracing(false);
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
void SmartCardUpgrade(uint64_t arg0) {
|
||||
|
||||
LED_C_ON();
|
||||
|
||||
#define I2C_BLOCK_SIZE 128
|
||||
// write. Sector0, with 11,22,33,44
|
||||
// erase is 128bytes, and takes 50ms to execute
|
||||
|
||||
I2C_init();
|
||||
I2C_Reset_EnterBootloader();
|
||||
|
||||
bool isOK = true;
|
||||
uint8_t res = 0;
|
||||
uint16_t length = arg0;
|
||||
uint16_t pos = 0;
|
||||
uint8_t *fwdata = BigBuf_get_addr();
|
||||
uint8_t *verfiydata = BigBuf_malloc(I2C_BLOCK_SIZE);
|
||||
|
||||
while (length) {
|
||||
|
||||
uint8_t msb = (pos >> 8) & 0xFF;
|
||||
uint8_t lsb = pos & 0xFF;
|
||||
|
||||
Dbprintf("FW %02X%02X", msb, lsb);
|
||||
|
||||
size_t size = MIN(I2C_BLOCK_SIZE, length);
|
||||
|
||||
// write
|
||||
res = I2C_WriteFW(fwdata+pos, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT);
|
||||
if ( !res ) {
|
||||
DbpString("Writing failed");
|
||||
isOK = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// writing takes time.
|
||||
SpinDelay(50);
|
||||
|
||||
// read
|
||||
res = I2C_ReadFW(verfiydata, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT);
|
||||
if ( res == 0) {
|
||||
DbpString("Reading back failed");
|
||||
isOK = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// cmp
|
||||
if ( 0 != memcmp(fwdata+pos, verfiydata, size)) {
|
||||
DbpString("not equal data");
|
||||
isOK = false;
|
||||
break;
|
||||
}
|
||||
|
||||
length -= size;
|
||||
pos += size;
|
||||
}
|
||||
cmd_send(CMD_ACK, isOK, pos, 0, 0, 0);
|
||||
LED_C_OFF();
|
||||
}
|
||||
|
||||
// unfinished (or not needed?)
|
||||
//void SmartCardSetBaud(uint64_t arg0) {
|
||||
//}
|
||||
|
||||
void SmartCardSetClock(uint64_t arg0) {
|
||||
LED_D_ON();
|
||||
set_tracing(true);
|
||||
I2C_init();
|
||||
I2C_Reset_EnterMainProgram();
|
||||
|
||||
// Send SIM CLC
|
||||
// start [C0 05 xx] stop
|
||||
I2C_WriteByte(arg0, I2C_DEVICE_CMD_SIM_CLC, I2C_DEVICE_ADDRESS_MAIN);
|
||||
|
||||
cmd_send(CMD_ACK, 1, 0, 0, 0, 0);
|
||||
set_tracing(false);
|
||||
LEDsoff();
|
||||
}
|
58
armsrc/i2c.h
Normal file
58
armsrc/i2c.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Willok, June 2018
|
||||
// Edits by Iceman, July 2018
|
||||
//
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
// The main i2c code, for communications with smart card module
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __I2C_H
|
||||
#define __I2C_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "proxmark3.h"
|
||||
#include "apps.h"
|
||||
#include "util.h"
|
||||
#include "BigBuf.h"
|
||||
#include "smartcard.h"
|
||||
|
||||
#define I2C_DEVICE_ADDRESS_BOOT 0xB0
|
||||
#define I2C_DEVICE_ADDRESS_MAIN 0xC0
|
||||
|
||||
#define I2C_DEVICE_CMD_GENERATE_ATR 0x01
|
||||
#define I2C_DEVICE_CMD_SEND 0x02
|
||||
#define I2C_DEVICE_CMD_READ 0x03
|
||||
#define I2C_DEVICE_CMD_SETBAUD 0x04
|
||||
#define I2C_DEVICE_CMD_SIM_CLC 0x05
|
||||
#define I2C_DEVICE_CMD_GETVERSION 0x06
|
||||
|
||||
|
||||
void I2C_init(void);
|
||||
void I2C_Reset(void);
|
||||
void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA);
|
||||
|
||||
void I2C_Reset_EnterMainProgram(void);
|
||||
void I2C_Reset_EnterBootloader(void);
|
||||
|
||||
bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address);
|
||||
|
||||
bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address);
|
||||
bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address);
|
||||
uint8_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address);
|
||||
|
||||
// for firmware
|
||||
uint8_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address);
|
||||
bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address);
|
||||
|
||||
bool GetATR(smart_card_atr_t *card_ptr);
|
||||
|
||||
// generic functions
|
||||
void SmartCardAtr(void);
|
||||
void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data);
|
||||
void SmartCardUpgrade(uint64_t arg0);
|
||||
//void SmartCardSetBaud(uint64_t arg0);
|
||||
void SmartCardSetClock(uint64_t arg0);
|
||||
void I2C_print_status(void);
|
||||
#endif
|
|
@ -26,6 +26,11 @@ CXXFLAGS = -I../include -Wall -O3
|
|||
APP_CFLAGS =
|
||||
include ../common/Makefile_Enabled_Options.common
|
||||
CFLAGS += $(APP_CFLAGS)
|
||||
ifneq (,$(findstring WITH_SMARTCARD,$(APP_CFLAGS)))
|
||||
SRC_SMARTCARD = cmdsmartcard.c
|
||||
else
|
||||
SRC_SMARTCARD =
|
||||
endif
|
||||
|
||||
LUAPLATFORM = generic
|
||||
platform = $(shell uname)
|
||||
|
@ -93,7 +98,8 @@ CORESRCS = uart_posix.c \
|
|||
ui.c \
|
||||
comms.c
|
||||
|
||||
CMDSRCS = crapto1/crapto1.c\
|
||||
CMDSRCS = $(SRC_SMARTCARD) \
|
||||
crapto1/crapto1.c\
|
||||
crapto1/crypto1.c\
|
||||
polarssl/des.c \
|
||||
polarssl/aes.c\
|
||||
|
@ -310,9 +316,7 @@ DEPENDENCY_FILES = $(patsubst %.c, $(OBJDIR)/%.d, $(CORESRCS) $(CMDSRCS) $(ZLIBS
|
|||
$(patsubst %.cpp, $(OBJDIR)/%.d, $(QTGUISRCS)) \
|
||||
$(OBJDIR)/proxmark3.d $(OBJDIR)/flash.d $(OBJDIR)/flasher.d $(OBJDIR)/fpga_compress.d
|
||||
|
||||
|
||||
$(DEPENDENCY_FILES): ;
|
||||
.PRECIOUS: $(DEPENDENCY_FILES)
|
||||
|
||||
-include $(DEPENDENCY_FILES)
|
||||
|
||||
|
|
|
@ -353,6 +353,12 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
|
|||
|
||||
int CmdHFList(const char *Cmd)
|
||||
{
|
||||
#ifdef WITH_SMARTCARD
|
||||
PrintAndLog("TEST_WITH_SMARTCARD");
|
||||
#endif
|
||||
#ifdef WITH_TEST
|
||||
PrintAndLog("TEST_WITH_TEST");
|
||||
#endif
|
||||
bool showWaitCycles = false;
|
||||
bool markCRCBytes = false;
|
||||
bool loadFromFile = false;
|
||||
|
|
|
@ -26,7 +26,9 @@
|
|||
#include "util.h"
|
||||
#include "util_posix.h"
|
||||
#include "cmdscript.h"
|
||||
|
||||
#ifdef WITH_SMARTCARD
|
||||
#include "cmdsmartcard.h"
|
||||
#endif
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
static int CmdQuit(const char *Cmd);
|
||||
|
@ -39,6 +41,9 @@ static command_t CommandTable[] =
|
|||
{"hf", CmdHF, 1, "{ High Frequency commands... }"},
|
||||
{"hw", CmdHW, 1, "{ Hardware commands... }"},
|
||||
{"lf", CmdLF, 1, "{ Low Frequency commands... }"},
|
||||
#ifdef WITH_SMARTCARD
|
||||
{"sc", CmdSmartcard,1,"{ Smartcard commands... }"},
|
||||
#endif
|
||||
{"script",CmdScript,1, "{ Scripting commands }"},
|
||||
{"quit", CmdQuit, 1, "Exit program"},
|
||||
{"exit", CmdQuit, 1, "Exit program"},
|
||||
|
|
707
client/cmdsmartcard.c
Normal file
707
client/cmdsmartcard.c
Normal file
|
@ -0,0 +1,707 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2018 iceman
|
||||
//
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Proxmark3 RDV40 Smartcard module commands
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdsmartcard.h"
|
||||
#include "smartcard.h"
|
||||
#include "comms.h"
|
||||
#include "protocols.h"
|
||||
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
int usage_sm_raw(void) {
|
||||
PrintAndLog("Usage: sc raw [h|r|c] d <0A 0B 0C ... hex>");
|
||||
PrintAndLog(" h : this help");
|
||||
PrintAndLog(" r : do not read response");
|
||||
PrintAndLog(" a : active signal field ON without select");
|
||||
PrintAndLog(" s : active signal field ON with select");
|
||||
PrintAndLog(" t : executes TLV decoder if it is possible");
|
||||
PrintAndLog(" d <bytes> : bytes to send");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("Examples:");
|
||||
PrintAndLog(" sc raw d 11223344");
|
||||
return 0;
|
||||
}
|
||||
int usage_sm_reader(void) {
|
||||
PrintAndLog("Usage: sc reader [h|s]");
|
||||
PrintAndLog(" h : this help");
|
||||
PrintAndLog(" s : silent (no messages)");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("Examples:");
|
||||
PrintAndLog(" sc reader");
|
||||
return 0;
|
||||
}
|
||||
int usage_sm_info(void) {
|
||||
PrintAndLog("Usage: sc info [h|s]");
|
||||
PrintAndLog(" h : this help");
|
||||
PrintAndLog(" s : silent (no messages)");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("Examples:");
|
||||
PrintAndLog(" sc info");
|
||||
return 0;
|
||||
}
|
||||
int usage_sm_upgrade(void) {
|
||||
PrintAndLog("Upgrade firmware");
|
||||
PrintAndLog("Usage: sc upgrade f <file name>");
|
||||
PrintAndLog(" h : this help");
|
||||
PrintAndLog(" f <filename> : firmware file name");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("Examples:");
|
||||
PrintAndLog(" sc upgrade f myfile");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("WARNING - Dangerous command, do wrong and you will brick the smart card socket");
|
||||
return 0;
|
||||
}
|
||||
int usage_sm_setclock(void) {
|
||||
PrintAndLog("Usage: sc setclock [h] c <clockspeed>");
|
||||
PrintAndLog(" h : this help");
|
||||
PrintAndLog(" c <> : clockspeed (0 = 16mhz, 1=8mhz, 2=4mhz) ");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("Examples:");
|
||||
PrintAndLog(" sc setclock c 2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdSmartRaw(const char *Cmd) {
|
||||
|
||||
int hexlen = 0;
|
||||
bool active = false;
|
||||
bool active_select = false;
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false, reply = true, decodeTLV = false, breakloop = false;
|
||||
uint8_t data[USB_CMD_DATA_SIZE] = {0x00};
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h': return usage_sm_raw();
|
||||
case 'r':
|
||||
reply = false;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'a':
|
||||
active = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 's':
|
||||
active_select = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 't':
|
||||
decodeTLV = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'd': {
|
||||
switch (param_gethex_to_eol(Cmd, cmdp+1, data, sizeof(data), &hexlen)) {
|
||||
case 1:
|
||||
PrintAndLog("Invalid HEX value.");
|
||||
return 1;
|
||||
case 2:
|
||||
PrintAndLog("Too many bytes. Max %d bytes", sizeof(data));
|
||||
return 1;
|
||||
case 3:
|
||||
PrintAndLog("Hex must have an even number of digits.");
|
||||
return 1;
|
||||
}
|
||||
cmdp++;
|
||||
breakloop = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( breakloop )
|
||||
break;
|
||||
}
|
||||
|
||||
//Validations
|
||||
if (errors || cmdp == 0 ) return usage_sm_raw();
|
||||
|
||||
// arg0 = RFU flags
|
||||
// arg1 = length
|
||||
UsbCommand c = {CMD_SMART_RAW, {0, hexlen, 0}};
|
||||
|
||||
if (active || active_select) {
|
||||
c.arg[0] |= SC_CONNECT;
|
||||
if (active)
|
||||
c.arg[0] |= SC_NO_SELECT;
|
||||
}
|
||||
|
||||
if (hexlen > 0) {
|
||||
c.arg[0] |= SC_RAW;
|
||||
}
|
||||
|
||||
memcpy(c.d.asBytes, data, hexlen );
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
// reading response from smart card
|
||||
if ( reply ) {
|
||||
UsbCommand resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
PrintAndLog("smart card response failed");
|
||||
return 1;
|
||||
}
|
||||
uint32_t datalen = resp.arg[0];
|
||||
|
||||
if ( !datalen ) {
|
||||
PrintAndLog("smart card response failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
PrintAndLog("received %i bytes", datalen);
|
||||
|
||||
if (!datalen)
|
||||
return 1;
|
||||
|
||||
uint8_t *data = resp.d.asBytes;
|
||||
|
||||
// TLV decoder
|
||||
if (decodeTLV ) {
|
||||
|
||||
if (datalen >= 2) {
|
||||
PrintAndLog("%02x %02x | %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1]));
|
||||
}
|
||||
if (datalen > 4) {
|
||||
TLVPrintFromBuffer(data, datalen - 2);
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("%s", sprint_hex(data, datalen));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdSmartUpgrade(const char *Cmd) {
|
||||
|
||||
PrintAndLog("WARNING - Smartcard socket firmware upgrade.");
|
||||
PrintAndLog("Dangerous command, do wrong and you will brick the smart card socket");
|
||||
|
||||
FILE *f;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'f':
|
||||
//File handling and reading
|
||||
if ( param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE ) {
|
||||
PrintAndLog("Filename too long");
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'h':
|
||||
return usage_sm_upgrade();
|
||||
default:
|
||||
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Validations
|
||||
if (errors || cmdp == 0 ) return usage_sm_upgrade();
|
||||
|
||||
// load file
|
||||
f = fopen(filename, "rb");
|
||||
if ( !f ) {
|
||||
PrintAndLog("File: %s: not found or locked.", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// get filesize in order to malloc memory
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if (fsize < 0) {
|
||||
PrintAndLog("error, when getting filesize");
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *dump = calloc(fsize, sizeof(uint8_t));
|
||||
if (!dump) {
|
||||
PrintAndLog("error, cannot allocate memory ");
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t bytes_read = fread(dump, 1, fsize, f);
|
||||
if (f)
|
||||
fclose(f);
|
||||
|
||||
PrintAndLog("Smartcard socket firmware uploading to PM3");
|
||||
//Send to device
|
||||
uint32_t index = 0;
|
||||
uint32_t bytes_sent = 0;
|
||||
uint32_t bytes_remaining = bytes_read;
|
||||
|
||||
while (bytes_remaining > 0){
|
||||
uint32_t bytes_in_packet = MIN(USB_CMD_DATA_SIZE, bytes_remaining);
|
||||
UsbCommand c = {CMD_SMART_UPLOAD, {index + bytes_sent, bytes_in_packet, 0}};
|
||||
|
||||
// Fill usb bytes with 0xFF
|
||||
memset(c.d.asBytes, 0xFF, USB_CMD_DATA_SIZE);
|
||||
memcpy(c.d.asBytes, dump + bytes_sent, bytes_in_packet);
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000) ) {
|
||||
PrintAndLog("timeout while waiting for reply.");
|
||||
free(dump);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bytes_remaining -= bytes_in_packet;
|
||||
bytes_sent += bytes_in_packet;
|
||||
printf("."); fflush(stdout);
|
||||
}
|
||||
free(dump);
|
||||
printf("\n");
|
||||
PrintAndLog("Smartcard socket firmware updating, don\'t turn off your PM3!");
|
||||
|
||||
// trigger the firmware upgrade
|
||||
UsbCommand c = {CMD_SMART_UPGRADE, {bytes_read, 0, 0}};
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
UsbCommand resp;
|
||||
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) {
|
||||
PrintAndLog("timeout while waiting for reply.");
|
||||
return 1;
|
||||
}
|
||||
if ( (resp.arg[0] && 0xFF ) )
|
||||
PrintAndLog("Smartcard socket firmware upgraded successful");
|
||||
else
|
||||
PrintAndLog("Smartcard socket firmware updating failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdSmartInfo(const char *Cmd){
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false, silent = false;
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h': return usage_sm_info();
|
||||
case 's':
|
||||
silent = true;
|
||||
break;
|
||||
default:
|
||||
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
cmdp++;
|
||||
}
|
||||
|
||||
//Validations
|
||||
if (errors ) return usage_sm_info();
|
||||
|
||||
UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}};
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
UsbCommand resp;
|
||||
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) {
|
||||
if (!silent) PrintAndLog("smart card select failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t isok = resp.arg[0] & 0xFF;
|
||||
if (!isok) {
|
||||
if (!silent) PrintAndLog("smart card select failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
smart_card_atr_t card;
|
||||
memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t));
|
||||
|
||||
// print header
|
||||
PrintAndLog("\n--- Smartcard Information ---------");
|
||||
PrintAndLog("-------------------------------------------------------------");
|
||||
PrintAndLog("ISO76183 ATR : %s", sprint_hex(card.atr, card.atr_len));
|
||||
PrintAndLog("look up ATR");
|
||||
PrintAndLog("http://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdSmartReader(const char *Cmd){
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false, silent = false;
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h': return usage_sm_reader();
|
||||
case 's':
|
||||
silent = true;
|
||||
break;
|
||||
default:
|
||||
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
cmdp++;
|
||||
}
|
||||
|
||||
//Validations
|
||||
if (errors ) return usage_sm_reader();
|
||||
|
||||
UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}};
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
UsbCommand resp;
|
||||
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) {
|
||||
if (!silent) PrintAndLog("smart card select failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t isok = resp.arg[0] & 0xFF;
|
||||
if (!isok) {
|
||||
if (!silent) PrintAndLog("smart card select failed");
|
||||
return 1;
|
||||
}
|
||||
smart_card_atr_t card;
|
||||
memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t));
|
||||
PrintAndLog("ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdSmartSetClock(const char *Cmd){
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
uint8_t clock = 0;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h': return usage_sm_setclock();
|
||||
case 'c':
|
||||
clock = param_get8ex(Cmd, cmdp+1, 2, 10);
|
||||
if ( clock > 2)
|
||||
errors = true;
|
||||
|
||||
cmdp += 2;
|
||||
break;
|
||||
default:
|
||||
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Validations
|
||||
if (errors || cmdp == 0) return usage_sm_setclock();
|
||||
|
||||
UsbCommand c = {CMD_SMART_SETCLOCK, {clock, 0, 0}};
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
UsbCommand resp;
|
||||
if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) {
|
||||
PrintAndLog("smart card select failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t isok = resp.arg[0] & 0xFF;
|
||||
if (!isok) {
|
||||
PrintAndLog("smart card set clock failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (clock) {
|
||||
case 0:
|
||||
PrintAndLog("Clock changed to 16mhz giving 10800 baudrate");
|
||||
break;
|
||||
case 1:
|
||||
PrintAndLog("Clock changed to 8mhz giving 21600 baudrate");
|
||||
break;
|
||||
case 2:
|
||||
PrintAndLog("Clock changed to 4mhz giving 86400 baudrate");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// iso 7816-3
|
||||
void annotateIso7816(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){
|
||||
// S-block
|
||||
if ( (cmd[0] & 0xC0) && (cmdsize == 3) ) {
|
||||
switch ( (cmd[0] & 0x3f) ) {
|
||||
case 0x00 : snprintf(exp, size, "S-block RESYNCH req"); break;
|
||||
case 0x20 : snprintf(exp, size, "S-block RESYNCH resp"); break;
|
||||
case 0x01 : snprintf(exp, size, "S-block IFS req"); break;
|
||||
case 0x21 : snprintf(exp, size, "S-block IFS resp"); break;
|
||||
case 0x02 : snprintf(exp, size, "S-block ABORT req"); break;
|
||||
case 0x22 : snprintf(exp, size, "S-block ABORT resp"); break;
|
||||
case 0x03 : snprintf(exp, size, "S-block WTX reqt"); break;
|
||||
case 0x23 : snprintf(exp, size, "S-block WTX resp"); break;
|
||||
default : snprintf(exp, size, "S-block"); break;
|
||||
}
|
||||
}
|
||||
// R-block (ack)
|
||||
else if ( ((cmd[0] & 0xD0) == 0x80) && ( cmdsize > 2) ) {
|
||||
if ( (cmd[0] & 0x10) == 0 )
|
||||
snprintf(exp, size, "R-block ACK");
|
||||
else
|
||||
snprintf(exp, size, "R-block NACK");
|
||||
}
|
||||
// I-block
|
||||
else {
|
||||
|
||||
int pos = (cmd[0] == 2 || cmd[0] == 3) ? 2 : 3;
|
||||
switch ( cmd[pos] ) {
|
||||
case ISO7816_READ_BINARY :snprintf(exp, size, "READ BIN");break;
|
||||
case ISO7816_WRITE_BINARY :snprintf(exp, size, "WRITE BIN");break;
|
||||
case ISO7816_UPDATE_BINARY :snprintf(exp, size, "UPDATE BIN");break;
|
||||
case ISO7816_ERASE_BINARY :snprintf(exp, size, "ERASE BIN");break;
|
||||
case ISO7816_READ_RECORDS :snprintf(exp, size, "READ RECORDS");break;
|
||||
case ISO7816_WRITE_RECORDS :snprintf(exp, size, "WRITE RECORDS");break;
|
||||
case ISO7816_APPEND_RECORD :snprintf(exp, size, "APPEND RECORD");break;
|
||||
case ISO7816_UPDATE_RECORD :snprintf(exp, size, "UPDATE RECORD");break;
|
||||
case ISO7816_GET_DATA :snprintf(exp, size, "GET DATA");break;
|
||||
case ISO7816_PUT_DATA :snprintf(exp, size, "PUT DATA");break;
|
||||
case ISO7816_SELECT_FILE :snprintf(exp, size, "SELECT FILE");break;
|
||||
case ISO7816_VERIFY :snprintf(exp, size, "VERIFY");break;
|
||||
case ISO7816_INTERNAL_AUTHENTICATION :snprintf(exp, size, "INTERNAL AUTH");break;
|
||||
case ISO7816_EXTERNAL_AUTHENTICATION :snprintf(exp, size, "EXTERNAL AUTH");break;
|
||||
case ISO7816_GET_CHALLENGE :snprintf(exp, size, "GET CHALLENGE");break;
|
||||
case ISO7816_MANAGE_CHANNEL :snprintf(exp, size, "MANAGE CHANNEL");break;
|
||||
default :snprintf(exp, size, "?"); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint16_t printScTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace) {
|
||||
// sanity check
|
||||
if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen) return traceLen;
|
||||
|
||||
bool isResponse;
|
||||
uint16_t data_len, parity_len;
|
||||
uint32_t duration, timestamp, first_timestamp, EndOfTransmissionTimestamp;
|
||||
char explanation[30] = {0};
|
||||
|
||||
first_timestamp = *((uint32_t *)(trace));
|
||||
timestamp = *((uint32_t *)(trace + tracepos));
|
||||
tracepos += 4;
|
||||
|
||||
duration = *((uint16_t *)(trace + tracepos));
|
||||
tracepos += 2;
|
||||
|
||||
data_len = *((uint16_t *)(trace + tracepos));
|
||||
tracepos += 2;
|
||||
|
||||
if (data_len & 0x8000) {
|
||||
data_len &= 0x7fff;
|
||||
isResponse = true;
|
||||
} else {
|
||||
isResponse = false;
|
||||
}
|
||||
|
||||
parity_len = (data_len-1)/8 + 1;
|
||||
if (tracepos + data_len + parity_len > traceLen) {
|
||||
return traceLen;
|
||||
}
|
||||
uint8_t *frame = trace + tracepos;
|
||||
tracepos += data_len;
|
||||
//uint8_t *parityBytes = trace + tracepos;
|
||||
tracepos += parity_len;
|
||||
|
||||
//--- Draw the data column
|
||||
char line[18][110];
|
||||
|
||||
if (data_len == 0 ) {
|
||||
sprintf(line[0],"<empty trace - possible error>");
|
||||
return tracepos;
|
||||
}
|
||||
|
||||
for (int j = 0; j < data_len && j/18 < 18; j++) {
|
||||
snprintf(line[j/18]+(( j % 18) * 4),110, "%02x ", frame[j]);
|
||||
}
|
||||
|
||||
EndOfTransmissionTimestamp = timestamp + duration;
|
||||
|
||||
annotateIso7816(explanation,sizeof(explanation),frame,data_len);
|
||||
|
||||
int num_lines = MIN((data_len - 1)/18 + 1, 18);
|
||||
for (int j = 0; j < num_lines ; j++) {
|
||||
if (j == 0) {
|
||||
PrintAndLog(" %10u | %10u | %s |%-72s | %s| %s",
|
||||
(timestamp - first_timestamp),
|
||||
(EndOfTransmissionTimestamp - first_timestamp),
|
||||
(isResponse ? "Tag" : "Rdr"),
|
||||
line[j],
|
||||
" ",
|
||||
(j == num_lines-1) ? explanation : "");
|
||||
} else {
|
||||
PrintAndLog(" | | |%-72s | %s| %s",
|
||||
line[j],
|
||||
" ",
|
||||
(j == num_lines-1) ? explanation : "");
|
||||
}
|
||||
}
|
||||
|
||||
// if is last record
|
||||
if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) >= traceLen) return traceLen;
|
||||
|
||||
return tracepos;
|
||||
}
|
||||
|
||||
int ScTraceList(const char *Cmd) {
|
||||
bool loadFromFile = false;
|
||||
bool saveToFile = false;
|
||||
char type[5] = {0};
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
|
||||
// parse command line
|
||||
param_getstr(Cmd, 0, type, sizeof(type));
|
||||
param_getstr(Cmd, 1, filename, sizeof(filename));
|
||||
|
||||
bool errors = false;
|
||||
if(type[0] == 'h') {
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if(!errors) {
|
||||
if (strcmp(type, "s") == 0) {
|
||||
saveToFile = true;
|
||||
} else if (strcmp(type,"l") == 0) {
|
||||
loadFromFile = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((loadFromFile || saveToFile) && strlen(filename) == 0) {
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (loadFromFile && saveToFile) {
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (errors) {
|
||||
PrintAndLog("List or save protocol data.");
|
||||
PrintAndLog("Usage: sc list [l <filename>]");
|
||||
PrintAndLog(" sc list [s <filename>]");
|
||||
PrintAndLog(" l - load data from file instead of trace buffer");
|
||||
PrintAndLog(" s - save data to file");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("example: sc list");
|
||||
PrintAndLog("example: sc list save myCardTrace.trc");
|
||||
PrintAndLog("example: sc list l myCardTrace.trc");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *trace;
|
||||
uint32_t tracepos = 0;
|
||||
uint32_t traceLen = 0;
|
||||
|
||||
if (loadFromFile) {
|
||||
#define TRACE_CHUNK_SIZE (1<<16) // 64K to start with. Will be enough for BigBuf and some room for future extensions
|
||||
FILE *tracefile = NULL;
|
||||
size_t bytes_read;
|
||||
trace = malloc(TRACE_CHUNK_SIZE);
|
||||
if (trace == NULL) {
|
||||
PrintAndLog("Cannot allocate memory for trace");
|
||||
return 2;
|
||||
}
|
||||
if ((tracefile = fopen(filename,"rb")) == NULL) {
|
||||
PrintAndLog("Could not open file %s", filename);
|
||||
free(trace);
|
||||
return 0;
|
||||
}
|
||||
while (!feof(tracefile)) {
|
||||
bytes_read = fread(trace+traceLen, 1, TRACE_CHUNK_SIZE, tracefile);
|
||||
traceLen += bytes_read;
|
||||
if (!feof(tracefile)) {
|
||||
uint8_t *p = realloc(trace, traceLen + TRACE_CHUNK_SIZE);
|
||||
if (p == NULL) {
|
||||
PrintAndLog("Cannot allocate memory for trace");
|
||||
free(trace);
|
||||
fclose(tracefile);
|
||||
return 2;
|
||||
}
|
||||
trace = p;
|
||||
}
|
||||
}
|
||||
fclose(tracefile);
|
||||
} else {
|
||||
trace = malloc(USB_CMD_DATA_SIZE);
|
||||
// Query for the size of the trace
|
||||
UsbCommand response;
|
||||
GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0, &response, -1, false);
|
||||
traceLen = response.arg[2];
|
||||
if (traceLen > USB_CMD_DATA_SIZE) {
|
||||
uint8_t *p = realloc(trace, traceLen);
|
||||
if (p == NULL) {
|
||||
PrintAndLog("Cannot allocate memory for trace");
|
||||
free(trace);
|
||||
return 2;
|
||||
}
|
||||
trace = p;
|
||||
GetFromBigBuf(trace, traceLen, 0, NULL, -1, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (saveToFile) {
|
||||
FILE *tracefile = NULL;
|
||||
if ((tracefile = fopen(filename,"wb")) == NULL) {
|
||||
PrintAndLog("Could not create file %s", filename);
|
||||
return 1;
|
||||
}
|
||||
fwrite(trace, 1, traceLen, tracefile);
|
||||
PrintAndLog("Recorded Activity (TraceLen = %d bytes) written to file %s", traceLen, filename);
|
||||
fclose(tracefile);
|
||||
} else {
|
||||
PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen);
|
||||
PrintAndLog("");
|
||||
PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
|
||||
PrintAndLog("");
|
||||
PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |");
|
||||
PrintAndLog("------------|------------|-----|-------------------------------------------------------------------------|-----|--------------------|");
|
||||
|
||||
while(tracepos < traceLen)
|
||||
{
|
||||
tracepos = printScTraceLine(tracepos, traceLen, trace);
|
||||
}
|
||||
}
|
||||
|
||||
free(trace);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdSmartList(const char *Cmd) {
|
||||
ScTraceList(Cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
{"list", CmdSmartList, 0, "List ISO 7816 history"},
|
||||
{"info", CmdSmartInfo, 1, "Tag information [rdv40]"},
|
||||
{"reader", CmdSmartReader, 1, "Act like an IS07816 reader [rdv40]"},
|
||||
{"raw", CmdSmartRaw, 1, "Send raw hex data to tag [rdv40]"},
|
||||
{"upgrade", CmdSmartUpgrade, 1, "Upgrade firmware [rdv40]"},
|
||||
{"setclock",CmdSmartSetClock, 1, "Set clock speed"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
int CmdSmartcard(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
CmdsParse(CommandTable, Cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdHelp(const char *Cmd) {
|
||||
CmdsHelp(CommandTable);
|
||||
return 0;
|
||||
}
|
39
client/cmdsmartcard.h
Normal file
39
client/cmdsmartcard.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2018 iceman
|
||||
//
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Proxmark3 RDV40 Smartcard module commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef CMDSMARTCARD_H__
|
||||
#define CMDSMARTCARD_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "proxmark3.h"
|
||||
#include "ui.h"
|
||||
#include "cmdparser.h"
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
#include "loclass/fileutils.h" // saveFile
|
||||
#include "cmdmain.h" // getfromdevice
|
||||
#include "emv/emvcore.h" // decodeTVL
|
||||
#include "emv/apduinfo.h" // APDUcode description
|
||||
|
||||
extern int CmdSmartcard(const char *Cmd);
|
||||
|
||||
extern int CmdSmartRaw(const char* cmd);
|
||||
extern int CmdSmartUpgrade(const char* cmd);
|
||||
extern int CmdSmartInfo(const char* cmd);
|
||||
extern int CmdSmartReader(const char *Cmd);
|
||||
|
||||
extern int usage_sm_raw(void);
|
||||
extern int usage_sm_reader(void);
|
||||
extern int usage_sm_info(void);
|
||||
extern int usage_sm_upgrade(void);
|
||||
#endif
|
|
@ -10,8 +10,8 @@
|
|||
//
|
||||
// NOTES:
|
||||
// LF Demod functions are placed here to allow the flexability to use client or
|
||||
// device side. Most BUT NOT ALL of these functions are currenlty safe for
|
||||
// device side use currently. (DetectST for example...)
|
||||
// device side. Most BUT NOT ALL of these functions are currently safe for
|
||||
// device side use. (DetectST for example...)
|
||||
//
|
||||
// There are likely many improvements to the code that could be made, please
|
||||
// make suggestions...
|
||||
|
|
|
@ -200,11 +200,12 @@ NXP/Philips CUSTOM COMMANDS
|
|||
#define TOPAZ_WRITE_NE8 0x1B // Write-no-erase (eight bytes)
|
||||
|
||||
|
||||
#define ISO_14443A 0
|
||||
#define ICLASS 1
|
||||
#define ISO_14443B 2
|
||||
#define TOPAZ 3
|
||||
#define PROTO_MIFARE 4
|
||||
#define ISO_14443A 0
|
||||
#define ICLASS 1
|
||||
#define ISO_14443B 2
|
||||
#define TOPAZ 3
|
||||
#define PROTO_MIFARE 4
|
||||
#define ISO_7816_4 5
|
||||
|
||||
//-- Picopass fuses
|
||||
#define FUSE_FPERS 0x80
|
||||
|
@ -216,6 +217,29 @@ NXP/Philips CUSTOM COMMANDS
|
|||
#define FUSE_FPROD0 0x02
|
||||
#define FUSE_RA 0x01
|
||||
|
||||
// ISO 7816-4 Basic interindustry commands. For command APDU's.
|
||||
#define ISO7816_READ_BINARY 0xB0
|
||||
#define ISO7816_WRITE_BINARY 0xD0
|
||||
#define ISO7816_UPDATE_BINARY 0xD6
|
||||
#define ISO7816_ERASE_BINARY 0x0E
|
||||
#define ISO7816_READ_RECORDS 0xB2
|
||||
#define ISO7816_WRITE_RECORDS 0xD2
|
||||
#define ISO7816_APPEND_RECORD 0xE2
|
||||
#define ISO7816_UPDATE_RECORD 0xDC
|
||||
#define ISO7816_GET_DATA 0xCA
|
||||
#define ISO7816_PUT_DATA 0xDA
|
||||
#define ISO7816_SELECT_FILE 0xA4
|
||||
#define ISO7816_VERIFY 0x20
|
||||
#define ISO7816_INTERNAL_AUTHENTICATION 0x88
|
||||
#define ISO7816_EXTERNAL_AUTHENTICATION 0x82
|
||||
#define ISO7816_GET_CHALLENGE 0xB4
|
||||
#define ISO7816_MANAGE_CHANNEL 0x70
|
||||
// ISO7816-4 For response APDU's
|
||||
#define ISO7816_OK 0x9000
|
||||
// 6x xx = ERROR
|
||||
|
||||
|
||||
|
||||
void printIclassDumpInfo(uint8_t* iclass_dump);
|
||||
void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *max_blk, uint8_t *app_areas, uint8_t *kb);
|
||||
|
||||
|
|
29
include/smartcard.h
Normal file
29
include/smartcard.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// (c) 2018 Iceman, adapted by Marshmellow
|
||||
//
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
// smart card type prototyping
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __SMARTCARD_H
|
||||
#define __SMARTCARD_H
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ISO 7618 Smart Card
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef struct {
|
||||
uint8_t atr_len;
|
||||
uint8_t atr[30];
|
||||
} __attribute__((__packed__)) smart_card_atr_t;
|
||||
|
||||
typedef enum SMARTCARD_COMMAND {
|
||||
SC_CONNECT = (1 << 0),
|
||||
SC_NO_DISCONNECT = (1 << 1),
|
||||
SC_RAW = (1 << 2),
|
||||
SC_NO_SELECT = (1 << 3)
|
||||
} smartcard_command_t;
|
||||
|
||||
|
||||
#endif
|
|
@ -60,8 +60,17 @@ typedef struct{
|
|||
#define CMD_BUFF_CLEAR 0x0105
|
||||
#define CMD_READ_MEM 0x0106
|
||||
#define CMD_VERSION 0x0107
|
||||
#define CMD_STATUS 0x0108
|
||||
#define CMD_PING 0x0109
|
||||
#define CMD_STATUS 0x0108
|
||||
#define CMD_PING 0x0109
|
||||
|
||||
// RDV40, Smart card operations
|
||||
#define CMD_SMART_RAW 0x0140
|
||||
#define CMD_SMART_UPGRADE 0x0141
|
||||
#define CMD_SMART_UPLOAD 0x0142
|
||||
#define CMD_SMART_ATR 0x0143
|
||||
// CMD_SMART_SETBAUD is unused for now
|
||||
#define CMD_SMART_SETBAUD 0x0144
|
||||
#define CMD_SMART_SETCLOCK 0x0145
|
||||
|
||||
// For low-frequency tags
|
||||
#define CMD_READ_TI_TYPE 0x0202
|
||||
|
@ -126,10 +135,10 @@ typedef struct{
|
|||
#define CMD_READER_HITAG 0x0372
|
||||
|
||||
#define CMD_SIMULATE_HITAG_S 0x0368
|
||||
#define CMD_TEST_HITAGS_TRACES 0x0367
|
||||
#define CMD_READ_HITAG_S 0x0373
|
||||
#define CMD_WR_HITAG_S 0x0375
|
||||
#define CMD_EMU_HITAG_S 0x0376
|
||||
#define CMD_TEST_HITAGS_TRACES 0x0367
|
||||
#define CMD_READ_HITAG_S 0x0373
|
||||
#define CMD_WR_HITAG_S 0x0375
|
||||
#define CMD_EMU_HITAG_S 0x0376
|
||||
|
||||
|
||||
#define CMD_SIMULATE_TAG_ISO_14443B 0x0381
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue