mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-02-12 18:25:07 +08:00
Merge pull request #447 from 7homasSutter/felica_support_request_service
Felica support: add command request service
This commit is contained in:
commit
0b48147485
4 changed files with 284 additions and 158 deletions
136
armsrc/felica.c
136
armsrc/felica.c
|
@ -3,7 +3,7 @@
|
|||
#include "BigBuf.h"
|
||||
#include "util.h"
|
||||
#include "protocols.h"
|
||||
#include "crc16.h" // crc16 ccitt
|
||||
#include "crc16.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "string.h"
|
||||
#include "commonutil.h"
|
||||
|
@ -14,17 +14,17 @@
|
|||
// FeliCa timings
|
||||
// minimum time between the start bits of consecutive transfers from reader to tag: 6800 carrier (13.56MHz) cycles
|
||||
#ifndef FELICA_REQUEST_GUARD_TIME
|
||||
# define FELICA_REQUEST_GUARD_TIME (6800/16 + 1)
|
||||
# define FELICA_REQUEST_GUARD_TIME (6800/16 + 1) // 426
|
||||
#endif
|
||||
// FRAME DELAY TIME 2672 carrier cycles
|
||||
#ifndef FELICA_FRAME_DELAY_TIME
|
||||
# define FELICA_FRAME_DELAY_TIME (2672/16 + 1)
|
||||
# define FELICA_FRAME_DELAY_TIME (2672/16 + 1) // 168
|
||||
#endif
|
||||
#ifndef DELAY_AIR2ARM_AS_READER
|
||||
#define DELAY_AIR2ARM_AS_READER (3 + 16 + 8 + 8*16 + 4*16 - 8*16)
|
||||
#define DELAY_AIR2ARM_AS_READER (3 + 16 + 8 + 8*16 + 4*16 - 8*16) // 91
|
||||
#endif
|
||||
#ifndef DELAY_ARM2AIR_AS_READER
|
||||
#define DELAY_ARM2AIR_AS_READER (4*16 + 8*16 + 8 + 8 + 1)
|
||||
#define DELAY_ARM2AIR_AS_READER (4*16 + 8*16 + 8 + 8 + 1) // 209
|
||||
#endif
|
||||
|
||||
// CRC skips two first sync bits in data buffer
|
||||
|
@ -229,21 +229,21 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
|||
|
||||
// timed-out
|
||||
if (len == 0) {
|
||||
if (DBGLEVEL > 3)
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("Error: Time out card selection!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// wrong answer
|
||||
if (FelicaFrame.framebytes[3] != FELICA_POLL_ACK) {
|
||||
if (DBGLEVEL > 3)
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("Error: Wrong answer selecting card!");
|
||||
return 2;
|
||||
}
|
||||
|
||||
// VALIDATE CRC residue is 0, hence if crc is a value it failed.
|
||||
if (!check_crc(CRC_FELICA, FelicaFrame.framebytes + 2, FelicaFrame.len - 2)) {
|
||||
if (DBGLEVEL > 3) {
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("Error: CRC check failed!");
|
||||
Dbprintf("CRC check was done on Frame: ");
|
||||
Dbhexdump(FelicaFrame.len - 2, FelicaFrame.framebytes + 2, 0);
|
||||
|
@ -251,7 +251,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
|||
return 3;
|
||||
}
|
||||
|
||||
if (DBGLEVEL > 3)
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("Card selection successful!");
|
||||
// copy UID
|
||||
// idm 8
|
||||
|
@ -263,7 +263,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
|||
memcpy(card->uid, card->IDm + 2, 6);
|
||||
memcpy(card->iccode, card->PMm, 2);
|
||||
memcpy(card->mrt, card->PMm + 2, 6);
|
||||
if (DBGLEVEL > 3) {
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("Received Frame: ");
|
||||
Dbhexdump(FelicaFrame.len, FelicaFrame.framebytes, 0);
|
||||
}
|
||||
|
@ -337,9 +337,7 @@ static void BuildFliteRdblk(uint8_t *idm, int blocknum, uint16_t *blocks) {
|
|||
}
|
||||
|
||||
static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed) {
|
||||
|
||||
uint8_t flags = FPGA_MAJOR_MODE_ISO18092;
|
||||
|
||||
if (power)
|
||||
flags |= FPGA_HF_ISO18092_FLAG_READER;
|
||||
if (highspeed)
|
||||
|
@ -357,7 +355,6 @@ static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing,
|
|||
// sending 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
uint16_t c = 0;
|
||||
while (c < 6) {
|
||||
|
||||
// keep tx buffer in a defined state anyway.
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
|
||||
AT91C_BASE_SSC->SSC_THR = 0x00;
|
||||
|
@ -366,13 +363,12 @@ static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing,
|
|||
}
|
||||
// sending data with sync bytes
|
||||
c = 0;
|
||||
if (DBGLEVEL > 3) {
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("Sending frame:");
|
||||
Dbhexdump(len, frame, 0);
|
||||
}
|
||||
|
||||
while (c < len) {
|
||||
|
||||
// Put byte into tx holding register as soon as it is ready
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
|
||||
AT91C_BASE_SSC->SSC_THR = frame[c++];
|
||||
|
@ -404,7 +400,7 @@ static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing,
|
|||
// stop when button is pressed
|
||||
// or return TRUE when command is captured
|
||||
bool WaitForFelicaReply(uint16_t maxbytes) {
|
||||
if (DBGLEVEL > 3)
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("WaitForFelicaReply Start");
|
||||
uint32_t c = 0;
|
||||
// power, no modulation
|
||||
|
@ -414,22 +410,18 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
|
|||
// clear RXRDY:
|
||||
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
uint32_t timeout = iso18092_get_timeout();
|
||||
if (DBGLEVEL > 3)
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("timeout set: %i", timeout);
|
||||
//TODO FIX THIS METHOD - Race Condition or something: TIMING/MEMORY ISSUES
|
||||
// If you add content here (dbprintf), timing problems appear?! Last Bytes (CRC) of frame will be cutoff.
|
||||
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
b = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
|
||||
Process18092Byte(b);
|
||||
if (FelicaFrame.state == STATE_FULL) {
|
||||
felica_nexttransfertime =
|
||||
MAX(
|
||||
felica_nexttransfertime,
|
||||
(GetCountSspClk() & 0xfffffff8) - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / 16 + FELICA_FRAME_DELAY_TIME
|
||||
);
|
||||
|
||||
felica_nexttransfertime = MAX(felica_nexttransfertime,
|
||||
(GetCountSspClk() & 0xfffffff8) - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / 16 + FELICA_FRAME_DELAY_TIME
|
||||
);
|
||||
LogTrace(
|
||||
FelicaFrame.framebytes,
|
||||
FelicaFrame.len,
|
||||
|
@ -438,10 +430,10 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
|
|||
NULL,
|
||||
false
|
||||
);
|
||||
if (DBGLEVEL > 3) Dbprintf("All bytes received! STATE_FULL");
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("All bytes received! STATE_FULL");
|
||||
return true;
|
||||
} else if (c++ > timeout && FelicaFrame.state == STATE_UNSYNCD) {
|
||||
if (DBGLEVEL > 3) Dbprintf("Error: Timeout! STATE_UNSYNCD");
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Error: Timeout! STATE_UNSYNCD");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -451,7 +443,7 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
|
|||
// Set up FeliCa communication (similar to iso14443a_setup)
|
||||
// field is setup for "Sending as Reader"
|
||||
static void iso18092_setup(uint8_t fpga_minor_mode) {
|
||||
if (DBGLEVEL > 3) Dbprintf("Start iso18092_setup");
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Start iso18092_setup");
|
||||
|
||||
LEDsoff();
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
@ -504,7 +496,7 @@ void felica_reset_frame_mode() {
|
|||
// arg1 len of commandbytes
|
||||
// d.asBytes command bytes to send
|
||||
void felica_sendraw(PacketCommandNG *c) {
|
||||
if (DBGLEVEL > 3) Dbprintf("FeliCa_sendraw Enter");
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("FeliCa_sendraw Enter");
|
||||
|
||||
felica_command_t param = c->oldarg[0];
|
||||
size_t len = c->oldarg[1] & 0xffff;
|
||||
|
@ -514,7 +506,7 @@ void felica_sendraw(PacketCommandNG *c) {
|
|||
felica_card_select_t card;
|
||||
|
||||
if ((param & FELICA_CONNECT))
|
||||
if (DBGLEVEL > 3) Dbprintf("Clear trace");
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Clear trace");
|
||||
clear_trace();
|
||||
|
||||
set_tracing(true);
|
||||
|
@ -527,13 +519,13 @@ void felica_sendraw(PacketCommandNG *c) {
|
|||
arg0 = felica_select_card(&card);
|
||||
reply_mix(CMD_ACK, arg0, sizeof(card.uid), 0, &card, sizeof(felica_card_select_t));
|
||||
if (arg0 > 0) {
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Error: Failed selecting card! ");
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Error: Failed selecting card! ");
|
||||
felica_reset_frame_mode();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (DBGLEVEL > 3) Dbprintf("No card selection");
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("No card selection");
|
||||
}
|
||||
|
||||
if ((param & FELICA_RAW)) {
|
||||
|
@ -554,17 +546,18 @@ void felica_sendraw(PacketCommandNG *c) {
|
|||
AddCrc(buf, len);
|
||||
}
|
||||
}
|
||||
if (DBGLEVEL > 3) {
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("Transmit Frame (no CRC shown):");
|
||||
Dbhexdump(len, buf, 0);
|
||||
Dbprintf("Buffer Length: %i", buf[2] + 4);
|
||||
};
|
||||
TransmitFor18092_AsReader(buf, buf[2] + 4, NULL, 1, 0);
|
||||
arg0 = WaitForFelicaReply(1024);
|
||||
if (DBGLEVEL > 3) {
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("Received Frame Code: %d", arg0);
|
||||
Dbhexdump(FelicaFrame.len, FelicaFrame.framebytes, 0);
|
||||
};
|
||||
|
||||
uint32_t result = reply_mix(CMD_ACK, FelicaFrame.len, arg0, 0, FelicaFrame.framebytes, FelicaFrame.len);
|
||||
if (result) {
|
||||
Dbprintf("Reply to Client Error Code: %i", result);
|
||||
|
@ -573,7 +566,7 @@ void felica_sendraw(PacketCommandNG *c) {
|
|||
if ((param & FELICA_NO_DISCONNECT)) {
|
||||
Dbprintf("Disconnect");
|
||||
}
|
||||
if (DBGLEVEL > 3)
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("FeliCa_sendraw Exit");
|
||||
felica_reset_frame_mode();
|
||||
return;
|
||||
|
@ -776,79 +769,6 @@ void felica_dump() {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void felica_send_request_service(uint8_t *request_service) {
|
||||
Dbprintf("Send Service Request - len: d%", RES_SVC_LEN);
|
||||
TransmitFor18092_AsReader(request_service, RES_SVC_LEN, NULL, 1, 0);
|
||||
if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_REQSRV_ACK) {
|
||||
Dbprintf("Got Service Response!");
|
||||
}
|
||||
}
|
||||
|
||||
/* Create Request Service Frame
|
||||
// Use this command to verify the existence of Area and Service, and to acquire Key Version.
|
||||
// When the specified Area or Service exists, the card returns Key Version.
|
||||
// When the specified Area or Service does not exist, the card returns FFFFh as Key Version.
|
||||
*/
|
||||
uint8_t *felica_create_request_service_frame(uint8_t nodeNumber, uint8_t *idm) {
|
||||
if (nodeNumber < 1 || nodeNumber > 32) {
|
||||
Dbprintf("Node number out of range: 1 <= %d <= 32 - set node number to 1");
|
||||
nodeNumber = 1;
|
||||
}
|
||||
// Sync 2-Byte, Length 1-Byte, CMD 1-Byte, IDm 8-Byte, nodeNumber 1 <= n <= 32 1-Byte, Node Code List <Little Endian>
|
||||
uint8_t *request_service = BigBuf_malloc(sizeof(uint8_t) * RES_SVC_LEN);
|
||||
//{ 0xb2, 0x4d, 0x06, FELICA_REQSRV_REQ, 0xff, 0xff, 0x00, 0x00, 0x09, 0x21};
|
||||
request_service[0] = 0xb2; //Sync
|
||||
request_service[1] = 0x4d; //Sync
|
||||
request_service[2] = 0x0B; // Length
|
||||
request_service[3] = FELICA_REQSRV_REQ; // CMD
|
||||
request_service[4] = idm[0];
|
||||
request_service[5] = idm[1];
|
||||
request_service[6] = idm[2];
|
||||
request_service[7] = idm[3];
|
||||
request_service[8] = idm[4];
|
||||
request_service[9] = idm[5];
|
||||
request_service[10] = idm[6];
|
||||
request_service[11] = idm[7];
|
||||
request_service[12] = nodeNumber; // Node we like to ask for services
|
||||
request_service[13] = 0x00; // Node Code List // TODO FIND OUT WHAT NEEDS TO BE IN HERE
|
||||
return request_service;
|
||||
}
|
||||
|
||||
// Create Frame for authentication1 CMD
|
||||
void felica_create_authentication1_frame() {
|
||||
|
||||
}
|
||||
|
||||
// Create Frame for authentication2 CMD
|
||||
void felica_create_authentication2_frame() {
|
||||
|
||||
}
|
||||
|
||||
// Create a Frame for Read without encryption CMD as Payload
|
||||
void felica_create_read_block_frame(uint16_t blockNr) {
|
||||
if (blockNr < 1 || blockNr > 567) {
|
||||
Dbprintf("Block number out of range!");
|
||||
return;
|
||||
}
|
||||
uint8_t c = 0;
|
||||
// First Byte of SYNC
|
||||
frameSpace[c++] = 0xb2;
|
||||
frameSpace[c++] = 0x4d;
|
||||
// skip Length of Frame
|
||||
c++;
|
||||
// Payload
|
||||
frameSpace[c++] = FELICA_RDBLK_REQ; //command number
|
||||
|
||||
// Set frame length
|
||||
|
||||
// CRC
|
||||
}
|
||||
|
||||
void felica_read_block(uint8_t *idm, uint16_t blockNr) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
void felica_dump_lite_s() {
|
||||
|
|
|
@ -19,11 +19,17 @@
|
|||
#include "comms.h"
|
||||
#include "cmdtrace.h"
|
||||
#include "crc16.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "ui.h"
|
||||
#include "mifare.h" // felica_card_select_t struct
|
||||
#define AddCrc(data, len) compute_crc(CRC_FELICA, (data), (len), (data)+(len)+1, (data)+(len))
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
static felica_card_select_t last_known_card;
|
||||
|
||||
static void set_last_known_card(felica_card_select_t card) {
|
||||
last_known_card = card;
|
||||
}
|
||||
|
||||
/*
|
||||
static int usage_hf_felica_sim(void) {
|
||||
|
@ -43,7 +49,7 @@ static int usage_hf_felica_sim(void) {
|
|||
static int usage_hf_felica_sniff(void) {
|
||||
PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer.");
|
||||
PrintAndLogEx(NORMAL, "Buffer accessible from command 'hf list felica'");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf felica sniff <s > <t>");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf felica sniff <s> <t>");
|
||||
PrintAndLogEx(NORMAL, " s samples to skip (decimal)");
|
||||
PrintAndLogEx(NORMAL, " t triggers to skip (decimal)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
|
@ -81,15 +87,90 @@ static int usage_hf_felica_raw(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_hf_felica_dump(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf felica dump [-h] <outputfile>");
|
||||
static int usage_hf_felica_request_service(void) {
|
||||
PrintAndLogEx(NORMAL, "\nInfo: Use this command to verify the existence of Area and Service, and to acquire Key Version:");
|
||||
PrintAndLogEx(NORMAL, " - When the specified Area or Service exists, the card returns Key Version.");
|
||||
PrintAndLogEx(NORMAL, " - When the specified Area or Service does not exist, the card returns FFFFh as Key Version.");
|
||||
PrintAndLogEx(NORMAL, "For Node Code List of a command packet, Area Code or Service Code of the target "
|
||||
"of acquisition of Key Version shall be enumerated in Little Endian format. "
|
||||
"If Key Version of System is the target of acquisition, FFFFh shall be specified "
|
||||
"in the command packet.");
|
||||
PrintAndLogEx(NORMAL, "\nUsage: hf felica rqservice [-h] [-i] <01 Number of Node hex> <0A 0B Node Code List hex (Little Endian)>");
|
||||
PrintAndLogEx(NORMAL, " -h this help");
|
||||
PrintAndLogEx(NORMAL, " -i <0A 0B 0C ... hex> set custom IDm to use");
|
||||
PrintAndLogEx(NORMAL, " -a auto node number mode - iterates through all possible nodes 1 < n < 32");
|
||||
PrintAndLogEx(NORMAL, "\nExamples: ");
|
||||
PrintAndLogEx(NORMAL, " hf felica rqservice 01 FFFF");
|
||||
PrintAndLogEx(NORMAL, " hf felica rqservice -a FFFF");
|
||||
PrintAndLogEx(NORMAL, " hf felica rqservice -i 01100910c11bc407 01 FFFF \n\n");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for response from pm3 or timeout.
|
||||
* Checks if receveid bytes have a valid CRC.
|
||||
*/
|
||||
static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp) {
|
||||
if (WaitForResponseTimeout(CMD_ACK, resp, 2000)) {
|
||||
uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff);
|
||||
PrintAndLogEx(NORMAL, "Client Received %i octets", len);
|
||||
if (!len || len < 2) {
|
||||
PrintAndLogEx(ERR, "Could not receive data correctly!");
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_hex(resp->data.asBytes, len));
|
||||
if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) {
|
||||
PrintAndLogEx(WARNING, "Wrong or no CRC bytes");
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Timeout while waiting for reply.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Counts and sets the number of parameters.
|
||||
*/
|
||||
static void strip_cmds(const char *Cmd) {
|
||||
while (*Cmd == ' ' || *Cmd == '\t') {
|
||||
Cmd++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts integer value to equivalent hex value.
|
||||
* Examples: 1 = 1, 11 = B
|
||||
* @param number number of hex bytes.
|
||||
* @return number as hex value.
|
||||
*/
|
||||
static uint8_t int_to_hex(uint16_t *number) {
|
||||
uint32_t hex;
|
||||
char dataLengthChar[5];
|
||||
sprintf(dataLengthChar, "%x", *number);
|
||||
sscanf(dataLengthChar, "%x", &hex);
|
||||
return (uint8_t)(hex & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the last known IDm (8-Byte) to the data frame.
|
||||
* @param position start of where the IDm is added within the frame.
|
||||
* @param data frame in where the IDM is added.
|
||||
* @return true if IDm was added;
|
||||
*/
|
||||
static bool add_last_IDm(uint8_t position, uint8_t *data) {
|
||||
if (last_known_card.IDm[0] != 0 && last_known_card.IDm[1] != 0) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint16_t number = (uint16_t)last_known_card.IDm[i];
|
||||
data[position + i] = int_to_hex(&number);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int CmdHFFelicaList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
//PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list felica' instead");
|
||||
(void)Cmd;
|
||||
CmdTraceList("felica");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -99,9 +180,131 @@ static int CmdHFFelicaReader(const char *Cmd) {
|
|||
return readFelicaUid(verbose);
|
||||
}
|
||||
|
||||
static int CmdHFFelicaDump(const char *Cmd) {
|
||||
if (strlen(Cmd) < 1) return usage_hf_felica_dump();
|
||||
return dump(*Cmd);
|
||||
/**
|
||||
* Sends a request service frame to the pm3.
|
||||
*/
|
||||
void send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data) {
|
||||
uint16_t numbits = 0;
|
||||
clearCommandBuffer();
|
||||
PrintAndLogEx(NORMAL, "Send Service Request Frame: %s", sprint_hex(data, datalen));
|
||||
SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen);
|
||||
PacketResponseNG resp;
|
||||
if (datalen > 0) {
|
||||
if (!waitCmdFelica(0, &resp)) {
|
||||
PrintAndLogEx(ERR, "\nGot no Response from card");
|
||||
return;
|
||||
}
|
||||
felica_request_service_response_t rqs_response;
|
||||
memcpy(&rqs_response, (felica_request_service_response_t *)resp.data.asBytes, sizeof(felica_request_service_response_t));
|
||||
|
||||
if (rqs_response.IDm[0] != 0) {
|
||||
PrintAndLogEx(SUCCESS, "\nGot Service Response:");
|
||||
PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rqs_response.IDm, sizeof(rqs_response.IDm)));
|
||||
PrintAndLogEx(NORMAL, " -Node Number: %s", sprint_hex(rqs_response.node_number, sizeof(rqs_response.node_number)));
|
||||
PrintAndLogEx(NORMAL, " -Node Key Version List: %s\n", sprint_hex(rqs_response.node_key_versions, sizeof(rqs_response.node_key_versions)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command parser for rqservice.
|
||||
* @param Cmd input data of the user.
|
||||
* @return client result code.
|
||||
*/
|
||||
static int CmdHFFelicaRequestService(const char *Cmd) {
|
||||
if (strlen(Cmd) < 2) return usage_hf_felica_request_service();
|
||||
int i = 0;
|
||||
uint8_t data[PM3_CMD_DATA_SIZE];
|
||||
bool custom_IDm = false;
|
||||
bool all_nodes = false;
|
||||
uint16_t datalen = 13; // length (1) + CMD (1) + IDm(8) + Node Number (1) + Node Code List (2)
|
||||
uint8_t flags = 0;
|
||||
uint8_t paramCount = 0;
|
||||
strip_cmds(Cmd);
|
||||
while (Cmd[i] != '\0') {
|
||||
if (Cmd[i] == '-') {
|
||||
switch (Cmd[i + 1]) {
|
||||
case 'H':
|
||||
case 'h':
|
||||
return usage_hf_felica_request_service();
|
||||
case 'i':
|
||||
paramCount++;
|
||||
custom_IDm = true;
|
||||
if (param_getlength(Cmd, paramCount) == 16) {
|
||||
param_gethex(Cmd, paramCount++, data + 2, 16);
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Incorrect IDm length! IDm must be 8-Byte.");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
i += 8;
|
||||
break;
|
||||
case 'a':
|
||||
paramCount++;
|
||||
all_nodes = true;
|
||||
break;
|
||||
default:
|
||||
return usage_hf_felica_request_service();
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!all_nodes) {
|
||||
// Node Number
|
||||
if (param_getlength(Cmd, paramCount) == 2) {
|
||||
param_gethex(Cmd, paramCount++, data + 10, 2);
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Incorrect Node number length!");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
}
|
||||
|
||||
// Node Code List
|
||||
if (param_getlength(Cmd, paramCount) == 4) {
|
||||
param_gethex(Cmd, paramCount++, data + 11, 4);
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Incorrect Node Code List length!");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
flags |= FELICA_APPEND_CRC;
|
||||
if (custom_IDm) {
|
||||
flags |= FELICA_NO_SELECT;
|
||||
}
|
||||
if (datalen > 0) {
|
||||
flags |= FELICA_RAW;
|
||||
}
|
||||
datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen;
|
||||
if (!custom_IDm) {
|
||||
if (!add_last_IDm(2, data)) {
|
||||
PrintAndLogEx(ERR, "No last known card! Use reader first or set a custom IDm!");
|
||||
return PM3_EINVARG;
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "Used last known IDm.", sprint_hex(data, datalen));
|
||||
}
|
||||
}
|
||||
data[0] = int_to_hex(&datalen);
|
||||
data[1] = 0x02; // Service Request Command ID
|
||||
if (all_nodes) {
|
||||
for (uint16_t y = 1; y < 32; y++) {
|
||||
data[10] = int_to_hex(&y);
|
||||
AddCrc(data, datalen);
|
||||
datalen += 2;
|
||||
send_request_service(flags, datalen, data);
|
||||
datalen -= 2; // Remove CRC bytes before adding new ones
|
||||
}
|
||||
} else {
|
||||
AddCrc(data, datalen);
|
||||
datalen += 2;
|
||||
send_request_service(flags, datalen, data);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFFelicaNotImplementedYet(const char *Cmd) {
|
||||
PrintAndLogEx(NORMAL, "Feature not implemented Yet!");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// simulate iso18092 / FeliCa tag
|
||||
|
@ -172,7 +375,6 @@ static int CmdHFFelicaSim(const char *Cmd) {
|
|||
*/
|
||||
|
||||
static int CmdHFFelicaSniff(const char *Cmd) {
|
||||
|
||||
uint8_t cmdp = 0;
|
||||
uint64_t samples2skip = 0;
|
||||
uint64_t triggers2skip = 0;
|
||||
|
@ -209,7 +411,6 @@ static int CmdHFFelicaSniff(const char *Cmd) {
|
|||
|
||||
// uid hex
|
||||
static int CmdHFFelicaSimLite(const char *Cmd) {
|
||||
|
||||
uint64_t uid = param_get64ex(Cmd, 0, 0, 16);
|
||||
|
||||
if (!uid)
|
||||
|
@ -436,19 +637,6 @@ static int CmdHFFelicaDumpLite(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void waitCmdFelica(uint8_t iSelect) {
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
uint16_t len = iSelect ? (resp.oldarg[1] & 0xffff) : (resp.oldarg[0] & 0xffff);
|
||||
PrintAndLogEx(NORMAL, "Client Received %i octets", len);
|
||||
if (!len)
|
||||
return;
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, len));
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Timeout while waiting for reply.");
|
||||
}
|
||||
}
|
||||
|
||||
static int CmdHFFelicaCmdRaw(const char *Cmd) {
|
||||
bool reply = 1;
|
||||
bool crc = false;
|
||||
|
@ -525,12 +713,9 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) {
|
|||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (crc && datalen > 0 && datalen < sizeof(data) - 2) {
|
||||
uint8_t b1, b2;
|
||||
compute_crc(CRC_FELICA, data, datalen, &b1, &b2);
|
||||
// TODO FIND OUT IF FeliCa Light has another CRC order - Order changed for FeliCa Standard cards
|
||||
data[datalen++] = b2;
|
||||
data[datalen++] = b1;
|
||||
if (crc) {
|
||||
AddCrc(data, datalen);
|
||||
datalen += 2;
|
||||
}
|
||||
|
||||
uint8_t flags = 0;
|
||||
|
@ -552,15 +737,18 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) {
|
|||
datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen;
|
||||
|
||||
clearCommandBuffer();
|
||||
PrintAndLogEx(NORMAL, "Data: %s", sprint_hex(data, datalen));
|
||||
SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen);
|
||||
|
||||
if (reply) {
|
||||
if (active_select) {
|
||||
PrintAndLogEx(NORMAL, "Active select wait for FeliCa.");
|
||||
waitCmdFelica(1);
|
||||
PacketResponseNG resp_IDm;
|
||||
waitCmdFelica(1, &resp_IDm);
|
||||
}
|
||||
if (datalen > 0) {
|
||||
waitCmdFelica(0);
|
||||
PacketResponseNG resp_frame;
|
||||
waitCmdFelica(0, &resp_frame);
|
||||
}
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
|
@ -573,7 +761,6 @@ int readFelicaUid(bool verbose) {
|
|||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "FeliCa card select failed");
|
||||
//SendCommandMIX(CMD_HF_FELICA_COMMAND, 0, 0, 0, NULL, 0);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -610,33 +797,45 @@ int readFelicaUid(bool verbose) {
|
|||
PrintAndLogEx(NORMAL, " - MRT %s", sprint_hex(card.mrt, sizeof(card.mrt)));
|
||||
|
||||
PrintAndLogEx(NORMAL, "SERVICE CODE %s", sprint_hex(card.servicecode, sizeof(card.servicecode)));
|
||||
set_last_known_card(card);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int dump(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_hf_felica_dumplite();
|
||||
|
||||
// TODO FINISH THIS METHOD
|
||||
PrintAndLogEx(SUCCESS, "NOT IMPLEMENTED YET!");
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"----------- General -----------", CmdHelp, IfPm3Iso14443a, ""},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHFFelicaList, AlwaysAvailable, "List ISO 18092/FeliCa history"},
|
||||
{"reader", CmdHFFelicaReader, IfPm3Felica, "Act like an ISO18092/FeliCa reader"},
|
||||
// {"sim", CmdHFFelicaSim, IfPm3Felica, "<UID> -- Simulate ISO 18092/FeliCa tag"},
|
||||
{"sniff", CmdHFFelicaSniff, IfPm3Felica, "sniff ISO 18092/Felica traffic"},
|
||||
{"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"},
|
||||
{"raw", CmdHFFelicaCmdRaw, IfPm3Felica, "Send raw hex data to tag"},
|
||||
{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping Felica"},
|
||||
{"----------- FeliCa Standard (support in progress) -----------", CmdHelp, IfPm3Iso14443a, ""},
|
||||
//{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"},
|
||||
{"rqservice", CmdHFFelicaRequestService, IfPm3Felica, "verify the existence of Area and Service, and to acquire Key Version."},
|
||||
{"rqresponse", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of a card and its Mode."},
|
||||
//{"rdNoEncryption", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-not-required Service."},
|
||||
//{"wrNoEncryption", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."},
|
||||
//{"searchSvCode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."},
|
||||
//{"rqSysCode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire System Code registered to the card."},
|
||||
//{"auth1", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."},
|
||||
//{"auth2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."},
|
||||
//{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."},
|
||||
//{"write", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."},
|
||||
//{"searchSvCodeV2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of Area or Service, and to acquire Key Version."},
|
||||
//{"getSysStatus", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the setup information in System."},
|
||||
//{"rqSpecVer", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the version of card OS."},
|
||||
//{"resetMode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "reset Mode to Mode 0."},
|
||||
//{"auth1V2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."},
|
||||
//{"auth2V2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."},
|
||||
//{"readV2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."},
|
||||
//{"writeV2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to authentication-required Service."},
|
||||
//{"upRandomID", CmdHFFelicaNotImplementedYet, IfPm3Felica, "update Random ID (IDr)."},
|
||||
{"----------- FeliCa Light -----------", CmdHelp, IfPm3Iso14443a, ""},
|
||||
{"litesim", CmdHFFelicaSimLite, IfPm3Felica, "<NDEF2> - only reply to poll request"},
|
||||
{"litedump", CmdHFFelicaDumpLite, IfPm3Felica, "Wait for and try dumping FelicaLite"},
|
||||
// {"sim", CmdHFFelicaSim, IfPm3Felica, "<UID> -- Simulate ISO 18092/FeliCa tag"}
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#include "common.h"
|
||||
|
||||
int CmdHFFelica(const char *Cmd);
|
||||
|
||||
int readFelicaUid(bool verbose);
|
||||
|
||||
int dump();
|
||||
void send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data);
|
||||
#endif
|
||||
|
|
|
@ -169,6 +169,15 @@ typedef struct {
|
|||
uint8_t servicecode[2];
|
||||
} PACKED felica_card_select_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t sync[2];
|
||||
uint8_t length[1];
|
||||
uint8_t cmd_code[1];
|
||||
uint8_t IDm[8];
|
||||
uint8_t node_number[1];
|
||||
uint8_t node_key_versions[2];
|
||||
} PACKED felica_request_service_response_t;
|
||||
|
||||
typedef enum FELICA_COMMAND {
|
||||
FELICA_CONNECT = (1 << 0),
|
||||
FELICA_NO_DISCONNECT = (1 << 1),
|
||||
|
|
Loading…
Reference in a new issue