mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-14 18:48:13 -07:00
Further implementation of iclass 'fullsim'. Moved protocol definitions to shared file. Had to add some loclass-function to arm-side to support authentication in fullsim mode
This commit is contained in:
parent
9a9bcea82b
commit
b67f7ec359
17 changed files with 1157 additions and 268 deletions
215
armsrc/iclass.c
215
armsrc/iclass.c
|
@ -47,7 +47,8 @@
|
|||
// different initial value (CRC_ICLASS)
|
||||
#include "iso14443crc.h"
|
||||
#include "iso15693tools.h"
|
||||
|
||||
#include "cipher.h"
|
||||
#include "protocols.h"
|
||||
static int timeout = 4096;
|
||||
|
||||
|
||||
|
@ -965,8 +966,11 @@ static void CodeIClassTagSOF()
|
|||
// Convert from last byte pos to length
|
||||
ToSendMax++;
|
||||
}
|
||||
#define MODE_SIM_CSN 0
|
||||
#define MODE_EXIT_AFTER_MAC 1
|
||||
#define MODE_FULLSIM 2
|
||||
|
||||
int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader_mac_buf);
|
||||
int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf);
|
||||
/**
|
||||
* @brief SimulateIClass simulates an iClass card.
|
||||
* @param arg0 type of simulation
|
||||
|
@ -988,15 +992,20 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
|
|||
// Enable and clear the trace
|
||||
set_tracing(TRUE);
|
||||
clear_trace();
|
||||
//Use the emulator memory for SIM
|
||||
uint8_t *emulator = BigBuf_get_EM_addr();
|
||||
|
||||
uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 };
|
||||
if(simType == 0) {
|
||||
// Use the CSN from commandline
|
||||
memcpy(csn_crc, datain, 8);
|
||||
doIClassSimulation(csn_crc,0,NULL);
|
||||
memcpy(emulator, datain, 8);
|
||||
doIClassSimulation(MODE_SIM_CSN,NULL);
|
||||
}else if(simType == 1)
|
||||
{
|
||||
doIClassSimulation(csn_crc,0,NULL);
|
||||
//Default CSN
|
||||
uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 };
|
||||
// Use the CSN from commandline
|
||||
memcpy(emulator, csn_crc, 8);
|
||||
doIClassSimulation(MODE_SIM_CSN,NULL);
|
||||
}
|
||||
else if(simType == 2)
|
||||
{
|
||||
|
@ -1011,8 +1020,8 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
|
|||
{
|
||||
// The usb data is 512 bytes, fitting 65 8-byte CSNs in there.
|
||||
|
||||
memcpy(csn_crc, datain+(i*8), 8);
|
||||
if(doIClassSimulation(csn_crc,1,mac_responses+i*8))
|
||||
memcpy(emulator, datain+(i*8), 8);
|
||||
if(doIClassSimulation(MODE_EXIT_AFTER_MAC,mac_responses+i*8))
|
||||
{
|
||||
cmd_send(CMD_ACK,CMD_SIMULATE_TAG_ICLASS,i,0,mac_responses,i*8);
|
||||
return; // Button pressed
|
||||
|
@ -1020,6 +1029,9 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
|
|||
}
|
||||
cmd_send(CMD_ACK,CMD_SIMULATE_TAG_ICLASS,i,0,mac_responses,i*8);
|
||||
|
||||
}else if(simType == 3){
|
||||
//This is 'full sim' mode, where we use the emulator storage for data.
|
||||
doIClassSimulation(MODE_FULLSIM, NULL);
|
||||
}
|
||||
else{
|
||||
// We may want a mode here where we hardcode the csns to use (from proxclone).
|
||||
|
@ -1029,29 +1041,40 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
|
|||
Dbprintf("Done...");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Does the actual simulation
|
||||
* @param csn - csn to use
|
||||
* @param breakAfterMacReceived if true, returns after reader MAC has been received.
|
||||
*/
|
||||
int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader_mac_buf)
|
||||
int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
|
||||
{
|
||||
// free eventually allocated BigBuf memory
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
uint8_t *csn = BigBuf_get_EM_addr();
|
||||
uint8_t *emulator = csn;
|
||||
uint8_t sof_data[] = { 0x0F} ;
|
||||
// CSN followed by two CRC bytes
|
||||
uint8_t response1[] = { 0x0F} ;
|
||||
uint8_t response2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t response3[] = { 0,0,0,0,0,0,0,0,0,0};
|
||||
memcpy(response3,csn,sizeof(response3));
|
||||
uint8_t anticoll_data[10] = { 0 };
|
||||
uint8_t csn_data[10] = { 0 };
|
||||
memcpy(csn_data,csn,sizeof(csn_data));
|
||||
Dbprintf("Simulating 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]);
|
||||
// e-Purse
|
||||
uint8_t response4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
// Construct anticollision-CSN
|
||||
rotateCSN(response3,response2);
|
||||
rotateCSN(csn_data,anticoll_data);
|
||||
|
||||
// Compute CRC on both CSNs
|
||||
ComputeCrc14443(CRC_ICLASS, response2, 8, &response2[8], &response2[9]);
|
||||
ComputeCrc14443(CRC_ICLASS, response3, 8, &response3[8], &response3[9]);
|
||||
ComputeCrc14443(CRC_ICLASS, anticoll_data, 8, &anticoll_data[8], &anticoll_data[9]);
|
||||
ComputeCrc14443(CRC_ICLASS, csn_data, 8, &csn_data[8], &csn_data[9]);
|
||||
|
||||
// e-Purse
|
||||
uint8_t card_challenge_data[8] = { 0x00 };
|
||||
if(simulationMode == MODE_FULLSIM)
|
||||
{
|
||||
//Card challenge, a.k.a e-purse is on block 2
|
||||
memcpy(card_challenge_data,emulator + (8 * 2) , 8);
|
||||
}
|
||||
|
||||
int exitLoop = 0;
|
||||
// Reader 0a
|
||||
|
@ -1065,28 +1088,26 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader
|
|||
int modulated_response_size;
|
||||
uint8_t* trace_data = NULL;
|
||||
int trace_data_size = 0;
|
||||
//uint8_t sof = 0x0f;
|
||||
|
||||
// free eventually allocated BigBuf memory
|
||||
BigBuf_free();
|
||||
|
||||
// Respond SOF -- takes 1 bytes
|
||||
uint8_t *resp1 = BigBuf_malloc(2);
|
||||
int resp1Len;
|
||||
uint8_t *resp_sof = BigBuf_malloc(2);
|
||||
int resp_sof_Len;
|
||||
|
||||
// Anticollision CSN (rotated CSN)
|
||||
// 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
|
||||
uint8_t *resp2 = BigBuf_malloc(28);
|
||||
int resp2Len;
|
||||
uint8_t *resp_anticoll = BigBuf_malloc(28);
|
||||
int resp_anticoll_len;
|
||||
|
||||
// CSN
|
||||
// 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
|
||||
uint8_t *resp3 = BigBuf_malloc(30);
|
||||
int resp3Len;
|
||||
uint8_t *resp_csn = BigBuf_malloc(30);
|
||||
int resp_csn_len;
|
||||
|
||||
// e-Purse
|
||||
// 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit)
|
||||
uint8_t *resp4 = BigBuf_malloc(20);
|
||||
int resp4Len;
|
||||
uint8_t *resp_cc = BigBuf_malloc(20);
|
||||
int resp_cc_len;
|
||||
|
||||
uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
|
||||
memset(receivedCmd, 0x44, MAX_FRAME_SIZE);
|
||||
|
@ -1097,20 +1118,22 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader
|
|||
|
||||
// First card answer: SOF
|
||||
CodeIClassTagSOF();
|
||||
memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;
|
||||
memcpy(resp_sof, ToSend, ToSendMax); resp_sof_Len = ToSendMax;
|
||||
|
||||
// Anticollision CSN
|
||||
CodeIClassTagAnswer(response2, sizeof(response2));
|
||||
memcpy(resp2, ToSend, ToSendMax); resp2Len = ToSendMax;
|
||||
CodeIClassTagAnswer(anticoll_data, sizeof(anticoll_data));
|
||||
memcpy(resp_anticoll, ToSend, ToSendMax); resp_anticoll_len = ToSendMax;
|
||||
|
||||
// CSN
|
||||
CodeIClassTagAnswer(response3, sizeof(response3));
|
||||
memcpy(resp3, ToSend, ToSendMax); resp3Len = ToSendMax;
|
||||
CodeIClassTagAnswer(csn_data, sizeof(csn_data));
|
||||
memcpy(resp_csn, ToSend, ToSendMax); resp_csn_len = ToSendMax;
|
||||
|
||||
// e-Purse
|
||||
CodeIClassTagAnswer(response4, sizeof(response4));
|
||||
memcpy(resp4, ToSend, ToSendMax); resp4Len = ToSendMax;
|
||||
CodeIClassTagAnswer(card_challenge_data, sizeof(card_challenge_data));
|
||||
memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax;
|
||||
|
||||
//This is used for responding to READ-block commands
|
||||
uint8_t *data_response = BigBuf_malloc(8 * 2 + 2);
|
||||
|
||||
// Start from off (no field generated)
|
||||
//FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
@ -1147,57 +1170,90 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader
|
|||
LED_C_ON();
|
||||
|
||||
// Okay, look at the command now.
|
||||
if(receivedCmd[0] == 0x0a ) {
|
||||
if(receivedCmd[0] == ICLASS_CMD_ACTALL ) {
|
||||
// Reader in anticollission phase
|
||||
modulated_response = resp1; modulated_response_size = resp1Len; //order = 1;
|
||||
trace_data = response1;
|
||||
trace_data_size = sizeof(response1);
|
||||
} else if(receivedCmd[0] == 0x0c) {
|
||||
modulated_response = resp_sof; modulated_response_size = resp_sof_Len; //order = 1;
|
||||
trace_data = sof_data;
|
||||
trace_data_size = sizeof(sof_data);
|
||||
} else if(receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) {
|
||||
// Reader asks for anticollission CSN
|
||||
modulated_response = resp2; modulated_response_size = resp2Len; //order = 2;
|
||||
trace_data = response2;
|
||||
trace_data_size = sizeof(response2);
|
||||
modulated_response = resp_anticoll; modulated_response_size = resp_anticoll_len; //order = 2;
|
||||
trace_data = anticoll_data;
|
||||
trace_data_size = sizeof(anticoll_data);
|
||||
//DbpString("Reader requests anticollission CSN:");
|
||||
} else if(receivedCmd[0] == 0x81) {
|
||||
} else if(receivedCmd[0] == ICLASS_CMD_SELECT) {
|
||||
// Reader selects anticollission CSN.
|
||||
// Tag sends the corresponding real CSN
|
||||
modulated_response = resp3; modulated_response_size = resp3Len; //order = 3;
|
||||
trace_data = response3;
|
||||
trace_data_size = sizeof(response3);
|
||||
modulated_response = resp_csn; modulated_response_size = resp_csn_len; //order = 3;
|
||||
trace_data = csn_data;
|
||||
trace_data_size = sizeof(csn_data);
|
||||
//DbpString("Reader selects anticollission CSN:");
|
||||
} else if(receivedCmd[0] == 0x88) {
|
||||
} else if(receivedCmd[0] == ICLASS_CMD_READCHECK_KD) {
|
||||
// Read e-purse (88 02)
|
||||
modulated_response = resp4; modulated_response_size = resp4Len; //order = 4;
|
||||
trace_data = response4;
|
||||
trace_data_size = sizeof(response4);
|
||||
modulated_response = resp_cc; modulated_response_size = resp_cc_len; //order = 4;
|
||||
trace_data = card_challenge_data;
|
||||
trace_data_size = sizeof(card_challenge_data);
|
||||
LED_B_ON();
|
||||
} else if(receivedCmd[0] == 0x05) {
|
||||
} else if(receivedCmd[0] == ICLASS_CMD_CHECK) {
|
||||
// Reader random and reader MAC!!!
|
||||
// Do not respond
|
||||
// We do not know what to answer, so lets keep quiet
|
||||
modulated_response = resp1; modulated_response_size = 0; //order = 5;
|
||||
trace_data = NULL;
|
||||
trace_data_size = 0;
|
||||
if (breakAfterMacReceived){
|
||||
// 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);
|
||||
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 = { 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, trace_data);
|
||||
trace_data_size = 4;
|
||||
CodeIClassTagAnswer(trace_data , trace_data_size);
|
||||
memcpy(data_response, ToSend, ToSendMax);
|
||||
modulated_response = data_response;
|
||||
modulated_response_size = ToSendMax;
|
||||
}else
|
||||
{ //Not fullsim, we don't respond
|
||||
// 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;
|
||||
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;
|
||||
}
|
||||
exitLoop = true;
|
||||
}
|
||||
} else if(receivedCmd[0] == 0x00 && len == 1) {
|
||||
|
||||
} else if(receivedCmd[0] == ICLASS_CMD_HALT && len == 1) {
|
||||
// Reader ends the session
|
||||
modulated_response = resp1; modulated_response_size = 0; //order = 0;
|
||||
modulated_response = resp_sof; modulated_response_size = 0; //order = 0;
|
||||
trace_data = NULL;
|
||||
trace_data_size = 0;
|
||||
} else {
|
||||
} 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;
|
||||
CodeIClassTagAnswer(trace_data , trace_data_size);
|
||||
memcpy(data_response, ToSend, ToSendMax);
|
||||
modulated_response = data_response;
|
||||
modulated_response_size = ToSendMax;
|
||||
}
|
||||
else {
|
||||
//#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44
|
||||
// Never seen this command before
|
||||
Dbprintf("Unknown command received from reader (len=%d): %x %x %x %x %x %x %x %x %x",
|
||||
|
@ -1206,7 +1262,7 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader
|
|||
receivedCmd[3], receivedCmd[4], receivedCmd[5],
|
||||
receivedCmd[6], receivedCmd[7], receivedCmd[8]);
|
||||
// Do not respond
|
||||
modulated_response = resp1; modulated_response_size = 0; //order = 0;
|
||||
modulated_response = resp_sof; modulated_response_size = 0; //order = 0;
|
||||
trace_data = NULL;
|
||||
trace_data_size = 0;
|
||||
}
|
||||
|
@ -1603,6 +1659,17 @@ void ReaderIClass(uint8_t arg0) {
|
|||
if(read_status == 1) datasize = 8;
|
||||
if(read_status == 2) datasize = 16;
|
||||
|
||||
//Todo, read the public blocks 1,5 aswell:
|
||||
//
|
||||
// 0 : CSN (we already have)
|
||||
// 1 : Configuration
|
||||
// 2 : e-purse (we already have)
|
||||
// (3,4 write-only)
|
||||
// 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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue