//
//-----------------------------------------------------------------------------
-#include "proxmark3.h"
+#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
// Needed for CRC in emulation mode;
// same construction as in ISO 14443;
// different initial value (CRC_ICLASS)
-#include "iso14443crc.h"
-#include "iso15693tools.h"
-#include "cipher.h"
+#include "../common/iso14443crc.h"
+#include "../common/iso15693tools.h"
+//#include "iso15693tools.h"
#include "protocols.h"
+#include "optimized_cipher.h"
+
static int timeout = 4096;
SUB_SECOND_HALF,
SUB_BOTH
} sub;
- uint8_t *output;
+ uint8_t *output;
} Demod;
static RAMFUNC int ManchesterDecoding(int v)
//-----------------------------------------------------------------------------
void RAMFUNC SnoopIClass(void)
{
-
-
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
// response from the tag.
clear_trace();
iso14a_set_trigger(FALSE);
- int lastRxCounter;
+ int lastRxCounter;
uint8_t *upTo;
int smpl;
int maxBehindBy = 0;
if(ManchesterDecoding(smpl & 0x0F)) {
time_stop = (GetCountSspClk()-time_0) << 4;
- rsamples = samples - Demod.samples;
+ rsamples = samples - Demod.samples;
LED_B_ON();
if(tracing) {
uint8_t b = cmd[i];
ToSend[++ToSendMax] = encode4Bits(b & 0xF); //Least significant half
ToSend[++ToSendMax] = encode4Bits((b >>4) & 0xF);//Most significant half
- }
+ }
// Send EOF
ToSend[++ToSendMax] = 0xB8;
Dbprintf("Done...");
}
+void AppendCrc(uint8_t* data, int len)
+{
+ ComputeCrc14443(CRC_ICLASS,data,len,data+len,data+len+1);
+}
/**
* @brief Does the actual simulation
// free eventually allocated BigBuf memory
BigBuf_free_keep_EM();
+ State cipher_state;
+// State cipher_state_reserve;
uint8_t *csn = BigBuf_get_EM_addr();
uint8_t *emulator = csn;
uint8_t sof_data[] = { 0x0F} ;
ComputeCrc14443(CRC_ICLASS, anticoll_data, 8, &anticoll_data[8], &anticoll_data[9]);
ComputeCrc14443(CRC_ICLASS, csn_data, 8, &csn_data[8], &csn_data[9]);
+ uint8_t diversified_key[8] = { 0 };
// e-Purse
uint8_t card_challenge_data[8] = { 0x00 };
if(simulationMode == MODE_FULLSIM)
{
+ //The diversified key should be stored on block 3
+ //Get the diversified key from emulator memory
+ memcpy(diversified_key, emulator+(8*3),8);
+
//Card challenge, a.k.a e-purse is on block 2
memcpy(card_challenge_data,emulator + (8 * 2) , 8);
+ //Precalculate the cipher state, feeding it the CC
+ cipher_state = opt_doTagMAC_1(card_challenge_data,diversified_key);
+
}
int exitLoop = 0;
memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax;
//This is used for responding to READ-block commands or other data which is dynamically generated
- uint8_t *data_response = BigBuf_malloc(8 * 2 + 2);
- //This is used for responding to READ-block commands or other data which is dynamically generated
- uint8_t *data_generic_trace = BigBuf_malloc(8 * 2 + 2);
+ //First the 'trace'-data, not encoded for FPGA
+ uint8_t *data_generic_trace = BigBuf_malloc(8 + 2);//8 bytes data + 2byte CRC is max tag answer
+ //Then storage for the modulated data
+ //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes)
+ uint8_t *data_response = BigBuf_malloc( (8+2) * 2 + 2);
// Start from off (no field generated)
//FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_A_ON();
bool buttonPressed = false;
-
+ uint8_t response_delay = 1;
while(!exitLoop) {
-
+ response_delay = 1;
LED_B_OFF();
//Signal tracer
// Can be used to get a trigger for an oscilloscope..
} else if(receivedCmd[0] == ICLASS_CMD_CHECK) {
// Reader random and reader MAC!!!
if(simulationMode == MODE_FULLSIM)
- { //This is what we must do..
- //Reader just sent us NR and MAC(k,cc * nr)
- //The diversified key should be stored on block 3
- //However, from a typical dump, the key will not be there
- uint8_t diversified_key[8] = { 0 };
-
- //Get the diversified key from emulator memory
- memcpy(diversified_key, emulator+(8*3),8);
- uint8_t ccnr[12] = { 0 };
- //Put our cc there (block 2)
- memcpy(ccnr, emulator + (8 * 2), 8);
- //Put nr there
- memcpy(ccnr+8, receivedCmd+1,4);
- //Now, calc MAC
- doMAC(ccnr,diversified_key, data_generic_trace);
+ {
+ //NR, from reader, is in receivedCmd +1
+ opt_doTagMAC_2(cipher_state,receivedCmd+1,data_generic_trace,diversified_key);
+
trace_data = data_generic_trace;
trace_data_size = 4;
CodeIClassTagAnswer(trace_data , trace_data_size);
memcpy(data_response, ToSend, ToSendMax);
modulated_response = data_response;
modulated_response_size = ToSendMax;
+ response_delay = 0;//We need to hurry here...
+ //exitLoop = true;
}else
{ //Not fullsim, we don't respond
- // We do not know what to answer, so lets keep quiet
+ // We do not know what to answer, so lets keep quiet
modulated_response = resp_sof; modulated_response_size = 0;
- trace_data = NULL;
- trace_data_size = 0;
+ trace_data = NULL;
+ trace_data_size = 0;
if (simulationMode == MODE_EXIT_AFTER_MAC){
- // dbprintf:ing ...
- Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x"
- ,csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]);
- Dbprintf("RDR: (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x",len,
- receivedCmd[0], receivedCmd[1], receivedCmd[2],
- receivedCmd[3], receivedCmd[4], receivedCmd[5],
- receivedCmd[6], receivedCmd[7], receivedCmd[8]);
- if (reader_mac_buf != NULL)
- {
- memcpy(reader_mac_buf,receivedCmd+1,8);
- }
- exitLoop = true;
+ // dbprintf:ing ...
+ Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x"
+ ,csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]);
+ Dbprintf("RDR: (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x",len,
+ receivedCmd[0], receivedCmd[1], receivedCmd[2],
+ receivedCmd[3], receivedCmd[4], receivedCmd[5],
+ receivedCmd[6], receivedCmd[7], receivedCmd[8]);
+ if (reader_mac_buf != NULL)
+ {
+ memcpy(reader_mac_buf,receivedCmd+1,8);
}
+ exitLoop = true;
+ }
}
} else if(receivedCmd[0] == ICLASS_CMD_HALT && len == 1) {
} else if(simulationMode == MODE_FULLSIM && receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4){
//Read block
uint16_t blk = receivedCmd[1];
- trace_data = emulator+(blk << 3);
- trace_data_size = 8;
+ //Take the data...
+ memcpy(data_generic_trace, emulator+(blk << 3),8);
+ //Add crc
+ AppendCrc(data_generic_trace, 8);
+ trace_data = data_generic_trace;
+ trace_data_size = 10;
+ CodeIClassTagAnswer(trace_data , trace_data_size);
+ memcpy(data_response, ToSend, ToSendMax);
+ modulated_response = data_response;
+ modulated_response_size = ToSendMax;
+ }else if(receivedCmd[0] == ICLASS_CMD_UPDATE && simulationMode == MODE_FULLSIM)
+ {//Probably the reader wants to update the nonce. Let's just ignore that for now.
+ // OBS! If this is implemented, don't forget to regenerate the cipher_state
+ //We're expected to respond with the data+crc, exactly what's already in the receivedcmd
+ //receivedcmd is now UPDATE 1b | ADDRESS 1b| DATA 8b| Signature 4b or CRC 2b|
+
+ //Take the data...
+ memcpy(data_generic_trace, receivedCmd+2,8);
+ //Add crc
+ AppendCrc(data_generic_trace, 8);
+ trace_data = data_generic_trace;
+ trace_data_size = 10;
CodeIClassTagAnswer(trace_data , trace_data_size);
memcpy(data_response, ToSend, ToSendMax);
modulated_response = data_response;
A legit tag has about 380us delay between reader EOT and tag SOF.
**/
if(modulated_response_size > 0) {
- SendIClassAnswer(modulated_response, modulated_response_size, 1);
+ SendIClassAnswer(modulated_response, modulated_response_size, response_delay);
t2r_time = GetCountSspClk();
}
{
if(*wait < 10) *wait = 10;
- for(c = 0; c < *wait;) {
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
- AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing!
- c++;
- }
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
- volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
- (void)r;
- }
- WDT_HIT();
- }
+ for(c = 0; c < *wait;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing!
+ c++;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
+ (void)r;
+ }
+ WDT_HIT();
+ }
}
void ReaderTransmitIClass(uint8_t* frame, int len)
{
- int wait = 0;
- int samples = 0;
+ int wait = 0;
+ int samples = 0;
- // This is tied to other size changes
- CodeIClassCommand(frame,len);
+ // This is tied to other size changes
+ CodeIClassCommand(frame,len);
- // Select the card
- TransmitIClassCommand(ToSend, ToSendMax, &samples, &wait);
- if(trigger)
- LED_A_ON();
+ // Select the card
+ TransmitIClassCommand(ToSend, ToSendMax, &samples, &wait);
+ if(trigger)
+ LED_A_ON();
- // Store reader command in buffer
+ // Store reader command in buffer
if (tracing) {
uint8_t par[MAX_PARITY_SIZE];
GetParity(frame, len, par);
for(;;) {
WDT_HIT();
- if(BUTTON_PRESS()) return FALSE;
+ if(BUTTON_PRESS()) return FALSE;
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = 0x00; // To make use of exact timing of next command from reader!!
static uint8_t act_all[] = { 0x0a };
static uint8_t identify[] = { 0x0c };
static uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- static uint8_t readcheck_cc[]= { 0x88, 0x02 };
+
+
+ static uint8_t readcheck_cc[]= { 0x88, 0x02,};
+
uint8_t resp[ICLASS_BUFFER_SIZE];
uint8_t read_status = 0;
if(ReaderReceiveIClass(resp) == 8) {
//Save CC (e-purse) in response data
memcpy(card_data+8,resp,8);
-
- //Got both
- read_status = 2;
+ read_status++;
}
return read_status;
}
+
// Reader iClass Anticollission
void ReaderIClass(uint8_t arg0) {
- uint8_t card_data[24]={0};
+ uint8_t card_data[6 * 8]={0};
+ memset(card_data, 0xFF, sizeof(card_data));
uint8_t last_csn[8]={0};
+ //Read conf block CRC(0x01) => 0xfa 0x22
+ uint8_t readConf[] = { ICLASS_CMD_READ_OR_IDENTIFY,0x01, 0xfa, 0x22};
+ //Read conf block CRC(0x05) => 0xde 0x64
+ uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY,0x05, 0xde, 0x64};
+
+
int read_status= 0;
+ uint8_t result_status = 0;
bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE;
- bool get_cc = arg0 & FLAG_ICLASS_READER_GET_CC;
+ bool try_once = arg0 & FLAG_ICLASS_READER_ONE_TRY;
set_tracing(TRUE);
setupIclassReader();
- size_t datasize = 0;
+ uint16_t tryCnt=0;
while(!BUTTON_PRESS())
{
-
+ if (try_once && tryCnt > 5) break;
+ tryCnt++;
if(!tracing) {
DbpString("Trace full");
break;
read_status = handshakeIclassTag(card_data);
if(read_status == 0) continue;
- if(read_status == 1) datasize = 8;
- if(read_status == 2) datasize = 16;
+ if(read_status == 1) result_status = FLAG_ICLASS_READER_CSN;
+ if(read_status == 2) result_status = FLAG_ICLASS_READER_CSN|FLAG_ICLASS_READER_CC;
+
+ // handshakeIclass returns CSN|CC, but the actual block
+ // layout is CSN|CONFIG|CC, so here we reorder the data,
+ // moving CC forward 8 bytes
+ memcpy(card_data+16,card_data+8, 8);
+ //Read block 1, config
+ if(arg0 & FLAG_ICLASS_READER_CONF)
+ {
+ if(sendCmdGetResponseWithRetries(readConf, sizeof(readConf),card_data+8, 10, 10))
+ {
+ Dbprintf("Failed to dump config block");
+ }else
+ {
+ result_status |= FLAG_ICLASS_READER_CONF;
+ }
+ }
- //Todo, read the public blocks 1,5 aswell:
- //
- // 0 : CSN (we already have)
+ //Read block 5, AA
+ if(arg0 & FLAG_ICLASS_READER_AA){
+ if(sendCmdGetResponseWithRetries(readAA, sizeof(readAA),card_data+(8*4), 10, 10))
+ {
+// Dbprintf("Failed to dump AA block");
+ }else
+ {
+ result_status |= FLAG_ICLASS_READER_AA;
+ }
+ }
+
+ // 0 : CSN
// 1 : Configuration
- // 2 : e-purse (we already have)
- // (3,4 write-only)
+ // 2 : e-purse
+ // (3,4 write-only, kc and kd)
// 5 Application issuer area
//
//Then we can 'ship' back the 8 * 5 bytes of data,
// with 0xFF:s in block 3 and 4.
- LED_B_ON();
- //Send back to client, but don't bother if we already sent this
- if(memcmp(last_csn, card_data, 8) != 0)
+ LED_B_ON();
+ //Send back to client, but don't bother if we already sent this
+ if(memcmp(last_csn, card_data, 8) != 0)
{
-
- if(!get_cc || (get_cc && read_status == 2))
+ // If caller requires that we get CC, continue until we got it
+ if( (arg0 & read_status & FLAG_ICLASS_READER_CC) || !(arg0 & FLAG_ICLASS_READER_CC))
{
- cmd_send(CMD_ACK,read_status,0,0,card_data,datasize);
+ cmd_send(CMD_ACK,result_status,0,0,card_data,sizeof(card_data));
if(abort_after_read) {
LED_A_OFF();
return;
}
- //Save that we already sent this....
- memcpy(last_csn, card_data, 8);
+ //Save that we already sent this....
+ memcpy(last_csn, card_data, 8);
}
- //If 'get_cc' was specified and we didn't get a CC, we'll just keep trying...
+
}
LED_B_OFF();
}
uint8_t read_status = handshakeIclassTag(card_data);
if(read_status < 2) continue;
- //for now replay captured auth (as cc not updated)
- memcpy(check+5,MAC,4);
+ //for now replay captured auth (as cc not updated)
+ memcpy(check+5,MAC,4);
if(sendCmdGetResponseWithRetries(check, sizeof(check),resp, 4, 5))
{
- Dbprintf("Error: Authentication Fail!");
+ Dbprintf("Error: Authentication Fail!");
continue;
- }
+ }
//first get configuration block (block 1)
crc = block_crc_LUT[1];
- read[1]=1;
- read[2] = crc >> 8;
- read[3] = crc & 0xff;
+ read[1]=1;
+ read[2] = crc >> 8;
+ read[3] = crc & 0xff;
if(sendCmdGetResponseWithRetries(read, sizeof(read),resp, 10, 10))
{
continue;
}
- mem=resp[5];
- memory.k16= (mem & 0x80);
- memory.book= (mem & 0x20);
- memory.k2= (mem & 0x8);
- memory.lockauth= (mem & 0x2);
- memory.keyaccess= (mem & 0x1);
+ mem=resp[5];
+ memory.k16= (mem & 0x80);
+ memory.book= (mem & 0x20);
+ memory.k2= (mem & 0x8);
+ memory.lockauth= (mem & 0x2);
+ memory.keyaccess= (mem & 0x1);
cardsize = memory.k16 ? 255 : 32;
WDT_HIT();
memset(card_data,0x0,USB_CMD_DATA_SIZE);
uint8_t failedRead =0;
uint32_t stored_data_length =0;
- //then loop around remaining blocks
+ //then loop around remaining blocks
for(int block=0; block < cardsize; block++){
read[1]= block;
crc = block_crc_LUT[block];
- read[2] = crc >> 8;
- read[3] = crc & 0xff;
+ read[2] = crc >> 8;
+ read[3] = crc & 0xff;
if(!sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 10))
{
- Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x",
+ Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x",
block, resp[0], resp[1], resp[2],
- resp[3], resp[4], resp[5],
- resp[6], resp[7]);
+ resp[3], resp[4], resp[5],
+ resp[6], resp[7]);
//Fill up the buffer
memcpy(card_data+stored_data_length,resp,8);
uint8_t* resp = (((uint8_t *)BigBuf) + 3560);
// Reset trace buffer
- memset(trace, 0x44, RECV_CMD_OFFSET);
+ memset(trace, 0x44, RECV_CMD_OFFSET);
traceLen = 0;
// Setup SSC