mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
+3
-2
@@ -3,8 +3,9 @@ All notable changes to this project will be documented in this file.
|
||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Add lf t55xx chk e <EM4100> option. Checks calculated password based on the EM4100 id from some white cloners forumla by paleopterix (@mwalker33)
|
||||
- Add lf t55xx sniff to allow extracting commands and passwords used be cloners. (@mwalker33)
|
||||
- Add `hf 14b apdu` - send APDU over ISO14443B (@iceman1001)
|
||||
- Add `lf t55xx chk e <EM4100> option` - Checks calculated password based on the EM4100 id from some white cloners forumla by paleopterix (@mwalker33)
|
||||
- Add `lf t55xx sniff` to allow extracting commands and passwords used be cloners. (@mwalker33)
|
||||
- Add options to `lf read`, `lf cmdread`, `lf sniff` for repeated acquisitions (@doegox)
|
||||
- Change options of `lf read` to match `lf cmdread`, this affects historical `d` and `s` options (@doegox)
|
||||
- Add `hf waveshare` to upload picture to Waveshare NFC-Powered e-Paper (@doegox)
|
||||
|
||||
+1
-1
@@ -297,7 +297,7 @@ void tosend_stuffbit(int b) {
|
||||
Dbprintf(_RED_("toSend overflow"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (toSend.bit >= 8) {
|
||||
toSend.max++;
|
||||
toSend.buf[toSend.max] = 0;
|
||||
|
||||
+5
-5
@@ -118,7 +118,7 @@ static int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response, uint16_t re
|
||||
case 'a':
|
||||
return iso14_apdu(apdu, (uint16_t) length, false, response, NULL);
|
||||
case 'b':
|
||||
return iso14443b_apdu(apdu, length, response, respmaxlen);
|
||||
return iso14443b_apdu(apdu, length, false, response, respmaxlen);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -225,10 +225,10 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) {
|
||||
|
||||
// select the file EF.CardAccess
|
||||
int rapdu_length = EPA_APDU((uint8_t *)apdu_select_binary_cardaccess,
|
||||
sizeof(apdu_select_binary_cardaccess),
|
||||
response_apdu,
|
||||
sizeof(response_apdu)
|
||||
);
|
||||
sizeof(apdu_select_binary_cardaccess),
|
||||
response_apdu,
|
||||
sizeof(response_apdu)
|
||||
);
|
||||
|
||||
if (rapdu_length < 6
|
||||
|| response_apdu[rapdu_length - 4] != 0x90
|
||||
|
||||
+1
-1
@@ -1748,7 +1748,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
||||
// init as reader
|
||||
lf_init(true, false);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
||||
|
||||
// Tag specific configuration settings (sof, timings, etc.)
|
||||
// TODO HTS
|
||||
/* if (htf <= HTS_LAST_CMD) {
|
||||
|
||||
+148
-98
@@ -41,15 +41,18 @@
|
||||
|
||||
// defaults to 2000ms
|
||||
#ifndef FWT_TIMEOUT_14B
|
||||
# define FWT_TIMEOUT_14B 35312
|
||||
# define FWT_TIMEOUT_14B 35312
|
||||
#endif
|
||||
|
||||
// 1 tick == 1/13.56 mhz
|
||||
// 1 us = 1.5 tick
|
||||
|
||||
// 330/848kHz = 1558us / 4 == 400us,
|
||||
#define ISO14443B_READER_TIMEOUT 1700 //330
|
||||
#define ISO14443B_READER_TIMEOUT 10000 //330
|
||||
|
||||
// 1024/3.39MHz = 302.1us between end of tag response and next reader cmd
|
||||
#define DELAY_ISO14443B_VICC_TO_VCD_READER 600 // 1024
|
||||
#define DELAY_ISO14443B_VCD_TO_VICC_READER 600// 1056
|
||||
#define DELAY_ISO14443B_VICC_TO_VCD_READER (28*9) // 1024 ( counting from start of PICC EOF 14 ETU's)
|
||||
#define DELAY_ISO14443B_VCD_TO_VICC_READER (28*9) // 1056
|
||||
|
||||
#ifndef RECEIVE_MASK
|
||||
# define RECEIVE_MASK (DMA_BUFFER_SIZE - 1)
|
||||
@@ -57,7 +60,7 @@
|
||||
|
||||
// Guard Time (per 14443-2)
|
||||
#ifndef TR0
|
||||
# define TR0 64 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA
|
||||
# define TR0 32 // TR0 max is 151/fs = 151/(848kHz) = 302us or 64 samples from FPGA
|
||||
#endif
|
||||
|
||||
// Synchronization time (per 14443-2)
|
||||
@@ -76,10 +79,9 @@ static void iso14b_set_timeout(uint32_t timeout);
|
||||
static void iso14b_set_maxframesize(uint16_t size);
|
||||
|
||||
// the block number for the ISO14443-4 PCB (used with APDUs)
|
||||
static uint8_t pcb_blocknum = 0;
|
||||
static uint8_t iso14b_pcb_blocknum = 0;
|
||||
static uint32_t iso14b_timeout = FWT_TIMEOUT_14B;
|
||||
|
||||
|
||||
/* ISO 14443 B
|
||||
*
|
||||
* Reader to card | ASK - Amplitude Shift Keying Modulation (PCD to PICC for Type B) (NRZ-L encodig)
|
||||
@@ -306,7 +308,6 @@ static void Demod14bInit(uint8_t *data, uint16_t max_len) {
|
||||
Demod14bReset();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 9.4395 us = 1 ETU and clock is about 1.5 us
|
||||
* 13560000Hz
|
||||
@@ -740,7 +741,7 @@ void SimulateIso14443bTag(uint32_t pupi) {
|
||||
*/
|
||||
static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
||||
|
||||
int v;
|
||||
int v = 0;
|
||||
|
||||
// The soft decision on the bit uses an estimate of just the
|
||||
// quadrant of the reference angle, not the exact angle.
|
||||
@@ -757,7 +758,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
||||
} \
|
||||
}
|
||||
|
||||
#define SUBCARRIER_DETECT_THRESHOLD 8
|
||||
#define SUBCARRIER_DETECT_THRESHOLD 8
|
||||
// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq)))
|
||||
#define AMPLITUDE(ci,cq) (MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2))
|
||||
|
||||
@@ -797,7 +798,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
||||
Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;
|
||||
Demod.posCount = 0; // start of SOF sequence
|
||||
} else {
|
||||
if (Demod.posCount > 200 / 4) { // maximum length of TR1 = 200 1/fs
|
||||
if (Demod.posCount > 200/4) { // maximum length of TR1 = 200 1/fs
|
||||
Demod.state = DEMOD_UNSYNCD;
|
||||
}
|
||||
}
|
||||
@@ -820,7 +821,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
||||
Demod.state = DEMOD_AWAITING_START_BIT;
|
||||
}
|
||||
} else {
|
||||
if (Demod.posCount > 14 * 2) { // low phase of SOF too long (> 12 etu)
|
||||
if (Demod.posCount > 12 * 2) { // low phase of SOF too long (> 12 etu)
|
||||
Demod.state = DEMOD_UNSYNCD;
|
||||
LED_C_OFF();
|
||||
}
|
||||
@@ -831,7 +832,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
||||
Demod.posCount++;
|
||||
MAKE_SOFT_DECISION();
|
||||
if (v > 0) {
|
||||
if (Demod.posCount > 6 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
|
||||
if (Demod.posCount > 3 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
|
||||
LED_C_OFF();
|
||||
if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass
|
||||
return true;
|
||||
@@ -873,7 +874,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
||||
Demod.bitCount = 0;
|
||||
Demod.state = DEMOD_AWAITING_START_BIT;
|
||||
} else {
|
||||
Demod.state = DEMOD_UNSYNCD;
|
||||
Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;
|
||||
LED_C_OFF();
|
||||
if (s == 0x000) {
|
||||
// This is EOF (start, stop and all data bits == '0'
|
||||
@@ -894,25 +895,18 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Demodulate the samples we received from the tag, also log to tracebuffer
|
||||
*/
|
||||
static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeout, uint32_t *eof_time) {
|
||||
|
||||
|
||||
int samples = 0, ret = 0;
|
||||
|
||||
// Set up the demodulator for tag -> reader responses.
|
||||
Demod14bInit(response, max_len);
|
||||
|
||||
// wait for last transfer to complete
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) {};
|
||||
|
||||
// And put the FPGA in the appropriate mode
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
|
||||
|
||||
|
||||
// Setup and start DMA.
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
|
||||
//FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
|
||||
|
||||
// The DMA buffer, used to stream samples from the FPGA
|
||||
dmabuf16_t *dma = get_dma16();
|
||||
@@ -924,6 +918,9 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
|
||||
uint32_t dma_start_time = 0;
|
||||
uint16_t *upTo = dma->buf;
|
||||
|
||||
// Put FPGA in the appropriate mode
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
|
||||
|
||||
for (;;) {
|
||||
|
||||
volatile uint16_t behindBy = ((uint16_t *)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1);
|
||||
@@ -971,7 +968,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
|
||||
|
||||
if (Handle14443bSamplesFromTag(ci, cq)) {
|
||||
|
||||
*eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM; // end of EOF
|
||||
*eof_time = dma_start_time + (samples ) - DELAY_TAG_TO_ARM; // end of EOF
|
||||
|
||||
if (Demod.len > Demod.max_len) {
|
||||
ret = -2; // overflow
|
||||
@@ -986,19 +983,17 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
|
||||
}
|
||||
|
||||
FpgaDisableSscDma();
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (Demod.len > 0) {
|
||||
uint32_t sof_time = *eof_time
|
||||
- (Demod.len * 8 * 8 * 16) // time for byte transfers
|
||||
- (32 * 16) // time for SOF transfer
|
||||
- 0; // time for EOF transfer
|
||||
- (Demod.len * (8 + 2)) // time for byte transfers
|
||||
- (12) // time for SOF transfer
|
||||
- (12); // time for EOF transfer
|
||||
LogTrace(Demod.output, Demod.len, (sof_time * 4), (*eof_time * 4), NULL, false);
|
||||
}
|
||||
|
||||
return Demod.len;
|
||||
}
|
||||
|
||||
@@ -1011,6 +1006,7 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) {
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD);
|
||||
|
||||
// TR2 minimum 14 ETUs
|
||||
if (*start_time < DELAY_ARM_TO_TAG) {
|
||||
*start_time = DELAY_ARM_TO_TAG;
|
||||
}
|
||||
@@ -1018,21 +1014,20 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) {
|
||||
*start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0;
|
||||
|
||||
if (GetCountSspClk() > *start_time) { // we may miss the intended time
|
||||
*start_time = (GetCountSspClk() + 16) & 0xfffffff0; // next possible time
|
||||
*start_time = (GetCountSspClk() + 32) & 0xfffffff0; // next possible time
|
||||
}
|
||||
|
||||
|
||||
// wait
|
||||
while (GetCountSspClk() < *start_time) ;
|
||||
while (GetCountSspClk() < *start_time);
|
||||
|
||||
LED_B_ON();
|
||||
for (int c = 0; c < ts->max; c++) {
|
||||
volatile uint8_t data = ts->buf[c];
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff;
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
volatile uint16_t send_word = (data & 0x80) ? 0x0000 : 0xFFFF;
|
||||
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ;
|
||||
|
||||
AT91C_BASE_SSC->SSC_THR = send_word;
|
||||
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ;
|
||||
@@ -1045,6 +1040,9 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) {
|
||||
LED_B_OFF();
|
||||
|
||||
*start_time += DELAY_ARM_TO_TAG;
|
||||
|
||||
// wait for last transfer to complete
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) {};
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -1061,32 +1059,38 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) {
|
||||
* - no modulation ONES
|
||||
*
|
||||
* 1 ETU == 1 BIT!
|
||||
* TR0 - 8 ETUS minimum.
|
||||
* TR0 - 8 ETU's minimum.
|
||||
* TR0 - 32 ETU's maximum for ATQB only
|
||||
* TR0 - FWT for all other commands
|
||||
*
|
||||
* QUESTION: how long is a 1 or 0 in pulses in the xcorr_848 mode?
|
||||
* 1 "stuffbit" = 1ETU (9us)
|
||||
*
|
||||
* TR2 - After the PICC response, the PCD is required to wait the Frame Delay Time (TR2)
|
||||
before transmission of the next command. The minimum frame delay time required for
|
||||
all commands is 14 ETUs
|
||||
*
|
||||
*/
|
||||
|
||||
int i;
|
||||
tosend_reset();
|
||||
|
||||
|
||||
// Send SOF
|
||||
// 10-11 ETUs of ZERO
|
||||
for (int i = 0; i < 10; i++)
|
||||
for (i = 0; i < 10; i++) {
|
||||
tosend_stuffbit(0);
|
||||
|
||||
|
||||
}
|
||||
// 2-3 ETUs of ONE
|
||||
tosend_stuffbit(1);
|
||||
tosend_stuffbit(1);
|
||||
|
||||
// Sending cmd, LSB
|
||||
// from here we add BITS
|
||||
for (int i = 0; i < len; i++) {
|
||||
for (i = 0; i < len; i++) {
|
||||
// Start bit
|
||||
tosend_stuffbit(0);
|
||||
// Data bits
|
||||
uint8_t b = cmd[i];
|
||||
|
||||
// Data bits
|
||||
volatile uint8_t b = cmd[i];
|
||||
tosend_stuffbit(b & 1);
|
||||
tosend_stuffbit((b >> 1) & 1);
|
||||
tosend_stuffbit((b >> 2) & 1);
|
||||
@@ -1098,31 +1102,29 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) {
|
||||
|
||||
// Stop bit
|
||||
tosend_stuffbit(1);
|
||||
// EGT extra guard time
|
||||
// For PCD it ranges 0-57us (1etu = 9us)
|
||||
// tosend_stuffbit(1);
|
||||
// tosend_stuffbit(1);
|
||||
// tosend_stuffbit(1);
|
||||
// EGT extra guard time 1 ETU = 9us
|
||||
// For PCD it ranges 0-57us === 0 - 6 ETU
|
||||
// FOR PICC it ranges 0-19us == 0 - 2 ETU
|
||||
|
||||
}
|
||||
|
||||
// Send EOF
|
||||
// 10-11 ETUs of ZERO
|
||||
for (int i = 0; i < 10; i++)
|
||||
for (i = 0; i < 10; i++) {
|
||||
tosend_stuffbit(0);
|
||||
}
|
||||
|
||||
// Transition time. TR0 - guard time
|
||||
// 8ETUS minum?
|
||||
// Per specification, Subcarrier must be stopped no later than 2 ETUs after EOF.
|
||||
// I'm guessing this is for the FPGA to be able to send all bits before we switch to listening mode
|
||||
tosend_stuffbit(1);
|
||||
/* Transition time. TR0 - guard time
|
||||
* TR0 - 8 ETU's minimum.
|
||||
* TR0 - 32 ETU's maximum for ATQB only
|
||||
* TR0 - FWT for all other commands
|
||||
* 32,64,128,256,512, ... , 262144, 524288 ETU
|
||||
*/
|
||||
int pad = (12 + (len * 10) + 11) & 0x7;
|
||||
|
||||
// ensure that last byte is filled up
|
||||
for (int i = 0; i < 8 ; ++i)
|
||||
for (i = 0; i < 16 - pad; ++i)
|
||||
tosend_stuffbit(1);
|
||||
|
||||
// TR1 - Synchronization time
|
||||
// Convert from last character reference to length
|
||||
tosend_t *ts = get_tosend();
|
||||
ts->max++;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1132,54 +1134,100 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t
|
||||
tosend_t *ts = get_tosend();
|
||||
CodeIso14443bAsReader(cmd, len);
|
||||
TransmitFor14443b_AsReader(start_time);
|
||||
*eof_time = *start_time + (32 * (8 * ts->max));
|
||||
*eof_time = *start_time + (10 * ts->max) + 10 + 2 + 10;
|
||||
LogTrace(cmd, len, *start_time, *eof_time, NULL, true);
|
||||
}
|
||||
|
||||
/* Sends an APDU to the tag
|
||||
* TODO: check CRC and preamble
|
||||
*/
|
||||
int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response, uint16_t respmaxlen) {
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, uint8_t *response, uint16_t respmaxlen) {
|
||||
|
||||
LED_A_ON();
|
||||
uint8_t message_frame[message_length + 4];
|
||||
// PCB
|
||||
message_frame[0] = 0x0A | pcb_blocknum;
|
||||
pcb_blocknum ^= 1;
|
||||
// CID
|
||||
message_frame[1] = 0;
|
||||
// INF
|
||||
memcpy(message_frame + 2, message, message_length);
|
||||
// EDC (CRC)
|
||||
AddCrc14B(message_frame, message_length + 2);
|
||||
uint8_t real_cmd[msg_len + 4];
|
||||
|
||||
if (msg_len) {
|
||||
// ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02
|
||||
real_cmd[0] = 0x02; // bnr, nad, cid, chn=0; i-block(0x00)
|
||||
if (send_chaining) {
|
||||
real_cmd[0] |= 0x10;
|
||||
}
|
||||
// put block number into the PCB
|
||||
real_cmd[0] |= iso14b_pcb_blocknum;
|
||||
memcpy(real_cmd + 1, msg, msg_len);
|
||||
} else {
|
||||
// R-block. ACK
|
||||
real_cmd[0] = 0xA2; // r-block + ACK
|
||||
real_cmd[0] |= iso14b_pcb_blocknum;
|
||||
}
|
||||
|
||||
AddCrc14B(real_cmd, msg_len + 1);
|
||||
|
||||
// send
|
||||
uint32_t start_time = 0;
|
||||
uint32_t eof_time = 0;
|
||||
CodeAndTransmit14443bAsReader(message_frame, sizeof(message_frame), &start_time, &eof_time);
|
||||
|
||||
// Get response?
|
||||
if (response == NULL) {
|
||||
LED_A_OFF();
|
||||
return 0;
|
||||
}
|
||||
CodeAndTransmit14443bAsReader(real_cmd, msg_len + 3, &start_time, &eof_time);
|
||||
|
||||
eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER;
|
||||
int retlen = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time);
|
||||
int len = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time);
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen < 3) {
|
||||
LED_A_OFF();
|
||||
return -1;
|
||||
uint8_t *data_bytes = (uint8_t *) response;
|
||||
|
||||
if (len <= 0) {
|
||||
return 0; //DATA LINK ERROR
|
||||
} else {
|
||||
// S-Block WTX
|
||||
while (len && ((data_bytes[0] & 0xF2) == 0xF2)) {
|
||||
uint32_t save_iso14b_timeout = iso14b_timeout;
|
||||
// temporarily increase timeout
|
||||
iso14b_set_timeout(MAX((data_bytes[1] & 0x3f) * save_iso14b_timeout, ISO14443B_READER_TIMEOUT));
|
||||
// Transmit WTX back
|
||||
// byte1 - WTXM [1..59]. command FWT = FWT * WTXM
|
||||
data_bytes[1] = data_bytes[1] & 0x3f; // 2 high bits mandatory set to 0b
|
||||
// now need to fix CRC.
|
||||
AddCrc14B(data_bytes, len - 2);
|
||||
|
||||
// transmit S-Block
|
||||
CodeAndTransmit14443bAsReader(data_bytes, len, &start_time, &eof_time);
|
||||
|
||||
// retrieve the result again (with increased timeout)
|
||||
eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER;
|
||||
len = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time);
|
||||
FpgaDisableTracing();
|
||||
|
||||
data_bytes = response;
|
||||
// restore timeout
|
||||
iso14b_set_timeout(save_iso14b_timeout);
|
||||
}
|
||||
|
||||
// if we received an I- or R(ACK)-Block with a block number equal to the
|
||||
// current block number, toggle the current block number
|
||||
if (len >= 3 // PCB + CRC = 3 bytes
|
||||
&& ((data_bytes[0] & 0xC0) == 0 // I-Block
|
||||
|| (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0
|
||||
&& (data_bytes[0] & 0x01) == iso14b_pcb_blocknum) { // equal block numbers
|
||||
iso14b_pcb_blocknum ^= 1;
|
||||
}
|
||||
|
||||
// if we received I-block with chaining we need to send ACK and receive another block of data
|
||||
if (response)
|
||||
*response = data_bytes[0];
|
||||
|
||||
// crc check
|
||||
if (len >= 3 && !check_crc(CRC_14443_B, data_bytes, len)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// VALIDATE CRC
|
||||
if (!check_crc(CRC_14443_B, response, retlen)) {
|
||||
if (DBGLEVEL > DBG_DEBUG) DbpString("CRC fail");
|
||||
return -2;
|
||||
if (len) {
|
||||
// cut frame byte
|
||||
len -= 1;
|
||||
// memmove(data_bytes, data_bytes + 1, len);
|
||||
for (int i = 0; i < len; i++)
|
||||
data_bytes[i] = data_bytes[i + 1];
|
||||
}
|
||||
|
||||
return retlen;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1272,7 +1320,10 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
||||
int iso14443b_select_card(iso14b_card_select_t *card) {
|
||||
// WUPB command (including CRC)
|
||||
// Note: WUPB wakes up all tags, REQB doesn't wake up tags in HALT state
|
||||
static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 };
|
||||
// WUTB or REQB is denoted in the third byte, lower nibble. 0 vs 8
|
||||
//static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 };
|
||||
static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x00, 0x71, 0xff };
|
||||
|
||||
// ATTRIB command (with space for CRC)
|
||||
uint8_t attrib[] = { ISO14443B_ATTRIB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
@@ -1350,7 +1401,7 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
|
||||
}
|
||||
}
|
||||
// reset PCB block number
|
||||
pcb_blocknum = 0;
|
||||
iso14b_pcb_blocknum = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1683,6 +1734,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
|
||||
size_t len = c->oldarg[1] & 0xffff;
|
||||
uint32_t timeout = c->oldarg[2];
|
||||
uint8_t *cmd = c->data.asBytes;
|
||||
uint8_t buf[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
|
||||
if (DBGLEVEL > DBG_DEBUG) Dbprintf("14b raw: param, %04x", param);
|
||||
|
||||
@@ -1719,9 +1771,9 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
|
||||
}
|
||||
|
||||
if ((param & ISO14B_APDU) == ISO14B_APDU) {
|
||||
uint8_t buf[100] = {0};
|
||||
status = iso14443b_apdu(cmd, len, buf, sizeof(buf));
|
||||
reply_mix(CMD_HF_ISO14443B_COMMAND, status, status, 0, buf, status);
|
||||
status = iso14443b_apdu(cmd, len, (param & ISO14B_SEND_CHAINING), buf, sizeof(buf));
|
||||
sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE);
|
||||
reply_mix(CMD_HF_ISO14443B_COMMAND, status, status, 0, buf, sendlen);
|
||||
}
|
||||
|
||||
if ((param & ISO14B_RAW) == ISO14B_RAW) {
|
||||
@@ -1729,8 +1781,6 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
|
||||
AddCrc14B(cmd, len);
|
||||
len += 2;
|
||||
}
|
||||
uint8_t buf[100] = {0};
|
||||
|
||||
uint32_t start_time = 0;
|
||||
uint32_t eof_time = 0;
|
||||
CodeAndTransmit14443bAsReader(cmd, len, &start_time, &eof_time);
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
#endif
|
||||
|
||||
void iso14443b_setup(void);
|
||||
int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response, uint16_t respmaxlen);
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, uint8_t *response, uint16_t respmaxlen);
|
||||
|
||||
int iso14443b_select_card(iso14b_card_select_t *card);
|
||||
int iso14443b_select_card_srx(iso14b_card_select_t *card);
|
||||
|
||||
+1
-1
@@ -465,7 +465,7 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint16_t period_0, uint
|
||||
} else if (*command == '1') {
|
||||
TurnReadLFOn(period_1);
|
||||
} else {
|
||||
for (uint8_t i=0; i < LF_CMDREAD_MAX_EXTRA_SYMBOLS; i++) {
|
||||
for (uint8_t i = 0; i < LF_CMDREAD_MAX_EXTRA_SYMBOLS; i++) {
|
||||
if (*command == symbol_extra[i]) {
|
||||
TurnReadLFOn(period_extra[i]);
|
||||
break;
|
||||
|
||||
+1
-1
@@ -332,7 +332,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
|
||||
if (verbose) {
|
||||
if (checked == -1) {
|
||||
Dbprintf("lf sampling aborted");
|
||||
} else if ((cancel_counter == cancel_after) && (cancel_after > 0)){
|
||||
} else if ((cancel_counter == cancel_after) && (cancel_after > 0)) {
|
||||
Dbprintf("lf sampling cancelled after %u", cancel_counter);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,25 @@
|
||||
#include "cliparser.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <util.h> // Get color constants
|
||||
#include <ui.h> // get PrintAndLogEx
|
||||
|
||||
#ifndef ARRAYLEN
|
||||
# define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
// Custom Colors
|
||||
// To default the color return s
|
||||
#define _SectionTagColor_(s) _GREEN_(s)
|
||||
#define _ExampleColor_(s) _YELLOW_(s)
|
||||
#define _CommandColor_(s) _RED_(s)
|
||||
#define _DescriptionColor_(s) _CYAN_(s)
|
||||
#define _ArgColor_(s) s
|
||||
#define _ArgHelpColor_(s) s
|
||||
// End Custom Colors
|
||||
// Option width set to 30 to allow option descriptions to align. approx line 74
|
||||
// Example width set to 50 to allow help descriptions to align. approx line 93
|
||||
|
||||
int CLIParserInit(CLIParserContext **ctx, const char *vprogramName, const char *vprogramHint, const char *vprogramHelp) {
|
||||
*ctx = malloc(sizeof(CLIParserContext));
|
||||
if (!*ctx) {
|
||||
@@ -40,7 +55,7 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
|
||||
/* verify the argtable[] entries were allocated sucessfully */
|
||||
if (arg_nullcheck(ctx->argtable) != 0) {
|
||||
/* NULL entries were detected, some allocations must have failed */
|
||||
printf("ERROR: Insufficient memory\n");
|
||||
PrintAndLogEx(ERR, "ERROR: Insufficient memory\n");
|
||||
fflush(stdout);
|
||||
return 2;
|
||||
}
|
||||
@@ -49,14 +64,50 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
|
||||
|
||||
/* special case: '--help' takes precedence over error reporting */
|
||||
if ((argc < 2 && !allowEmptyExec) || ((struct arg_lit *)(ctx->argtable)[0])->count > 0) { // help must be the first record
|
||||
printf("Usage: %s", ctx->programName);
|
||||
arg_print_syntaxv(stdout, ctx->argtable, "\n");
|
||||
if (ctx->programHint)
|
||||
printf("%s\n\n", ctx->programHint);
|
||||
arg_print_glossary(stdout, ctx->argtable, " %-20s %s\n");
|
||||
printf("\n");
|
||||
if (ctx->programHelp)
|
||||
printf("%s \n", ctx->programHelp);
|
||||
PrintAndLogEx(NORMAL, "\n"_DescriptionColor_("%s"), ctx->programHint);
|
||||
|
||||
PrintAndLogEx(NORMAL, "\n"_SectionTagColor_("usage:"));
|
||||
PrintAndLogEx(NORMAL, " "_CommandColor_("%s")NOLF, ctx->programName);
|
||||
arg_print_syntaxv(stdout, ctx->argtable, "\n\n");
|
||||
|
||||
PrintAndLogEx(NORMAL, _SectionTagColor_("options:"));
|
||||
|
||||
arg_print_glossary(stdout, ctx->argtable, " "_ArgColor_("%-30s")" "_ArgHelpColor_("%s")"\n");
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
if (ctx->programHelp) {
|
||||
PrintAndLogEx(NORMAL, _SectionTagColor_("examples/notes:"));
|
||||
char *buf = NULL;
|
||||
int idx = 0;
|
||||
buf = realloc(buf, strlen(ctx->programHelp) + 1); // more then enough as we are splitting
|
||||
|
||||
char *p2; // pointer to split example from comment.
|
||||
int egWidth = 30;
|
||||
for (int i = 0; i <= strlen(ctx->programHelp); i++) { // <= so to get string terminator.
|
||||
buf[idx++] = ctx->programHelp[i];
|
||||
if ((ctx->programHelp[i] == '\n') || (ctx->programHelp[i] == 0x00)) {
|
||||
buf[idx - 1] = 0x00;
|
||||
p2 = strstr(buf, "->"); // See if the example has a comment.
|
||||
if (p2 != NULL) {
|
||||
*(p2 - 1) = 0x00;
|
||||
|
||||
if (strlen(buf) > 28)
|
||||
egWidth = strlen(buf) + 5;
|
||||
else
|
||||
egWidth = 30;
|
||||
|
||||
PrintAndLogEx(NORMAL, " "_ExampleColor_("%-*s")" %s", egWidth, buf, p2);
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " "_ExampleColor_("%-*s"), egWidth, buf);
|
||||
}
|
||||
idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
free(buf);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
return 1;
|
||||
@@ -66,7 +117,7 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
|
||||
if (nerrors > 0) {
|
||||
/* Display the error details contained in the arg_end struct.*/
|
||||
arg_print_errors(stdout, ((struct arg_end *)(ctx->argtable)[vargtableLen - 1]), ctx->programName);
|
||||
printf("Try '%s --help' for more information.\n", ctx->programName);
|
||||
PrintAndLogEx(WARNING, "Try '%s --help' for more information.\n", ctx->programName);
|
||||
fflush(stdout);
|
||||
return 3;
|
||||
}
|
||||
@@ -74,6 +125,7 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
enum ParserState {
|
||||
PS_FIRST,
|
||||
PS_ARGUMENT,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "util.h"
|
||||
|
||||
#define arg_param_begin arg_lit0("hH", "help", "This help")
|
||||
#define arg_param_begin arg_lit0("h", "help", "This help")
|
||||
#define arg_param_end arg_end(20)
|
||||
|
||||
#define arg_getsize(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
+13
-11
@@ -93,8 +93,10 @@ Command = {
|
||||
o.data = data
|
||||
return o
|
||||
end,
|
||||
parse = function (packet)
|
||||
local count, cmd, arg1, arg2, arg3, data = bin.unpack('LLLLH511', packet)
|
||||
parse = function(packet)
|
||||
local count, cmd, arg1, arg2, arg3, data = bin.unpack('LLLL', packet)
|
||||
local length = #packet - count + 1
|
||||
count, data = bin.unpack('H'..length, packet, count)
|
||||
return Command:new{cmd = cmd, arg1 = arg1, arg2 = arg2, arg3 = arg3, data = data}
|
||||
end
|
||||
}
|
||||
@@ -121,26 +123,28 @@ end
|
||||
-- @param command - the usb packet to send
|
||||
-- @param ignoreresponse - if set to true, we don't read the device answer packet
|
||||
-- which is usually recipe for fail. If not sent, the host will wait 2s for a
|
||||
-- response of type CMD_ACK
|
||||
-- response of type CMD_ACK or like NG use the CMD as ack..
|
||||
-- @return packet,nil if successful
|
||||
-- nil, errormessage if unsuccessful
|
||||
function Command:sendMIX( ignore_response, timeout )
|
||||
function Command:sendMIX( ignore_response, timeout, use_cmd_ack)
|
||||
if timeout == nil then timeout = TIMEOUT end
|
||||
local data = self.data
|
||||
local cmd = self.cmd
|
||||
local arg1, arg2, arg3 = self.arg1, self.arg2, self.arg3
|
||||
|
||||
local err, msg = core.SendCommandMIX(cmd, arg1, arg2, arg3, data)
|
||||
if err == nil then return err, msg end
|
||||
|
||||
if ignore_response then return true, nil end
|
||||
|
||||
if timeout == nil then timeout = TIMEOUT end
|
||||
local ack = _commands.CMD_ACK
|
||||
if use_cmd_ack then
|
||||
ack = cmd
|
||||
end
|
||||
|
||||
local response, msg = core.WaitForResponseTimeout(_commands.CMD_ACK, timeout)
|
||||
local response, msg = core.WaitForResponseTimeout(ack, timeout)
|
||||
if response == nil then
|
||||
return nil, 'Error, waiting for response timed out :: '..msg
|
||||
end
|
||||
|
||||
-- lets digest
|
||||
data = nil
|
||||
cmd = nil
|
||||
@@ -157,15 +161,13 @@ function Command:sendMIX( ignore_response, timeout )
|
||||
return packed, nil;
|
||||
end
|
||||
function Command:sendNG( ignore_response, timeout )
|
||||
if timeout == nil then timeout = TIMEOUT end
|
||||
local data = self.data
|
||||
local cmd = self.cmd
|
||||
local err, msg = core.SendCommandNG(cmd, data)
|
||||
if err == nil then return nil, msg end
|
||||
|
||||
if ignore_response then return true, nil end
|
||||
|
||||
if timeout == nil then timeout = TIMEOUT end
|
||||
|
||||
local response, msg = core.WaitForResponseTimeout(cmd, timeout)
|
||||
if response == nil then
|
||||
return nil, 'Error, waiting for response timed out :: '..msg
|
||||
|
||||
+12
-12
@@ -15,17 +15,18 @@ local cmds = require('commands')
|
||||
local utils = require('utils')
|
||||
|
||||
-- Shouldn't take longer than 2.5 seconds
|
||||
local TIMEOUT = 2500
|
||||
local TIMEOUT = 2000
|
||||
|
||||
local ISO14B_COMMAND = {
|
||||
ISO14B_CONNECT = 1,
|
||||
ISO14B_DISCONNECT = 2,
|
||||
ISO14B_APDU = 4,
|
||||
ISO14B_RAW = 8,
|
||||
ISO14B_CONNECT = 0x1,
|
||||
ISO14B_DISCONNECT = 0x2,
|
||||
ISO14B_APDU = 0x4,
|
||||
ISO14B_RAW = 0x8,
|
||||
ISO14B_REQUEST_TRIGGER = 0x10,
|
||||
ISO14B_APPEND_CRC = 0x20,
|
||||
ISO14B_SELECT_STD = 0x40,
|
||||
ISO14B_SELECT_SR = 0x80,
|
||||
ISO14B_SET_TIMEOUT = 0x100,
|
||||
}
|
||||
|
||||
local function parse14443b(data)
|
||||
@@ -74,9 +75,11 @@ local function read14443b(disconnect)
|
||||
arg1 = flags
|
||||
}
|
||||
|
||||
local result, err = command:sendMIX()
|
||||
info = nil
|
||||
|
||||
local result, err = command:sendMIX(false, TIMEOUT, true)
|
||||
if result then
|
||||
local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL',result)
|
||||
local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL', result)
|
||||
if arg0 == 0 then
|
||||
data = string.sub(result, count)
|
||||
info, err = parse14443b(data)
|
||||
@@ -88,12 +91,10 @@ local function read14443b(disconnect)
|
||||
end
|
||||
|
||||
if err then
|
||||
print(err)
|
||||
return nil, err
|
||||
end
|
||||
return info
|
||||
return info, nil
|
||||
end
|
||||
|
||||
---
|
||||
-- Waits for a mifare card to be placed within the vicinity of the reader.
|
||||
-- @return if successful: an table containing card info
|
||||
@@ -102,12 +103,11 @@ local function waitFor14443b()
|
||||
print('Waiting for card... press Enter to quit')
|
||||
while not core.kbd_enter_pressed() do
|
||||
res, err = read14443b(false)
|
||||
if res then return res end
|
||||
if res then return res, err end
|
||||
-- err means that there was no response from card
|
||||
end
|
||||
return nil, 'Aborted by user'
|
||||
end
|
||||
|
||||
---
|
||||
-- turns on the HF field.
|
||||
local function connect14443b()
|
||||
|
||||
@@ -11,10 +11,10 @@ This is a script to allow raw 14443a commands to be sent and received.
|
||||
]]
|
||||
example = [[
|
||||
# 1. Connect and don't disconnect
|
||||
script run hf_14a_raw -p
|
||||
script run hf_14a_raw -k
|
||||
|
||||
# 2. Send mf auth, read response (nonce)
|
||||
script run hf_14a_raw -o -x 6000F57b -p
|
||||
script run hf_14a_raw -o -x 6000F57b -k
|
||||
|
||||
# 3. disconnect
|
||||
script run hf_14a_raw -o
|
||||
@@ -26,10 +26,10 @@ usage = [[
|
||||
script run hf_14a_raw -x 6000F57b
|
||||
]]
|
||||
arguments = [[
|
||||
-o do not connect - use this only if you previously used -p to stay connected
|
||||
-o do not connect - use this only if you previously used -k to stay connected
|
||||
-r do not read response
|
||||
-c calculate and append CRC
|
||||
-p stay connected - dont inactivate the field
|
||||
-k stay connected - dont inactivate the field
|
||||
-x <payload> Data to send (NO SPACES!)
|
||||
-d Debug flag
|
||||
-t Topaz mode
|
||||
@@ -187,8 +187,8 @@ function selftest()
|
||||
DEBUG = true
|
||||
dbg('Performing test')
|
||||
main()
|
||||
main('-p')
|
||||
main(' -o -x 6000F57b -p')
|
||||
main('-k')
|
||||
main(' -o -x 6000F57b -k')
|
||||
main('-o')
|
||||
main('-x 6000F57b')
|
||||
dbg('Tests done')
|
||||
|
||||
@@ -135,13 +135,13 @@ function main(args)
|
||||
end
|
||||
|
||||
-- Original loop
|
||||
-- core.console("hf 14a raw -a -p -b 7 45")
|
||||
-- local cmd_select = string.format("hf 14a raw -c -p 9370%s", serial_number)
|
||||
-- core.console("hf 14a raw -a -k -b 7 45")
|
||||
-- local cmd_select = string.format("hf 14a raw -c -k 9370%s", serial_number)
|
||||
-- core.console(cmd_select)
|
||||
-- for i = 0, 254 do
|
||||
-- local cmd_rd_blk = string.format("hf 14a raw -c -p 30 %02x", i)
|
||||
-- local cmd_rd_blk = string.format("hf 14a raw -c -k 30 %02x", i)
|
||||
-- core.console(cmd_rd_blk)
|
||||
-- core.console("hf 14a raw -p 80")
|
||||
-- core.console("hf 14a raw -k 80")
|
||||
-- end
|
||||
-- core.console("hf 14a raw -r")
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ local ansicolors = require('ansicolors')
|
||||
|
||||
copyright = ''
|
||||
author = 'Iceman'
|
||||
version = 'v1.0.2'
|
||||
version = 'v1.0.4'
|
||||
desc = [[
|
||||
This is a script to communicate with a CALYSPO / 14443b tag using the '14b raw' commands
|
||||
]]
|
||||
@@ -31,11 +31,12 @@ device-side.
|
||||
|
||||
local function calypso_parse(result)
|
||||
local r = Command.parse(result)
|
||||
local len = r.arg2 * 2
|
||||
r.data = string.sub(r.data, 0, len);
|
||||
print('GOT:', r.data)
|
||||
if r.arg1 == 0 then
|
||||
return r, nil
|
||||
if r.arg1 >= 0 then
|
||||
local len = r.arg2 * 2
|
||||
if len > 0 then
|
||||
r.data = string.sub(r.data, 0, len);
|
||||
return r, nil
|
||||
end
|
||||
end
|
||||
return nil,nil
|
||||
end
|
||||
@@ -123,12 +124,19 @@ local function calypso_send_cmd_raw(data, ignoreresponse )
|
||||
arg2 = #data/2, -- LEN of data, half the length of the ASCII-string hex string
|
||||
data = data} -- data bytes (commands etc)
|
||||
|
||||
result, err = command:sendMIX(ignoreresponse)
|
||||
local use_cmd_ack = true
|
||||
result, err = command:sendMIX(ignoreresponse, 2000, use_cmd_ack)
|
||||
if result then
|
||||
local r = calypso_parse(result)
|
||||
return r, nil
|
||||
local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL', result)
|
||||
if arg0 >= 0 then
|
||||
return calypso_parse(result)
|
||||
else
|
||||
err = 'card response failed'
|
||||
end
|
||||
else
|
||||
err = 'No response from card'
|
||||
end
|
||||
return respone, err
|
||||
return result, err
|
||||
end
|
||||
---
|
||||
-- calypso_card_num : Reads card number from ATR and
|
||||
@@ -136,23 +144,22 @@ end
|
||||
local function calypso_card_num(card)
|
||||
if not card then return end
|
||||
local card_num = tonumber( card.uid:sub(1,8),16 )
|
||||
print('Card UID', card.uid)
|
||||
print('Card Number', card_num)
|
||||
print('')
|
||||
print('Card UID ' ..ansicolors.green..card.uid:format('%x')..ansicolors.reset)
|
||||
print('Card Number ' ..ansicolors.green..string.format('%u', card_num)..ansicolors.reset)
|
||||
print('-----------------------')
|
||||
end
|
||||
---
|
||||
-- analyse CALYPSO apdu status bytes.
|
||||
local function calypso_apdu_status(apdu)
|
||||
-- last two is CRC
|
||||
-- next two is APDU status bytes.
|
||||
local status = false
|
||||
local mess = 'FAIL'
|
||||
local sw = apdu:sub( #apdu-7, #apdu-4)
|
||||
desc, err = iso7816.tostring(sw)
|
||||
print ('SW', sw, desc, err )
|
||||
|
||||
status = ( sw == '9000' )
|
||||
|
||||
return status
|
||||
--print ('SW', sw, desc, err )
|
||||
local status = ( sw == '9000' )
|
||||
return status, desc, err
|
||||
end
|
||||
|
||||
local _calypso_cmds = {
|
||||
@@ -215,7 +222,7 @@ function main(args)
|
||||
if o == 'b' then bytes = a end
|
||||
end
|
||||
|
||||
lib14b.connect()
|
||||
-- lib14b.connect()
|
||||
|
||||
-- Select 14b tag.
|
||||
card, err = lib14b.waitFor14443b()
|
||||
@@ -241,14 +248,23 @@ function main(args)
|
||||
--for i = 1,10 do
|
||||
--result, err = calypso_send_cmd_raw('0294a40800043f000002',false) --select ICC file
|
||||
for i, apdu in spairs(_calypso_cmds) do
|
||||
print('>>', i )
|
||||
print('>> '..ansicolors.yellow..i..ansicolors.reset)
|
||||
apdu = apdu:gsub('%s+', '')
|
||||
result, err = calypso_send_cmd_raw(apdu , false)
|
||||
if result then
|
||||
calypso_apdu_status(result.data)
|
||||
print('<<', result.data )
|
||||
if err then
|
||||
print('<< '..err)
|
||||
else
|
||||
print('<< no answer')
|
||||
if result then
|
||||
local status, desc, err = calypso_apdu_status(result.data)
|
||||
local d = result.data:sub(3, (#result.data - 8))
|
||||
if status then
|
||||
print('<< '..d..' ('..ansicolors.green..'ok'..ansicolors.reset..')')
|
||||
else
|
||||
print('<< '..d..' '..ansicolors.red..err..ansicolors.reset )
|
||||
end
|
||||
else
|
||||
print('<< no answer')
|
||||
end
|
||||
end
|
||||
end
|
||||
lib14b.disconnect()
|
||||
|
||||
@@ -59,24 +59,24 @@ end
|
||||
|
||||
local function cmdUltralight()
|
||||
return {
|
||||
[0] = 'hf 14a raw -p -a -b 7 40',
|
||||
[1] = 'hf 14a raw -p -a 43',
|
||||
[0] = 'hf 14a raw -k -a -b 7 40',
|
||||
[1] = 'hf 14a raw -k -a 43',
|
||||
[2] = 'hf 14a raw -c -a A2005380712A',
|
||||
[3] = 'hf 14a raw -p -a -b 7 40',
|
||||
[4] = 'hf 14a raw -p -a 43',
|
||||
[3] = 'hf 14a raw -k -a -b 7 40',
|
||||
[4] = 'hf 14a raw -k -a 43',
|
||||
[5] = 'hf 14a raw -c -a A2010200D980',
|
||||
[6] = 'hf 14a raw -p -a -b 7 40',
|
||||
[7] = 'hf 14a raw -p -a 43',
|
||||
[6] = 'hf 14a raw -k -a -b 7 40',
|
||||
[7] = 'hf 14a raw -k -a 43',
|
||||
[8] = 'hf 14a raw -c -a A2025B480000',
|
||||
[9] = 'hf 14a raw -c -a 5000',
|
||||
}
|
||||
end
|
||||
local function cmdClassic()
|
||||
return {
|
||||
[0] = 'hf 14a raw -p -a -b 7 40',
|
||||
[1] = 'hf 14a raw -p -a 43',
|
||||
[2] = 'hf 14a raw -c -p -a A000',
|
||||
[3] = 'hf 14a raw -c -p -a 01020304049802000000000000001001',
|
||||
[0] = 'hf 14a raw -k -a -b 7 40',
|
||||
[1] = 'hf 14a raw -k -a 43',
|
||||
[2] = 'hf 14a raw -c -k -a A000',
|
||||
[3] = 'hf 14a raw -c -k -a 01020304049802000000000000001001',
|
||||
[4] = 'hf 14a raw -c -a 5000',
|
||||
}
|
||||
end
|
||||
|
||||
@@ -70,18 +70,18 @@ function magicUID(b0, b1, b2)
|
||||
print('Using backdoor Magic tag function')
|
||||
|
||||
-- write block 0
|
||||
core.console('hf 14a raw -p -a -b 7 40')
|
||||
core.console('hf 14a raw -p -a 43')
|
||||
core.console('hf 14a raw -k -a -b 7 40')
|
||||
core.console('hf 14a raw -k -a 43')
|
||||
core.console('hf 14a raw -c -a A200'..b0)
|
||||
|
||||
-- write block 1
|
||||
core.console('hf 14a raw -p -a -b 7 40')
|
||||
core.console('hf 14a raw -p -a 43')
|
||||
core.console('hf 14a raw -k -a -b 7 40')
|
||||
core.console('hf 14a raw -k -a 43')
|
||||
core.console('hf 14a raw -c -a A201'..b1)
|
||||
|
||||
-- write block 2
|
||||
core.console('hf 14a raw -p -a -b 7 40')
|
||||
core.console('hf 14a raw -p -a 43')
|
||||
core.console('hf 14a raw -k -a -b 7 40')
|
||||
core.console('hf 14a raw -k -a 43')
|
||||
core.console('hf 14a raw -c -a A202'..b2)
|
||||
end
|
||||
--
|
||||
@@ -90,16 +90,16 @@ function brickableUID(b0, b1, b2)
|
||||
|
||||
print('Using BRICKABLE Magic tag function')
|
||||
|
||||
core.console('hf 14a raw -p -s -3')
|
||||
core.console('hf 14a raw -k -s -3')
|
||||
|
||||
-- write block 0
|
||||
core.console('hf 14a raw -p -c A200'..b0)
|
||||
core.console('hf 14a raw -k -c A200'..b0)
|
||||
|
||||
-- write block 1
|
||||
core.console('hf 14a raw -p -c A201'..b1)
|
||||
core.console('hf 14a raw -k -c A201'..b1)
|
||||
|
||||
-- write block 2
|
||||
core.console('hf 14a raw -p -c A202'..b2)
|
||||
core.console('hf 14a raw -k -c A202'..b2)
|
||||
end
|
||||
---
|
||||
-- The main entry point
|
||||
|
||||
@@ -660,7 +660,7 @@ static int Cmdaskmandemod(const char *Cmd) {
|
||||
Cmd++;
|
||||
} else if (Cmd[1] == 's') {
|
||||
st = true;
|
||||
Cmd+=2;
|
||||
Cmd += 2;
|
||||
}
|
||||
int clk = 0;
|
||||
int invert = 0;
|
||||
@@ -2264,15 +2264,14 @@ static int CmdDataNDEF(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "data ndef",
|
||||
"Decode and print NFC Data Exchange Format (NDEF)",
|
||||
"Samples:\n"
|
||||
_YELLOW_("\tdata ndef -d 9101085402656e48656c6c6f5101085402656e576f726c64\n")
|
||||
_YELLOW_("\tdata ndef -d 0103d020240203e02c040300fe\n")
|
||||
"data ndef -d 9101085402656e48656c6c6f5101085402656e576f726c64\n"
|
||||
"data ndef -d 0103d020240203e02c040300fe\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0("dD", "data", "<hex>", "NDEF data to decode"),
|
||||
arg_lit0("vV", "verbose", "verbose mode"),
|
||||
arg_strx0("d", "data", "<hex>", "NDEF data to decode"),
|
||||
arg_lit0("v", "verbose", "verbose mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
+51
-54
@@ -246,11 +246,11 @@ static int usage_hf_14a_sniff(void) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_14a_raw(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14a raw [-h] [-r] [-c] [-p] [-a] [-T] [-t] <milliseconds> [-b] <number of bits> <0A 0B 0C ... hex>");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14a raw [-h] [-r] [-c] [-k] [-a] [-T] [-t] <milliseconds> [-b] <number of bits> <0A 0B 0C ... hex>");
|
||||
PrintAndLogEx(NORMAL, " -h this help");
|
||||
PrintAndLogEx(NORMAL, " -r do not read response");
|
||||
PrintAndLogEx(NORMAL, " -c calculate and append CRC");
|
||||
PrintAndLogEx(NORMAL, " -p leave the signal field ON after receive");
|
||||
PrintAndLogEx(NORMAL, " -k keep signal field ON after receive");
|
||||
PrintAndLogEx(NORMAL, " -a active signal field ON without select");
|
||||
PrintAndLogEx(NORMAL, " -s active signal field ON with select");
|
||||
PrintAndLogEx(NORMAL, " -b number of bits to send. Useful for send partial byte");
|
||||
@@ -563,13 +563,13 @@ static int CmdHF14AInfo(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14a info",
|
||||
"This command makes more extensive tests against a ISO14443a tag in order to collect information",
|
||||
"Sample:\n\thf 14a info -nsv - shows full information about the card\n");
|
||||
"hf 14a info -nsv -> shows full information about the card\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("vV", "verbose", "adds some information to results"),
|
||||
arg_lit0("nN", "nacktest", "test for nack bug"),
|
||||
arg_lit0("sS", "aidsearch", "checks if AIDs from aidlist.json is present on the card and prints information about found AIDs"),
|
||||
arg_lit0("v", "verbose", "adds some information to results"),
|
||||
arg_lit0("n", "nacktest", "test for nack bug"),
|
||||
arg_lit0("s", "aidsearch", "checks if AIDs from aidlist.json is present on the card and prints information about found AIDs"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
@@ -1080,20 +1080,20 @@ static int CmdHF14AAPDU(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14a apdu",
|
||||
"Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). works with all apdu types from ISO 7816-4:2013",
|
||||
"Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n"
|
||||
"\thf 14a apdu -sd 00A404000E325041592E5359532E444446303100 - decode apdu\n"
|
||||
"\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 - encode standard apdu\n"
|
||||
"\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 - encode extended apdu\n");
|
||||
"hf 14a apdu -st 00A404000E325041592E5359532E444446303100\n"
|
||||
"hf 14a apdu -sd 00A404000E325041592E5359532E444446303100 -> decode apdu\n"
|
||||
"hf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 -> encode standard apdu\n"
|
||||
"hf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 -> encode extended apdu\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "activate field and select card"),
|
||||
arg_lit0("kK", "keep", "leave the signal field ON after receive response"),
|
||||
arg_lit0("tT", "tlv", "executes TLV decoder if it possible"),
|
||||
arg_lit0("dD", "decapdu", "decode apdu request if it possible"),
|
||||
arg_str0("mM", "make", "<head (CLA INS P1 P2) hex>", "make apdu with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
|
||||
arg_lit0("eE", "extended", "make extended length apdu if `m` parameter included"),
|
||||
arg_int0("lL", "le", "<Le (int)>", "Le apdu parameter if `m` parameter included"),
|
||||
arg_lit0("s", "select", "activate field and select card"),
|
||||
arg_lit0("k", "keep", "leave the signal field ON after receive response"),
|
||||
arg_lit0("t", "tlv", "executes TLV decoder if it possible"),
|
||||
arg_lit0("d", "decapdu", "decode apdu request if it possible"),
|
||||
arg_str0("m", "make", "<head (CLA INS P1 P2) hex>", "make apdu with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
|
||||
arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"),
|
||||
arg_int0("l", "le", "<Le (int)>", "Le apdu parameter if `m` parameter included"),
|
||||
arg_strx1(NULL, NULL, "<APDU (hex) | data (hex)>", "data if `m` parameter included"),
|
||||
arg_param_end
|
||||
};
|
||||
@@ -1186,7 +1186,7 @@ static int CmdHF14AAPDU(const char *Cmd) {
|
||||
static int CmdHF14ACmdRaw(const char *Cmd) {
|
||||
bool reply = 1;
|
||||
bool crc = false;
|
||||
bool power = false;
|
||||
bool keep_field_on = false;
|
||||
bool active = false;
|
||||
bool active_select = false;
|
||||
bool no_rats = false;
|
||||
@@ -1218,8 +1218,8 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
|
||||
case 'c':
|
||||
crc = true;
|
||||
break;
|
||||
case 'p':
|
||||
power = true;
|
||||
case 'k':
|
||||
keep_field_on = true;
|
||||
break;
|
||||
case 'a':
|
||||
active = true;
|
||||
@@ -1306,7 +1306,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
|
||||
argtimeout = 13560000 / 1000 / (8 * 16) * timeout; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us)
|
||||
}
|
||||
|
||||
if (power) {
|
||||
if (keep_field_on) {
|
||||
flags |= ISO14A_NO_DISCONNECT;
|
||||
}
|
||||
|
||||
@@ -1369,8 +1369,7 @@ static int CmdHF14AAntiFuzz(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14a antifuzz",
|
||||
"Tries to fuzz the ISO14443a anticollision phase",
|
||||
"Usage:\n"
|
||||
"\thf 14a antifuzz -4\n");
|
||||
"hf 14a antifuzz -4\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
@@ -1398,9 +1397,8 @@ static int CmdHF14AChaining(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14a chaining",
|
||||
"Enable/Disable ISO14443a input chaining. Maximum input length goes from ATS.",
|
||||
"Usage:\n"
|
||||
"\thf 14a chaining disable -> disable chaining\n"
|
||||
"\thf 14a chaining -> show chaining enable/disable state\n");
|
||||
"hf 14a chaining disable -> disable chaining\n"
|
||||
"hf 14a chaining -> show chaining enable/disable state\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
@@ -1425,38 +1423,10 @@ static int CmdHF14AChaining(const char *Cmd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHF14AList, AlwaysAvailable, "List ISO 14443-a history"},
|
||||
{"info", CmdHF14AInfo, IfPm3Iso14443a, "Tag information"},
|
||||
{"reader", CmdHF14AReader, IfPm3Iso14443a, "Act like an ISO14443-a reader"},
|
||||
{"cuids", CmdHF14ACUIDs, IfPm3Iso14443a, "<n> Collect n>0 ISO14443-a UIDs in one go"},
|
||||
{"sim", CmdHF14ASim, IfPm3Iso14443a, "<UID> -- Simulate ISO 14443-a tag"},
|
||||
{"sniff", CmdHF14ASniff, IfPm3Iso14443a, "sniff ISO 14443-a traffic"},
|
||||
{"apdu", CmdHF14AAPDU, IfPm3Iso14443a, "Send ISO 14443-4 APDU to tag"},
|
||||
{"chaining", CmdHF14AChaining, IfPm3Iso14443a, "Control ISO 14443-4 input chaining"},
|
||||
{"raw", CmdHF14ACmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"},
|
||||
{"antifuzz", CmdHF14AAntiFuzz, IfPm3Iso14443a, "Fuzzing the anticollision phase. Warning! Readers may react strange"},
|
||||
{"config", CmdHf14AConfig, IfPm3Iso14443a, "Configure 14a settings (use with caution)"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdsHelp(CommandTable);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdHF14A(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
static void printTag(const char *tag) {
|
||||
PrintAndLogEx(SUCCESS, " " _YELLOW_("%s"), tag);
|
||||
}
|
||||
|
||||
|
||||
typedef enum {
|
||||
MTNONE = 0,
|
||||
MTCLASSIC = 1,
|
||||
@@ -2032,3 +2002,30 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||
DropField();
|
||||
return select_status;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHF14AList, AlwaysAvailable, "List ISO 14443-a history"},
|
||||
{"info", CmdHF14AInfo, IfPm3Iso14443a, "Tag information"},
|
||||
{"reader", CmdHF14AReader, IfPm3Iso14443a, "Act like an ISO14443-a reader"},
|
||||
{"cuids", CmdHF14ACUIDs, IfPm3Iso14443a, "<n> Collect n>0 ISO14443-a UIDs in one go"},
|
||||
{"sim", CmdHF14ASim, IfPm3Iso14443a, "<UID> -- Simulate ISO 14443-a tag"},
|
||||
{"sniff", CmdHF14ASniff, IfPm3Iso14443a, "sniff ISO 14443-a traffic"},
|
||||
{"apdu", CmdHF14AAPDU, IfPm3Iso14443a, "Send ISO 14443-4 APDU to tag"},
|
||||
{"chaining", CmdHF14AChaining, IfPm3Iso14443a, "Control ISO 14443-4 input chaining"},
|
||||
{"raw", CmdHF14ACmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"},
|
||||
{"antifuzz", CmdHF14AAntiFuzz, IfPm3Iso14443a, "Fuzzing the anticollision phase. Warning! Readers may react strange"},
|
||||
{"config", CmdHf14AConfig, IfPm3Iso14443a, "Configure 14a settings (use with caution)"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdsHelp(CommandTable);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdHF14A(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
+427
-86
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user