mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-14 02:26:59 -07:00
commit
389d0360e1
11 changed files with 525 additions and 456 deletions
307
armsrc/iclass.c
307
armsrc/iclass.c
|
@ -1474,97 +1474,142 @@ void setupIclassReader()
|
|||
|
||||
}
|
||||
|
||||
size_t sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, uint8_t expected_size, uint8_t retries)
|
||||
{
|
||||
while(retries-- > 0)
|
||||
{
|
||||
ReaderTransmitIClass(command, cmdsize);
|
||||
if(expected_size == ReaderReceiveIClass(resp)){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;//Error
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Talks to an iclass tag, sends the commands to get CSN and CC.
|
||||
* @param card_data where the CSN and CC are stored for return
|
||||
* @return 0 = fail
|
||||
* 1 = Got CSN
|
||||
* 2 = Got CSN and CC
|
||||
*/
|
||||
uint8_t handshakeIclassTag(uint8_t *card_data)
|
||||
{
|
||||
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 };
|
||||
uint8_t *resp = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET);
|
||||
|
||||
uint8_t read_status = 0;
|
||||
|
||||
// Send act_all
|
||||
ReaderTransmitIClass(act_all, 1);
|
||||
// Card present?
|
||||
if(!ReaderReceiveIClass(resp)) return read_status;//Fail
|
||||
//Send Identify
|
||||
ReaderTransmitIClass(identify, 1);
|
||||
//We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC
|
||||
uint8_t len = ReaderReceiveIClass(resp);
|
||||
if(len != 10) return read_status;//Fail
|
||||
|
||||
//Copy the Anti-collision CSN to our select-packet
|
||||
memcpy(&select[1],resp,8);
|
||||
//Select the card
|
||||
ReaderTransmitIClass(select, sizeof(select));
|
||||
//We expect a 10-byte response here, 8 byte CSN and 2 byte CRC
|
||||
len = ReaderReceiveIClass(resp);
|
||||
if(len != 10) return read_status;//Fail
|
||||
|
||||
//Success - level 1, we got CSN
|
||||
//Save CSN in response data
|
||||
memcpy(card_data,resp,8);
|
||||
|
||||
//Flag that we got to at least stage 1, read CSN
|
||||
read_status = 1;
|
||||
|
||||
// Card selected, now read e-purse (cc)
|
||||
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
|
||||
if(ReaderReceiveIClass(resp) == 8) {
|
||||
//Save CC (e-purse) in response data
|
||||
memcpy(card_data+8,resp,8);
|
||||
|
||||
//Got both
|
||||
read_status = 2;
|
||||
}
|
||||
|
||||
return read_status;
|
||||
}
|
||||
|
||||
// Reader iClass Anticollission
|
||||
void ReaderIClass(uint8_t arg0) {
|
||||
uint8_t act_all[] = { 0x0a };
|
||||
uint8_t identify[] = { 0x0c };
|
||||
uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t readcheck_cc[]= { 0x88, 0x02 };
|
||||
|
||||
uint8_t card_data[24]={0};
|
||||
uint8_t last_csn[8]={0};
|
||||
|
||||
uint8_t *resp = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET);
|
||||
|
||||
int read_status= 0;
|
||||
bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE;
|
||||
bool get_cc = arg0 & FLAG_ICLASS_READER_GET_CC;
|
||||
|
||||
setupIclassReader();
|
||||
|
||||
size_t datasize = 0;
|
||||
while(!BUTTON_PRESS())
|
||||
{
|
||||
WDT_HIT();
|
||||
|
||||
// Send act_all
|
||||
ReaderTransmitIClass(act_all, 1);
|
||||
// Card present?
|
||||
if(ReaderReceiveIClass(resp)) {
|
||||
if(traceLen > TRACE_SIZE) {
|
||||
DbpString("Trace full");
|
||||
break;
|
||||
}
|
||||
WDT_HIT();
|
||||
|
||||
ReaderTransmitIClass(identify, 1);
|
||||
read_status = handshakeIclassTag(card_data);
|
||||
|
||||
if(ReaderReceiveIClass(resp) == 10) {
|
||||
//Copy the Anti-collision CSN to our select-packet
|
||||
memcpy(&select[1],resp,8);
|
||||
//Dbprintf("Anti-collision CSN: %02x %02x %02x %02x %02x %02x %02x %02x",resp[0], resp[1], resp[2],
|
||||
// resp[3], resp[4], resp[5],
|
||||
// resp[6], resp[7]);
|
||||
//Select the card
|
||||
ReaderTransmitIClass(select, sizeof(select));
|
||||
if(read_status == 0) continue;
|
||||
if(read_status == 1) datasize = 8;
|
||||
if(read_status == 2) datasize = 16;
|
||||
|
||||
if(ReaderReceiveIClass(resp) == 10) {
|
||||
//Save CSN in response data
|
||||
memcpy(card_data,resp,8);
|
||||
datasize += 8;
|
||||
//Flag that we got to at least stage 1, read CSN
|
||||
read_status = 1;
|
||||
LED_B_ON();
|
||||
//Send back to client, but don't bother if we already sent this
|
||||
if(memcmp(last_csn, card_data, 8) != 0)
|
||||
{
|
||||
|
||||
// Card selected
|
||||
//Dbprintf("Readcheck on Sector 2");
|
||||
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
|
||||
if(ReaderReceiveIClass(resp) == 8) {
|
||||
//Save CC (e-purse) in response data
|
||||
memcpy(card_data+8,resp,8);
|
||||
datasize += 8;
|
||||
//Got both
|
||||
read_status = 2;
|
||||
}
|
||||
|
||||
LED_B_ON();
|
||||
//Send back to client, but don't bother if we already sent this
|
||||
if(memcmp(last_csn, card_data, 8) != 0)
|
||||
cmd_send(CMD_ACK,read_status,0,0,card_data,datasize);
|
||||
|
||||
//Save that we already sent this....
|
||||
if(read_status == 2)
|
||||
memcpy(last_csn, card_data, 8);
|
||||
|
||||
LED_B_OFF();
|
||||
|
||||
if(abort_after_read) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(traceLen > TRACE_SIZE) {
|
||||
DbpString("Trace full");
|
||||
break;
|
||||
}
|
||||
if(!get_cc || (get_cc && read_status == 2))
|
||||
{
|
||||
cmd_send(CMD_ACK,read_status,0,0,card_data,datasize);
|
||||
if(abort_after_read) {
|
||||
LED_A_OFF();
|
||||
return;
|
||||
}
|
||||
//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();
|
||||
}
|
||||
cmd_send(CMD_ACK,0,0,0,card_data, 0);
|
||||
LED_A_OFF();
|
||||
}
|
||||
|
||||
void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
|
||||
uint8_t act_all[] = { 0x0a };
|
||||
uint8_t identify[] = { 0x0c };
|
||||
uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t readcheck_cc[]= { 0x88, 0x02 };
|
||||
|
||||
uint8_t card_data[24]={0};
|
||||
uint16_t block_crc_LUT[255] = {0};
|
||||
|
||||
{//Generate a lookup table for block crc
|
||||
for(int block = 0; block < 255; block++){
|
||||
char bl = block;
|
||||
block_crc_LUT[block] = iclass_crc16(&bl ,1);
|
||||
}
|
||||
}
|
||||
//Dbprintf("Lookup table: %02x %02x %02x" ,block_crc_LUT[0],block_crc_LUT[1],block_crc_LUT[2]);
|
||||
|
||||
uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 };
|
||||
|
||||
uint16_t crc = 0;
|
||||
uint8_t cardsize=0;
|
||||
bool read_success=false;
|
||||
uint8_t mem=0;
|
||||
|
||||
static struct memory_t{
|
||||
|
@ -1580,102 +1625,72 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
|
|||
setupIclassReader();
|
||||
|
||||
|
||||
for(int i=0;i<1;i++) {
|
||||
while(!BUTTON_PRESS()) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
if(traceLen > TRACE_SIZE) {
|
||||
DbpString("Trace full");
|
||||
break;
|
||||
}
|
||||
|
||||
if (BUTTON_PRESS()) break;
|
||||
uint8_t read_status = handshakeIclassTag(card_data);
|
||||
if(read_status < 2) continue;
|
||||
|
||||
// Send act_all
|
||||
ReaderTransmitIClass(act_all, 1);
|
||||
// Card present?
|
||||
if(ReaderReceiveIClass(resp)) {
|
||||
ReaderTransmitIClass(identify, 1);
|
||||
if(ReaderReceiveIClass(resp) == 10) {
|
||||
// Select card
|
||||
memcpy(&select[1],resp,8);
|
||||
ReaderTransmitIClass(select, sizeof(select));
|
||||
//for now replay captured auth (as cc not updated)
|
||||
memcpy(check+5,MAC,4);
|
||||
|
||||
if(ReaderReceiveIClass(resp) == 10) {
|
||||
Dbprintf(" Selected CSN: %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
resp[0], resp[1], resp[2],
|
||||
resp[3], resp[4], resp[5],
|
||||
resp[6], resp[7]);
|
||||
}
|
||||
// Card selected
|
||||
Dbprintf("Readcheck on Sector 2");
|
||||
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
|
||||
if(ReaderReceiveIClass(resp) == 8) {
|
||||
Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
resp[0], resp[1], resp[2],
|
||||
resp[3], resp[4], resp[5],
|
||||
resp[6], resp[7]);
|
||||
}else return;
|
||||
Dbprintf("Authenticate");
|
||||
//for now replay captured auth (as cc not updated)
|
||||
memcpy(check+5,MAC,4);
|
||||
//Dbprintf(" AA: %02x %02x %02x %02x",
|
||||
// check[5], check[6], check[7],check[8]);
|
||||
ReaderTransmitIClass(check, sizeof(check));
|
||||
if(ReaderReceiveIClass(resp) == 4) {
|
||||
Dbprintf(" AR: %02x %02x %02x %02x",
|
||||
resp[0], resp[1], resp[2],resp[3]);
|
||||
}else {
|
||||
Dbprintf("Error: Authentication Fail!");
|
||||
return;
|
||||
}
|
||||
Dbprintf("Dump Contents");
|
||||
//first get configuration block
|
||||
read_success=false;
|
||||
read[1]=1;
|
||||
uint8_t *blockno=&read[1];
|
||||
crc = iclass_crc16((char *)blockno,1);
|
||||
read[2] = crc >> 8;
|
||||
read[3] = crc & 0xff;
|
||||
while(!read_success){
|
||||
ReaderTransmitIClass(read, sizeof(read));
|
||||
if(ReaderReceiveIClass(resp) == 10) {
|
||||
read_success=true;
|
||||
mem=resp[5];
|
||||
memory.k16= (mem & 0x80);
|
||||
memory.book= (mem & 0x20);
|
||||
memory.k2= (mem & 0x8);
|
||||
memory.lockauth= (mem & 0x2);
|
||||
memory.keyaccess= (mem & 0x1);
|
||||
if(sendCmdGetResponseWithRetries(check, sizeof(check),resp, 4, 5))
|
||||
{
|
||||
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;
|
||||
|
||||
if(sendCmdGetResponseWithRetries(read, sizeof(read),resp, 10, 10))
|
||||
{
|
||||
Dbprintf("Dump config (block 1) failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
//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;
|
||||
|
||||
if(!sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 10))
|
||||
{
|
||||
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]);
|
||||
|
||||
}else{
|
||||
Dbprintf("Failed to dump block %d", block);
|
||||
|
||||
}
|
||||
}
|
||||
if (memory.k16){
|
||||
cardsize=255;
|
||||
}else cardsize=32;
|
||||
//then loop around remaining blocks
|
||||
for(uint8_t j=0; j<cardsize; j++){
|
||||
read_success=false;
|
||||
uint8_t *blockno=&j;
|
||||
//crc_data[0]=j;
|
||||
read[1]=j;
|
||||
crc = iclass_crc16((char *)blockno,1);
|
||||
read[2] = crc >> 8;
|
||||
read[3] = crc & 0xff;
|
||||
while(!read_success){
|
||||
ReaderTransmitIClass(read, sizeof(read));
|
||||
if(ReaderReceiveIClass(resp) == 10) {
|
||||
read_success=true;
|
||||
Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
j, resp[0], resp[1], resp[2],
|
||||
resp[3], resp[4], resp[5],
|
||||
resp[6], resp[7]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
WDT_HIT();
|
||||
//If we got here, let's break
|
||||
break;
|
||||
}
|
||||
|
||||
LED_A_OFF();
|
||||
}
|
||||
|
||||
|
|
279
client/cmdhf.c
279
client/cmdhf.c
|
@ -9,6 +9,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
//#include "proxusb.h"
|
||||
#include "proxmark3.h"
|
||||
#include "graph.h"
|
||||
|
@ -31,6 +32,279 @@ int CmdHFTune(const char *Cmd)
|
|||
SendCommand(&c);
|
||||
return 0;
|
||||
}
|
||||
// for the time being. Need better Bigbuf handling.
|
||||
#define TRACE_SIZE 3000
|
||||
|
||||
#define ICLASS_CMD_ACTALL 0x0A
|
||||
#define ICLASS_CMD_IDENTIFY 0x0C
|
||||
#define ICLASS_CMD_READ 0x0C
|
||||
#define ICLASS_CMD_SELECT 0x81
|
||||
#define ICLASS_CMD_PAGESEL 0x84
|
||||
#define ICLASS_CMD_READCHECK 0x88
|
||||
#define ICLASS_CMD_CHECK 0x05
|
||||
#define ICLASS_CMD_SOF 0x0F
|
||||
#define ICLASS_CMD_HALT 0x00
|
||||
|
||||
#define iso14443_CMD_WUPA 0x52
|
||||
#define iso14443_CMD_SELECT 0x93
|
||||
#define iso14443_CMD_SELECT_2 0x95
|
||||
#define iso14443_CMD_REQ 0x26
|
||||
#define iso14443_CMD_READBLOCK 0x30
|
||||
#define iso14443_CMD_WRITEBLOCK 0xA0
|
||||
#define iso14443_CMD_INC 0xC0
|
||||
#define iso14443_CMD_DEC 0xC1
|
||||
#define iso14443_CMD_RESTORE 0xC2
|
||||
#define iso14443_CMD_TRANSFER 0xB0
|
||||
#define iso14443_CMD_HALT 0x50
|
||||
#define iso14443_CMD_RATS 0xE0
|
||||
|
||||
|
||||
void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
|
||||
{
|
||||
switch(cmd[0])
|
||||
{
|
||||
case iso14443_CMD_WUPA: snprintf(exp,size,"WUPA"); break;
|
||||
case iso14443_CMD_SELECT:{
|
||||
if(cmdsize > 2)
|
||||
{
|
||||
snprintf(exp,size,"SELECT_UID"); break;
|
||||
}else
|
||||
{
|
||||
snprintf(exp,size,"SELECT_ALL"); break;
|
||||
}
|
||||
}
|
||||
case iso14443_CMD_SELECT_2: snprintf(exp,size,"SELECT_2"); break;
|
||||
case iso14443_CMD_REQ: snprintf(exp,size,"REW"); break;
|
||||
case iso14443_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break;
|
||||
case iso14443_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break;
|
||||
case iso14443_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break;
|
||||
case iso14443_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break;
|
||||
case iso14443_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break;
|
||||
case iso14443_CMD_TRANSFER: snprintf(exp,size,"TRANSFER(%d)",cmd[1]); break;
|
||||
case iso14443_CMD_HALT: snprintf(exp,size,"HALT"); break;
|
||||
case iso14443_CMD_RATS: snprintf(exp,size,"RATS"); break;
|
||||
default: snprintf(exp,size,"?"); break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
|
||||
{
|
||||
|
||||
if(cmdsize > 1 && cmd[0] == ICLASS_CMD_READ)
|
||||
{
|
||||
snprintf(exp,size,"READ(%d)",cmd[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(cmd[0])
|
||||
{
|
||||
case ICLASS_CMD_ACTALL: snprintf(exp,size,"ACTALL"); break;
|
||||
case ICLASS_CMD_IDENTIFY: snprintf(exp,size,"IDENTIFY"); break;
|
||||
case ICLASS_CMD_SELECT: snprintf(exp,size,"SELECT"); break;
|
||||
case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL"); break;
|
||||
case ICLASS_CMD_READCHECK: snprintf(exp,size,"READCHECK"); break;
|
||||
case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break;
|
||||
case ICLASS_CMD_SOF: snprintf(exp,size,"SOF"); break;
|
||||
case ICLASS_CMD_HALT: snprintf(exp,size,"HALT"); break;
|
||||
default: snprintf(exp,size,"?"); break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool showWaitCycles)
|
||||
{
|
||||
bool isResponse;
|
||||
uint16_t duration, data_len,parity_len;
|
||||
|
||||
uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp;
|
||||
char explanation[30] = {0};
|
||||
|
||||
first_timestamp = *((uint32_t *)(trace));
|
||||
timestamp = *((uint32_t *)(trace + tracepos));
|
||||
// Break and stick with current result if buffer was not completely full
|
||||
if (timestamp == 0x44444444) return TRACE_SIZE;
|
||||
|
||||
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 >= TRACE_SIZE) {
|
||||
return TRACE_SIZE;
|
||||
}
|
||||
|
||||
uint8_t *frame = trace + tracepos;
|
||||
tracepos += data_len;
|
||||
uint8_t *parityBytes = trace + tracepos;
|
||||
tracepos += parity_len;
|
||||
|
||||
//--- Draw the data column
|
||||
char line[16][110];
|
||||
for (int j = 0; j < data_len; j++) {
|
||||
int oddparity = 0x01;
|
||||
int k;
|
||||
|
||||
for (k=0 ; k<8 ; k++) {
|
||||
oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);
|
||||
}
|
||||
|
||||
uint8_t parityBits = parityBytes[j>>3];
|
||||
|
||||
if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
|
||||
sprintf(line[j/16]+((j%16)*4), "%02x! ", frame[j]);
|
||||
} else {
|
||||
sprintf(line[j/16]+((j%16)*4), "%02x ", frame[j]);
|
||||
}
|
||||
}
|
||||
//--- Draw the CRC column
|
||||
bool crcError = false;
|
||||
|
||||
if (data_len > 2) {
|
||||
uint8_t b1, b2;
|
||||
if(iclass)
|
||||
{
|
||||
if(!isResponse && data_len == 4 ) {
|
||||
// Rough guess that this is a command from the reader
|
||||
// For iClass the command byte is not part of the CRC
|
||||
ComputeCrc14443(CRC_ICLASS, &frame[1], data_len-3, &b1, &b2);
|
||||
}
|
||||
else {
|
||||
// For other data.. CRC might not be applicable (UPDATE commands etc.)
|
||||
ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2);
|
||||
}
|
||||
|
||||
if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) {
|
||||
crcError = true;
|
||||
}
|
||||
|
||||
}else{//Iso 14443a
|
||||
|
||||
ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2);
|
||||
|
||||
if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) {
|
||||
if(!(isResponse & (data_len < 6)))
|
||||
{
|
||||
crcError = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
char *crc = crcError ? "!crc" :" ";
|
||||
|
||||
EndOfTransmissionTimestamp = timestamp + duration;
|
||||
|
||||
if(!isResponse)
|
||||
{
|
||||
if(iclass) annotateIclass(explanation,sizeof(explanation),frame,data_len);
|
||||
else annotateIso14443a(explanation,sizeof(explanation),frame,data_len);
|
||||
}
|
||||
|
||||
int num_lines = (data_len - 1)/16 + 1;
|
||||
for (int j = 0; j < num_lines; j++) {
|
||||
if (j == 0) {
|
||||
PrintAndLog(" %9d | %9d | %s | %-64s| %s| %s",
|
||||
(timestamp - first_timestamp),
|
||||
(EndOfTransmissionTimestamp - first_timestamp),
|
||||
(isResponse ? "Tag" : "Rdr"),
|
||||
line[j],
|
||||
(j == num_lines-1) ? crc : " ",
|
||||
(j == num_lines-1) ? explanation : "");
|
||||
} else {
|
||||
PrintAndLog(" | | | %-64s| %s| %s",
|
||||
line[j],
|
||||
(j == num_lines-1)?crc:" ",
|
||||
(j == num_lines-1) ? explanation : "");
|
||||
}
|
||||
}
|
||||
|
||||
bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000;
|
||||
|
||||
if (showWaitCycles && !isResponse && next_isResponse) {
|
||||
uint32_t next_timestamp = *((uint32_t *)(trace + tracepos));
|
||||
if (next_timestamp != 0x44444444) {
|
||||
PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d",
|
||||
(EndOfTransmissionTimestamp - first_timestamp),
|
||||
(next_timestamp - first_timestamp),
|
||||
" ",
|
||||
(next_timestamp - EndOfTransmissionTimestamp));
|
||||
}
|
||||
}
|
||||
return tracepos;
|
||||
}
|
||||
|
||||
int CmdHFList(const char *Cmd)
|
||||
{
|
||||
bool showWaitCycles = false;
|
||||
char type[40] = {0};
|
||||
int tlen = param_getstr(Cmd,0,type);
|
||||
char param = param_getchar(Cmd, 1);
|
||||
bool errors = false;
|
||||
bool iclass = false;
|
||||
//Validate params
|
||||
if(tlen == 0 || (strcmp(type, "iclass") != 0 && strcmp(type,"14a") != 0))
|
||||
{
|
||||
errors = true;
|
||||
}
|
||||
if(param == 'h' || (param !=0 && param != 'f'))
|
||||
{
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (errors) {
|
||||
PrintAndLog("List protocol data in trace buffer.");
|
||||
PrintAndLog("Usage: hf list [14a|iclass] [f]");
|
||||
PrintAndLog(" 14a - interpret data as iso14443a communications");
|
||||
PrintAndLog(" iclass - interpret data as iclass communications");
|
||||
PrintAndLog(" f - show frame delay times as well");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("example: hf list 14a f");
|
||||
PrintAndLog("example: hf list iclass");
|
||||
return 0;
|
||||
}
|
||||
if(strcmp(type, "iclass") == 0)
|
||||
{
|
||||
iclass = true;
|
||||
}
|
||||
|
||||
if (param == 'f') {
|
||||
showWaitCycles = true;
|
||||
}
|
||||
|
||||
|
||||
uint8_t trace[TRACE_SIZE];
|
||||
uint16_t tracepos = 0;
|
||||
GetFromBigBuf(trace, TRACE_SIZE, 0);
|
||||
WaitForResponse(CMD_ACK, NULL);
|
||||
|
||||
PrintAndLog("Recorded Activity");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
|
||||
PrintAndLog("iso14443a - All times are in carrier periods (1/13.56Mhz)");
|
||||
PrintAndLog("iClass - Timings are not as accurate");
|
||||
PrintAndLog("");
|
||||
PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |");
|
||||
PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------|-----|--------------------|");
|
||||
|
||||
while(tracepos < TRACE_SIZE)
|
||||
{
|
||||
tracepos = printTraceLine(tracepos, trace, iclass, showWaitCycles);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static command_t CommandTable[] =
|
||||
{
|
||||
|
@ -41,9 +315,10 @@ static command_t CommandTable[] =
|
|||
{"epa", CmdHFEPA, 1, "{ German Identification Card... }"},
|
||||
{"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"},
|
||||
{"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"},
|
||||
{"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"},
|
||||
{"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"},
|
||||
{"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
{"list", CmdHFList, 1, "List protocol data in trace buffer"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
int CmdHF(const char *Cmd)
|
||||
|
|
|
@ -13,5 +13,5 @@
|
|||
|
||||
int CmdHF(const char *Cmd);
|
||||
int CmdHFTune(const char *Cmd);
|
||||
|
||||
int CmdHFList(const char *Cmd);
|
||||
#endif
|
||||
|
|
|
@ -29,145 +29,7 @@ static void waitCmd(uint8_t iLen);
|
|||
|
||||
int CmdHF14AList(const char *Cmd)
|
||||
{
|
||||
bool ShowWaitCycles = false;
|
||||
char param = param_getchar(Cmd, 0);
|
||||
|
||||
if (param == 'h' || (param != 0 && param != 'f')) {
|
||||
PrintAndLog("List data in trace buffer.");
|
||||
PrintAndLog("Usage: hf 14a list [f]");
|
||||
PrintAndLog("f - show frame delay times as well");
|
||||
PrintAndLog("sample: hf 14a list f");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (param == 'f') {
|
||||
ShowWaitCycles = true;
|
||||
}
|
||||
|
||||
// for the time being. Need better Bigbuf handling.
|
||||
#define TRACE_SIZE 3000
|
||||
|
||||
uint8_t trace[TRACE_SIZE];
|
||||
GetFromBigBuf(trace, TRACE_SIZE, 0);
|
||||
WaitForResponse(CMD_ACK, NULL);
|
||||
|
||||
PrintAndLog("Recorded Activity");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
|
||||
PrintAndLog("All times are in carrier periods (1/13.56Mhz)");
|
||||
PrintAndLog("");
|
||||
PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC ");
|
||||
PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------------");
|
||||
|
||||
uint16_t tracepos = 0;
|
||||
uint16_t duration;
|
||||
uint16_t data_len;
|
||||
uint16_t parity_len;
|
||||
bool isResponse;
|
||||
uint32_t timestamp;
|
||||
uint32_t first_timestamp;
|
||||
uint32_t EndOfTransmissionTimestamp;
|
||||
|
||||
for (;;) {
|
||||
|
||||
if(tracepos >= TRACE_SIZE) {
|
||||
break;
|
||||
}
|
||||
|
||||
timestamp = *((uint32_t *)(trace + tracepos));
|
||||
if(tracepos == 0) {
|
||||
first_timestamp = timestamp;
|
||||
}
|
||||
|
||||
// Break and stick with current result if buffer was not completely full
|
||||
if (timestamp == 0x44444444) break;
|
||||
|
||||
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 >= TRACE_SIZE) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t *frame = trace + tracepos;
|
||||
tracepos += data_len;
|
||||
uint8_t *parityBytes = trace + tracepos;
|
||||
tracepos += parity_len;
|
||||
|
||||
char line[16][110];
|
||||
for (int j = 0; j < data_len; j++) {
|
||||
int oddparity = 0x01;
|
||||
int k;
|
||||
|
||||
for (k=0;k<8;k++) {
|
||||
oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);
|
||||
}
|
||||
|
||||
uint8_t parityBits = parityBytes[j>>3];
|
||||
if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
|
||||
sprintf(line[j/16]+((j%16)*4), "%02x! ", frame[j]);
|
||||
} else {
|
||||
sprintf(line[j/16]+((j%16)*4), "%02x ", frame[j]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
char crc[5] = "";
|
||||
if (data_len > 2) {
|
||||
uint8_t b1, b2;
|
||||
ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2);
|
||||
if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) {
|
||||
sprintf(crc, (isResponse & (data_len < 6)) ? "" : "!crc");
|
||||
} else {
|
||||
sprintf(crc, "");
|
||||
}
|
||||
}
|
||||
|
||||
EndOfTransmissionTimestamp = timestamp + duration;
|
||||
|
||||
int num_lines = (data_len - 1)/16 + 1;
|
||||
for (int j = 0; j < num_lines; j++) {
|
||||
if (j == 0) {
|
||||
PrintAndLog(" %9d | %9d | %s | %-64s| %s",
|
||||
(timestamp - first_timestamp),
|
||||
(EndOfTransmissionTimestamp - first_timestamp),
|
||||
(isResponse ? "Tag" : "Rdr"),
|
||||
line[j],
|
||||
(j == num_lines-1)?crc:"");
|
||||
} else {
|
||||
PrintAndLog(" | | | %-64s| %s",
|
||||
line[j],
|
||||
(j == num_lines-1)?crc:"");
|
||||
}
|
||||
}
|
||||
|
||||
bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000;
|
||||
|
||||
if (ShowWaitCycles && !isResponse && next_isResponse) {
|
||||
uint32_t next_timestamp = *((uint32_t *)(trace + tracepos));
|
||||
if (next_timestamp != 0x44444444) {
|
||||
PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d",
|
||||
(EndOfTransmissionTimestamp - first_timestamp),
|
||||
(next_timestamp - first_timestamp),
|
||||
" ",
|
||||
(next_timestamp - EndOfTransmissionTimestamp));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PrintAndLog("Deprecated command, use 'hf list 14a' instead");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -510,7 +372,7 @@ int CmdHF14ASnoop(const char *Cmd) {
|
|||
|
||||
if (param_getchar(Cmd, 0) == 'h') {
|
||||
PrintAndLog("It get data from the field and saves it into command buffer.");
|
||||
PrintAndLog("Buffer accessible from command hf 14a list.");
|
||||
PrintAndLog("Buffer accessible from command hf list 14a.");
|
||||
PrintAndLog("Usage: hf 14a snoop [c][r]");
|
||||
PrintAndLog("c - triggered by first data from card");
|
||||
PrintAndLog("r - triggered by first 7-bit request from reader (REQ,WUP,...)");
|
||||
|
@ -671,7 +533,7 @@ static void waitCmd(uint8_t iSelect)
|
|||
static command_t CommandTable[] =
|
||||
{
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
{"list", CmdHF14AList, 0, "List ISO 14443a history"},
|
||||
{"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443a history"},
|
||||
{"reader", CmdHF14AReader, 0, "Act like an ISO14443 Type A reader"},
|
||||
{"cuids", CmdHF14ACUIDs, 0, "<n> Collect n>0 ISO14443 Type A UIDs in one go"},
|
||||
{"sim", CmdHF14ASim, 0, "<UID> -- Fake ISO 14443a tag"},
|
||||
|
|
|
@ -44,150 +44,7 @@ int xorbits_8(uint8_t val)
|
|||
|
||||
int CmdHFiClassList(const char *Cmd)
|
||||
{
|
||||
bool ShowWaitCycles = false;
|
||||
char param = param_getchar(Cmd, 0);
|
||||
|
||||
if (param != 0) {
|
||||
PrintAndLog("List data in trace buffer.");
|
||||
PrintAndLog("Usage: hf iclass list");
|
||||
PrintAndLog("h - help");
|
||||
PrintAndLog("sample: hf iclass list");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// for the time being. Need better Bigbuf handling.
|
||||
#define TRACE_SIZE 3000
|
||||
|
||||
uint8_t trace[TRACE_SIZE];
|
||||
GetFromBigBuf(trace, TRACE_SIZE, 0);
|
||||
WaitForResponse(CMD_ACK, NULL);
|
||||
|
||||
PrintAndLog("Recorded Activity");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
|
||||
PrintAndLog("All times are in carrier periods (1/13.56Mhz)");
|
||||
PrintAndLog("");
|
||||
PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC ");
|
||||
PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------------");
|
||||
|
||||
uint16_t tracepos = 0;
|
||||
uint16_t duration;
|
||||
uint16_t data_len;
|
||||
uint16_t parity_len;
|
||||
bool isResponse;
|
||||
uint32_t timestamp;
|
||||
uint32_t first_timestamp;
|
||||
uint32_t EndOfTransmissionTimestamp;
|
||||
|
||||
for (;;) {
|
||||
|
||||
if(tracepos >= TRACE_SIZE) {
|
||||
break;
|
||||
}
|
||||
|
||||
timestamp = *((uint32_t *)(trace + tracepos));
|
||||
if(tracepos == 0) {
|
||||
first_timestamp = timestamp;
|
||||
}
|
||||
|
||||
// Break and stick with current result if buffer was not completely full
|
||||
if (timestamp == 0x44444444) break;
|
||||
|
||||
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 >= TRACE_SIZE) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t *frame = trace + tracepos;
|
||||
tracepos += data_len;
|
||||
uint8_t *parityBytes = trace + tracepos;
|
||||
tracepos += parity_len;
|
||||
|
||||
char line[16][110];
|
||||
for (int j = 0; j < data_len; j++) {
|
||||
int oddparity = 0x01;
|
||||
int k;
|
||||
|
||||
for (k=0;k<8;k++) {
|
||||
oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);
|
||||
}
|
||||
|
||||
uint8_t parityBits = parityBytes[j>>3];
|
||||
if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
|
||||
sprintf(line[j/16]+((j%16)*4), "%02x! ", frame[j]);
|
||||
} else {
|
||||
sprintf(line[j/16]+((j%16)*4), "%02x ", frame[j]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
char *crc = "";
|
||||
if (data_len > 2) {
|
||||
uint8_t b1, b2;
|
||||
if(!isResponse && data_len == 4 ) {
|
||||
// Rough guess that this is a command from the reader
|
||||
// For iClass the command byte is not part of the CRC
|
||||
ComputeCrc14443(CRC_ICLASS, &frame[1], data_len-3, &b1, &b2);
|
||||
if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) {
|
||||
crc = "!crc";
|
||||
}
|
||||
}
|
||||
else {
|
||||
// For other data.. CRC might not be applicable (UPDATE commands etc.)
|
||||
ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2);
|
||||
if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) {
|
||||
crc = "!crc";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndOfTransmissionTimestamp = timestamp + duration;
|
||||
|
||||
int num_lines = (data_len - 1)/16 + 1;
|
||||
for (int j = 0; j < num_lines; j++) {
|
||||
if (j == 0) {
|
||||
PrintAndLog(" %9d | %9d | %s | %-64s| %s",
|
||||
(timestamp - first_timestamp),
|
||||
(EndOfTransmissionTimestamp - first_timestamp),
|
||||
(isResponse ? "Tag" : "Rdr"),
|
||||
line[j],
|
||||
(j == num_lines-1)?crc:"");
|
||||
} else {
|
||||
PrintAndLog(" | | | %-64s| %s",
|
||||
line[j],
|
||||
(j == num_lines-1)?crc:"");
|
||||
}
|
||||
}
|
||||
|
||||
bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000;
|
||||
|
||||
if (ShowWaitCycles && !isResponse && next_isResponse) {
|
||||
uint32_t next_timestamp = *((uint32_t *)(trace + tracepos));
|
||||
if (next_timestamp != 0x44444444) {
|
||||
PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d",
|
||||
(EndOfTransmissionTimestamp - first_timestamp),
|
||||
(next_timestamp - first_timestamp),
|
||||
" ",
|
||||
(next_timestamp - EndOfTransmissionTimestamp));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PrintAndLog("Deprecated command, use 'hf list iclass' instead");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -322,7 +179,11 @@ int CmdHFiClassReader(const char *Cmd)
|
|||
uint8_t * data = resp.d.asBytes;
|
||||
|
||||
PrintAndLog("isOk:%02x", isOK);
|
||||
|
||||
if( isOK == 0){
|
||||
//Aborted
|
||||
PrintAndLog("Quitting...");
|
||||
return 0;
|
||||
}
|
||||
if(isOK > 0)
|
||||
{
|
||||
PrintAndLog("CSN: %s",sprint_hex(data,8));
|
||||
|
@ -425,7 +286,7 @@ int CmdHFiClassReader_Dump(const char *Cmd)
|
|||
|
||||
|
||||
UsbCommand c = {CMD_READER_ICLASS, {0}};
|
||||
c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE;
|
||||
c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE| FLAG_ICLASS_READER_GET_CC;
|
||||
if(!fake_dummy_test)
|
||||
SendCommand(&c);
|
||||
|
||||
|
@ -573,19 +434,64 @@ int CmdHFiClass_iso14443A_write(const char *Cmd)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
int CmdHFiClass_loclass(const char *Cmd)
|
||||
{
|
||||
char opt = param_getchar(Cmd, 0);
|
||||
|
||||
if (strlen(Cmd)<1 || opt == 'h') {
|
||||
PrintAndLog("Usage: hf iclass loclass [options]");
|
||||
PrintAndLog("Options:");
|
||||
PrintAndLog("h Show this help");
|
||||
PrintAndLog("t Perform self-test");
|
||||
PrintAndLog("f <filename> Bruteforce iclass dumpfile");
|
||||
PrintAndLog(" An iclass dumpfile is assumed to consist of an arbitrary number of");
|
||||
PrintAndLog(" malicious CSNs, and their protocol responses");
|
||||
PrintAndLog(" The the binary format of the file is expected to be as follows: ");
|
||||
PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
|
||||
PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
|
||||
PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
|
||||
PrintAndLog(" ... totalling N*24 bytes");
|
||||
return 0;
|
||||
}
|
||||
char fileName[255] = {0};
|
||||
if(opt == 'f')
|
||||
{
|
||||
if(param_getstr(Cmd, 1, fileName) > 0)
|
||||
{
|
||||
return bruteforceFileNoKeys(fileName);
|
||||
}else
|
||||
{
|
||||
PrintAndLog("You must specify a filename");
|
||||
}
|
||||
}
|
||||
else if(opt == 't')
|
||||
{
|
||||
int errors = testCipherUtils();
|
||||
errors += testMAC();
|
||||
errors += doKeyTests(0);
|
||||
errors += testElite();
|
||||
if(errors)
|
||||
{
|
||||
prnlog("OBS! There were errors!!!");
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] =
|
||||
{
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
{"list", CmdHFiClassList, 0, "List iClass history"},
|
||||
{"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"},
|
||||
{"sim", CmdHFiClassSim, 0, "Simulate iClass tag"},
|
||||
{"reader",CmdHFiClassReader, 0, "Read an iClass tag"},
|
||||
{"replay",CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"},
|
||||
{"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"},
|
||||
{"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
{"list", CmdHFiClassList, 0, "[Deprecated] List iClass history"},
|
||||
{"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"},
|
||||
{"sim", CmdHFiClassSim, 0, "Simulate iClass tag"},
|
||||
{"reader",CmdHFiClassReader, 0, "Read an iClass tag"},
|
||||
{"replay",CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"},
|
||||
{"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"},
|
||||
{"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"},
|
||||
{"loclass", CmdHFiClass_loclass, 1, "Use loclass to perform bruteforce of reader attack dump"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
int CmdHFiClass(const char *Cmd)
|
||||
|
|
|
@ -526,7 +526,7 @@ int bruteforceFile(const char *filename, uint16_t keytable[])
|
|||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
uint8_t *dump = malloc(fsize);
|
||||
size_t bytes_read = fread(dump, fsize, 1, f);
|
||||
size_t bytes_read = fread(dump, 1, fsize, f);
|
||||
|
||||
fclose(f);
|
||||
if (bytes_read < fsize)
|
||||
|
@ -577,9 +577,18 @@ int _testBruteforce()
|
|||
**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ****
|
||||
**/
|
||||
uint16_t keytable[128] = {0};
|
||||
//save some time...
|
||||
startvalue = 0x7B0000;
|
||||
errors |= bruteforceFile("iclass_dump.bin",keytable);
|
||||
|
||||
//Test a few variants
|
||||
if(fileExists("iclass_dump.bin"))
|
||||
{
|
||||
errors |= bruteforceFile("iclass_dump.bin",keytable);
|
||||
}else if(fileExists("loclass/iclass_dump.bin")){
|
||||
errors |= bruteforceFile("loclass/iclass_dump.bin",keytable);
|
||||
}else if(fileExists("client/loclass/iclass_dump.bin")){
|
||||
errors |= bruteforceFile("client/loclass/iclass_dump.bin",keytable);
|
||||
}else{
|
||||
prnlog("Error: The file iclass_dump.bin was not found!");
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
|
|
@ -57,11 +57,11 @@ int saveFile(const char *preferredName, const char *suffix, const void* data, si
|
|||
*/
|
||||
void prnlog(char *fmt, ...)
|
||||
{
|
||||
|
||||
char buffer[2048] = {0};
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
PrintAndLog(fmt, args);
|
||||
//vprintf(fmt,args);
|
||||
vsprintf (buffer,fmt, args);
|
||||
va_end(args);
|
||||
//printf("\n");
|
||||
PrintAndLog(buffer);
|
||||
|
||||
}
|
||||
|
|
|
@ -21,4 +21,5 @@ int saveFile(const char *preferredName, const char *suffix, const void* data, si
|
|||
* @param fmt
|
||||
*/
|
||||
void prnlog(char *fmt, ...);
|
||||
int fileExists(const char *filename);
|
||||
#endif // FILEUTILS_H
|
||||
|
|
BIN
client/loclass/iclass_dump.bin
Normal file
BIN
client/loclass/iclass_dump.bin
Normal file
Binary file not shown.
|
@ -66,11 +66,11 @@ char* Iso15693sprintUID(char *target,uint8_t *uid) {
|
|||
return target;
|
||||
}
|
||||
|
||||
unsigned short iclass_crc16(char *data_p, unsigned short length)
|
||||
uint16_t iclass_crc16(char *data_p, unsigned short length)
|
||||
{
|
||||
unsigned char i;
|
||||
unsigned int data;
|
||||
unsigned int crc = 0xffff;
|
||||
uint16_t crc = 0xffff;
|
||||
|
||||
if (length == 0)
|
||||
return (~crc);
|
||||
|
|
|
@ -167,7 +167,8 @@ typedef struct {
|
|||
|
||||
|
||||
//Iclass reader flags
|
||||
#define FLAG_ICLASS_READER_ONLY_ONCE 0x01
|
||||
#define FLAG_ICLASS_READER_ONLY_ONCE 0x01
|
||||
#define FLAG_ICLASS_READER_GET_CC 0x02
|
||||
|
||||
// CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions:
|
||||
/* Whether a bootloader that understands the common_area is present */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue