diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 56bf67e0..41993089 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -398,7 +398,7 @@ void SendStatus(void) { LED_A_OFF(); } -#if defined(WITH_ISO14443a_StandAlone) || defined(WITH_LF_StandAlone) +#if defined(WITH_ISO14443a_StandAlone) || defined(WITH_ISO15693_StandAlone) || defined(WITH_LF_StandAlone) #define OPTS 2 @@ -778,6 +778,106 @@ void SamyRun() { } } +#elif WITH_ISO15693_StandAlone + +void StandAloneMode15() { + StandAloneMode(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + int mode = 0; + bool done = false; + const char *modes[] = { "Set password", "Reveal tag", "Lock password", "Stresstest", "Bruteforce", "Quit standalone" }; + + Dbprintf("Starting standalone mode: Menu"); + LED(0x0F, 0); + + /* wait for button being released before preoceeding evaluation */ + while(BUTTON_PRESS()) { + WDT_HIT(); + } + + while(!done) { + if(usb_poll_validate_length()) { + done = true; + continue; + } + + SpinDelay(50); + usb_poll(); + WDT_HIT(); + + LEDsoff(); + switch(mode) { + case 0: + LED_A_ON(); + break; + case 1: + LED_B_ON(); + break; + case 2: + LED_C_ON(); + break; + case 3: + LED_D_ON(); + break; + case 4: + LED_D_ON(); + LED_A_ON(); + break; + case 5: + LED_A_ON(); + LED_B_ON(); + LED_C_ON(); + LED_D_ON(); + break; + } + + switch(BUTTON_HELD(1000)) { + case BUTTON_SINGLE_CLICK: + mode++; + mode %= 6; + Dbprintf(" Menu #%d: %s", mode, modes[mode]); + break; + case BUTTON_HOLD: + Dbprintf(" Execute #%d", mode); + LEDsoff(); + while(BUTTON_PRESS()) { + WDT_HIT(); + } + + switch(mode) { + case 0: + ChangePassSlixLIso15693(4, 0, 0x7FFD6E5B); + break; + case 1: + DisablePrivacySlixLIso15693(0x7FFD6E5B); + DisablePrivacySlixLIso15693(0x0F0F0F0F); + break; + case 2: + LockPassSlixLIso15693(4, 0x7FFD6E5B); + break; + case 3: + StressSlixLIso15693(0x0F0F0F0F, 7); + break; + case 4: + BruteforceIso15693(0x40, 0xFF); + break; + case 5: + done = true; + break; + } + LEDsoff(); + while(BUTTON_PRESS()) { + WDT_HIT(); + } + break; + default: + SpinDelay(50); + continue; + } + } +} + #endif /* @@ -1095,6 +1195,10 @@ void UsbPacketReceived(UsbCommand *c) { DirectTag15693Command(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes); break; + case CMD_ISO_15693_SLIX_L_DISABLE_PRIVACY: + DisablePrivacySlixLIso15693(c->arg[0]); + break; + case CMD_ISO_15693_FIND_AFI: BruteforceIso15693Afi(c->arg[0]); break; @@ -1494,6 +1598,10 @@ void __attribute__((noreturn)) AppMain(void) { #if defined(WITH_ISO14443a) && defined(WITH_ISO14443a_StandAlone) if (BUTTON_HELD(1000) > 0) StandAloneMode14a(); +#endif +#if defined(WITH_ISO15693) && defined(WITH_ISO15693_StandAlone) + if (BUTTON_HELD(1000) > 0) + StandAloneMode15(); #endif } } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index f16698bb..bf2bedb6 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -61,6 +61,7 @@ #include "usb_cdc.h" #include "BigBuf.h" #include "fpgaloader.h" +#include "printf.h" #define arraylen(x) (sizeof(x)/sizeof((x)[0])) @@ -1093,6 +1094,12 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo break; } + /* cancel receive operation when there is USB activity */ + if (usb_poll_validate_length()) { + DecodeReader.byteCount = -2; + break; + } + if (BUTTON_PRESS()) { DecodeReader.byteCount = -1; break; @@ -1632,6 +1639,735 @@ void ReaderIso15693(uint32_t parameter) { LED_A_OFF(); } +#define SLIX_ERR_OK 0 +#define SLIX_ERR_NORESP 1 +#define SLIX_ERR_INVPASS 2 + +void SetupPasswordSlixLIso15693(uint8_t *buffer, uint32_t password, uint8_t *rnd) { + buffer[0] = (password>>0) & 0xFF; + buffer[1] = (password>>8) & 0xFF; + buffer[2] = (password>>16) & 0xFF; + buffer[3] = (password>>24) & 0xFF; + + if(rnd) { + buffer[0] ^= rnd[0]; + buffer[1] ^= rnd[1]; + buffer[2] ^= rnd[0]; + buffer[3] ^= rnd[1]; + } +} + +bool GetRandomSlixLIso15693(uint32_t start_time, uint32_t *eof_time, uint8_t *rnd) { + uint8_t cmd_get_rnd[] = {ISO15693_REQ_DATARATE_HIGH, ISO15693_CMD_NXP_GET_RANDOM_NUMBER, ISO15693_MANUFACTURER_NXP, 0x00, 0x00 }; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + + Iso15693AddCrc(cmd_get_rnd, 3); + + recvlen = SendDataTag(cmd_get_rnd, sizeof(cmd_get_rnd), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); + if (recvlen != 5) { + return false; + } + + if(rnd) { + memcpy(rnd, &recvbuf[1], 2); + } + return true; +} + +uint32_t SetPassSlixLIso15693(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, uint32_t password) { + uint8_t cmd_set_pass[] = {ISO15693_REQ_DATARATE_HIGH, ISO15693_CMD_NXP_SET_PASSWORD, ISO15693_MANUFACTURER_NXP, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + + uint8_t rnd[2]; + if (!GetRandomSlixLIso15693(start_time, eof_time, rnd)) { + return SLIX_ERR_NORESP; + } + + cmd_set_pass[3] = pass_id; + SetupPasswordSlixLIso15693(&cmd_set_pass[4], password, rnd); + Iso15693AddCrc(cmd_set_pass, 8); + + start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + recvlen = SendDataTag(cmd_set_pass, sizeof(cmd_set_pass), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); + if (recvlen != 3) { + return SLIX_ERR_INVPASS; + } + + return SLIX_ERR_OK; +} + +bool GetInventoryIso15693(uint32_t start_time, uint32_t *eof_time, uint8_t *uid) { + uint8_t cmd_inventory[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1, 0x01, 0x00, 0x00, 0x00 }; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + + Iso15693AddCrc(cmd_inventory, 3); + + recvlen = SendDataTag(cmd_inventory, sizeof(cmd_inventory), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); + if (recvlen != 12) { + return false; + } + + memcpy(uid, &recvbuf[2], 8); + return true; +} + +uint32_t EnablePrivacySlixLIso15693(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint32_t password) { + uint8_t cmd_enable_priv[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, ISO15693_CMD_NXP_ENABLE_PRIVACY, ISO15693_MANUFACTURER_NXP, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + + uint8_t rnd[2]; + if (!GetRandomSlixLIso15693(start_time, eof_time, rnd)) { + return SLIX_ERR_NORESP; + } + + memcpy(&cmd_enable_priv[3], uid, 8); + SetupPasswordSlixLIso15693(&cmd_enable_priv[11], password, rnd); + + Iso15693AddCrc(cmd_enable_priv, 15); + + start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + recvlen = SendDataTag(cmd_enable_priv, sizeof(cmd_enable_priv), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); + if (recvlen != 3) { + return SLIX_ERR_INVPASS; + } + + return SLIX_ERR_OK; +} + +uint32_t DestroySlixLIso15693(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint32_t password) { + uint8_t cmd_enable_priv[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, ISO15693_CMD_NXP_DESTROY, ISO15693_CMD_NXP_ENABLE_PRIVACY, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + + uint8_t rnd[2]; + if (!GetRandomSlixLIso15693(start_time, eof_time, rnd)) { + return SLIX_ERR_NORESP; + } + + memcpy(&cmd_enable_priv[3], uid, 8); + SetupPasswordSlixLIso15693(&cmd_enable_priv[11], password, rnd); + + Iso15693AddCrc(cmd_enable_priv, 15); + + start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + recvlen = SendDataTag(cmd_enable_priv, sizeof(cmd_enable_priv), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); + if (recvlen != 3) { + return SLIX_ERR_INVPASS; + } + + return SLIX_ERR_OK; +} + +uint32_t WritePassSlixLIso15693(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t pass_id, uint32_t password) { + uint8_t cmd_write_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, ISO15693_CMD_NXP_WRITE_PASSWORD, ISO15693_MANUFACTURER_NXP, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + + uint8_t rnd[2]; + if (!GetRandomSlixLIso15693(start_time, eof_time, rnd)) { + return SLIX_ERR_NORESP; + } + + memcpy(&cmd_write_pass[3], uid, 8); + cmd_write_pass[11] = pass_id; + SetupPasswordSlixLIso15693(&cmd_write_pass[12], password, NULL); + + Iso15693AddCrc(cmd_write_pass, 16); + + start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + recvlen = SendDataTag(cmd_write_pass, sizeof(cmd_write_pass), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); + if (recvlen != 3) { + return SLIX_ERR_INVPASS; + } + + return SLIX_ERR_OK; +} + +int WriteMemoryIso15693(uint32_t start_time, uint32_t *eof_time, uint8_t bank, uint8_t *data) { + uint8_t cmd_write_mem[] = {ISO15693_REQ_DATARATE_HIGH , ISO15693_WRITEBLOCK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + + memcpy(&cmd_write_mem[3], data, 4); + cmd_write_mem[2] = bank; + Iso15693AddCrc(cmd_write_mem, 7); + + recvlen = SendDataTag(cmd_write_mem, sizeof(cmd_write_mem), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); + if (recvlen != 3) { + return SLIX_ERR_NORESP; + } + + return SLIX_ERR_OK; +} + +int ReadMemoryIso15693(uint32_t start_time, uint32_t *eof_time, uint8_t bank, uint8_t *data) { + uint8_t cmd_read_mem[] = {ISO15693_REQ_DATARATE_HIGH, ISO15693_READBLOCK, 0x00, 0x00, 0x00 }; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + + cmd_read_mem[2] = bank; + Iso15693AddCrc(cmd_read_mem, 3); + + recvlen = SendDataTag(cmd_read_mem, sizeof(cmd_read_mem), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); + if (recvlen != 7) { + return SLIX_ERR_NORESP; + } + memcpy(data, &recvbuf[1], 4); + + return SLIX_ERR_OK; +} + +void DisablePrivacySlixLIso15693(uint32_t password) { + uint32_t start_time = 0; + uint32_t eof_time = 0; + + Dbprintf(" [x] Set password"); + + LED_D_ON(); + Iso15693InitReader(); + StartCountSspClk(); + + switch(SetPassSlixLIso15693(start_time, &eof_time, 4, password)) { + case SLIX_ERR_NORESP: + Dbprintf(" [i] No tag found"); + cmd_send(CMD_NACK, 0, 0, 0, NULL, 0); + LED_C_ON(); + return; + + case SLIX_ERR_INVPASS: + Dbprintf(" [E] Password was not accepted"); + cmd_send(CMD_NACK, 1, 0, 0, NULL, 0); + LED_B_ON(); + return; + } + Dbprintf(" [x] Success"); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + cmd_send(CMD_ACK,1,0,0,0,0); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); +} + +#if defined(WITH_ISO15693_StandAlone) + +void ChangePassSlixLIso15693(uint32_t pass_id, uint32_t old_password, uint32_t password) { + uint8_t uid[8]; + bool done = false; + uint32_t start_time = 0; + uint32_t eof_time = 0; + + Iso15693InitReader(); + StartCountSspClk(); + + Dbprintf("ChangePass: Press button set password, long-press to terminate."); + + while (!done) { + LED_D_ON(); + switch(BUTTON_HELD(1000)) { + case BUTTON_SINGLE_CLICK: + Dbprintf("ChangePass: Execute"); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + break; + case BUTTON_HOLD: + Dbprintf("ChangePass: Terminating"); + done = true; + continue; + default: + SpinDelay(50); + continue; + } + + if(usb_poll_validate_length()) { + done = true; + continue; + } + + /* check if a tag is available */ + if(!GetRandomSlixLIso15693(start_time, &eof_time, NULL)) { + Dbprintf(" [E] No tag detected"); + SpinDelay(50); + continue; + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + /* make set password which should reveal the tag if in privacy */ + Dbprintf(" [x] Set password"); + switch(SetPassSlixLIso15693(start_time, &eof_time, 4, old_password)) { + case SLIX_ERR_NORESP: + Dbprintf(" [E] Tag disappeared"); + LED_C_ON(); + continue; + + case SLIX_ERR_INVPASS: + Dbprintf(" [E] Password was not accepted"); + LED_B_ON(); + continue; + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + /* for writing password we will have to address directly */ + Dbprintf(" [x] Get tag UID"); + if(GetInventoryIso15693(start_time, &eof_time, uid)) { + Dbprintf(" [i] Tag %02X%02X%02X%02X%02X%02X%02X%02X is responding.", uid[7], uid[6], uid[5], uid[4], uid[3], uid[2], uid[1], uid[0]); + } else { + Dbprintf(" [E] Tag did not appear. Invalid password?"); + LED_B_ON(); + continue; + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + /* now its time to write the new password */ + Dbprintf(" [x] Write password"); + switch(WritePassSlixLIso15693(start_time, &eof_time, uid, 4, password)) { + case SLIX_ERR_NORESP: + Dbprintf(" [E] Tag disappeared"); + LED_C_ON(); + continue; + + case SLIX_ERR_INVPASS: + Dbprintf(" [E] Password was not accepted"); + LED_B_ON(); + continue; + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + Dbprintf(" [x] Success"); + } + + Dbprintf("ChangePass: Finishing"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + cmd_send(CMD_ACK,1,0,0,0,0); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); +} + +#define STRESS_TEST_PRIVACY 1 +#define STRESS_TEST_WRITE 2 +#define STRESS_TEST_READ 4 + +void StressSlixLIso15693(uint32_t password, uint32_t flags) { + uint32_t loops = 0; + bool done = false; + uint8_t uid[8]; + uint32_t start_time = 0; + uint32_t eof_time = 0; + + Dbprintf("Stress SLIX-L: Stressing tag. Password 0x%08X", password); + Dbprintf("Stress SLIX-L: Press button to terminate."); + + LED_D_ON(); + Iso15693InitReader(); + StartCountSspClk(); + + while (!done) { + LED_D_ON(); + WDT_HIT(); + + switch(BUTTON_HELD(1000)) { + case BUTTON_HOLD: + Dbprintf("Stress SLIX-L: Terminating"); + done = true; + continue; + default: + break; + } + + if(usb_poll_validate_length()) { + done = true; + continue; + } + + if(!GetRandomSlixLIso15693(start_time, &eof_time, NULL)) { + SpinDelay(50); + continue; + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + if(GetInventoryIso15693(start_time, &eof_time, uid)) { + Dbprintf(" [i] Tag %02X%02X%02X%02X%02X%02X%02X%02X was responding when started", uid[7], uid[6], uid[5], uid[4], uid[3], uid[2], uid[1], uid[0]); + } else { + Dbprintf(" [i] Tag was in privacy mode when started"); + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + loops = 0; + bool term = false; + while(!term) { + + if (BUTTON_PRESS()) { + Dbprintf(" [i] Terminating"); + term = true; + continue; + } + + Dbprintf("Loop #%d", ++loops); + + if(flags & STRESS_TEST_PRIVACY) { + Dbprintf(" [x] Set password"); + + switch(SetPassSlixLIso15693(start_time, &eof_time, 4, password)) { + case SLIX_ERR_NORESP: + Dbprintf(" [i] No tag found"); + LED_C_ON(); + term = true; + continue; + + case SLIX_ERR_INVPASS: + Dbprintf(" [E] Password was not accepted"); + LED_B_ON(); + term = true; + continue; + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + Dbprintf(" [x] Scan for tag"); + if(GetInventoryIso15693(start_time, &eof_time, uid)) { + Dbprintf(" [i] Tag %02X%02X%02X%02X%02X%02X%02X%02X is responding.", uid[7], uid[6], uid[5], uid[4], uid[3], uid[2], uid[1], uid[0]); + } else { + Dbprintf(" [E] Tag did not appear. Invalid password?"); + LED_B_ON(); + term = true; + continue; + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + } + + if(flags & STRESS_TEST_WRITE) { + Dbprintf(" [x] Write memory"); + switch(WriteMemoryIso15693(start_time, &eof_time, 0, (uint8_t *)&loops)) { + case SLIX_ERR_NORESP: + Dbprintf(" [E] Tag not found anymore"); + LED_B_ON(); + term = true; + continue; + + case SLIX_ERR_OK: + break; + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + } + + if(flags & STRESS_TEST_READ) { + uint32_t read_value = 0; + + Dbprintf(" [x] Read memory"); + switch(ReadMemoryIso15693(start_time, &eof_time, 0, (uint8_t *)&read_value)) { + case SLIX_ERR_NORESP: + Dbprintf(" [E] Tag not found anymore"); + LED_B_ON(); + term = true; + continue; + + case SLIX_ERR_OK: + Dbprintf(" [i] Read 0x%04X", read_value); + break; + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + } + + if(flags & STRESS_TEST_PRIVACY) { + Dbprintf(" [x] Set privacy mode"); + switch(EnablePrivacySlixLIso15693(start_time, &eof_time, uid, password)) { + case SLIX_ERR_NORESP: + Dbprintf(" [E] Tag not found anymore"); + LED_B_ON(); + term = true; + continue; + + case SLIX_ERR_INVPASS: + Dbprintf(" [E] Password was not accepted"); + LED_B_ON(); + term = true; + continue; + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + Dbprintf(" [x] Scan for tag again"); + if(GetInventoryIso15693(start_time, &eof_time, uid)) { + Dbprintf(" [E] Tag %02X%02X%02X%02X%02X%02X%02X%02X is responding. Unexpected. Should have been silent.", uid[7], uid[6], uid[5], uid[4], uid[3], uid[2], uid[1], uid[0]); + LED_B_ON(); + term = true; + continue; + } else { + Dbprintf(" [i] Tag not found anymore"); + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + } + + Dbprintf(" [x] Success"); + WDT_HIT(); + } + + /* wait for tag being removed */ + Dbprintf(" [i] Wait for tag being removed"); + while(GetRandomSlixLIso15693(start_time, &eof_time, NULL) && !BUTTON_PRESS()) { + SpinDelay(50); + WDT_HIT(); + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + } + + Dbprintf("Stress SLIX-L: Finishing"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + cmd_send(CMD_ACK,1,0,0,0,0); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); +} + +void LockPassSlixLIso15693(uint32_t pass_id, uint32_t password) { + uint8_t cmd_inventory[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1, 0x01, 0x00, 0x00, 0x00 }; + uint8_t cmd_get_rnd[] = {ISO15693_REQ_DATARATE_HIGH, 0xB2, 0x04, 0x00, 0x00 }; + uint8_t cmd_set_pass[] = {ISO15693_REQ_DATARATE_HIGH, 0xB3, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + //uint8_t cmd_write_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t cmd_lock_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00 }; + uint16_t crc; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + uint32_t start_time = 0; + uint32_t eof_time = 0; + bool done = false; + + Iso15693InitReader(); + StartCountSspClk(); + + /* setup 'get random number' command */ + crc = Iso15693Crc(cmd_get_rnd, 3); + cmd_get_rnd[3] = crc & 0xff; + cmd_get_rnd[4] = crc >> 8; + + Dbprintf("LockPass: Press button lock password, long-press to terminate."); + + while (!done) { + LED_D_ON(); + switch(BUTTON_HELD(1000)) { + case BUTTON_SINGLE_CLICK: + Dbprintf("LockPass: Reset 'DONE'-LED (A)"); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + break; + case BUTTON_HOLD: + Dbprintf("LockPass: Terminating"); + done = true; + continue; + default: + SpinDelay(50); + continue; + } + + if(usb_poll_validate_length()) { + done = true; + continue; + } + + recvlen = SendDataTag(cmd_get_rnd, sizeof(cmd_get_rnd), true, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, &eof_time); + if (recvlen != 5) { + LED_C_ON(); + } else { + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + Dbprintf("LockPass: Received random 0x%02X%02X (%d)", recvbuf[1], recvbuf[2], recvlen); + + /* setup 'set password' command */ + cmd_set_pass[4] = ((password>>0) &0xFF) ^ recvbuf[1]; + cmd_set_pass[5] = ((password>>8) &0xFF) ^ recvbuf[2]; + cmd_set_pass[6] = ((password>>16) &0xFF) ^ recvbuf[1]; + cmd_set_pass[7] = ((password>>24) &0xFF) ^ recvbuf[2]; + + crc = Iso15693Crc(cmd_set_pass, 8); + cmd_set_pass[8] = crc & 0xff; + cmd_set_pass[9] = crc >> 8; + + Dbprintf("LockPass: Sending old password to end privacy mode"); + recvlen = SendDataTag(cmd_set_pass, sizeof(cmd_set_pass), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, &eof_time); + if (recvlen != 3) { + Dbprintf("LockPass: Failed to set password (%d)", recvlen); + LED_B_ON(); + } else { + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + crc = Iso15693Crc(cmd_inventory, 3); + cmd_inventory[3] = crc & 0xff; + cmd_inventory[4] = crc >> 8; + + Dbprintf("LockPass: Searching for tag..."); + recvlen = SendDataTag(cmd_inventory, sizeof(cmd_inventory), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, &eof_time); + if (recvlen != 12) { + Dbprintf("LockPass: Failed to read inventory (%d)", recvlen); + LED_B_ON(); + LED_C_ON(); + } else { + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + Dbprintf("LockPass: Answer from %02X%02X%02X%02X%02X%02X%02X%02X", recvbuf[9], recvbuf[8], recvbuf[7], recvbuf[6], recvbuf[5], recvbuf[4], recvbuf[3], recvbuf[2]); + + memcpy(&cmd_lock_pass[3], &recvbuf[2], 8); + + cmd_lock_pass[8+3] = pass_id; + + crc = Iso15693Crc(cmd_lock_pass, 8+4); + cmd_lock_pass[8+4] = crc & 0xff; + cmd_lock_pass[8+5] = crc >> 8; + + Dbprintf("LockPass: locking to password 0x%02X%02X%02X%02X for ID %02X", cmd_set_pass[4], cmd_set_pass[5], cmd_set_pass[6], cmd_set_pass[7], pass_id); + + recvlen = SendDataTag(cmd_lock_pass, sizeof(cmd_lock_pass), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, &eof_time); + if (recvlen != 3) { + Dbprintf("LockPass: Failed to lock password (%d)", recvlen); + } else { + Dbprintf("LockPass: Successful (%d)", recvlen); + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + LED_A_ON(); + } + } + } + } + + Dbprintf("LockPass: Finishing"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + cmd_send(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); +} + + +void BruteforceIso15693(uint32_t start_cmd, uint32_t end_cmd) { + uint8_t cmd_buffer[64]; + uint8_t max_payload = 8; /* make sure buffer is big enough */ + uint8_t uid[8]; + int recvlen = 0; + uint32_t start_time = 0; + uint32_t eof_time = 0; + bool done = false; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + + Dbprintf(" [x] Starting brute force"); + Dbprintf(" [x] Start 0x%02X", start_cmd); + Dbprintf(" [x] End 0x%02X", end_cmd); + + LED_D_ON(); + Iso15693InitReader(); + StartCountSspClk(); + + if(GetInventoryIso15693(start_time, &eof_time, uid)) { + Dbprintf(" [i] Tag %02X%02X%02X%02X%02X%02X%02X%02X found", uid[7], uid[6], uid[5], uid[4], uid[3], uid[2], uid[1], uid[0]); + } else { + Dbprintf(" [E] Tag was in privacy mode. Exiting."); + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + for(uint16_t current_cmd = start_cmd; current_cmd <= end_cmd; current_cmd++) { + Dbprintf(" [x] Test command 0x%02X", current_cmd); + + if( current_cmd == ISO15693_LOCKBLOCK || + current_cmd == ISO15693_LOCK_AFI || + current_cmd == ISO15693_LOCK_DSFID || + current_cmd == ISO15693_CMD_NXP_LOCK_EAS || + current_cmd == ISO15693_CMD_NXP_PASSWORD_PROTECT_EAS_AFI || + current_cmd == ISO15693_CMD_NXP_SET_PASSWORD || + current_cmd == ISO15693_CMD_NXP_DESTROY || + current_cmd == ISO15693_CMD_NXP_SET_PASSWORD ) { + + Dbprintf(" [i] Skipping command, it is known to lock stuff"); + continue; + } + + for(int payload = 0; payload < max_payload; payload++) { + if(done) { + break; + } + /* also probe for an extra magic byte as e.g. SLIX tags use */ + for(uint16_t magic = 0; magic <= 0x100; magic++) { + int extra = (magic < 0x100) ? 1 : 0; + + if (BUTTON_PRESS() || usb_poll_validate_length()) { + Dbprintf(" [i] Terminating"); + done = true; + break; + } + + if(!GetInventoryIso15693(start_time, &eof_time, uid)) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); + SpinDelay(50); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + if(!GetInventoryIso15693(start_time, &eof_time, uid)) { + Dbprintf(" [E] Tag doesnt respond anymore. Terminating."); + done = true; + break; + } + } + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + /* build command buffer */ + memset(cmd_buffer, 0x00, sizeof(cmd_buffer)); + cmd_buffer[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS; + cmd_buffer[1] = current_cmd; + if(extra) { + cmd_buffer[2] = magic; + } + memcpy(&cmd_buffer[2 + extra], uid, 8); + memset(&cmd_buffer[10 + extra], 0x00, payload); + Iso15693AddCrc(cmd_buffer, 10 + extra + payload); + + int cmd_len = 10 + extra + payload + 2; + + recvlen = SendDataTag(cmd_buffer, cmd_len, false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, &eof_time); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + if (recvlen > 0) { + if(recvlen != 4 || !(recvbuf[0] == ISO15693_ERROR_CMD_NOT_SUP && recvbuf[1] == 0x0F)) { + uint8_t buf[16*3 + 1]; + + Dbprintf(" - success with %d byte payload (%d byte answer)", payload, recvlen); + + DbpString("request"); + buf[0] = 0; + for(int pos = 0; pos < cmd_len; pos++) { + sprintf((char *)&buf[3*pos], "%02X ", cmd_buffer[pos]); + } + DbpString((char *)buf); + + DbpString("response"); + buf[0] = 0; + for(int pos = 0; pos < recvlen; pos++) { + sprintf((char *)&buf[3*pos], "%02X ", recvbuf[pos]); + } + DbpString((char *)buf); + } + } + } + } + + if(done) { + break; + } + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + cmd_send(CMD_ACK,1,0,0,0,0); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); +} +#endif // Initialize the proxmark as iso15k tag void Iso15693InitTag(void) { @@ -1643,38 +2379,334 @@ void Iso15693InitTag(void) { StartCountSspClk(); } +bool RevUidMatch(uint8_t *uid, uint8_t *pkt) { + for(int pos = 0; pos < 8; pos++) { + if(uid[pos] != pkt[7-pos]) { + return false; + } + } + return true; +} // Simulate an ISO15693 TAG. // For Inventory command: print command and send Inventory Response with given UID // TODO: interpret other reader commands and send appropriate response void SimTagIso15693(uint32_t parameter, uint8_t *uid) { + bool private = true; + bool done = false; + bool debug = false; + bool passive = false; + uint32_t privacy_pass = 0x0F0F0F0F; + for(int pos = 0; pos < 8; pos++) + { + if(uid[pos] != 0) + { + break; + } + if(pos == 7) + { + passive = true; + privacy_pass = 0xDEADBEEF; + } + } + LEDsoff(); LED_A_ON(); Iso15693InitTag(); - // Build a suitable response to the reader INVENTORY command - BuildInventoryResponse(uid); + uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; + uint8_t memory[32]; + + memcpy(memory, &uid[8], 32); + + Dbprintf("SimTag: Simulating a tag. Press button one second to terminate."); // Listen to reader - while (!BUTTON_PRESS()) { - uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; + while (!done) { + switch(BUTTON_HELD(1000)) { + case BUTTON_NO_CLICK: + break; + case BUTTON_SINGLE_CLICK: + Dbprintf("SimTag: Reset 'DONE'-LED (D)"); + LED_D_OFF(); + break; + case BUTTON_HOLD: + Dbprintf("SimTag: Terminating"); + done = true; + continue; + } + uint32_t eof_time = 0, start_time = 0; int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &eof_time); - if ((cmd_len >= 5) && (cmd[0] & ISO15693_REQ_INVENTORY) && (cmd[1] == ISO15693_INVENTORY)) { // TODO: check more flags - bool slow = !(cmd[0] & ISO15693_REQ_DATARATE_HIGH); - start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; - TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + switch(cmd_len) { + case -1: + /* button pressed */ + continue; + case -2: + /* USB activity */ + Dbprintf("SimTag: Terminating due to USB activity"); + done = true; + continue; + default: + /* data received */ + break; } - Dbprintf("%d bytes read from reader:", cmd_len); - Dbhexdump(cmd_len, cmd, false); + uint8_t flags = cmd[0]; + uint8_t command = cmd[1]; + bool slow = !(flags & ISO15693_REQ_DATARATE_HIGH); + bool addressed = !(flags & ISO15693_REQ_INVENTORY) && (flags & ISO15693_REQ_ADDRESS); + /* when commands above 0xA0 are sent, its most likely a manufacturer code. for SLIX-L it contains an extra byte 0x04 right after the command */ + bool advanced = addressed && (command >= 0xA0); + uint8_t *address = &cmd[2 + (advanced?1:0)]; + + start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; + + if(addressed && !RevUidMatch(address, uid)) { + Dbprintf("(addressed packet, but not for us)"); + continue; + } + + if(debug || passive) { + Dbprintf("%d bytes read from reader:", cmd_len); + Dbhexdump(cmd_len, cmd, false); + } + + switch(command) { + case ISO15693_GET_SYSTEM_INFO: { + if(!private) { + Dbprintf("ISO15693_GET_SYSTEM_INFO"); + uint8_t resp[17]; + uint16_t crc; + + resp[0] = ISO15693_NOERROR; + resp[1] = 0x0F; + memcpy(&resp[2], uid, 8); + resp[10] = 0x00; /* DSFID */ + resp[11] = 0x00; /* AFI */ + resp[12] = 0x07; /* number of blocks */ + resp[13] = 0x03; /* block size */ + resp[14] = 0x03; /* IC reference */ + + crc = Iso15693Crc(resp, 15); + resp[15] = crc & 0xff; + resp[16] = crc >> 8; + + CodeIso15693AsTag(resp, sizeof(resp)); + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + break; + } else { + Dbprintf("ISO15693_GET_SYSTEM_INFO (won't answer, privacy mode)"); + } + break; + } + + case ISO15693_INVENTORY: { + if(!private) { + Dbprintf("INVENTORY"); + BuildInventoryResponse(uid); + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + } else { + Dbprintf("INVENTORY (won't answer, privacy mode)"); + } + break; + } + + case ISO15693_READBLOCK: { + uint8_t resp[7]; + uint16_t crc; + uint8_t block = cmd[2 + (addressed ? 8 : 0)]; + + if(!private) { + if(block < 8) + { + Dbprintf("READBLOCK %d", block); + + resp[0] = ISO15693_NOERROR; + memcpy(&resp[1], &memory[4 * (block%8)], 4); + + crc = Iso15693Crc(resp, 5); + resp[5] = crc & 0xff; + resp[6] = crc >> 8; + + CodeIso15693AsTag(resp, sizeof(resp)); + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + } else { + Dbprintf("READBLOCK %d (error, beyond size)", block); + + resp[0] = ISO15693_RES_ERROR; + resp[1] = ISO15693_ERROR_GENERIC; + crc = Iso15693Crc(resp, 2); + resp[2] = crc & 0xff; + resp[3] = crc >> 8; + + CodeIso15693AsTag(resp, 4); + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + } + } else { + Dbprintf("READBLOCK %d (won't answer, privacy mode)", block); + } + break; + } + + case 0xB2: { /* SLS2S5002_GET_RANDOM_NUMBER */ + uint8_t resp[5]; + uint16_t crc; + + Dbprintf("SLS2S5002: GET RANDOM"); + + resp[0] = ISO15693_NOERROR; + resp[1] = 0x00; /* set number to 0x0000 so we get the key in plaintext */ + resp[2] = 0x00; + crc = Iso15693Crc(resp, 3); + resp[3] = crc & 0xff; + resp[4] = crc >> 8; + + /* never respond in passive mode */ + if(!passive) { + CodeIso15693AsTag(resp, sizeof(resp)); + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + } + break; + } + + case 0xB3: { /* SLS2S5002_SET_PASSWORD */ + uint8_t resp[3]; + uint16_t crc; + uint8_t offset = 3 + (addressed ? 8 : 0); + uint32_t pass = (cmd[offset + 1] << 24) | (cmd[offset + 2] << 16) | (cmd[offset + 3] << 8) | (cmd[offset + 4] << 0); + + Dbprintf("SLS2S5002: SET PASSWORD #%02X: 0x%08X", cmd[offset + 0], pass); + + if(!passive && (pass == privacy_pass)) { + Dbprintf("SLS2S5002: Correct password"); + + resp[0] = ISO15693_NOERROR; + crc = Iso15693Crc(resp, 1); + resp[1] = crc & 0xff; + resp[2] = crc >> 8; + + private = false; + + CodeIso15693AsTag(resp, sizeof(resp)); + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + } else { + Dbprintf("SLS2S5002: Incorrect password"); + } + + break; + } + + case 0xB4: { /* SLS2S5002_WRITE_PASSWORD */ + uint8_t resp[3]; + uint16_t crc; + uint8_t offset = 3 + (addressed ? 8 : 0); + + Dbprintf("SLS2S5002: WRITE PASSWORD #%02X: %02X%02X%02X%02X", cmd[offset + 0], cmd[offset + 1], cmd[offset + 2], cmd[offset + 3], cmd[offset + 4]); + + if(!private) { + resp[0] = ISO15693_NOERROR; + crc = Iso15693Crc(resp, 1); + resp[1] = crc & 0xff; + resp[2] = crc >> 8; + + CodeIso15693AsTag(resp, sizeof(resp)); + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + } + break; + } + + case 0xB5: { /* SLS2S5002_LOCK_PASSWORD */ + uint8_t resp[3]; + uint16_t crc; + uint8_t offset = 3 + (addressed ? 8 : 0); + + Dbprintf("SLS2S5002: LOCK PASSWORD #%02X", cmd[offset + 0]); + + if(!private) { + resp[0] = ISO15693_NOERROR; + crc = Iso15693Crc(resp, 1); + resp[1] = crc & 0xff; + resp[2] = crc >> 8; + + CodeIso15693AsTag(resp, sizeof(resp)); + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + } + break; + } + + case 0xB8: { /* SLS2S5002_B8 */ + if(!private) { + Dbprintf("ISO15693_B8"); + uint8_t resp[4]; + uint16_t crc; + + resp[0] = ISO15693_ERROR_CMD_NOT_SUP; + resp[1] = 0x0F; /* unknown */ + + crc = Iso15693Crc(resp, 2); + resp[2] = crc & 0xff; + resp[3] = crc >> 8; + + CodeIso15693AsTag(resp, sizeof(resp)); + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + break; + } else { + Dbprintf("ISO15693_GET_SYSTEM_INFO (won't answer, privacy mode)"); + } + break; + } + + case 0xB9: { /* SLS2S5002_DESTROY */ + uint8_t resp[3]; + uint16_t crc; + + Dbprintf("SLS2S5002: DESTROY. POOOOF!"); + + if(!private) { + resp[0] = ISO15693_NOERROR; + crc = Iso15693Crc(resp, 1); + resp[1] = crc & 0xff; + resp[2] = crc >> 8; + + CodeIso15693AsTag(resp, sizeof(resp)); + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + } + break; + } + + case 0xBA: { /* SLS2S5002_ENABLE_PRIVACY */ + uint8_t resp[3]; + uint16_t crc; + + Dbprintf("SLS2S5002: ENABLE PRIVACY"); + + if(!private) { + resp[0] = ISO15693_NOERROR; + crc = Iso15693Crc(resp, 1); + resp[1] = crc & 0xff; + resp[2] = crc >> 8; + + private = true; + + CodeIso15693AsTag(resp, sizeof(resp)); + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + } + break; + } + + default: { + Dbprintf("SLS2S5002: unknown command 0x%02X", command); + break; + } + } } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - LED_A_OFF(); + cmd_send(CMD_ACK,1,0,0,0,0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); } diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index 15dfe763..e7667363 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -39,5 +39,10 @@ extern void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t rec extern void SetTag15693Uid(uint8_t *uid); extern void SetDebugIso15693(uint32_t flag); extern bool LogTrace_ISO15693(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); +extern void BruteforceIso15693(uint32_t start_cmd, uint32_t end_cmd); +extern void StressSlixLIso15693(uint32_t password, uint32_t flags); +extern void ChangePassSlixLIso15693(uint32_t pass_id, uint32_t old_password, uint32_t password); +extern void LockPassSlixLIso15693(uint32_t pass_id, uint32_t password); +extern void DisablePrivacySlixLIso15693(uint32_t password); #endif diff --git a/client/cmdhf15.c b/client/cmdhf15.c index cc86841b..a48e8b64 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -263,26 +263,35 @@ static int CmdHF15Reader(const char *Cmd) { static int CmdHF15Sim(const char *Cmd) { char cmdp = param_getchar(Cmd, 0); uint8_t uid[8] = {0x00}; + uint8_t memory[32] = {0x00}; - //E0 16 24 00 00 00 00 00 if (cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf 15 sim "); + PrintAndLog("Usage: hf 15 sim []"); PrintAndLog(""); - PrintAndLog(" sample: hf 15 sim E016240000000000"); + PrintAndLog(" example: hf 15 sim E016240000000000"); + PrintAndLog(" hf 15 sim E016240000000000 0001020304..1D1E1F"); + PrintAndLog(" "); + PrintAndLog(" sniff/decode mode: (live snooping reader commands)"); + PrintAndLog(" hf 15 sim 0000000000000000"); return 0; } if (param_gethex(Cmd, 0, uid, 16)) { - PrintAndLog("UID must include 16 HEX symbols"); + PrintAndLog("UID must have 16 HEX symbols"); return 0; } + if (param_gethex(Cmd, 1, memory, 64)) { + PrintAndLog("you should include 32 hex bytes for the tag memory"); + } + PrintAndLog("Starting simulating UID %02X %02X %02X %02X %02X %02X %02X %02X", uid[0],uid[1],uid[2],uid[3],uid[4], uid[5], uid[6], uid[7]); PrintAndLog("Press the button to stop simulation"); UsbCommand c = {CMD_SIMTAG_ISO_15693, {0, 0, 0}}; memcpy(c.d.asBytes,uid,8); + memcpy(&c.d.asBytes[8],memory,32); SendCommand(&c); return 0; @@ -297,6 +306,31 @@ static int CmdHF15Afi(const char *Cmd) { return 0; } +static int CmdHF15SlixDisablePrivacy(const char *Cmd) +{ + char cmdp = param_getchar(Cmd, 0); + uint8_t pass[4] = {0x00}; + + if (cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: hf 15 slix_disable_privacy "); + PrintAndLog(""); + PrintAndLog(" example: hf 15 slix_disable_privacy 0F0F0F0F"); + return 0; + } + + if (param_gethex(Cmd, 0, pass, 8)) { + PrintAndLog("password must have 8 HEX symbols"); + return 0; + } + + PrintAndLog("Disabling privacy mode using password %02X%02X%02X%02X", pass[0], pass[1], pass[2], pass[3]); + + UsbCommand c = {CMD_ISO_15693_SLIX_L_DISABLE_PRIVACY, {0, 0, 0}}; + memcpy(&c.arg[0],pass,4); + + SendCommand(&c); + return 0; +} // Reads all memory pages static int CmdHF15DumpMem(const char*Cmd) { @@ -1061,6 +1095,7 @@ static command_t CommandTable15[] = { {"reader", CmdHF15Reader, 0, "Act like an ISO15693 reader"}, {"sim", CmdHF15Sim, 0, "Fake an ISO15693 tag"}, {"cmd", CmdHF15Cmd, 0, "Send direct commands to ISO15693 tag"}, + {"slix_disable_privacy", CmdHF15SlixDisablePrivacy, 0, "Disable privacy mode on SLIX ISO15693 tag"}, {"findafi", CmdHF15Afi, 0, "Brute force AFI of an ISO15693 tag"}, {"dumpmemory", CmdHF15DumpMem, 0, "Read all memory pages of an ISO15693 tag"}, {"csetuid", CmdHF15CSetUID, 0, "Set UID for magic Chinese card"}, diff --git a/common/Makefile_Enabled_Options.common b/common/Makefile_Enabled_Options.common index edc86b85..527c15b0 100644 --- a/common/Makefile_Enabled_Options.common +++ b/common/Makefile_Enabled_Options.common @@ -3,7 +3,7 @@ # All definition lines except the last must end in a \ # #BEGIN -APP_CFLAGS += -DWITH_ISO14443a_StandAlone \ +APP_CFLAGS += -DWITH_ISO15693_StandAlone \ -DWITH_LF \ -DWITH_ISO15693 \ -DWITH_ISO14443a \ diff --git a/common/protocols.h b/common/protocols.h index 37a88449..49be78d5 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -197,6 +197,24 @@ NXP/Philips CUSTOM COMMANDS #define ISO15693_GET_SYSTEM_INFO 0x2B #define ISO15693_READ_MULTI_SECSTATUS 0x2C +// ISO15693 MANUFACTURER CODES +#define ISO15693_MANUFACTURER_NXP 0x04 + +// ISO15693-3 CUSTOM NXP COMMANDS +#define ISO15693_CMD_NXP_SET_EAS 0xA2 +#define ISO15693_CMD_NXP_RESET_EAS 0xA3 +#define ISO15693_CMD_NXP_LOCK_EAS 0xA4 +#define ISO15693_CMD_NXP_EAS_ALARM 0xA5 +#define ISO15693_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6 +#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7 +#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0 +#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1 +#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2 +#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3 +#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4 +#define ISO15693_CMD_NXP_DESTROY 0xB9 +#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA + // ISO15693 REQUEST FLAGS #define ISO15693_REQ_SUBCARRIER_TWO (1<<0) #define ISO15693_REQ_DATARATE_HIGH (1<<1) diff --git a/include/usb_cmd.h b/include/usb_cmd.h index a4d164f0..6dd00b9f 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -146,6 +146,7 @@ typedef struct { #define CMD_ISO_15693_DEBUG 0x0316 #define CMD_LF_SNOOP_RAW_ADC_SAMPLES 0x0317 #define CMD_CSETUID_ISO_15693 0x0318 +#define CMD_ISO_15693_SLIX_L_DISABLE_PRIVACY 0x0319 // For Hitag2 transponders #define CMD_SNOOP_HITAG 0x0370