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:
marshmellow42 2018-08-20 23:08:49 -04:00 committed by pwpiwi
parent f684231796
commit 43591e6464
14 changed files with 1661 additions and 22 deletions

View file

@ -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) - Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi)
### Added ### 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 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 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) - Added lf pac demod and lf pac read - extracts the raw blocks from a PAC/Stanley tag (marshmellow)

View file

@ -15,18 +15,22 @@ APP_CFLAGS = -DON_DEVICE \
include ../common/Makefile_Enabled_Options.common include ../common/Makefile_Enabled_Options.common
ifneq (,$(findstring LCD,$(APP_CFLAGS))) ifneq (,$(findstring WITH_LCD,$(APP_CFLAGS)))
SRC_LCD = fonts.c LCD.c SRC_LCD = fonts.c LCD.c
else else
SRC_LCD = SRC_LCD =
endif endif
#SRC_LCD = fonts.c LCD.c
SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c protocols.c SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c protocols.c
SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO15693 = iso15693.c iso15693tools.c
SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c mifaresim.c SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c mifaresim.c
SRC_ISO14443b = iso14443b.c SRC_ISO14443b = iso14443b.c
SRC_CRAPTO1 = crypto1.c des.c SRC_CRAPTO1 = crypto1.c des.c
SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c parity.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! #the FPGA bitstream files. Note: order matters!
FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit
@ -44,6 +48,7 @@ THUMBSRC = start.c \
$(SRC_ISO15693) \ $(SRC_ISO15693) \
$(SRC_LF) \ $(SRC_LF) \
$(SRC_ZLIB) \ $(SRC_ZLIB) \
$(SRC_SMARTCARD) \
appmain.c \ appmain.c \
printf.c \ printf.c \
util.c \ util.c \

View file

@ -30,6 +30,10 @@
#ifdef WITH_LCD #ifdef WITH_LCD
#include "LCD.h" #include "LCD.h"
#endif #endif
#ifdef WITH_SMARTCARD
#include "i2c.h"
#endif
// Craig Young - 14a stand-alone code // Craig Young - 14a stand-alone code
#ifdef WITH_ISO14443a #ifdef WITH_ISO14443a
@ -357,12 +361,15 @@ void SendStatus(void)
{ {
BigBuf_print_status(); BigBuf_print_status();
Fpga_print_status(); Fpga_print_status();
#ifdef WITH_SMARTCARD
I2C_print_status();
#endif
printConfig(); //LF Sampling config printConfig(); //LF Sampling config
printUSBSpeed(); printUSBSpeed();
Dbprintf("Various"); Dbprintf("Various");
Dbprintf(" MF_DBGLEVEL......%d", MF_DBGLEVEL); Dbprintf(" MF_DBGLEVEL........%d", MF_DBGLEVEL);
Dbprintf(" ToSendMax........%d",ToSendMax); Dbprintf(" ToSendMax..........%d", ToSendMax);
Dbprintf(" ToSendBit........%d",ToSendBit); Dbprintf(" ToSendBit..........%d", ToSendBit);
cmd_send(CMD_ACK,1,0,0,0,0); 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]); HfSnoop(c->arg[0], c->arg[1]);
break; break;
#endif #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: case CMD_BUFF_CLEAR:
BigBuf_Clear(); BigBuf_Clear();

720
armsrc/i2c.c Normal file
View 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
// ReserveFor 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
View 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

View file

@ -26,6 +26,11 @@ CXXFLAGS = -I../include -Wall -O3
APP_CFLAGS = APP_CFLAGS =
include ../common/Makefile_Enabled_Options.common include ../common/Makefile_Enabled_Options.common
CFLAGS += $(APP_CFLAGS) CFLAGS += $(APP_CFLAGS)
ifneq (,$(findstring WITH_SMARTCARD,$(APP_CFLAGS)))
SRC_SMARTCARD = cmdsmartcard.c
else
SRC_SMARTCARD =
endif
LUAPLATFORM = generic LUAPLATFORM = generic
platform = $(shell uname) platform = $(shell uname)
@ -93,7 +98,8 @@ CORESRCS = uart_posix.c \
ui.c \ ui.c \
comms.c comms.c
CMDSRCS = crapto1/crapto1.c\ CMDSRCS = $(SRC_SMARTCARD) \
crapto1/crapto1.c\
crapto1/crypto1.c\ crapto1/crypto1.c\
polarssl/des.c \ polarssl/des.c \
polarssl/aes.c\ polarssl/aes.c\
@ -310,9 +316,7 @@ DEPENDENCY_FILES = $(patsubst %.c, $(OBJDIR)/%.d, $(CORESRCS) $(CMDSRCS) $(ZLIBS
$(patsubst %.cpp, $(OBJDIR)/%.d, $(QTGUISRCS)) \ $(patsubst %.cpp, $(OBJDIR)/%.d, $(QTGUISRCS)) \
$(OBJDIR)/proxmark3.d $(OBJDIR)/flash.d $(OBJDIR)/flasher.d $(OBJDIR)/fpga_compress.d $(OBJDIR)/proxmark3.d $(OBJDIR)/flash.d $(OBJDIR)/flasher.d $(OBJDIR)/fpga_compress.d
$(DEPENDENCY_FILES): ; $(DEPENDENCY_FILES): ;
.PRECIOUS: $(DEPENDENCY_FILES) .PRECIOUS: $(DEPENDENCY_FILES)
-include $(DEPENDENCY_FILES) -include $(DEPENDENCY_FILES)

View file

@ -353,6 +353,12 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
int CmdHFList(const char *Cmd) 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 showWaitCycles = false;
bool markCRCBytes = false; bool markCRCBytes = false;
bool loadFromFile = false; bool loadFromFile = false;

View file

@ -26,7 +26,9 @@
#include "util.h" #include "util.h"
#include "util_posix.h" #include "util_posix.h"
#include "cmdscript.h" #include "cmdscript.h"
#ifdef WITH_SMARTCARD
#include "cmdsmartcard.h"
#endif
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static int CmdQuit(const char *Cmd); static int CmdQuit(const char *Cmd);
@ -39,6 +41,9 @@ static command_t CommandTable[] =
{"hf", CmdHF, 1, "{ High Frequency commands... }"}, {"hf", CmdHF, 1, "{ High Frequency commands... }"},
{"hw", CmdHW, 1, "{ Hardware commands... }"}, {"hw", CmdHW, 1, "{ Hardware commands... }"},
{"lf", CmdLF, 1, "{ Low Frequency commands... }"}, {"lf", CmdLF, 1, "{ Low Frequency commands... }"},
#ifdef WITH_SMARTCARD
{"sc", CmdSmartcard,1,"{ Smartcard commands... }"},
#endif
{"script",CmdScript,1, "{ Scripting commands }"}, {"script",CmdScript,1, "{ Scripting commands }"},
{"quit", CmdQuit, 1, "Exit program"}, {"quit", CmdQuit, 1, "Exit program"},
{"exit", CmdQuit, 1, "Exit program"}, {"exit", CmdQuit, 1, "Exit program"},

707
client/cmdsmartcard.c Normal file
View 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
View 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

View file

@ -10,8 +10,8 @@
// //
// NOTES: // NOTES:
// LF Demod functions are placed here to allow the flexability to use client or // 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. Most BUT NOT ALL of these functions are currently safe for
// device side use currently. (DetectST for example...) // device side use. (DetectST for example...)
// //
// There are likely many improvements to the code that could be made, please // There are likely many improvements to the code that could be made, please
// make suggestions... // make suggestions...

View file

@ -200,11 +200,12 @@ NXP/Philips CUSTOM COMMANDS
#define TOPAZ_WRITE_NE8 0x1B // Write-no-erase (eight bytes) #define TOPAZ_WRITE_NE8 0x1B // Write-no-erase (eight bytes)
#define ISO_14443A 0 #define ISO_14443A 0
#define ICLASS 1 #define ICLASS 1
#define ISO_14443B 2 #define ISO_14443B 2
#define TOPAZ 3 #define TOPAZ 3
#define PROTO_MIFARE 4 #define PROTO_MIFARE 4
#define ISO_7816_4 5
//-- Picopass fuses //-- Picopass fuses
#define FUSE_FPERS 0x80 #define FUSE_FPERS 0x80
@ -216,6 +217,29 @@ NXP/Philips CUSTOM COMMANDS
#define FUSE_FPROD0 0x02 #define FUSE_FPROD0 0x02
#define FUSE_RA 0x01 #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 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); 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
View 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

View file

@ -60,8 +60,17 @@ typedef struct{
#define CMD_BUFF_CLEAR 0x0105 #define CMD_BUFF_CLEAR 0x0105
#define CMD_READ_MEM 0x0106 #define CMD_READ_MEM 0x0106
#define CMD_VERSION 0x0107 #define CMD_VERSION 0x0107
#define CMD_STATUS 0x0108 #define CMD_STATUS 0x0108
#define CMD_PING 0x0109 #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 // For low-frequency tags
#define CMD_READ_TI_TYPE 0x0202 #define CMD_READ_TI_TYPE 0x0202
@ -126,10 +135,10 @@ typedef struct{
#define CMD_READER_HITAG 0x0372 #define CMD_READER_HITAG 0x0372
#define CMD_SIMULATE_HITAG_S 0x0368 #define CMD_SIMULATE_HITAG_S 0x0368
#define CMD_TEST_HITAGS_TRACES 0x0367 #define CMD_TEST_HITAGS_TRACES 0x0367
#define CMD_READ_HITAG_S 0x0373 #define CMD_READ_HITAG_S 0x0373
#define CMD_WR_HITAG_S 0x0375 #define CMD_WR_HITAG_S 0x0375
#define CMD_EMU_HITAG_S 0x0376 #define CMD_EMU_HITAG_S 0x0376
#define CMD_SIMULATE_TAG_ISO_14443B 0x0381 #define CMD_SIMULATE_TAG_ISO_14443B 0x0381