mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-12-30 20:23:46 +08:00
CHG: renamed iso7816 files
ADD: smartcard functionality (big thanks to Chris Nocker!)
This commit is contained in:
parent
726edb87cb
commit
192aa9abd7
6 changed files with 735 additions and 172 deletions
|
@ -23,7 +23,7 @@ APP_CFLAGS = -DWITH_CRC \
|
|||
-DWITH_ICLASS \
|
||||
-DWITH_FELICA \
|
||||
-DWITH_FLASH \
|
||||
-DWITH_ISO7816 \
|
||||
-DWITH_SMARTCARD \
|
||||
-DWITH_HFSNOOP \
|
||||
-DWITH_LF_SAMYRUN \
|
||||
-fno-strict-aliasing -ffunction-sections -fdata-sections
|
||||
|
@ -55,7 +55,7 @@ SRC_CRC = crc.c crc16.c crc32.c
|
|||
SRC_ICLASS = iclass.c optimized_cipher.c
|
||||
SRC_LEGIC = legicrf.c legic_prng.c
|
||||
SRC_FLASH = flashmem.c
|
||||
SRC_ISO7816 = iso7816.c
|
||||
SRC_SMARTCARD = smartcard.c
|
||||
SRC_BEE = bee.c
|
||||
|
||||
#the FPGA bitstream files. Note: order matters!
|
||||
|
@ -81,7 +81,7 @@ THUMBSRC = start.c \
|
|||
$(SRC_ZLIB) \
|
||||
$(SRC_LEGIC) \
|
||||
$(SRC_FLASH) \
|
||||
$(SRC_ISO7816) \
|
||||
$(SRC_SMARTCARD) \
|
||||
appmain.c \
|
||||
printf.c \
|
||||
util.c \
|
||||
|
|
|
@ -26,6 +26,11 @@
|
|||
#include "LCD.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_SMARTCARD
|
||||
#include "smartcard.h"
|
||||
#endif
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// A buffer where we can queue things up to be sent through the FPGA, for
|
||||
// any purpose (fake tag, as reader, whatever). We go MSB first, since that
|
||||
|
@ -364,7 +369,7 @@ void SendStatus(void) {
|
|||
BigBuf_print_status();
|
||||
Fpga_print_status();
|
||||
Flashmem_print_status();
|
||||
//Iso7816_print_status();
|
||||
SmartCard_print_status();
|
||||
printConfig(); //LF Sampling config
|
||||
printUSBSpeed();
|
||||
Dbprintf("Various");
|
||||
|
@ -1203,6 +1208,10 @@ void __attribute__((noreturn)) AppMain(void) {
|
|||
LCDInit();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_SMARTCARD
|
||||
SmartCard_init();
|
||||
#endif
|
||||
|
||||
byte_t rx[sizeof(UsbCommand)];
|
||||
|
||||
for(;;) {
|
||||
|
@ -1212,6 +1221,9 @@ void __attribute__((noreturn)) AppMain(void) {
|
|||
if ( cmd_receive( (UsbCommand*)rx ) )
|
||||
UsbPacketReceived(rx, sizeof(UsbCommand) );
|
||||
|
||||
#ifdef WITH_SMARTCARD
|
||||
SMART_CARD_ServiceSmartCard();
|
||||
#endif
|
||||
// Press button for one second to enter a possible standalone mode
|
||||
if (BUTTON_HELD(1000) > 0) {
|
||||
|
||||
|
|
148
armsrc/iso7816.c
148
armsrc/iso7816.c
|
@ -1,148 +0,0 @@
|
|||
#include "iso7816.h"
|
||||
|
||||
/* here: use NCPS2 @ PA10: */
|
||||
#define SPI_CSR_NUM 2 // Chip Select register[] 0,1,2,3 (at91samv512 has 4)
|
||||
|
||||
/* PCS_0 for NPCS0, PCS_1 for NPCS1 ... */
|
||||
#define PCS_0 ((0<<0)|(1<<1)|(1<<2)|(1<<3)) // 0xE - 1110
|
||||
#define PCS_1 ((1<<0)|(0<<1)|(1<<2)|(1<<3)) // 0xD - 1101
|
||||
#define PCS_2 ((1<<0)|(1<<1)|(0<<2)|(1<<3)) // 0xB - 1011
|
||||
#define PCS_3 ((1<<0)|(1<<1)|(1<<2)|(0<<3)) // 0x7 - 0111
|
||||
|
||||
// TODO
|
||||
#if (SPI_CSR_NUM == 0)
|
||||
#define SPI_MR_PCS PCS_0
|
||||
#elif (SPI_CSR_NUM == 1)
|
||||
#define SPI_MR_PCS PCS_1
|
||||
#elif (SPI_CSR_NUM == 2)
|
||||
#define SPI_MR_PCS PCS_2
|
||||
#elif (SPI_CSR_NUM == 3)
|
||||
#define SPI_MR_PCS PCS_3
|
||||
#else
|
||||
#error "SPI_CSR_NUM invalid"
|
||||
// not realy - when using an external address decoder...
|
||||
// but this code takes over the complete SPI-interace anyway
|
||||
#endif
|
||||
|
||||
|
||||
void ISO7816_setup(void) {
|
||||
// PA1 -> SIM RST
|
||||
// PA5 -> SIM I/O
|
||||
// PA7 -> SIM CLK
|
||||
|
||||
// Disable PIO control of the following pins, allows use by the SPI peripheral
|
||||
AT91C_BASE_PIOA->PIO_PDR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2;
|
||||
|
||||
// Pull-up Enable
|
||||
AT91C_BASE_PIOA->PIO_PPUER = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2;
|
||||
|
||||
// Peripheral A
|
||||
AT91C_BASE_PIOA->PIO_ASR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK;
|
||||
|
||||
// Peripheral B
|
||||
AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2;
|
||||
|
||||
//enable the SPI Peripheral clock
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI);
|
||||
|
||||
// Enable SPI
|
||||
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
|
||||
|
||||
// NPCS2 Mode 0
|
||||
AT91C_BASE_SPI->SPI_MR =
|
||||
( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
|
||||
(0xB << 16) | // Peripheral Chip Select (selects SPI_NCS2 or PA10)
|
||||
( 0 << 7) | // Local Loopback Disabled
|
||||
( 1 << 4) | // Mode Fault Detection disabled
|
||||
( 0 << 2) | // Chip selects connected directly to peripheral
|
||||
( 0 << 1) | // Fixed Peripheral Select
|
||||
( 1 << 0); // Master Mode
|
||||
|
||||
// 8 bit
|
||||
AT91C_BASE_SPI->SPI_CSR[2] =
|
||||
( 0 << 24) | // Delay between Consecutive Transfers (32 MCK periods)
|
||||
( 0 << 16) | // Delay Before SPCK (1 MCK period)
|
||||
( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud
|
||||
( 0 << 4) | // Bits per Transfer (8 bits)
|
||||
( 1 << 3) | // Chip Select inactive after transfer
|
||||
( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge
|
||||
( 0 << 0); // Clock Polarity inactive state is logic 0
|
||||
|
||||
// read first, empty buffer
|
||||
if (AT91C_BASE_SPI->SPI_RDR == 0) {};
|
||||
}
|
||||
|
||||
void ISO7816_stop(void) {
|
||||
//* Reset all the Chip Select register
|
||||
AT91C_BASE_SPI->SPI_CSR[0] = 0;
|
||||
AT91C_BASE_SPI->SPI_CSR[1] = 0;
|
||||
AT91C_BASE_SPI->SPI_CSR[2] = 0;
|
||||
AT91C_BASE_SPI->SPI_CSR[3] = 0;
|
||||
|
||||
// Reset the SPI mode
|
||||
AT91C_BASE_SPI->SPI_MR = 0;
|
||||
|
||||
// Disable all interrupts
|
||||
AT91C_BASE_SPI->SPI_IDR = 0xFFFFFFFF;
|
||||
|
||||
// SPI disable
|
||||
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;
|
||||
|
||||
if ( MF_DBGLEVEL > 3 ) Dbprintf("ISO7816 Stop");
|
||||
|
||||
StopTicks();
|
||||
}
|
||||
|
||||
// send one byte over SPI
|
||||
uint16_t ISO7816_sendbyte(uint32_t data) {
|
||||
uint16_t incoming = 0;
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
// wait until SPI is ready for transfer
|
||||
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {};
|
||||
|
||||
// send the data
|
||||
AT91C_BASE_SPI->SPI_TDR = data;
|
||||
|
||||
// wait recive transfer is complete
|
||||
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0)
|
||||
WDT_HIT();
|
||||
|
||||
// reading incoming data
|
||||
incoming = ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF);
|
||||
|
||||
return incoming;
|
||||
}
|
||||
|
||||
// initialize
|
||||
bool ISO7816_init(void) {
|
||||
ISO7816_setup();
|
||||
|
||||
StartTicks();
|
||||
|
||||
// StopTicks();
|
||||
// return false;
|
||||
|
||||
if ( MF_DBGLEVEL > 3 ) Dbprintf("ISO7816 OK");
|
||||
return true;
|
||||
}
|
||||
|
||||
void ISO7816_test(void) {
|
||||
|
||||
if (!ISO7816_init()) return;
|
||||
|
||||
ISO7816_stop();
|
||||
}
|
||||
|
||||
void Iso7816_print_status(void) {
|
||||
DbpString("Contact module (iso7816)");
|
||||
|
||||
if (!ISO7816_init()) {
|
||||
DbpString(" init....................FAIL");
|
||||
return;
|
||||
}
|
||||
DbpString(" init....................OK");
|
||||
|
||||
ISO7816_stop();
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef __ISO7816_H
|
||||
#define __ISO7816_H
|
||||
|
||||
#include "proxmark3.h"
|
||||
#include "apps.h"
|
||||
#include "ticks.h"
|
||||
|
||||
#define ISO_CLK 75000000 //Hex equivalent of 75MHz
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
extern void Dbprintf(const char *fmt, ...);
|
||||
|
||||
void ISO7816_setup(void);
|
||||
void ISO7816_stop(void);
|
||||
bool ISO7816_waitidle(void);
|
||||
uint16_t ISO7816_sendbyte(uint32_t data);
|
||||
bool ISO7816_init();
|
||||
void ISO7816_test(void);
|
||||
void Iso7816_print_status(void);
|
||||
#endif
|
702
armsrc/smartcard.c
Normal file
702
armsrc/smartcard.c
Normal file
|
@ -0,0 +1,702 @@
|
|||
/**************************************************************************************************
|
||||
*
|
||||
* @project Proxmark 3
|
||||
* @file smartcard.c
|
||||
* @author Chris Nocker <nocker02@gmail.com>
|
||||
* @created 03/04/2018
|
||||
* @brief Implements communication with a smart card.
|
||||
*
|
||||
*************************************************************************************************/
|
||||
#include "smartcard.h"
|
||||
|
||||
//#define SMART_CARD_DEBUG_ENABLED
|
||||
#ifndef SMART_CARD_DEBUG_ENABLED
|
||||
|
||||
#endif // SMART_CARD_DEBUG_ENABLED
|
||||
|
||||
// -- Defines ---------------------------------------------------------------------------------- //
|
||||
#define SMART_CARD_RST_PIN AT91C_PIO_PA1
|
||||
#define SMART_CARD_IO_PIN AT91C_PIO_PA5
|
||||
#define SMART_CARD_CLK_PIN AT91C_PIO_PA7
|
||||
#define SMART_CARD_RST_LO AT91C_BASE_PIOA->PIO_CODR |= SMART_CARD_RST_PIN
|
||||
#define SMART_CARD_RST_HI AT91C_BASE_PIOA->PIO_SODR |= SMART_CARD_RST_PIN
|
||||
#define SMART_CARD_RST_STATE AT91C_BASE_PIOA->PIO_ODSR & SMART_CARD_RST_PIN
|
||||
#define SMART_CARD_IO_LO AT91C_BASE_PIOA->PIO_CODR |= SMART_CARD_IO_PIN
|
||||
#define SMART_CARD_IO_HI AT91C_BASE_PIOA->PIO_SODR |= SMART_CARD_IO_PIN
|
||||
#define SMART_CARD_IO_STATE AT91C_BASE_PIOA->PIO_ODSR & SMART_CARD_IO_PIN
|
||||
#define SMART_CARD_CLK_LO AT91C_BASE_PIOA->PIO_CODR |= SMART_CARD_CLK_PIN
|
||||
#define SMART_CARD_CLK_HI AT91C_BASE_PIOA->PIO_SODR |= SMART_CARD_CLK_PIN
|
||||
#define SMART_CARD_CLK_STATE AT91C_BASE_PIOA->PIO_ODSR & SMART_CARD_CLK_PIN
|
||||
#define SMART_CARD_IO_OUPUT_MODE AT91C_BASE_PIOA->PIO_OER = SMART_CARD_IO_PIN
|
||||
#define SMART_CARD_IO_RECEPTION_MODE AT91C_BASE_PIOA->PIO_ODR = SMART_CARD_IO_PIN
|
||||
#define SMART_CARD_RECEIVE_BUFFER_SIZE (10)
|
||||
#define SMART_CARD_TRANSMIT_BUFFER_SIZE (10)
|
||||
|
||||
// true = the distance between a and b is greater than c
|
||||
#define RANGE(a,b,c) ((MAX(a,b))-(MIN(a,b))>(c))
|
||||
|
||||
// -- Private Variables ------------------------------------------------------------------------ //
|
||||
|
||||
static bool triggerDeactivation;
|
||||
static bool communicationsEstablished;
|
||||
static uint16_t receiveBuffer[SMART_CARD_RECEIVE_BUFFER_SIZE]; // Raw received bytes that need their parity checked before using them
|
||||
static uint8_t receiveGetPtr;
|
||||
static uint8_t receivePutPtr;
|
||||
static uint8_t transmitBuffer[SMART_CARD_TRANSMIT_BUFFER_SIZE];
|
||||
static uint8_t transmitGetPtr;
|
||||
static uint8_t transmitPutPtr;
|
||||
static bool generateClk;
|
||||
static bool receptionMode;
|
||||
static bool transmitMode;
|
||||
|
||||
/**
|
||||
* @brief Get a transmit byte
|
||||
* @description Get a byte from the transmit buffer
|
||||
* @param receivedByte Pointer to return the byte from the buffer to the caller
|
||||
* @return bool true = A byte was removed from the buffer and returned to the caller
|
||||
* false = No byte available
|
||||
*/
|
||||
static bool SMART_CARD_GetTransmitByte( uint8_t * receivedByte ) {
|
||||
bool result = false;
|
||||
uint8_t tempGetPtr = transmitGetPtr;
|
||||
|
||||
// Move the temp put pointer to the next index
|
||||
if ( ++tempGetPtr >= SMART_CARD_RECEIVE_BUFFER_SIZE ) {
|
||||
tempGetPtr = 0;
|
||||
}
|
||||
|
||||
// If the get pointer does not match the put pointer then there is data to be taken from the buffer
|
||||
if ( transmitGetPtr != transmitPutPtr ) {
|
||||
*receivedByte = transmitBuffer[transmitGetPtr];
|
||||
transmitGetPtr = tempGetPtr;
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put transmit byte
|
||||
* @description Store a byte in the transmit buffer
|
||||
* @param transmitByte The byte to try and put in the buffer
|
||||
* @return bool true = Operation was performed successfully
|
||||
* false = No room in buffer :-(
|
||||
*/
|
||||
static bool SMART_CARD_PutTransmitByte( uint8_t transmitByte ) {
|
||||
bool result = false;
|
||||
uint8_t tempPutPtr = transmitPutPtr;
|
||||
|
||||
// Move the temp put pointer to the next index
|
||||
if ( ++tempPutPtr >= SMART_CARD_RECEIVE_BUFFER_SIZE ) {
|
||||
tempPutPtr = 0;
|
||||
}
|
||||
|
||||
// If the new put pointer does not match the get pointer then it is safe to save this byte
|
||||
if ( tempPutPtr != transmitGetPtr ) {
|
||||
transmitBuffer[transmitPutPtr] = transmitByte;
|
||||
transmitPutPtr = tempPutPtr;
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get received byte
|
||||
* @description Get a byte from the receive buffer
|
||||
* @param receivedByte Pointer to return the byte from the buffer to the caller
|
||||
* @return bool true = A byte was removed from the buffer and returned to the caller
|
||||
* false = No byte available
|
||||
*/
|
||||
static bool SMART_CARD_GetRecievedByte( uint16_t * receivedByte ) {
|
||||
bool result = false;
|
||||
uint8_t tempGetPtr = receiveGetPtr;
|
||||
|
||||
// Move the temp put pointer to the next index
|
||||
if ( ++tempGetPtr >= SMART_CARD_RECEIVE_BUFFER_SIZE ) {
|
||||
tempGetPtr = 0;
|
||||
}
|
||||
|
||||
// If the get pointer does not match the put pointer then there is data to be taken from the buffer
|
||||
if ( receiveGetPtr != receivePutPtr ) {
|
||||
*receivedByte = receiveBuffer[receiveGetPtr];
|
||||
receiveGetPtr = tempGetPtr;
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put received byte
|
||||
* @description Store a verified, received byte in the receive buffer
|
||||
* @param receivedByte The byte to try and put in the buffer
|
||||
* @return bool true = Operation was performed successfully
|
||||
* false = No room in buffer :-(
|
||||
*/
|
||||
static bool SMART_CARD_PutRecievedByte( uint16_t receivedByte ) {
|
||||
bool result = false;
|
||||
uint8_t tempPutPtr = receivePutPtr;
|
||||
|
||||
// Move the temp put pointer to the next index
|
||||
if ( ++tempPutPtr >= SMART_CARD_RECEIVE_BUFFER_SIZE ) {
|
||||
tempPutPtr = 0;
|
||||
}
|
||||
|
||||
// If the new put pointer does not match the get pointer then it is safe to save this byte
|
||||
if ( tempPutPtr != receiveGetPtr ) {
|
||||
receiveBuffer[receivePutPtr] = receivedByte;
|
||||
receivePutPtr = tempPutPtr;
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate byte parity
|
||||
* @description Calculate the parity of a byte
|
||||
* @param dataByte Byte to calculate the parity of
|
||||
* @return bool true = Parity of the byte is high
|
||||
* false = Parity of the byte is low
|
||||
*/
|
||||
static bool SMART_CARD_CalculateByteParity( uint8_t dataByte ) {
|
||||
bool result;
|
||||
uint8_t i, parity;
|
||||
|
||||
// Accumulate the parity
|
||||
for ( i = 0, parity = 0; i < 8; i++ ) {
|
||||
if ( dataByte & ( 1 << i ) ) {
|
||||
parity++;
|
||||
}
|
||||
}
|
||||
|
||||
// The high (1) bits of the byte plus the parity bit must be even for the byte to be considered as good
|
||||
result = ( parity % 2 ) ? true : false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Verify received byte parity
|
||||
* @description Calculate the parity of a received sampled byte and compare it to the parity in the received sampled byte
|
||||
* @param receivedSampledByte Byte to verify the parity of
|
||||
* @return bool true = Parity of the received byte is good
|
||||
* false = Parity of the received byte is bad (reject)
|
||||
*/
|
||||
static bool SMART_CARD_VerifyReceivedByteParity( uint16_t receivedSampledByte ) {
|
||||
bool result;
|
||||
uint8_t dataByte = (uint8_t)(receivedSampledByte >> 1 );
|
||||
|
||||
// Check if the calculated parity is the same as the parity in the received sampled byte
|
||||
if ( SMART_CARD_CalculateByteParity( dataByte ) == ( receivedSampledByte & 1 ) )
|
||||
result = true;
|
||||
else
|
||||
result = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Maintain the smart card connection
|
||||
* @description Send and receive commands
|
||||
* @param void
|
||||
* @return bool true = Operation was performed successfully
|
||||
* false = An error occurred
|
||||
*/
|
||||
static bool SMART_CARD_MaintainConnection( void ) {
|
||||
// TODO: This functions implementation is not yet complete
|
||||
|
||||
bool result = true;
|
||||
uint16_t rxByte;
|
||||
uint8_t verifiedRxByte;
|
||||
|
||||
// See if there has been a new byte sampled
|
||||
if ( SMART_CARD_GetRecievedByte( &rxByte ) ) {
|
||||
// Check that the parity is correct
|
||||
if ( SMART_CARD_VerifyReceivedByteParity( rxByte ) ) {
|
||||
verifiedRxByte = rxByte >> 1;
|
||||
|
||||
// TODO: Dummy code that is to remove compiler warnings during development
|
||||
if ( verifiedRxByte ) {
|
||||
SMART_CARD_PutTransmitByte( verifiedRxByte );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the clock
|
||||
* @description
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
static void SMART_CARD_DisableClock( void ) {
|
||||
// Disable TC2
|
||||
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS;
|
||||
generateClk = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the clock
|
||||
* @description
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
static void SMART_CARD_EnableClock( void ) {
|
||||
// Enable and reset TC2
|
||||
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
generateClk = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform deactivation
|
||||
* @description Control the signals to the smart card to perform a deactivation operation
|
||||
* @param void
|
||||
* @return bool true = Operation was performed successfully
|
||||
* false = An error occurred
|
||||
*/
|
||||
static void SMART_CARD_PerformDeactivation( void ) {
|
||||
/*
|
||||
* 1. Reset L
|
||||
* 2. CLK L
|
||||
* 3. I/O L
|
||||
* 4. VCC L (NOTE: This may require a circuit change!!!)
|
||||
*/
|
||||
SMART_CARD_RST_LO;
|
||||
SMART_CARD_IO_LO;
|
||||
SMART_CARD_DisableClock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Negotiate parameters
|
||||
* @description
|
||||
* @param void
|
||||
* @return bool true = Operation was performed successfully
|
||||
* false = An error occurred
|
||||
*/
|
||||
//static bool SMART_CARD_NegotiateProtocolParameters( void ) {
|
||||
// TODO: This functions implementation is not yet complete
|
||||
// bool result = false;
|
||||
//
|
||||
// // Check if the card is in a specific mode
|
||||
// if ( 0xFF )
|
||||
// {
|
||||
// // Have to use this mode
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // Negotiate
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
//}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Class selection
|
||||
* @description Class selection
|
||||
* @param void
|
||||
* @return bool true = Operation was performed successfully
|
||||
* false = An error occurred
|
||||
*/
|
||||
static bool SMART_CARD_ClassSelection( uint8_t class, uint8_t * answer, uint8_t length ) {
|
||||
bool result = false;
|
||||
|
||||
// Check that an answer was received
|
||||
if ( answer[0] ) {
|
||||
// Check that the answer was valid
|
||||
if ( answer[1] ) {
|
||||
// See if the card indicated a class
|
||||
if ( answer[2] ) {
|
||||
// Check that we are happy with the class (i.e. this is the 3V one that we supplied)
|
||||
if ( answer[2] == 2 ) {
|
||||
result = true;
|
||||
} else {
|
||||
// We cannot work with this class
|
||||
triggerDeactivation = true;
|
||||
}
|
||||
} else {
|
||||
// Card did not indicate class, just accept this answer
|
||||
result = true;
|
||||
}
|
||||
} else {
|
||||
// Error handling
|
||||
}
|
||||
} else {
|
||||
// Card did not answer
|
||||
triggerDeactivation = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Process the reset answer
|
||||
* @description
|
||||
* @param answer
|
||||
* @return bool true = Operation was performed successfully
|
||||
* false = An error occurred
|
||||
*/
|
||||
static bool SMART_CARD_ProcessResetAnswer( uint8_t * answer, uint8_t length ) {
|
||||
// TODO: This functions implementation is not yet complete
|
||||
bool result = false;
|
||||
uint8_t class;
|
||||
|
||||
for ( class = 0; class < 3; class++ ) {
|
||||
// We can only do one class as we cannot adjust the VCC voltage
|
||||
if ( SMART_CARD_ClassSelection( class, answer, length ) ) {
|
||||
result = true;
|
||||
break;
|
||||
} else {
|
||||
if ( triggerDeactivation ) {
|
||||
triggerDeactivation = false;
|
||||
SMART_CARD_PerformDeactivation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Perform warm reset
|
||||
* @description Can be performed at any time (not sure we'll use this one???)
|
||||
* @param void
|
||||
* @return bool true = Operation was performed successfully
|
||||
* false = An error occurred
|
||||
*/
|
||||
//static bool SMART_CARD_PerformWarmReset( void ) {
|
||||
// TODO: This functions implementation is not yet complete
|
||||
// bool result = false;
|
||||
// /*
|
||||
// * 1. the interface device initiates a warm reset (at time Tc) by putting RST to state L for at least 400 clock cycles (delay te) while VCC remains powered and CLK provided
|
||||
// * 2. The card shall set I/O to state H within 200 clock cycles (delay td) after state L is applied to RST
|
||||
// * 3. RST is put to state H
|
||||
// * 4. The answer on I/O shall begin between 400 and 40 000 clock cycles (delay tf) after the rising edge of the signal on RST
|
||||
// * 5. If the answer does not begin within 40 000 clock cycles with RST at state H, the interface device shall perform a deactivation
|
||||
// */
|
||||
//
|
||||
// return result;
|
||||
//}
|
||||
|
||||
/**
|
||||
* @brief Perform cold reset
|
||||
* @description We are outputting the CLK to the smart card. Wait for the initial reset answer
|
||||
* @param void
|
||||
* @return bool true = Operation was performed successfully
|
||||
* false = An error occurred
|
||||
*/
|
||||
static bool SMART_CARD_PerformColdReset( void ) {
|
||||
// TODO: This functions implementation is not yet complete
|
||||
bool result = false;
|
||||
/*
|
||||
* 1. The card shall set I/O to state H within 200 clock cycles
|
||||
* The cold reset results from maintaining RST at state L for at least 400 clock cycles (delay tb) after the clock signal is applied to CLK
|
||||
* 2. The interface device shall ignore the state on I/O while RST is at state L
|
||||
* 3. RST is put to state H
|
||||
* 4. The answer on I/O shall begin between 400 and 40 000 clock cycles (delay tc) after the rising edge of the signal on RST
|
||||
* 5. If the answer does not begin within 40 000 clock cycles with RST at state H, the interface device shall perform a deactivation
|
||||
*/
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Activate the smart card interface
|
||||
* @description Control the interface signals to perform an activation on the smart card
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
static void SMART_CARD_ActivateInterface( void ) {
|
||||
/*
|
||||
* 1. RST shall be put to state L
|
||||
* 2. VCC shall be powered
|
||||
* 3. I/O in the interface device shall be put in reception mode
|
||||
* 4. CLK shall be provided with a clock signal (1MHz to 5MHz)
|
||||
*/
|
||||
SMART_CARD_RST_LO;
|
||||
SMART_CARD_IO_RECEPTION_MODE;
|
||||
SMART_CARD_EnableClock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Establish communications
|
||||
* @description Activate the smart card, perform a cold reset & process the reset answer
|
||||
* @param void
|
||||
* @return bool true = Operation was performed successfully and communications have been established
|
||||
* false = An error occurred
|
||||
*/
|
||||
static bool SMART_CARD_EstablishCommunications( void ) {
|
||||
// TODO: This functions implementation is not yet complete
|
||||
bool result = false;
|
||||
uint8_t answer;
|
||||
|
||||
// Activate the interface
|
||||
SMART_CARD_ActivateInterface();
|
||||
|
||||
// Perform a cold reset
|
||||
result = SMART_CARD_PerformColdReset();
|
||||
|
||||
// Process the "answer" if it was received
|
||||
if ( result ) {
|
||||
result = SMART_CARD_ProcessResetAnswer( &answer, 100 );
|
||||
|
||||
// Check if the "answer" was acceptable
|
||||
if ( !result ) {
|
||||
// Delay for 20ms
|
||||
WaitMS( 20 );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure timer
|
||||
* @description Configure the timer to generate an interrupt every 500ns. This is 2MHz. From this we will
|
||||
* generate the 1MHz clock signal and sample the I/O line every 2 interrupt triggers
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
static void SMART_CARD_ConfigureClock( void ) {
|
||||
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC2); // Enable Clock TC2
|
||||
|
||||
AT91C_BASE_TCB->TCB_BMR &= AT91C_TCB_TC2XC2S; // Clear the external clock selection
|
||||
AT91C_BASE_TCB->TCB_BMR |= AT91C_TCB_TC2XC2S_NONE; // XC2 Clock = None
|
||||
|
||||
// Configure TC2 to count up to RC, then reset and generate an interrupt
|
||||
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // Disable TC2
|
||||
AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC2 Clock = MCK(48MHz)/2 = 24MHz
|
||||
| AT91C_TC_CPCTRG; // Capture Mode, reset the TC2 counter when RC is reached
|
||||
AT91C_BASE_TC2->TC_RC = 12; // RC Compare value = 24MHz / 2MHz = 12
|
||||
AT91C_BASE_TC2->TC_IER = AT91C_TC_CPCS; // Generate an interrupt when the RC value is reached
|
||||
}
|
||||
|
||||
|
||||
// -- Public Functions ------------------------------------------------------------------------- //
|
||||
|
||||
/**
|
||||
* @brief CLK interrupt handler
|
||||
*
|
||||
* @description Implements a bit banged CLK signal to the smart card. Also outputs data on the I/O line on rising
|
||||
* CLK edges when transmiting and samples the I/O line on falling CLK edges when receiving
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
void SMART_CARD_ClockInterruptHandler( void ) {
|
||||
static uint8_t clkCount;
|
||||
static uint8_t previousSampleRxClkCount;
|
||||
static uint8_t previousSampleTxClkCount;
|
||||
static uint16_t sampledRxData; // The bits of the Rx byte are accumulated here
|
||||
static uint8_t sampleBitIndex; // Used during both Tx and Rx as the comms are half duplex
|
||||
static uint8_t transmitByte;
|
||||
bool sampleBit = SMART_CARD_IO_STATE; // Read the state of the I/O signal in case we are going to use it
|
||||
|
||||
// Clear the interrupt
|
||||
// TODO: This functions implementation is not yet complete... just need to handle the interrupt
|
||||
|
||||
// Check if we are meant to be generating the CLK signal
|
||||
if ( generateClk )
|
||||
{
|
||||
// On the even clock counts we will toggle the CLK signal
|
||||
if ( clkCount++ % 2 )
|
||||
{
|
||||
// Read the current state of the CLK signal, if it is High then set it Low and if it is Low set it High
|
||||
if ( SMART_CARD_CLK_STATE )
|
||||
{
|
||||
// Generate a falling edge
|
||||
SMART_CARD_CLK_LO;
|
||||
|
||||
// ******************************************************************* //
|
||||
// On the falling edge of the CLK signal we sample from the I/O signal //
|
||||
// ******************************************************************* //
|
||||
|
||||
// See if we are receiving
|
||||
if ( receptionMode )
|
||||
{
|
||||
// See if we are already looking for the start of a new byte OR
|
||||
// It has been a while since we last captured a byte (this provides resynchronising)
|
||||
if ( ( sampleBitIndex == 0 ) || ( RANGE( clkCount, previousSampleRxClkCount, 5 ) ) )
|
||||
{
|
||||
sampleBitIndex = 0;
|
||||
previousSampleRxClkCount = clkCount;
|
||||
|
||||
// The start bit must be low
|
||||
if ( sampleBit == 0 )
|
||||
{
|
||||
// Set the bit index to indicate that we've detected a start bit
|
||||
sampleBitIndex = 1;
|
||||
|
||||
// Initialise the sample data byte where the received bits will be put
|
||||
sampledRxData = 0;
|
||||
}
|
||||
}
|
||||
// Otherwise see if we are in the process of collecting bits of a sample byte
|
||||
else if ( ( sampleBitIndex ) && ( sampleBitIndex <= 10 ) )
|
||||
{
|
||||
// Shift the bits of the sampled byte up by 1 to make room for this new bit
|
||||
sampledRxData = sampledRxData << 1;
|
||||
|
||||
// Or in the new sample bit
|
||||
sampledRxData |= sampleBit << sampleBitIndex;
|
||||
|
||||
// Check if we've received the start bit, 8 bits of the byte and the parity bit
|
||||
if ( sampleBitIndex == 10 )
|
||||
{
|
||||
// Transfer the sampled data into the receive buffer so that it can be processed
|
||||
if ( !SMART_CARD_PutRecievedByte( sampledRxData ) )
|
||||
{
|
||||
// An error has occured as there was no space to save this byte!
|
||||
}
|
||||
}
|
||||
|
||||
// Increment index and wait for next bit
|
||||
sampleBitIndex++;
|
||||
|
||||
// Update the Rx CLK count so we know how long to wait
|
||||
previousSampleRxClkCount = clkCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
// CLK is Low so set it High
|
||||
else
|
||||
{
|
||||
// Generate a rising edge
|
||||
SMART_CARD_CLK_HI;
|
||||
|
||||
// ***************************************************************************************** //
|
||||
// On the rising edge of the CLK signal we output the next bit of the byte to the I/O signal //
|
||||
// ***************************************************************************************** //
|
||||
|
||||
// See if we are transmitting
|
||||
if ( transmitMode )
|
||||
{
|
||||
// See if we are already looking for new byte to transmit OR
|
||||
// It has been a while since we last sent a byte (this allows for the "pause" time)
|
||||
if ( ( sampleBitIndex == 0 ) || ( RANGE( clkCount, previousSampleTxClkCount, 7 ) ) )
|
||||
{
|
||||
sampleBitIndex = 0;
|
||||
previousSampleTxClkCount = clkCount;
|
||||
|
||||
// See if there is a byte to transmit
|
||||
if ( SMART_CARD_GetTransmitByte( &transmitByte ) )
|
||||
{
|
||||
// The start bit must be low
|
||||
SMART_CARD_IO_LO;
|
||||
|
||||
// Set the bit index to indicate that we've started transmitting
|
||||
sampleBitIndex = 1;
|
||||
}
|
||||
}
|
||||
// We are in the process of collecting bits of a sample byte
|
||||
else if ( ( sampleBitIndex ) && ( sampleBitIndex <= 11 ) )
|
||||
{
|
||||
// Check if we've output the start bit and the 8 bits of the byte and the parity bit
|
||||
if ( sampleBitIndex == 11 )
|
||||
{
|
||||
// There is nothing left to output, set the I/O signal high during the "pause" time
|
||||
SMART_CARD_IO_HI;
|
||||
}
|
||||
// Check if we've output the start bit and the 8 bits of the byte
|
||||
else if ( sampleBitIndex == 10 )
|
||||
{
|
||||
// Calculate the parity bit and output it appropriately
|
||||
if ( SMART_CARD_CalculateByteParity( transmitByte ) )
|
||||
{
|
||||
SMART_CARD_IO_HI;
|
||||
}
|
||||
else
|
||||
{
|
||||
SMART_CARD_IO_LO;
|
||||
}
|
||||
}
|
||||
// Otherwise we are still outputting the bits of the byte
|
||||
else
|
||||
{
|
||||
// Set the state of the I/O signal according to the bits of the transmit byte
|
||||
if ( transmitByte & ( 1 << ( sampleBitIndex - 1 ) ) )
|
||||
{
|
||||
SMART_CARD_IO_HI;
|
||||
}
|
||||
else
|
||||
{
|
||||
SMART_CARD_IO_LO;
|
||||
}
|
||||
}
|
||||
|
||||
// Increment index for when the next bit is output
|
||||
sampleBitIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Service the smart card interface
|
||||
* @description Check if a transaction needs to occur
|
||||
* @param void
|
||||
* @return bool true = The smart card was service successfully
|
||||
* false = An error occurred
|
||||
*/
|
||||
void SMART_CARD_ServiceSmartCard( void ) {
|
||||
|
||||
if ( !communicationsEstablished ) {
|
||||
// Attempt to establish communications if they are not currently working
|
||||
communicationsEstablished = SMART_CARD_EstablishCommunications();
|
||||
} else {
|
||||
// Communications are working, processs any commands/responses
|
||||
|
||||
// If a fatal error occurs we will need to re-establish communications
|
||||
communicationsEstablished = SMART_CARD_MaintainConnection();
|
||||
}
|
||||
}
|
||||
|
||||
void SmartCard_setup(void) {
|
||||
// Enable the pins to be controlled
|
||||
AT91C_BASE_PIOA->PIO_PER = SMART_CARD_RST_PIN | SMART_CARD_CLK_PIN | SMART_CARD_IO_PIN;
|
||||
|
||||
// Configure the pins to be outputs
|
||||
AT91C_BASE_PIOA->PIO_OER = SMART_CARD_RST_PIN | SMART_CARD_CLK_PIN | SMART_CARD_IO_PIN;
|
||||
|
||||
// Configure the IO pin for multi-drive mode (is this right?)
|
||||
AT91C_BASE_PIOA->PIO_MDER = SMART_CARD_IO_PIN;
|
||||
AT91C_BASE_PIOA->PIO_PPUER = SMART_CARD_IO_PIN;
|
||||
|
||||
// Configure a timer to generate an interrupt for the clock signal and sampling of the I/O line
|
||||
SMART_CARD_ConfigureClock();
|
||||
}
|
||||
|
||||
void SmartCard_stop(void) {
|
||||
StopTicks();
|
||||
if ( MF_DBGLEVEL > 3 ) Dbprintf("Smart Card Stop");
|
||||
LED_A_OFF();
|
||||
}
|
||||
|
||||
bool SmartCard_init(void) {
|
||||
|
||||
StartTicks();
|
||||
|
||||
LED_A_ON();
|
||||
SmartCard_setup();
|
||||
|
||||
if ( MF_DBGLEVEL > 3 ) Dbprintf("Smart Card Init OK");
|
||||
return true;
|
||||
}
|
||||
|
||||
void SmartCard_print_status(void) {
|
||||
DbpString("Smart card module (ISO 7816)");
|
||||
|
||||
if (!SmartCard_init()) {
|
||||
DbpString(" init....................FAIL");
|
||||
return;
|
||||
}
|
||||
DbpString(" init....................OK");
|
||||
|
||||
SmartCard_stop();
|
||||
}
|
17
armsrc/smartcard.h
Normal file
17
armsrc/smartcard.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef __SMARTCARD_H
|
||||
#define __SMARTCARD_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
#include "proxmark3.h"
|
||||
#include "apps.h"
|
||||
#include "ticks.h"
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
extern void Dbprintf(const char *fmt, ...);
|
||||
|
||||
void SmartCard_setup(void);
|
||||
void SmartCard_stop(void);
|
||||
bool SmartCard_init();
|
||||
|
||||
void SMART_CARD_ServiceSmartCard( void );
|
||||
void SmartCard_print_status(void);
|
||||
#endif
|
Loading…
Reference in a new issue