- `hf iclass encryptblk` - to encrypt a data block hex to prep for writing that block (marshmellow)
- ISO14443a stand-alone operation with ARM CFLAG="WITH_ISO14443a_StandAlone". This code can read & emulate two banks of 14a tag UIDs and write to "magic" cards (Craig Young)
- AWID26 command context added as 'lf awid' containing realtime demodulation as well as cloning/simulation based on tag numbers (Craig Young)
+- Added 'hw status'. This command makes the ARM print out some runtime information. (holiman)
+- Added 'hw ping'. This command just sends a usb packets and checks if the pm3 is responsive. Can be used to abort certain operations which supports abort over usb. (holiman)
+- Added `data hex2bin` and `data bin2hex` for command line conversion between binary and hexadecimal (holiman)
### Changed
+<<<<<<< HEAD
- changed `lf config t <threshold>` to be 0 - 128 and will trigger on + or - threshold value (marshmellow)
- `hf iclass dump` cli options - can now dump AA1 and AA2 with different keys in one run (does not go to muliple pages for the larger tags yet)
+=======
+- Revised workflow for StandAloneMode14a (Craig Young)
+>>>>>>> Proxmark/master
- EPA functions (`hf epa`) now support both ISO 14443-A and 14443-B cards (frederikmoellers)
+- 'hw version' only talks to ARM at startup, after that the info is cached. (pwpiwi)
## [2.2.0][2015-07-12]
}
}
+void BigBuf_print_status(void)
+{
+ Dbprintf("Memory");
+ Dbprintf(" BIGBUF_SIZE.............%d", BIGBUF_SIZE);
+ Dbprintf(" BigBuf_hi .............%d", BigBuf_hi);
+ Dbprintf("Tracing");
+ Dbprintf(" tracing ................%d", tracing);
+ Dbprintf(" traceLen ...............%d", traceLen);
+}
+
// return the maximum trace length (i.e. the unallocated size of BigBuf)
uint16_t BigBuf_max_traceLen(void)
extern uint8_t *BigBuf_malloc(uint16_t);
extern void BigBuf_free(void);
extern void BigBuf_free_keep_EM(void);
-
+extern void BigBuf_print_status(void);
extern uint16_t BigBuf_get_traceLen(void);
extern void clear_trace();
extern void set_tracing(bool enable);
#include <hitag2.h>
#include "lfsampling.h"
#include "BigBuf.h"
+#include "mifareutil.h"
#ifdef WITH_LCD
#include "LCD.h"
#endif
cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, 0, VersionString, strlen(VersionString));
}
+// measure the USB Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time.
+// Note: this mimics GetFromBigbuf(), i.e. we have the overhead of the UsbCommand structure included.
+void printUSBSpeed(void)
+{
+ Dbprintf("USB Speed:");
+ Dbprintf(" Sending USB packets to client...");
+
+ #define USB_SPEED_TEST_MIN_TIME 1500 // in milliseconds
+ uint8_t *test_data = BigBuf_get_addr();
+ uint32_t end_time;
+
+ uint32_t start_time = end_time = GetTickCount();
+ uint32_t bytes_transferred = 0;
+
+ LED_B_ON();
+ while(end_time < start_time + USB_SPEED_TEST_MIN_TIME) {
+ cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, 0, USB_CMD_DATA_SIZE, 0, test_data, USB_CMD_DATA_SIZE);
+ end_time = GetTickCount();
+ bytes_transferred += USB_CMD_DATA_SIZE;
+ }
+ LED_B_OFF();
+
+ Dbprintf(" Time elapsed: %dms", end_time - start_time);
+ Dbprintf(" Bytes transferred: %d", bytes_transferred);
+ Dbprintf(" USB Transfer Speed PM3 -> Client = %d Bytes/s",
+ 1000 * bytes_transferred / (end_time - start_time));
+
+}
+
+/**
+ * Prints runtime information about the PM3.
+**/
+void SendStatus(void)
+{
+ BigBuf_print_status();
+ Fpga_print_status();
+ printConfig(); //LF Sampling config
+ printUSBSpeed();
+ Dbprintf("Various");
+ Dbprintf(" MF_DBGLEVEL......%d", MF_DBGLEVEL);
+ Dbprintf(" ToSendMax........%d",ToSendMax);
+ Dbprintf(" ToSendBit........%d",ToSendBit);
+
+ cmd_send(CMD_ACK,1,0,0,0,0);
+}
+
#if defined(WITH_ISO14443a_StandAlone) || defined(WITH_LF)
#define OPTS 2
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
int selected = 0;
- int playing = 0;
+ int playing = 0, iGotoRecord = 0, iGotoClone = 0;
int cardRead[OPTS] = {0};
uint8_t readUID[10] = {0};
uint32_t uid_1st[OPTS]={0};
uint32_t uid_2nd[OPTS]={0};
+ uint32_t uid_tmp1 = 0;
+ uint32_t uid_tmp2 = 0;
+ iso14a_card_select_t hi14a_card[OPTS];
LED(selected + 1, 0);
{
usb_poll();
WDT_HIT();
-
- // Was our button held down or pressed?
- int button_pressed = BUTTON_HELD(1000);
SpinDelay(300);
- // Button was held for a second, begin recording
- if (button_pressed > 0 && cardRead[selected] == 0)
+ if (iGotoRecord == 1 || cardRead[selected] == 0)
{
+ iGotoRecord = 0;
LEDsoff();
LED(selected + 1, 0);
LED(LED_RED2, 0);
// record
Dbprintf("Enabling iso14443a reader mode for [Bank: %u]...", selected);
-
- // wait for button to be released
- while(BUTTON_PRESS())
- WDT_HIT();
/* need this delay to prevent catching some weird data */
SpinDelay(500);
/* Code for reading from 14a tag */
for ( ; ; )
{
WDT_HIT();
- if (!iso14443a_select_card(uid, NULL, &cuid))
+ if (BUTTON_PRESS()) {
+ if (cardRead[selected]) {
+ Dbprintf("Button press detected -- replaying card in bank[%d]", selected);
+ break;
+ }
+ else if (cardRead[(selected+1)%OPTS]) {
+ Dbprintf("Button press detected but no card in bank[%d] so playing from bank[%d]", selected, (selected+1)%OPTS);
+ selected = (selected+1)%OPTS;
+ break; // playing = 1;
+ }
+ else {
+ Dbprintf("Button press detected but no stored tag to play. (Ignoring button)");
+ SpinDelay(300);
+ }
+ }
+ if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid))
continue;
else
{
Dbprintf("Read UID:"); Dbhexdump(10,uid,0);
memcpy(readUID,uid,10*sizeof(uint8_t));
- uint8_t *dst = (uint8_t *)&uid_1st[selected];
+ uint8_t *dst = (uint8_t *)&uid_tmp1;
// Set UID byte order
for (int i=0; i<4; i++)
dst[i] = uid[3-i];
- dst = (uint8_t *)&uid_2nd[selected];
+ dst = (uint8_t *)&uid_tmp2;
for (int i=0; i<4; i++)
dst[i] = uid[7-i];
- break;
+ if (uid_1st[(selected+1)%OPTS] == uid_tmp1 && uid_2nd[(selected+1)%OPTS] == uid_tmp2) {
+ Dbprintf("Card selected has same UID as what is stored in the other bank. Skipping.");
+ }
+ else {
+ if (uid_tmp2) {
+ Dbprintf("Bank[%d] received a 7-byte UID",selected);
+ uid_1st[selected] = (uid_tmp1)>>8;
+ uid_2nd[selected] = (uid_tmp1<<24) + (uid_tmp2>>8);
+ }
+ else {
+ Dbprintf("Bank[%d] received a 4-byte UID",selected);
+ uid_1st[selected] = uid_tmp1;
+ uid_2nd[selected] = uid_tmp2;
+ }
+ break;
+ }
}
}
+ Dbprintf("ATQA = %02X%02X",hi14a_card[selected].atqa[0],hi14a_card[selected].atqa[1]);
+ Dbprintf("SAK = %02X",hi14a_card[selected].sak);
LEDsoff();
LED(LED_GREEN, 200);
LED(LED_ORANGE, 200);
LEDsoff();
LED(selected + 1, 0);
- // Finished recording
- // If we were previously playing, set playing off
- // so next button push begins playing what we recorded
- playing = 0;
+ // Next state is replay:
+ playing = 1;
cardRead[selected] = 1;
-
}
- /* MF UID clone */
- else if (button_pressed > 0 && cardRead[selected] == 1)
+ /* MF Classic UID clone */
+ else if (iGotoClone==1)
{
- LEDsoff();
- LED(selected + 1, 0);
- LED(LED_ORANGE, 250);
-
+ iGotoClone=0;
+ LEDsoff();
+ LED(selected + 1, 0);
+ LED(LED_ORANGE, 250);
- // record
- Dbprintf("Preparing to Clone card [Bank: %x]; uid: %08x", selected, uid_1st[selected]);
- // wait for button to be released
- while(BUTTON_PRESS())
- {
- // Delay cloning until card is in place
- WDT_HIT();
- }
- Dbprintf("Starting clone. [Bank: %u]", selected);
- // need this delay to prevent catching some weird data
- SpinDelay(500);
- // Begin clone function here:
- /* Example from client/mifarehost.c for commanding a block write for "magic Chinese" cards:
- UsbCommand c = {CMD_MIFARE_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}};
- memcpy(c.d.asBytes, data, 16);
- SendCommand(&c);
-
- Block read is similar:
- UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, 0, blockNo}};
- We need to imitate that call with blockNo 0 to set a uid.
-
- The get and set commands are handled in this file:
- // Work with "magic Chinese" card
- case CMD_MIFARE_CSETBLOCK:
- MifareCSetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
- break;
- case CMD_MIFARE_CGETBLOCK:
- MifareCGetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
- //
- break;
-
- mfCSetUID provides example logic for UID set workflow:
- -Read block0 from card in field with MifareCGetBlock()
- -Configure new values without replacing reserved bytes
- memcpy(block0, uid, 4); // Copy UID bytes from byte array
- // Mifare UID BCC
- block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // BCC on byte 5
- Bytes 5-7 are reserved SAK and ATQA for mifare classic
- -Use mfCSetBlock(0, block0, oldUID, wantWipe, CSETBLOCK_SINGLE_OPER) to write it
- */
- uint8_t oldBlock0[16] = {0}, newBlock0[16] = {0}, testBlock0[16] = {0};
- // arg0 = Flags == CSETBLOCK_SINGLE_OPER=0x1F, arg1=returnSlot, arg2=blockNo
- MifareCGetBlock(0x1F, 1, 0, oldBlock0);
- Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0],oldBlock0[1],oldBlock0[2],oldBlock0[3]);
- memcpy(newBlock0,oldBlock0,16);
- // Copy uid_1st for bank (2nd is for longer UIDs not supported if classic)
-
- newBlock0[0] = uid_1st[selected]>>24;
- newBlock0[1] = 0xFF & (uid_1st[selected]>>16);
- newBlock0[2] = 0xFF & (uid_1st[selected]>>8);
- newBlock0[3] = 0xFF & (uid_1st[selected]);
- newBlock0[4] = newBlock0[0]^newBlock0[1]^newBlock0[2]^newBlock0[3];
- // arg0 = needWipe, arg1 = workFlags, arg2 = blockNo, datain
- MifareCSetBlock(0, 0xFF,0, newBlock0);
- MifareCGetBlock(0x1F, 1, 0, testBlock0);
- if (memcmp(testBlock0,newBlock0,16)==0)
- {
- DbpString("Cloned successfull!");
- cardRead[selected] = 0; // Only if the card was cloned successfully should we clear it
- }
- LEDsoff();
- LED(selected + 1, 0);
- // Finished recording
+ // record
+ Dbprintf("Preparing to Clone card [Bank: %x]; uid: %08x", selected, uid_1st[selected]);
- // If we were previously playing, set playing off
- // so next button push begins playing what we recorded
+ // wait for button to be released
+ while(BUTTON_PRESS())
+ {
+ // Delay cloning until card is in place
+ WDT_HIT();
+ }
+ Dbprintf("Starting clone. [Bank: %u]", selected);
+ // need this delay to prevent catching some weird data
+ SpinDelay(500);
+ // Begin clone function here:
+ /* Example from client/mifarehost.c for commanding a block write for "magic Chinese" cards:
+ UsbCommand c = {CMD_MIFARE_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}};
+ memcpy(c.d.asBytes, data, 16);
+ SendCommand(&c);
+
+ Block read is similar:
+ UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, 0, blockNo}};
+ We need to imitate that call with blockNo 0 to set a uid.
+
+ The get and set commands are handled in this file:
+ // Work with "magic Chinese" card
+ case CMD_MIFARE_CSETBLOCK:
+ MifareCSetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
+ break;
+ case CMD_MIFARE_CGETBLOCK:
+ MifareCGetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
+ break;
+
+ mfCSetUID provides example logic for UID set workflow:
+ -Read block0 from card in field with MifareCGetBlock()
+ -Configure new values without replacing reserved bytes
+ memcpy(block0, uid, 4); // Copy UID bytes from byte array
+ // Mifare UID BCC
+ block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // BCC on byte 5
+ Bytes 5-7 are reserved SAK and ATQA for mifare classic
+ -Use mfCSetBlock(0, block0, oldUID, wantWipe, CSETBLOCK_SINGLE_OPER) to write it
+ */
+ uint8_t oldBlock0[16] = {0}, newBlock0[16] = {0}, testBlock0[16] = {0};
+ // arg0 = Flags == CSETBLOCK_SINGLE_OPER=0x1F, arg1=returnSlot, arg2=blockNo
+ MifareCGetBlock(0x3F, 1, 0, oldBlock0);
+ if (oldBlock0[0] == 0 && oldBlock0[0] == oldBlock0[1] && oldBlock0[1] == oldBlock0[2] && oldBlock0[2] == oldBlock0[3]) {
+ Dbprintf("No changeable tag detected. Returning to replay mode for bank[%d]", selected);
+ playing = 1;
+ }
+ else {
+ Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0],oldBlock0[1],oldBlock0[2],oldBlock0[3]);
+ memcpy(newBlock0,oldBlock0,16);
+ // Copy uid_1st for bank (2nd is for longer UIDs not supported if classic)
+
+ newBlock0[0] = uid_1st[selected]>>24;
+ newBlock0[1] = 0xFF & (uid_1st[selected]>>16);
+ newBlock0[2] = 0xFF & (uid_1st[selected]>>8);
+ newBlock0[3] = 0xFF & (uid_1st[selected]);
+ newBlock0[4] = newBlock0[0]^newBlock0[1]^newBlock0[2]^newBlock0[3];
+ // arg0 = needWipe, arg1 = workFlags, arg2 = blockNo, datain
+ MifareCSetBlock(0, 0xFF,0, newBlock0);
+ MifareCGetBlock(0x3F, 1, 0, testBlock0);
+ if (memcmp(testBlock0,newBlock0,16)==0)
+ {
+ DbpString("Cloned successfull!");
+ cardRead[selected] = 0; // Only if the card was cloned successfully should we clear it
playing = 0;
+ iGotoRecord = 1;
+ selected = (selected+1) % OPTS;
+ }
+ else {
+ Dbprintf("Clone failed. Back to replay mode on bank[%d]", selected);
+ playing = 1;
+ }
+ }
+ LEDsoff();
+ LED(selected + 1, 0);
}
// Change where to record (or begin playing)
- else if (button_pressed && cardRead[selected])
+ else if (playing==1) // button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected])
{
- // Next option if we were previously playing
- if (playing)
- selected = (selected + 1) % OPTS;
- playing = !playing;
-
LEDsoff();
LED(selected + 1, 0);
{
LED(LED_GREEN, 0);
DbpString("Playing");
- while (!BUTTON_HELD(500)) { // Loop simulating tag until the button is held a half-sec
+ for ( ; ; ) {
+ WDT_HIT();
+ int button_action = BUTTON_HELD(1000);
+ if (button_action == 0) { // No button action, proceed with sim
+ uint8_t data[512] = {0}; // in case there is a read command received we shouldn't break
Dbprintf("Simulating ISO14443a tag with uid[0]: %08x, uid[1]: %08x [Bank: %u]", uid_1st[selected],uid_2nd[selected],selected);
- SimulateIso14443aTag(1,uid_1st[selected],uid_2nd[selected],NULL);
+ if (hi14a_card[selected].sak == 8 && hi14a_card[selected].atqa[0] == 4 && hi14a_card[selected].atqa[1] == 0) {
+ DbpString("Mifare Classic");
+ SimulateIso14443aTag(1,uid_1st[selected], uid_2nd[selected], data); // Mifare Classic
+ }
+ else if (hi14a_card[selected].sak == 0 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 0) {
+ DbpString("Mifare Ultralight");
+ SimulateIso14443aTag(2,uid_1st[selected],uid_2nd[selected],data); // Mifare Ultralight
+ }
+ else if (hi14a_card[selected].sak == 20 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 3) {
+ DbpString("Mifare DESFire");
+ SimulateIso14443aTag(3,uid_1st[selected],uid_2nd[selected],data); // Mifare DESFire
+ }
+ else {
+ Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation");
+ SimulateIso14443aTag(1,uid_1st[selected], uid_2nd[selected], data);
+ }
+ }
+ else if (button_action == BUTTON_SINGLE_CLICK) {
+ selected = (selected + 1) % OPTS;
+ Dbprintf("Done playing. Switching to record mode on bank %d",selected);
+ iGotoRecord = 1;
+ break;
}
- //cardRead[selected] = 1;
- Dbprintf("Done playing [Bank: %u]",selected);
+ else if (button_action == BUTTON_HOLD) {
+ Dbprintf("Playtime over. Begin cloning...");
+ iGotoClone = 1;
+ break;
+ }
+ WDT_HIT();
+ }
/* We pressed a button so ignore it here with a delay */
SpinDelay(300);
-
- // when done, we're done playing, move to next option
- selected = (selected + 1) % OPTS;
- playing = !playing;
LEDsoff();
LED(selected + 1, 0);
}
ReadPCF7931();
cmd_send(CMD_ACK,0,0,0,0,0);
break;
+ case CMD_PCF7931_WRITE:
+ WritePCF7931(c->d.asDwords[0],c->d.asDwords[1],c->d.asDwords[2],c->d.asDwords[3],c->d.asDwords[4],c->d.asDwords[5],c->d.asDwords[6], c->d.asDwords[9], c->d.asDwords[7]-128,c->d.asDwords[8]-128, c->arg[0], c->arg[1], c->arg[2]);
+ break;
case CMD_EM4X_READ_WORD:
EM4xReadWord(c->arg[1], c->arg[2],c->d.asBytes[0]);
break;
case CMD_VERSION:
SendVersion();
break;
-
+ case CMD_STATUS:
+ SendStatus();
+ break;
+ case CMD_PING:
+ cmd_send(CMD_ACK,0,0,0,0,0);
+ break;
#ifdef WITH_LCD
case CMD_LCD_RESET:
LCDReset();
void ModThenAcquireRawAdcSamples125k(int delay_off,int period_0,int period_1,uint8_t *command);
void ReadTItag(void);
void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc);
+
void AcquireTiType(void);
void AcquireRawBitsTI(void);
void SimulateTagLowFrequency(int period, int gap, int ledcontrol);
int IsBlock0PCF7931(uint8_t *Block);
int IsBlock1PCF7931(uint8_t *Block);
void ReadPCF7931();
+void SendCmdPCF7931(uint32_t * tab);
+bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p);
+bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p);
+bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab);
+void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data);
void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
HIGH(whichGpio);
}
+
+void Fpga_print_status(void)
+{
+ Dbprintf("Fgpa");
+ if(downloaded_bitstream == FPGA_BITSTREAM_HF) Dbprintf(" mode.............HF");
+ else if(downloaded_bitstream == FPGA_BITSTREAM_LF) Dbprintf(" mode.............LF");
+ else Dbprintf(" mode.............%d", downloaded_bitstream);
+}
void FpgaSetupSsc(void);
void SetupSpi(int mode);
bool FpgaSetupSscDma(uint8_t *buf, int len);
+void Fpga_print_status();
#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
#define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN;
void SetAdcMuxFor(uint32_t whichGpio);
LED_A_ON();
for(;;) {
// Clean receive command buffer
-
if(!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) {
DbpString("Button press");
break;
byte_t par_list[8] = {0x00};
byte_t ks_list[8] = {0x00};
+ #define PRNG_SEQUENCE_LENGTH (1 << 16);
static uint32_t sync_time;
static uint32_t sync_cycles;
int catch_up_cycles = 0;
if (first_try) {
mf_nr_ar3 = 0;
sync_time = GetCountSspClk() & 0xfffffff8;
- sync_cycles = 65536; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces).
+ sync_cycles = PRNG_SEQUENCE_LENGTH; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the tag nonces).
nt_attacked = 0;
nt = 0;
par[0] = 0;
LED_C_OFF();
- #define DARKSIDE_MAX_TRIES 32 // number of tries to sync on PRNG cycle. Then give up.
- uint16_t unsuccessfull_tries = 0;
+ #define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up.
+ #define MAX_SYNC_TRIES 16
+ uint16_t unexpected_random = 0;
+ uint16_t sync_tries = 0;
+ int16_t debug_info_nr = -1;
+ uint32_t debug_info[MAX_SYNC_TRIES];
for(uint16_t i = 0; TRUE; i++) {
continue;
}
- sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles;
- catch_up_cycles = 0;
+ if (debug_info_nr == -1) {
+ sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles;
+ catch_up_cycles = 0;
- // if we missed the sync time already, advance to the next nonce repeat
- while(GetCountSspClk() > sync_time) {
- sync_time = (sync_time & 0xfffffff8) + sync_cycles;
- }
+ // if we missed the sync time already, advance to the next nonce repeat
+ while(GetCountSspClk() > sync_time) {
+ sync_time = (sync_time & 0xfffffff8) + sync_cycles;
+ }
- // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked)
- ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time);
+ // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked)
+ ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time);
+ } else {
+ ReaderTransmit(mf_auth, sizeof(mf_auth), NULL);
+ }
// Receive the (4 Byte) "random" nonce
if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) {
int nt_distance = dist_nt(previous_nt, nt);
if (nt_distance == 0) {
nt_attacked = nt;
- }
- else {
+ } else {
if (nt_distance == -99999) { // invalid nonce received
- unsuccessfull_tries++;
- if (!nt_attacked && unsuccessfull_tries > DARKSIDE_MAX_TRIES) {
+ unexpected_random++;
+ if (!nt_attacked && unexpected_random > MAX_UNEXPECTED_RANDOM) {
isOK = -3; // Card has an unpredictable PRNG. Give up
break;
} else {
continue; // continue trying...
}
}
+ if (++sync_tries > MAX_SYNC_TRIES) {
+ if (sync_tries > 2 * MAX_SYNC_TRIES) {
+ isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly
+ break;
+ } else { // continue for a while, just to collect some debug info
+ debug_info[++debug_info_nr] = nt_distance;
+ continue;
+ }
+ }
sync_cycles = (sync_cycles - nt_distance);
- if (MF_DBGLEVEL >= 3) Dbprintf("calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d\n", i, nt_distance, sync_cycles);
+ if (sync_cycles <= 0) {
+ sync_cycles += PRNG_SEQUENCE_LENGTH;
+ }
+ if (MF_DBGLEVEL >= 3) {
+ Dbprintf("calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d\n", i, nt_distance, sync_cycles);
+ }
continue;
}
}
mf_nr_ar[3] &= 0x1F;
+
+ if (isOK == -4) {
+ if (MF_DBGLEVEL >= 3) {
+ for(uint16_t i = 0; i < MAX_SYNC_TRIES; i++) {
+ Dbprintf("collected debug info[%d] = %d\n", i, debug_info[i]);
+ }
+ }
+ }
byte_t buf[28];
memcpy(buf + 0, uid, 4);
#include "string.h"
#include "lfdemod.h"
#include "lfsampling.h"
-#include "usb_cdc.h"
-
+#include "usb_cdc.h" //test
/**
* Function to do a modulation and then get samples.
}
}
+
+
void WriteTIbyte(uint8_t b)
{
int i = 0;
}
}
+
+
+
// arguments: 64bit data split into 32bit idhi:idlo and optional 16bit crc
// if crc provided, it will be written with the data verbatim (even if bogus)
// if not provided a valid crc will be computed from the data and written.
void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc)
{
+
+
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
if(crc == 0) {
crc = update_crc16(crc, (idlo)&0xff);
if(num_blocks == 4) break;
}
memcpy(outBlocks, Blocks, 16*num_blocks);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+
return num_blocks;
}
Dbprintf("Memory content:");
Dbprintf("-----------------------------------------");
for(i=0; i<max_blocks; i++) {
- if(Blocks[i][ALLOC]==1)
+ if(Blocks[i][ALLOC]==1){
Dbprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
Blocks[i][0], Blocks[i][1], Blocks[i][2], Blocks[i][3], Blocks[i][4], Blocks[i][5], Blocks[i][6], Blocks[i][7],
Blocks[i][8], Blocks[i][9], Blocks[i][10], Blocks[i][11], Blocks[i][12], Blocks[i][13], Blocks[i][14], Blocks[i][15]);
- else
+ }else
Dbprintf("<missing block %d>", i);
}
Dbprintf("-----------------------------------------");
+
return ;
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
LED_D_OFF();
}
+
+
+#define T0_PCF 8 //period for the pcf7931 in us
+
+/* Write on a byte of a PCF7931 tag
+ * @param address : address of the block to write
+ @param byte : address of the byte to write
+ @param data : data to write
+ */
+void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data)
+{
+
+ uint32_t tab[1024]={0}; // data times frame
+ uint32_t u = 0;
+ uint8_t parity = 0;
+ bool comp = 0;
+
+
+ //BUILD OF THE DATA FRAME
+
+ //alimentation of the tag (time for initializing)
+ AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab);
+
+ //PMC
+ Dbprintf("Initialization delay : %d us", init_delay);
+ AddPatternPCF7931(8192/2*T0_PCF + 319*T0_PCF+70, 3*T0_PCF, 29*T0_PCF, tab);
+
+ Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p);
+
+ //password indication bit
+ AddBitPCF7931(1, tab, l, p);
+
+
+ //password (on 56 bits)
+ Dbprintf("Password (LSB first on each byte) : %02x %02x %02x %02x %02x %02x %02x", pass1,pass2,pass3,pass4,pass5,pass6,pass7);
+ AddBytePCF7931(pass1, tab, l, p);
+ AddBytePCF7931(pass2, tab, l, p);
+ AddBytePCF7931(pass3, tab, l, p);
+ AddBytePCF7931(pass4, tab, l, p);
+ AddBytePCF7931(pass5, tab, l, p);
+ AddBytePCF7931(pass6, tab, l, p);
+ AddBytePCF7931(pass7, tab, l, p);
+
+
+ //programming mode (0 or 1)
+ AddBitPCF7931(0, tab, l, p);
+
+ //block adress on 6 bits
+ Dbprintf("Block address : %02x", address);
+ for (u=0; u<6; u++)
+ {
+ if (address&(1<<u)) { // bit 1
+ parity++;
+ AddBitPCF7931(1, tab, l, p);
+ } else{ // bit 0
+ AddBitPCF7931(0, tab, l, p);
+ }
+ }
+
+ //byte address on 4 bits
+ Dbprintf("Byte address : %02x", byte);
+ for (u=0; u<4; u++)
+ {
+ if (byte&(1<<u)) { // bit 1
+ parity++;
+ AddBitPCF7931(1, tab, l, p);
+ } else{ // bit 0
+ AddBitPCF7931(0, tab, l, p);
+ }
+ }
+
+ //data on 8 bits
+ Dbprintf("Data : %02x", data);
+ for (u=0; u<8; u++)
+ {
+ if (data&(1<<u)) { // bit 1
+ parity++;
+ AddBitPCF7931(1, tab, l, p);
+ } else{ //bit 0
+ AddBitPCF7931(0, tab, l, p);
+ }
+ }
+
+
+ //parity bit
+ if((parity%2)==0){
+ AddBitPCF7931(0, tab, l, p); //even parity
+ }else{
+ AddBitPCF7931(1, tab, l, p);//odd parity
+ }
+
+ //time access memory
+ AddPatternPCF7931(5120+2680, 0, 0, tab);
+
+ //conversion of the scale time
+ for(u=0;u<500;u++){
+ tab[u]=(tab[u] * 3)/2;
+ }
+
+
+ //compennsation of the counter reload
+ while (!comp){
+ comp = 1;
+ for(u=0;tab[u]!=0;u++){
+ if(tab[u] > 0xFFFF){
+ tab[u] -= 0xFFFF;
+ comp = 0;
+ }
+ }
+ }
+
+ SendCmdPCF7931(tab);
+}
+
+
+
+/* Send a trame to a PCF7931 tags
+ * @param tab : array of the data frame
+ */
+
+void SendCmdPCF7931(uint32_t * tab){
+ uint16_t u=0;
+ uint16_t tempo=0;
+
+ Dbprintf("SENDING DATA FRAME...");
+
+ FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
+
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU );
+
+ LED_A_ON();
+
+ // steal this pin from the SSP and use it to control the modulation
+ AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
+ AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
+
+ //initialization of the timer
+ AT91C_BASE_PMC->PMC_PCER |= (0x1 << 12) | (0x1 << 13) | (0x1 << 14);
+ AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
+ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
+ AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; //clock at 48/32 MHz
+ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
+ AT91C_BASE_TCB->TCB_BCR = 1;
+
+
+ tempo = AT91C_BASE_TC0->TC_CV;
+ for(u=0;tab[u]!= 0;u+=3){
+
+
+ // modulate antenna
+ HIGH(GPIO_SSC_DOUT);
+ while(tempo != tab[u]){
+ tempo = AT91C_BASE_TC0->TC_CV;
+ }
+
+ // stop modulating antenna
+ LOW(GPIO_SSC_DOUT);
+ while(tempo != tab[u+1]){
+ tempo = AT91C_BASE_TC0->TC_CV;
+ }
+
+
+ // modulate antenna
+ HIGH(GPIO_SSC_DOUT);
+ while(tempo != tab[u+2]){
+ tempo = AT91C_BASE_TC0->TC_CV;
+ }
+
+
+ }
+
+ LED_A_OFF();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ SpinDelay(200);
+
+
+ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
+ DbpString("FINISH !");
+ DbpString("(Could be usefull to send the same trame many times)");
+ LED(0xFFFF, 1000);
+}
+
+
+/* Add a byte for building the data frame of PCF7931 tags
+ * @param b : byte to add
+ * @param tab : array of the data frame
+ * @param l : offset on low pulse width
+ * @param p : offset on low pulse positioning
+ */
+
+bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p){
+
+ uint32_t u;
+ for (u=0; u<8; u++)
+ {
+ if (byte&(1<<u)) { //bit à 1
+ if(AddBitPCF7931(1, tab, l, p)==1)return 1;
+ } else { //bit à 0
+ if(AddBitPCF7931(0, tab, l, p)==1)return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Add a bits for building the data frame of PCF7931 tags
+ * @param b : bit to add
+ * @param tab : array of the data frame
+ * @param l : offset on low pulse width
+ * @param p : offset on low pulse positioning
+ */
+bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p){
+ uint8_t u = 0;
+
+ for(u=0;tab[u]!=0;u+=3){} //we put the cursor at the last value of the array
+
+
+ if(b==1){ //add a bit 1
+ if(u==0) tab[u] = 34*T0_PCF+p;
+ else tab[u] = 34*T0_PCF+tab[u-1]+p;
+
+ tab[u+1] = 6*T0_PCF+tab[u]+l;
+ tab[u+2] = 88*T0_PCF+tab[u+1]-l-p;
+ return 0;
+ }else{ //add a bit 0
+
+ if(u==0) tab[u] = 98*T0_PCF+p;
+ else tab[u] = 98*T0_PCF+tab[u-1]+p;
+
+ tab[u+1] = 6*T0_PCF+tab[u]+l;
+ tab[u+2] = 24*T0_PCF+tab[u+1]-l-p;
+ return 0;
+ }
+
+
+ return 1;
+}
+
+/* Add a custom pattern in the data frame
+ * @param a : delay of the first high pulse
+ * @param b : delay of the low pulse
+ * @param c : delay of the last high pulse
+ * @param tab : array of the data frame
+ */
+bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab){
+ uint32_t u = 0;
+ for(u=0;tab[u]!=0;u+=3){} //we put the cursor at the last value of the array
+
+ if(u==0) tab[u] = a;
+ else tab[u] = a + tab[u-1];
+
+ tab[u+1] = b+tab[u];
+ tab[u+2] = c+tab[u+1];
+
+ return 0;
+}
\ No newline at end of file
void printConfig()
{
- Dbprintf("Sampling config: ");
+ Dbprintf("LF Sampling config: ");
Dbprintf(" [q] divisor: %d ", config.divisor);
Dbprintf(" [b] bps: %d ", config.bits_per_sample);
Dbprintf(" [d] decimation: %d ", config.decimation);
void setSamplingConfig(sample_config *sc);
sample_config * getSamplingConfig();
+
+void printConfig();
+
+
#endif // LFSAMPLING_H
// bit 2 - need HALT after sequence\r
// bit 3 - need init FPGA and field before sequence\r
// bit 4 - need reset FPGA and LED\r
+ // bit 5 - need to set datain instead of issuing USB reply (called via ARM for StandAloneMode14a)\r
uint8_t workFlags = arg0;\r
uint8_t blockNo = arg2;\r
\r
}\r
\r
LED_B_ON();\r
- cmd_send(CMD_ACK,isOK,0,0,data,18);\r
+ if (workFlags & 0x20) {\r
+ if (isOK)\r
+ memcpy(datain, data, 18);\r
+ }\r
+ else\r
+ cmd_send(CMD_ACK,isOK,0,0,data,18);\r
LED_B_OFF();\r
\r
if ((workFlags & 0x10) || (!isOK)) {\r
//-----------------------------------------------------------------------------\r
// code for work with mifare cards.\r
//-----------------------------------------------------------------------------\r
+#include "crapto1.h"\r
\r
#ifndef __MIFAREUTIL_H\r
#define __MIFAREUTIL_H\r
void StartTickCount()
{
-// must be 0x40, but on my cpu - included divider is optimal
-// 0x20 - 1 ms / bit
-// 0x40 - 2 ms / bit
-
- AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST + 0x001D; // was 0x003B
+ // This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz.
+ // We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register.
+ uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff; // = 16 * main clock frequency (16MHz) / slow clock frequency
+ // set RealTimeCounter divider to count at 1kHz:
+ AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST | ((256000 + (mainf/2)) / mainf);
+ // note: worst case precision is approx 2.5%
}
/*
#include "usb_cmd.h"
#include "crc.h"
#include "crc16.h"
+#include "loclass/cipherutils.h"
uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];
uint8_t g_debugMode=0;
RepaintGraphWindow();
return 0;
}
-typedef struct {
- uint8_t * buffer;
- uint32_t numbits;
- uint32_t position;
-}BitstreamOut;
-bool _headBit( BitstreamOut *stream)
-{
- int bytepos = stream->position >> 3; // divide by 8
- int bitpos = (stream->position++) & 7; // mask out 00000111
- return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
-}
-
-uint8_t getByte(uint8_t bits_per_sample, BitstreamOut* b)
+uint8_t getByte(uint8_t bits_per_sample, BitstreamIn* b)
{
int i;
uint8_t val = 0;
for(i =0 ; i < bits_per_sample; i++)
{
- val |= (_headBit(b) << (7-i));
+ val |= (headBit(b) << (7-i));
}
return val;
}
if(bits_per_sample < 8)
{
PrintAndLog("Unpacking...");
- BitstreamOut bout = { got, bits_per_sample * n, 0};
+ BitstreamIn bout = { got, bits_per_sample * n, 0};
int j =0;
for (j = 0; j * bits_per_sample < n * 8 && j < n; j++) {
uint8_t sample = getByte(bits_per_sample, &bout);
return 0;
}
+int usage_data_bin2hex(){
+ PrintAndLog("Usage: data bin2hex <binary_digits>");
+ PrintAndLog(" This function will ignore all characters not 1 or 0 (but stop reading on whitespace)");
+ return 0;
+}
+
+/**
+ * @brief Utility for conversion via cmdline.
+ * @param Cmd
+ * @return
+ */
+int Cmdbin2hex(const char *Cmd)
+{
+ int bg =0, en =0;
+ if(param_getptr(Cmd, &bg, &en, 0))
+ {
+ return usage_data_bin2hex();
+ }
+ //Number of digits supplied as argument
+ size_t length = en - bg +1;
+ size_t bytelen = (length+7) / 8;
+ uint8_t* arr = (uint8_t *) malloc(bytelen);
+ memset(arr, 0, bytelen);
+ BitstreamOut bout = { arr, 0, 0 };
+
+ for(; bg <= en ;bg++)
+ {
+ char c = Cmd[bg];
+ if( c == '1') pushBit(&bout, 1);
+ else if( c == '0') pushBit(&bout, 0);
+ else PrintAndLog("Ignoring '%c'", c);
+ }
+
+ if(bout.numbits % 8 != 0)
+ {
+ printf("[padded with %d zeroes]\n", 8-(bout.numbits % 8));
+ }
+
+ //Uses printf instead of PrintAndLog since the latter
+ // adds linebreaks to each printout - this way was more convenient since we don't have to
+ // allocate a string and write to that first...
+ for(size_t x = 0; x < bytelen ; x++)
+ {
+ printf("%02X", arr[x]);
+ }
+ printf("\n");
+ free(arr);
+ return 0;
+}
+
+int usage_data_hex2bin(){
+
+ PrintAndLog("Usage: data bin2hex <binary_digits>");
+ PrintAndLog(" This function will ignore all non-hexadecimal characters (but stop reading on whitespace)");
+ return 0;
+
+}
+
+int Cmdhex2bin(const char *Cmd)
+{
+ int bg =0, en =0;
+ if(param_getptr(Cmd, &bg, &en, 0))
+ {
+ return usage_data_hex2bin();
+ }
+
+
+ while(bg <= en )
+ {
+ char x = Cmd[bg++];
+ // capitalize
+ if (x >= 'a' && x <= 'f')
+ x -= 32;
+ // convert to numeric value
+ if (x >= '0' && x <= '9')
+ x -= '0';
+ else if (x >= 'A' && x <= 'F')
+ x -= 'A' - 10;
+ else
+ continue;
+
+ //Uses printf instead of PrintAndLog since the latter
+ // adds linebreaks to each printout - this way was more convenient since we don't have to
+ // allocate a string and write to that first...
+
+ for(int i= 0 ; i < 4 ; ++i)
+ printf("%d",(x >> (3 - i)) & 1);
+ }
+ printf("\n");
+
+ return 0;
+}
+
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"askgproxiidemod", CmdG_Prox_II_Demod, 1, "Demodulate a G Prox II tag from GraphBuffer"},
{"autocorr", CmdAutoCorr, 1, "[window length] [g] -- Autocorrelation over window - g to save back to GraphBuffer (overwrite)"},
{"biphaserawdecode",CmdBiphaseDecodeRaw,1, "[offset] [invert<0|1>] [maxErr] -- Biphase decode bin stream in DemodBuffer (offset = 0|1 bits to shift the decode start)"},
+ {"bin2hex", Cmdbin2hex, 1, "bin2hex <digits> -- Converts binary to hexadecimal"},
{"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"},
{"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"},
{"dec", CmdDec, 1, "Decimate samples"},
{"getbitstream", CmdGetBitStream, 1, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"},
{"grid", CmdGrid, 1, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},
{"hexsamples", CmdHexsamples, 0, "<bytes> [<offset>] -- Dump big buffer as hex bytes"},
+ {"hex2bin", Cmdhex2bin, 1, "hex2bin <hexadecimal> -- Converts hexadecimal to binary"},
{"hide", CmdHide, 1, "Hide graph window"},
{"hpf", CmdHpf, 1, "Remove DC offset from trace"},
{"load", CmdLoad, 1, "<filename> -- Load trace (to graph window"},
case -1 : PrintAndLog("Button pressed. Aborted.\n"); break;\r
case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).\n"); break;\r
case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable).\n"); break;\r
+ case -4 : PrintAndLog("The card's random number generator is vulnerable but behaves somewhat weird (Mifare clone?). This needs to be fixed.\n"); break;\r
default: ;\r
}\r
break;\r
#include "cmdhw.h"
#include "cmdmain.h"
#include "cmddata.h"
+#include "data.h"
/* low-level hardware control */
int CmdVersion(const char *Cmd)
{
+ clearCommandBuffer();
UsbCommand c = {CMD_VERSION};
- UsbCommand resp = {0, {0, 0, 0}};
+ static UsbCommand resp = {0, {0, 0, 0}};
- SendCommand(&c);
- if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
+ if (resp.arg[0] == 0 && resp.arg[1] == 0) { // no cached information available
+ SendCommand(&c);
+ if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
+ PrintAndLog("Prox/RFID mark3 RFID instrument");
+ PrintAndLog((char*)resp.d.asBytes);
+ lookupChipID(resp.arg[0], resp.arg[1]);
+ }
+ } else {
+ PrintAndLog("[[[ Cached information ]]]\n");
PrintAndLog("Prox/RFID mark3 RFID instrument");
PrintAndLog((char*)resp.d.asBytes);
lookupChipID(resp.arg[0], resp.arg[1]);
+ PrintAndLog("");
+ }
+ return 0;
+}
+
+int CmdStatus(const char *Cmd)
+{
+ uint8_t speed_test_buffer[USB_CMD_DATA_SIZE];
+ sample_buf = speed_test_buffer;
+
+ clearCommandBuffer();
+ UsbCommand c = {CMD_STATUS};
+ SendCommand(&c);
+ if (!WaitForResponseTimeout(CMD_ACK,&c,1900)) {
+ PrintAndLog("Status command failed. USB Speed Test timed out");
}
+ return 0;
+}
+
+int CmdPing(const char *Cmd)
+{
+ clearCommandBuffer();
+ UsbCommand resp;
+ UsbCommand c = {CMD_PING};
+ SendCommand(&c);
+ if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
+ PrintAndLog("Ping successfull");
+ }else{
+ PrintAndLog("Ping failed");
+ }
return 0;
}
static command_t CommandTable[] =
{
- {"help", CmdHelp, 1, "This help"},
- {"detectreader", CmdDetectReader,0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"},
- {"fpgaoff", CmdFPGAOff, 0, "Set FPGA off"},
- {"lcd", CmdLCD, 0, "<HEX command> <count> -- Send command/data to LCD"},
- {"lcdreset", CmdLCDReset, 0, "Hardware reset LCD"},
- {"readmem", CmdReadmem, 0, "[address] -- Read memory at decimal address from flash"},
- {"reset", CmdReset, 0, "Reset the Proxmark3"},
- {"setlfdivisor", CmdSetDivisor, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"},
- {"setmux", CmdSetMux, 0, "<loraw|hiraw|lopkd|hipkd> -- Set the ADC mux to a specific value"},
- {"tune", CmdTune, 0, "Measure antenna tuning"},
- {"version", CmdVersion, 0, "Show version information about the connected Proxmark"},
- {NULL, NULL, 0, NULL}
+ {"help", CmdHelp, 1, "This help"},
+ {"detectreader", CmdDetectReader,0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"},
+ {"fpgaoff", CmdFPGAOff, 0, "Set FPGA off"},
+ {"lcd", CmdLCD, 0, "<HEX command> <count> -- Send command/data to LCD"},
+ {"lcdreset", CmdLCDReset, 0, "Hardware reset LCD"},
+ {"readmem", CmdReadmem, 0, "[address] -- Read memory at decimal address from flash"},
+ {"reset", CmdReset, 0, "Reset the Proxmark3"},
+ {"setlfdivisor", CmdSetDivisor, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"},
+ {"setmux", CmdSetMux, 0, "<loraw|hiraw|lopkd|hipkd> -- Set the ADC mux to a specific value"},
+ {"tune", CmdTune, 0, "Measure antenna tuning"},
+ {"version", CmdVersion, 0, "Show version information about the connected Proxmark"},
+ {"status", CmdStatus, 0, "Show runtime status information about the connected Proxmark"},
+ {"ping", CmdPing, 0, "Test if the pm3 is responsive"},
+ {NULL, NULL, 0, NULL}
};
int CmdHW(const char *Cmd)
//-----------------------------------------------------------------------------
// Copyright (C) 2012 Chalk <chalk.secu at gmail.com>
-//
+// 2015 Dake <thomas.cayrou at gmail.com>
+
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
static int CmdHelp(const char *Cmd);
+struct pcf7931_config configPcf = {{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},17500,{0,0}};
+
int CmdLFPCF7931Read(const char *Cmd)
{
UsbCommand c = {CMD_PCF7931_READ};
return 0;
}
+int CmdLFPCF7931Config(const char *Cmd)
+{
+ int res = 0;
+ res = sscanf(Cmd, "%02x %02x %02x %02x %02x %02x %02x %d %d %d", &configPcf.password[0], &configPcf.password[1], &configPcf.password[2], &configPcf.password[3], &configPcf.password[4], &configPcf.password[5], &configPcf.password[6], &configPcf.init_delay, &configPcf.offset[0], &configPcf.offset[1]);
+
+ if (res >= 7 || res < 1){
+ if(res == 7) configPcf.init_delay = 17500; //default value
+
+ if(res<=8){
+ configPcf.offset[0] = 0; //default value
+ configPcf.offset[1] = 0; //default value
+ }
+
+ if(res < 1){
+ PrintAndLog("Usage: <password byte 1 (in hex, lsb first)> <password byte 2 (in hex, lsb first)> [...] <password byte 7 (in hex, lsb first)> <tag initialization delay (in us)> <optional : offset on the low pulses width (in us)> <optional : offset on the low pulses position (in us)>");
+ PrintAndLog("The time offsets could be usefull to correct slew rate generated by the antenna.");
+ }
+
+ PrintAndLog("Current configuration :");
+ PrintAndLog("Password (LSB first on each byte) : %02x %02x %02x %02x %02x %02x %02x", configPcf.password[0], configPcf.password[1], configPcf.password[2], configPcf.password[3], configPcf.password[4], configPcf.password[5], configPcf.password[6]);
+ PrintAndLog("Tag initialization delay : %d us", configPcf.init_delay);
+ PrintAndLog("Offsets : %d us on the low pulses width, %d us on the low pulses positions", configPcf.offset[0], configPcf.offset[1]);
+
+ return 0;
+ }
+
+ //default values
+ configPcf.password[0] = 0xFF;
+ configPcf.password[1] = 0xFF;
+ configPcf.password[2] = 0xFF;
+ configPcf.password[3] = 0xFF;
+ configPcf.password[4] = 0xFF;
+ configPcf.password[5] = 0xFF;
+ configPcf.password[6] = 0xFF;
+
+ configPcf.init_delay = 17500;
+ configPcf.offset[0] = 0;
+ configPcf.offset[1] = 0;
+
+ PrintAndLog("Incorrect format");
+ PrintAndLog("Examples of right usage : lf pcf7931 config 11 22 33 44 55 66 77 20000");
+ PrintAndLog(" lf pcf7931 config FF FF FF FF FF FF FF 17500 -10 30");
+ return 0;
+}
+
+
+
+int CmdLFPCF7931Write(const char *Cmd)
+{
+ UsbCommand c = {CMD_PCF7931_WRITE};
+
+ int res = 0;
+ res = sscanf(Cmd, "%x %x %x", &c.arg[0], &c.arg[1], &c.arg[2]);
+
+ if(res < 1) {
+ PrintAndLog("Please specify the block address in hex");
+ return 0;
+ }
+ if (res == 1){
+ PrintAndLog("Please specify the byte address in hex");
+ return 0;
+ }
+ if(res == 2) {
+ PrintAndLog("Please specify the data in hex (1 byte)");
+ return 0;
+ }
+ if(res == 3) {
+ uint8_t n=0;
+ for(n=0;n<7;n++) c.d.asDwords[n] = configPcf.password[n];
+ c.d.asDwords[7] = (configPcf.offset[0]+128);
+ c.d.asDwords[8] = (configPcf.offset[1]+128);
+ c.d.asDwords[9] = configPcf.init_delay;
+ SendCommand(&c);
+ return 0;
+ }
+
+ PrintAndLog("INCORRECT FORMAT");
+ return 0;
+}
+
+
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"read", CmdLFPCF7931Read, 1, "Read content of a PCF7931 transponder"},
+ {"write", CmdLFPCF7931Write, 1, "Write data on a PCF7931 transponder. Usage : lf pcf7931 write <bloc address> <byte address> <data>"},
+ {"config", CmdLFPCF7931Config, 1, "Configure the password, the tags initialization delay and time offsets (optional)"},
{NULL, NULL, 0, NULL}
};
//-----------------------------------------------------------------------------
// Copyright (C) 2012 Chalk <chalk.secu at gmail.com>
-//
+// 2015 Dake <thomas.cayrou at gmail.com>
+
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
#ifndef CMDLFPCF7931_H__
#define CMDLFPCF7931_H__
+struct pcf7931_config{
+ uint8_t password[7];
+ uint16_t init_delay;
+ int16_t offset[2];
+};
+
int CmdLFPCF7931(const char *Cmd);
int CmdLFPCF7931Read(const char *Cmd);
+int CmdLFPCF7931Write(const char *Cmd);
+
+int CmdLFPCF7931Config(const char *Cmd);
+
#endif
memcpy(destination, command, sizeof(UsbCommand));
cmd_head = (cmd_head +1) % CMD_BUFFER_SIZE; //increment head and wrap
-
}
+
+
/**
* @brief getCommand gets a command from an internal circular buffer.
* @param response location to write command
cmd_tail = (cmd_tail +1 ) % CMD_BUFFER_SIZE;
return 1;
-
}
+
/**
* Waits for a certain response type. This method waits for a maximum of
* ms_timeout milliseconds for a specified response command.
*/
bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) {
- UsbCommand resp;
+ UsbCommand resp;
- if (response == NULL)
- response = &resp;
-
-
- // Wait until the command is received
- for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) {
+ if (response == NULL) {
+ response = &resp;
+ }
+ // Wait until the command is received
+ for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) {
while(getCommand(response)) {
- if(response->cmd == cmd){
- return true;
- }
- }
- msleep(10); // XXX ugh
- if (dm_seconds == 200) { // Two seconds elapsed
- PrintAndLog("Waiting for a response from the proxmark...");
- PrintAndLog("Don't forget to cancel its operation first by pressing on the button");
- }
+ if(response->cmd == cmd){
+ return true;
+ }
+ }
+ msleep(10); // XXX ugh
+ if (dm_seconds == 200) { // Two seconds elapsed
+ PrintAndLog("Waiting for a response from the proxmark...");
+ PrintAndLog("Don't forget to cancel its operation first by pressing on the button");
+ }
}
- return false;
+ return false;
}
+
bool WaitForResponse(uint32_t cmd, UsbCommand* response) {
return WaitForResponseTimeout(cmd,response,-1);
}
+
//-----------------------------------------------------------------------------
// Entry point into our code: called whenever the user types a command and
// then presses Enter, which the full command line that they typed.
CmdsParse(CommandTable, Cmd);
}
+
//-----------------------------------------------------------------------------
// Entry point into our code: called whenever we received a packet over USB
// that we weren't necessarily expecting, for example a debug print.
case CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K: {
memcpy(sample_buf+(UC->arg[0]),UC->d.asBytes,UC->arg[1]);
+ return;
} break;
default:
+ storeCommand(UC);
break;
}
- storeCommand(UC);
}
CMD_BUFF_CLEAR = 0x0105,
CMD_READ_MEM = 0x0106,
CMD_VERSION = 0x0107,
-
+ CMD_STATUS = 0x0108,
+ CMD_PING = 0x0109,
--// For low-frequency tags
CMD_READ_TI_TYPE = 0x0202,
CMD_WRITE_TI_TYPE = 0x0203,
return nil, "Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys."
elseif isOK == 0xFFFFFFFD then
return nil, "Card is not vulnerable to Darkside attack (its random number generator is not predictable). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys."
+ elseif isOK == 0xFFFFFFFC then
+ return nil, "The card's random number generator is vulnerable but behaves somewhat weird (Mifare clone?). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys."
elseif isOK ~= 1 then
return nil, "Error occurred"
end
uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
char param_getchar(const char *line, int paramnum);
+int param_getptr(const char *line, int *bg, int *en, int paramnum);
uint8_t param_get8(const char *line, int paramnum);
uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base);
uint32_t param_get32ex(const char *line, int paramnum, int deflt, int base);
#define CMD_BUFF_CLEAR 0x0105
#define CMD_READ_MEM 0x0106
#define CMD_VERSION 0x0107
+#define CMD_STATUS 0x0108
+#define CMD_PING 0x0109
// For low-frequency tags
#define CMD_READ_TI_TYPE 0x0202
#define CMD_T55XX_WRITE_BLOCK 0x0215
#define CMD_T55XX_READ_TRACE 0x0216
#define CMD_PCF7931_READ 0x0217
+#define CMD_PCF7931_WRITE 0x0222
#define CMD_EM4X_READ_WORD 0x0218
#define CMD_EM4X_WRITE_WORD 0x0219
#define CMD_IO_DEMOD_FSK 0x021A
#define CMD_PSK_SIM_TAG 0x0220
#define CMD_AWID_DEMOD_FSK 0x0221
+
/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */
// For the 13.56 MHz tags