## [unreleased][unreleased]
### Added
+- Added EM4x05/EM4x69 chip detection to lf search (marshmellow)
+- Added lf em 4x05dump command to read and output all the blocks of the chip (marshmellow)
+- Added lf em 4x05info command to read and display information about the chip (marshmellow)
- Added lf cotag read, and added it to lf search (iceman)
- Added hitag2 read UID only and added that to lf search (marshmellow)
- Added lf pyramid commands (iceman)
- Added option c to 'hf list' (mark CRC bytes) (piwi)
### Changed
+- small changes to lf psk and fsk demods to improve results when the trace begins with noise or the chip isn't broadcasting yet (marshmellow)
+- NOTE CHANGED ALL `lf em4x em*` cmds to simpler `lf em ` - example: `lf em4x em410xdemod` is now `lf em 410xdemod`
+- Renamed and rebuilt `lf em readword` && readwordpwd to `lf em 4x05readword` - it now demods and outputs the read block (marshmellow/iceman)
+- Renamed and rebuilt `lf em writeword` && writewordpwd to `lf em 4x05writeword` - it now also reads validation output from the tag (marshmellow/iceman)
- Fixed bug in lf sim and continuous demods not turning off antenna when finished
- Fixed bug(s) in hf iclass write
- Fixed bug in lf biphase sim - `lf simask b` (and any tagtype that relies on it - gproxii...) (marshmellow)
WritePCF7931(c->d.asBytes[0],c->d.asBytes[1],c->d.asBytes[2],c->d.asBytes[3],c->d.asBytes[4],c->d.asBytes[5],c->d.asBytes[6], c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[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]);
+ EM4xReadWord(c->arg[0], c->arg[1],c->arg[2]);
break;
case CMD_EM4X_WRITE_WORD:
- EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]);
+ EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2]);
break;
case CMD_AWID_DEMOD_FSK: // Set realtime AWID demodulation
CmdAWIDdemodFSK(c->arg[0], 0, 0, 1);
void TurnReadLFOn();
//void T55xxReadTrace(void);
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);
+void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd);
void Cotag(uint32_t arg0);
/// iso14443.h
for (i=0; i<size; i++){
askSimBit(BitStream[i]^invert, &n, clk, encoding);
}
- if (encoding==0 && BitStream[0]==BitStream[size-1]){ //run a second set inverted (for biphase phase)
+ if (encoding==0 && BitStream[0]==BitStream[size-1]){ //run a second set inverted (for ask/raw || biphase phase)
for (i=0; i<size; i++){
askSimBit(BitStream[i]^invert^1, &n, clk, encoding);
}
//Config for Indala (RF/32;PSK1 with RF/2;Maxblock=7)
data[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (7 << T55x7_MAXBLOCK_SHIFT);
//TODO add selection of chip for Q5 or T55x7
- // data[0] = (((32-2)/2)<<T5555_BITRATE_SHIFT) | T5555_MODULATION_PSK1 | 7 << T5555_MAXBLOCK_SHIFT;
+ // data[0] = (((32-2)>>1)<<T5555_BITRATE_SHIFT) | T5555_MODULATION_PSK1 | 7 << T5555_MAXBLOCK_SHIFT;
WriteT55xx(data, 0, 8);
//Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=7;Inverse data)
// T5567WriteBlock(0x603E10E2,0);
// clone viking tag to T55xx
void CopyVikingtoT55xx(uint32_t block1, uint32_t block2, uint8_t Q5) {
uint32_t data[] = {T55x7_BITRATE_RF_32 | T55x7_MODULATION_MANCHESTER | (2 << T55x7_MAXBLOCK_SHIFT), block1, block2};
- if (Q5) data[0] = (32 << T5555_BITRATE_SHIFT) | T5555_MODULATION_MANCHESTER | 2 << T5555_MAXBLOCK_SHIFT;
+ if (Q5) data[0] = ( ((32-2)>>1) << T5555_BITRATE_SHIFT) | T5555_MODULATION_MANCHESTER | 2 << T5555_MAXBLOCK_SHIFT;
// Program the data blocks for supplied ID and the block 0 config
WriteT55xx(data, 0, 3);
LED_D_OFF();
fwd_write_ptr = forwardLink_data;
fwd_bit_sz = fwd_bit_count;
- LED_D_ON();
-
// Set up FPGA, 125kHz
LFSetupFPGAForADC(95, true);
fwd_bit_sz--; //prepare next bit modulation
fwd_write_ptr++;
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
- SpinDelayUs(55*8); //55 cycles off (8us each)for 4305
+ SpinDelayUs(56*8); //55 cycles off (8us each)for 4305 /another reader has 37 here...
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on
- SpinDelayUs(16*8); //16 cycles on (8us each)
+ SpinDelayUs(18*8); //16 cycles on (8us each) // another reader has 18 here
// now start writting
while(fwd_bit_sz-- > 0) { //prepare next bit modulation
else {
//These timings work for 4469/4269/4305 (with the 55*8 above)
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
- SpinDelayUs(23*8); //16-4 cycles off (8us each)
+ SpinDelayUs(23*8); //16-4 cycles off (8us each) //23 //one reader goes as high as 25 here
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on
- SpinDelayUs(9*8); //16 cycles on (8us each)
+ SpinDelayUs(16*8); //16 cycles on (8us each) //9 // another reader goes to 17 here
}
}
}
void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
uint8_t fwd_bit_count;
- uint8_t *dest = BigBuf_get_addr();
- uint16_t bufferlength = BigBuf_max_traceLen();
- uint32_t i = 0;
// Clear destination buffer before sending the command
BigBuf_Clear_ext(false);
+ LED_A_ON();
//If password mode do login
if (PwdMode == 1) EM4xLogin(Pwd);
fwd_bit_count = Prepare_Cmd( FWD_CMD_READ );
fwd_bit_count += Prepare_Addr( Address );
- // Connect the A/D to the peak-detected low-frequency path.
- SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
- // Now set up the SSC to get the ADC samples that are now streaming at us.
- FpgaSetupSsc();
-
SendForward(fwd_bit_count);
-
+ SpinDelayUs(400);
// Now do the acquisition
- i = 0;
- for(;;) {
- if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
- AT91C_BASE_SSC->SSC_THR = 0x43;
- }
- if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
- dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
- i++;
- if (i >= bufferlength) break;
- }
- }
+ DoPartialAcquisition(20, true, 6000);
+
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
+ LED_A_OFF();
cmd_send(CMD_ACK,0,0,0,0,0);
- LED_D_OFF();
}
-void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
-
+void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd) {
+
+ bool PwdMode = (flag & 0xF);
+ uint8_t Address = (flag >> 8) & 0xFF;
uint8_t fwd_bit_count;
+ //clear buffer now so it does not interfere with timing later
+ BigBuf_Clear_ext(false);
+
+ LED_A_ON();
//If password mode do login
- if (PwdMode == 1) EM4xLogin(Pwd);
+ if (PwdMode) EM4xLogin(Pwd);
forward_ptr = forwardLink_data;
fwd_bit_count = Prepare_Cmd( FWD_CMD_WRITE );
SendForward(fwd_bit_count);
//Wait for write to complete
- SpinDelay(20);
+ //SpinDelay(10);
+
+ SpinDelayUs(6500);
+ //Capture response if one exists
+ DoPartialAcquisition(20, true, 6000);
+
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
- LED_D_OFF();
+ LED_A_OFF();
+ cmd_send(CMD_ACK,0,0,0,0,0);
}
/*
Reading a COTAG.
* @param silent - is true, now outputs are made. If false, dbprints the status
* @return the number of bits occupied by the samples.
*/
-uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent)
+uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize)
{
//.
uint8_t *dest = BigBuf_get_addr();
- int bufsize = BigBuf_max_traceLen();
+ bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen();
//memset(dest, 0, bufsize); //creates issues with cmdread (marshmellow)
*/
uint32_t DoAcquisition_default(int trigger_threshold, bool silent)
{
- return DoAcquisition(1,8,0,trigger_threshold,silent);
+ return DoAcquisition(1,8,0,trigger_threshold,silent,0);
}
uint32_t DoAcquisition_config( bool silent)
{
,config.bits_per_sample
,config.averaging
,config.trigger_threshold
- ,silent);
+ ,silent
+ ,0);
+}
+
+uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size) {
+ return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size);
}
uint32_t ReadLF(bool activeField, bool silent)
* Initializes the FPGA for snoop-mode (field off), and acquires the samples.
* @return number of bits sampled
**/
-
uint32_t SnoopLF();
+// adds sample size to default options
+uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size);
+
/**
* @brief Does sample acquisition, ignoring the config values set in the sample_config.
* This method is typically used by tag-specific readers who just wants to read the samples
int CmdData(const char *Cmd);
void printDemodBuff(void);
void setDemodBuf(uint8_t *buff, size_t size, size_t startIdx);
+int CmdPrintDemodBuff(const char *Cmd);
int CmdAskEM410xDemod(const char *Cmd);
int CmdVikingDemod(const char *Cmd);
int CmdG_Prox_II_Demod(const char *Cmd);
return 0;
}
+
+//by marshmellow
+int CheckChipType(char cmdp) {
+ uint32_t wordData = 0;
+
+ //check for em4x05/em4x69 chips first
+ save_restoreGB(1);
+ if ((!offline && (cmdp != '1')) && EM4x05Block0Test(&wordData)) {
+ PrintAndLog("\nValid EM4x05/EM4x69 Chip Found\nTry lf em 4x05... commands\n");
+ save_restoreGB(0);
+ return 1;
+ }
+
+ //TODO check for t55xx chip...
+
+ save_restoreGB(0);
+ return 1;
+}
+
//by marshmellow
int CmdLFfind(const char *Cmd)
{
+ uint32_t wordData = 0;
int ans=0;
size_t minLength = 1000;
char cmdp = param_getchar(Cmd, 0);
// only run if graphbuffer is just noise as it should be for hitag/cotag
if (graphJustNoise(GraphBuffer, testLen)) {
// only run these tests if we are in online mode
- if (!offline && (cmdp != '1')){
+ if (!offline && (cmdp != '1')) {
+ // test for em4x05 in reader talk first mode.
+ if (EM4x05Block0Test(&wordData)) {
+ PrintAndLog("\nValid EM4x05/EM4x69 Chip Found\nUse lf em 4x05readword/dump commands to read\n");
+ return 1;
+ }
ans=CmdLFHitagReader("26");
if (ans==0) {
return 1;
ans=CmdFSKdemodIO("");
if (ans>0) {
PrintAndLog("\nValid IO Prox ID Found!");
- return 1;
+ return CheckChipType(cmdp);
}
ans=CmdFSKdemodPyramid("");
if (ans>0) {
PrintAndLog("\nValid Pyramid ID Found!");
- return 1;
+ return CheckChipType(cmdp);
}
ans=CmdFSKdemodParadox("");
if (ans>0) {
PrintAndLog("\nValid Paradox ID Found!");
- return 1;
+ return CheckChipType(cmdp);
}
ans=CmdFSKdemodAWID("");
if (ans>0) {
PrintAndLog("\nValid AWID ID Found!");
- return 1;
+ return CheckChipType(cmdp);
}
ans=CmdFSKdemodHID("");
if (ans>0) {
PrintAndLog("\nValid HID Prox ID Found!");
- return 1;
+ return CheckChipType(cmdp);
}
ans=CmdAskEM410xDemod("");
if (ans>0) {
PrintAndLog("\nValid EM410x ID Found!");
- return 1;
+ return CheckChipType(cmdp);
}
ans=CmdG_Prox_II_Demod("");
if (ans>0) {
PrintAndLog("\nValid G Prox II ID Found!");
- return 1;
+ return CheckChipType(cmdp);
}
ans=CmdFDXBdemodBI("");
if (ans>0) {
PrintAndLog("\nValid FDX-B ID Found!");
- return 1;
+ return CheckChipType(cmdp);
}
ans=EM4x50Read("", false);
ans=CmdVikingDemod("");
if (ans>0) {
PrintAndLog("\nValid Viking ID Found!");
- return 1;
+ return CheckChipType(cmdp);
}
ans=CmdIndalaDecode("");
if (ans>0) {
PrintAndLog("\nValid Indala ID Found!");
- return 1;
+ return CheckChipType(cmdp);
}
ans=CmdPSKNexWatch("");
if (ans>0) {
PrintAndLog("\nValid NexWatch ID Found!");
- return 1;
+ return CheckChipType(cmdp);
}
PrintAndLog("\nNo Known Tags Found!\n");
if (testRaw=='u' || testRaw=='U'){
- //test unknown tag formats (raw mode)
+ ans=CheckChipType(cmdp);
+ //test unknown tag formats (raw mode)0
PrintAndLog("\nChecking for Unknown tags:\n");
ans=AutoCorrelate(4000, FALSE, FALSE);
if (ans > 0) PrintAndLog("Possible Auto Correlation of %d repeating samples",ans);
{"help", CmdHelp, 1, "This help"},
{"awid", CmdLFAWID, 1, "{ AWID RFIDs... }"},
{"cotag", CmdLFCOTAG, 1, "{ COTAG RFIDs... }"},
- {"em4x", CmdLFEM4X, 1, "{ EM4X RFIDs... }"},
+ {"em", CmdLFEM4X, 1, "{ EM4X RFIDs... }"},
{"hid", CmdLFHID, 1, "{ HID RFIDs... }"},
{"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders... }"},
{"io", CmdLFIO, 1, "{ ioProx tags... }"},
if (sscanf(Cmd, "%u %u", &fc, &cn ) != 2) return usage_lf_awid_clone();
if (param_getchar(Cmd, 3) == 'Q' || param_getchar(Cmd, 3) == 'q')
- blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | 50<<T5555_BITRATE_SHIFT | 3<<T5555_MAXBLOCK_SHIFT;
+ blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | ((50-2)>>1)<<T5555_BITRATE_SHIFT | 3<<T5555_MAXBLOCK_SHIFT;
if ((fc & 0xFF) != fc) {
fc &= 0xFF;
#include "cmdparser.h"
#include "cmddata.h"
#include "cmdlf.h"
+#include "cmdmain.h"
#include "cmdlfem4x.h"
#include "lfdemod.h"
uint8_t uid[5] = {0x00};
if (cmdp == 'h' || cmdp == 'H') {
- PrintAndLog("Usage: lf em4x em410xsim <UID> <clock>");
+ PrintAndLog("Usage: lf em 410xsim <UID> <clock>");
PrintAndLog("");
- PrintAndLog(" sample: lf em4x em410xsim 0F0368568B");
+ PrintAndLog(" sample: lf em 410xsim 0F0368568B");
return 0;
}
/* clock is 64 in EM410x tags */
return 0;
}
+//**************** Start of EM4x50 Code ************************
bool EM_EndParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType)
{
if (rows*cols>size) return false;
}
return code;
}
-/* Read the transmitted data of an EM4x50 tag
+/* Read the transmitted data of an EM4x50 tag from the graphbuffer
* Format:
*
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
return EM4x50Read(Cmd, true);
}
-int CmdReadWord(const char *Cmd)
-{
- int Word = -1; //default to invalid word
- UsbCommand c;
-
- sscanf(Cmd, "%d", &Word);
-
- if ( (Word > 15) | (Word < 0) ) {
- PrintAndLog("Word must be between 0 and 15");
- return 1;
+//**************** Start of EM4x05/EM4x69 Code ************************
+int usage_lf_em_read(void) {
+ PrintAndLog("Read EM4x05/EM4x69. Tag must be on antenna. ");
+ PrintAndLog("");
+ PrintAndLog("Usage: lf em 4x05readword [h] <address> <pwd>");
+ PrintAndLog("Options:");
+ PrintAndLog(" h - this help");
+ PrintAndLog(" address - memory address to read. (0-15)");
+ PrintAndLog(" pwd - password (hex) (optional)");
+ PrintAndLog("samples:");
+ PrintAndLog(" lf em 4x05readword 1");
+ PrintAndLog(" lf em 4x05readword 1 11223344");
+ return 0;
+}
+
+// for command responses from em4x05 or em4x69
+// download samples from device and copy them to the Graphbuffer
+bool downloadSamplesEM() {
+ // 8 bit preamble + 32 bit word response (max clock (128) * 40bits = 5120 samples)
+ uint8_t got[6000];
+ GetFromBigBuf(got, sizeof(got), 0);
+ if ( !WaitForResponseTimeout(CMD_ACK, NULL, 4000) ) {
+ PrintAndLog("command execution time out");
+ return false;
}
-
- PrintAndLog("Reading word %d", Word);
-
- c.cmd = CMD_EM4X_READ_WORD;
- c.d.asBytes[0] = 0x0; //Normal mode
- c.arg[0] = 0;
- c.arg[1] = Word;
- c.arg[2] = 0;
+ setGraphBuf(got, sizeof(got));
+ return true;
+}
+
+bool EM4x05testDemodReadData(uint32_t *word, bool readCmd) {
+ // em4x05/em4x69 command response preamble is 00001010
+ // skip first two 0 bits as they might have been missed in the demod
+ uint8_t preamble[] = {0,0,1,0,1,0};
+ size_t startIdx = 0;
+
+ // set size to 20 to only test first 14 positions for the preamble or less if not a read command
+ size_t size = (readCmd) ? 20 : 11;
+ // sanity check
+ size = (size > DemodBufferLen) ? DemodBufferLen : size;
+ // test preamble
+ if ( !onePreambleSearch(DemodBuffer, preamble, sizeof(preamble), size, &startIdx) ) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305 preamble not found :: %d", startIdx);
+ return false;
+ }
+ // if this is a readword command, get the read bytes and test the parities
+ if (readCmd) {
+ if (!EM_EndParityTest(DemodBuffer + startIdx + sizeof(preamble), 45, 5, 9, 0)) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - End Parity check failed");
+ return false;
+ }
+ // test for even parity bits.
+ if ( removeParity(DemodBuffer, startIdx + sizeof(preamble),9,0,44) == 0 ) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - Parity not detected");
+ return false;
+ }
+
+ setDemodBuf(DemodBuffer, 40, 0);
+ *word = bytebits_to_byteLSBF(DemodBuffer, 32);
+ }
+ return true;
+}
+
+// FSK, PSK, ASK/MANCHESTER, ASK/BIPHASE, ASK/DIPHASE
+// should cover 90% of known used configs
+// the rest will need to be manually demoded for now...
+int demodEM4x05resp(uint32_t *word, bool readCmd) {
+ int ans = 0;
+
+ // test for FSK wave (easiest to 99% ID)
+ if (GetFskClock("", false, false)) {
+ //valid fsk clocks found
+ ans = FSKrawDemod("0 0", false);
+ if (!ans) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: FSK Demod failed, ans: %d", ans);
+ } else {
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ }
+ }
+ }
+ // PSK clocks should be easy to detect ( but difficult to demod a non-repeating pattern... )
+ ans = GetPskClock("", false, false);
+ if (ans>0) {
+ //try psk1
+ ans = PSKDemod("0 0 6", false);
+ if (!ans) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: PSK1 Demod failed, ans: %d", ans);
+ } else {
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ } else {
+ //try psk2
+ psk1TOpsk2(DemodBuffer, DemodBufferLen);
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ }
+ }
+ //try psk1 inverted
+ ans = PSKDemod("0 1 6", false);
+ if (!ans) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: PSK1 Demod failed, ans: %d", ans);
+ } else {
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ } else {
+ //try psk2
+ psk1TOpsk2(DemodBuffer, DemodBufferLen);
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ }
+ }
+ }
+ }
+ }
+
+ // manchester is more common than biphase... try first
+ bool stcheck = false;
+ // try manchester - NOTE: ST only applies to T55x7 tags.
+ ans = ASKDemod_ext("0,0,1", false, false, 1, &stcheck);
+ if (!ans) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: ASK/Manchester Demod failed, ans: %d", ans);
+ } else {
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ }
+ }
+
+ //try biphase
+ ans = ASKbiphaseDemod("0 0 1", false);
+ if (!ans) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: ASK/biphase Demod failed, ans: %d", ans);
+ } else {
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ }
+ }
+
+ //try diphase (differential biphase or inverted)
+ ans = ASKbiphaseDemod("0 1 1", false);
+ if (!ans) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: ASK/biphase Demod failed, ans: %d", ans);
+ } else {
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ }
+ }
+
+ return -1;
+}
+
+int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *wordData) {
+ UsbCommand c = {CMD_EM4X_READ_WORD, {addr, pwd, usePwd}};
+ clearCommandBuffer();
SendCommand(&c);
- return 0;
+ UsbCommand resp;
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)){
+ PrintAndLog("Command timed out");
+ return -1;
+ }
+ if ( !downloadSamplesEM() ) {
+ return -1;
+ }
+ int testLen = (GraphTraceLen < 1000) ? GraphTraceLen : 1000;
+ if (graphJustNoise(GraphBuffer, testLen)) {
+ PrintAndLog("no tag not found");
+ return -1;
+ }
+ //attempt demod:
+ return demodEM4x05resp(wordData, true);
}
-int CmdReadWordPWD(const char *Cmd)
-{
- int Word = -1; //default to invalid word
- int Password = 0xFFFFFFFF; //default to blank password
- UsbCommand c;
-
- sscanf(Cmd, "%d %x", &Word, &Password);
+int EM4x05ReadWord(uint8_t addr, uint32_t pwd, bool usePwd) {
+ uint32_t wordData = 0;
+ int success = EM4x05ReadWord_ext(addr, pwd, usePwd, &wordData);
+ if (success == 1)
+ PrintAndLog("%s Address %02d | %08X", (addr>13) ? "Lock":" Got",addr,wordData);
+ else
+ PrintAndLog("Read Address %02d | failed",addr);
+
+ return success;
+}
+
+int CmdEM4x05ReadWord(const char *Cmd) {
+ uint8_t addr;
+ uint32_t pwd;
+ bool usePwd = false;
+ uint8_t ctmp = param_getchar(Cmd, 0);
+ if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_read();
+
+ addr = param_get8ex(Cmd, 0, 50, 10);
+ // for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
+ pwd = param_get32ex(Cmd, 1, 1, 16);
- if ( (Word > 15) | (Word < 0) ) {
- PrintAndLog("Word must be between 0 and 15");
+ if ( (addr > 15) ) {
+ PrintAndLog("Address must be between 0 and 15");
return 1;
}
+ if ( pwd == 1 ) {
+ PrintAndLog("Reading address %02u", addr);
+ } else {
+ usePwd = true;
+ PrintAndLog("Reading address %02u | password %08X", addr, pwd);
+ }
+
+ return EM4x05ReadWord(addr, pwd, usePwd);
+}
+
+int usage_lf_em_dump(void) {
+ PrintAndLog("Dump EM4x05/EM4x69. Tag must be on antenna. ");
+ PrintAndLog("");
+ PrintAndLog("Usage: lf em 4x05dump [h] <pwd>");
+ PrintAndLog("Options:");
+ PrintAndLog(" h - this help");
+ PrintAndLog(" pwd - password (hex) (optional)");
+ PrintAndLog("samples:");
+ PrintAndLog(" lf em 4x05dump");
+ PrintAndLog(" lf em 4x05dump 11223344");
+ return 0;
+}
+
+int CmdEM4x05dump(const char *Cmd) {
+ uint8_t addr = 0;
+ uint32_t pwd;
+ bool usePwd = false;
+ uint8_t ctmp = param_getchar(Cmd, 0);
+ if ( ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_dump();
+
+ // for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
+ pwd = param_get32ex(Cmd, 0, 1, 16);
- PrintAndLog("Reading word %d with password %08X", Word, Password);
-
- c.cmd = CMD_EM4X_READ_WORD;
- c.d.asBytes[0] = 0x1; //Password mode
- c.arg[0] = 0;
- c.arg[1] = Word;
- c.arg[2] = Password;
- SendCommand(&c);
+ if ( pwd != 1 ) {
+ usePwd = true;
+ }
+ int success = 1;
+ for (; addr < 16; addr++) {
+ if (addr == 2) {
+ if (usePwd) {
+ PrintAndLog(" PWD Address %02u | %08X",addr,pwd);
+ } else {
+ PrintAndLog(" PWD Address 02 | cannot read");
+ }
+ } else {
+ success &= EM4x05ReadWord(addr, pwd, usePwd);
+ }
+ }
+
+ return success;
+}
+
+
+int usage_lf_em_write(void) {
+ PrintAndLog("Write EM4x05/EM4x69. Tag must be on antenna. ");
+ PrintAndLog("");
+ PrintAndLog("Usage: lf em 4x05writeword [h] <address> <data> <pwd>");
+ PrintAndLog("Options:");
+ PrintAndLog(" h - this help");
+ PrintAndLog(" address - memory address to write to. (0-15)");
+ PrintAndLog(" data - data to write (hex)");
+ PrintAndLog(" pwd - password (hex) (optional)");
+ PrintAndLog("samples:");
+ PrintAndLog(" lf em 4x05writeword 1");
+ PrintAndLog(" lf em 4x05writeword 1 deadc0de 11223344");
return 0;
}
-int CmdWriteWord(const char *Cmd)
-{
- int Word = 16; //default to invalid block
- int Data = 0xFFFFFFFF; //default to blank data
- UsbCommand c;
+int CmdEM4x05WriteWord(const char *Cmd) {
+ uint8_t ctmp = param_getchar(Cmd, 0);
+ if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_write();
- sscanf(Cmd, "%x %d", &Data, &Word);
+ bool usePwd = false;
+
+ uint8_t addr = 16; // default to invalid address
+ uint32_t data = 0xFFFFFFFF; // default to blank data
+ uint32_t pwd = 0xFFFFFFFF; // default to blank password
+
+ addr = param_get8ex(Cmd, 0, 16, 10);
+ data = param_get32ex(Cmd, 1, 0, 16);
+ pwd = param_get32ex(Cmd, 2, 1, 16);
- if (Word > 15) {
- PrintAndLog("Word must be between 0 and 15");
+
+ if ( (addr > 15) ) {
+ PrintAndLog("Address must be between 0 and 15");
return 1;
}
+ if ( pwd == 1 )
+ PrintAndLog("Writing address %d data %08X", addr, data);
+ else {
+ usePwd = true;
+ PrintAndLog("Writing address %d data %08X using password %08X", addr, data, pwd);
+ }
- PrintAndLog("Writing word %d with data %08X", Word, Data);
+ uint16_t flag = (addr << 8 ) | usePwd;
- c.cmd = CMD_EM4X_WRITE_WORD;
- c.d.asBytes[0] = 0x0; //Normal mode
- c.arg[0] = Data;
- c.arg[1] = Word;
- c.arg[2] = 0;
+ UsbCommand c = {CMD_EM4X_WRITE_WORD, {flag, data, pwd}};
+ clearCommandBuffer();
SendCommand(&c);
- return 0;
+ UsbCommand resp;
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)){
+ PrintAndLog("Error occurred, device did not respond during write operation.");
+ return -1;
+ }
+ if ( !downloadSamplesEM() ) {
+ return -1;
+ }
+ //check response for 00001010 for write confirmation!
+ //attempt demod:
+ uint32_t dummy = 0;
+ int result = demodEM4x05resp(&dummy,false);
+ if (result == 1) {
+ PrintAndLog("Write Verified");
+ } else {
+ PrintAndLog("Write could not be verified");
+ }
+ return result;
}
-int CmdWriteWordPWD(const char *Cmd)
-{
- int Word = 16; //default to invalid word
- int Data = 0xFFFFFFFF; //default to blank data
- int Password = 0xFFFFFFFF; //default to blank password
- UsbCommand c;
-
- sscanf(Cmd, "%x %d %x", &Data, &Word, &Password);
+void printEM4x05config(uint32_t wordData) {
+ uint16_t datarate = (((wordData & 0x3F)+1)*2);
+ uint8_t encoder = ((wordData >> 6) & 0xF);
+ char enc[14];
+ memset(enc,0,sizeof(enc));
+
+ uint8_t PSKcf = (wordData >> 10) & 0x3;
+ char cf[10];
+ memset(cf,0,sizeof(cf));
+ uint8_t delay = (wordData >> 12) & 0x3;
+ char cdelay[33];
+ memset(cdelay,0,sizeof(cdelay));
+ uint8_t LWR = (wordData >> 14) & 0xF; //last word read
+
+ switch (encoder) {
+ case 0: snprintf(enc,sizeof(enc),"NRZ"); break;
+ case 1: snprintf(enc,sizeof(enc),"Manchester"); break;
+ case 2: snprintf(enc,sizeof(enc),"Biphase"); break;
+ case 3: snprintf(enc,sizeof(enc),"Miller"); break;
+ case 4: snprintf(enc,sizeof(enc),"PSK1"); break;
+ case 5: snprintf(enc,sizeof(enc),"PSK2"); break;
+ case 6: snprintf(enc,sizeof(enc),"PSK3"); break;
+ case 7: snprintf(enc,sizeof(enc),"Unknown"); break;
+ case 8: snprintf(enc,sizeof(enc),"FSK1"); break;
+ case 9: snprintf(enc,sizeof(enc),"FSK2"); break;
+ default: snprintf(enc,sizeof(enc),"Unknown"); break;
+ }
+
+ switch (PSKcf) {
+ case 0: snprintf(cf,sizeof(cf),"RF/2"); break;
+ case 1: snprintf(cf,sizeof(cf),"RF/8"); break;
+ case 2: snprintf(cf,sizeof(cf),"RF/4"); break;
+ case 3: snprintf(cf,sizeof(cf),"unknown"); break;
+ }
+
+ switch (delay) {
+ case 0: snprintf(cdelay, sizeof(cdelay),"no delay"); break;
+ case 1: snprintf(cdelay, sizeof(cdelay),"BP/8 or 1/8th bit period delay"); break;
+ case 2: snprintf(cdelay, sizeof(cdelay),"BP/4 or 1/4th bit period delay"); break;
+ case 3: snprintf(cdelay, sizeof(cdelay),"no delay"); break;
+ }
+ PrintAndLog("ConfigWord: %08X (Word 4)\n", wordData);
+ PrintAndLog("Config Breakdown:", wordData);
+ PrintAndLog(" Data Rate: %02u | RF/%u", wordData & 0x3F, datarate);
+ PrintAndLog(" Encoder: %u | %s", encoder, enc);
+ PrintAndLog(" PSK CF: %u | %s", PSKcf, cf);
+ PrintAndLog(" Delay: %u | %s", delay, cdelay);
+ PrintAndLog(" LastWordR: %02u | Address of last word for default read", LWR);
+ PrintAndLog(" ReadLogin: %u | Read Login is %s", (wordData & 0x40000)>>18, (wordData & 0x40000) ? "Required" : "Not Required");
+ PrintAndLog(" ReadHKL: %u | Read Housekeeping Words Login is %s", (wordData & 0x80000)>>19, (wordData & 0x80000) ? "Required" : "Not Required");
+ PrintAndLog("WriteLogin: %u | Write Login is %s", (wordData & 0x100000)>>20, (wordData & 0x100000) ? "Required" : "Not Required");
+ PrintAndLog(" WriteHKL: %u | Write Housekeeping Words Login is %s", (wordData & 0x200000)>>21, (wordData & 0x200000) ? "Required" : "Not Required");
+ PrintAndLog(" R.A.W.: %u | Read After Write is %s", (wordData & 0x400000)>>22, (wordData & 0x400000) ? "On" : "Off");
+ PrintAndLog(" Disable: %u | Disable Command is %s", (wordData & 0x800000)>>23, (wordData & 0x800000) ? "Accepted" : "Not Accepted");
+ PrintAndLog(" R.T.F.: %u | Reader Talk First is %s", (wordData & 0x1000000)>>24, (wordData & 0x1000000) ? "Enabled" : "Disabled");
+ PrintAndLog(" Pigeon: %u | Pigeon Mode is %s\n", (wordData & 0x4000000)>>26, (wordData & 0x4000000) ? "Enabled" : "Disabled");
+}
+
+void printEM4x05info(uint8_t chipType, uint8_t cap, uint16_t custCode, uint32_t serial) {
+ switch (chipType) {
+ case 9: PrintAndLog("\n Chip Type: %u | EM4305", chipType); break;
+ case 4: PrintAndLog(" Chip Type: %u | Unknown", chipType); break;
+ case 2: PrintAndLog(" Chip Type: %u | EM4469", chipType); break;
+ //add more here when known
+ default: PrintAndLog(" Chip Type: %u Unknown", chipType); break;
+ }
+
+ switch (cap) {
+ case 3: PrintAndLog(" Cap Type: %u | 330pF",cap); break;
+ case 2: PrintAndLog(" Cap Type: %u | %spF",cap, (chipType==2)? "75":"210"); break;
+ case 1: PrintAndLog(" Cap Type: %u | 250pF",cap); break;
+ case 0: PrintAndLog(" Cap Type: %u | no resonant capacitor",cap); break;
+ default: PrintAndLog(" Cap Type: %u | unknown",cap); break;
+ }
+
+ PrintAndLog(" Cust Code: %03u | %s", custCode, (custCode == 0x200) ? "Default": "Unknown");
+ if (serial != 0) {
+ PrintAndLog("\n Serial #: %08X\n", serial);
+ }
+}
+
+void printEM4x05ProtectionBits(uint32_t wordData) {
+ for (uint8_t i = 0; i < 15; i++) {
+ PrintAndLog(" Word: %02u | %s", i, (((1 << i) & wordData ) || i < 2) ? "Is Write Locked" : "Is Not Write Locked");
+ if (i==14) {
+ PrintAndLog(" Word: %02u | %s", i+1, (((1 << i) & wordData ) || i < 2) ? "Is Write Locked" : "Is Not Write Locked");
+ }
+ }
+}
+
+//quick test for EM4x05/EM4x69 tag
+bool EM4x05Block0Test(uint32_t *wordData) {
+ if (EM4x05ReadWord_ext(0,0,false,wordData) == 1) {
+ return true;
+ }
+ return false;
+}
+
+int CmdEM4x05info(const char *Cmd) {
+ //uint8_t addr = 0;
+ uint32_t pwd;
+ uint32_t wordData = 0;
+ bool usePwd = false;
+ uint8_t ctmp = param_getchar(Cmd, 0);
+ if ( ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_dump();
+
+ // for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
+ pwd = param_get32ex(Cmd, 0, 1, 16);
- if (Word > 15) {
- PrintAndLog("Word must be between 0 and 15");
- return 1;
+ if ( pwd != 1 ) {
+ usePwd = true;
}
+
+ // read word 0 (chip info)
+ // block 0 can be read even without a password.
+ if ( !EM4x05Block0Test(&wordData) )
+ return -1;
- PrintAndLog("Writing word %d with data %08X and password %08X", Word, Data, Password);
+ uint8_t chipType = (wordData >> 1) & 0xF;
+ uint8_t cap = (wordData >> 5) & 3;
+ uint16_t custCode = (wordData >> 9) & 0x3FF;
- c.cmd = CMD_EM4X_WRITE_WORD;
- c.d.asBytes[0] = 0x1; //Password mode
- c.arg[0] = Data;
- c.arg[1] = Word;
- c.arg[2] = Password;
- SendCommand(&c);
- return 0;
+ // read word 1 (serial #) doesn't need pwd
+ wordData = 0;
+ if (EM4x05ReadWord_ext(1, 0, false, &wordData) != 1) {
+ //failed, but continue anyway...
+ }
+ printEM4x05info(chipType, cap, custCode, wordData);
+
+ // read word 4 (config block)
+ // needs password if one is set
+ wordData = 0;
+ if ( EM4x05ReadWord_ext(4, pwd, usePwd, &wordData) != 1 ) {
+ //failed
+ return 0;
+ }
+ printEM4x05config(wordData);
+
+ // read word 14 and 15 to see which is being used for the protection bits
+ wordData = 0;
+ if ( EM4x05ReadWord_ext(14, pwd, usePwd, &wordData) != 1 ) {
+ //failed
+ return 0;
+ }
+ // if status bit says this is not the used protection word
+ if (!(wordData & 0x8000)) {
+ if ( EM4x05ReadWord_ext(15, pwd, usePwd, &wordData) != 1 ) {
+ //failed
+ return 0;
+ }
+ }
+ if (!(wordData & 0x8000)) {
+ //something went wrong
+ return 0;
+ }
+ printEM4x05ProtectionBits(wordData);
+
+ return 1;
}
+
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
- {"em410xdemod", CmdEMdemodASK, 0, "[findone] -- Extract ID from EM410x tag (option 0 for continuous loop, 1 for only 1 tag)"},
- {"em410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag in GraphBuffer"},
- {"em410xsim", CmdEM410xSim, 0, "<UID> [clock rate] -- Simulate EM410x tag"},
- {"em410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
- {"em410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
- {"em410xwrite", CmdEM410xWrite, 0, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
- {"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"},
- {"readword", CmdReadWord, 1, "<Word> -- Read EM4xxx word data"},
- {"readwordPWD", CmdReadWordPWD, 1, "<Word> <Password> -- Read EM4xxx word data in password mode"},
- {"writeword", CmdWriteWord, 1, "<Data> <Word> -- Write EM4xxx word data"},
- {"writewordPWD", CmdWriteWordPWD, 1, "<Data> <Word> <Password> -- Write EM4xxx word data in password mode"},
+ {"410xdemod", CmdEMdemodASK, 0, "[findone] -- Extract ID from EM410x tag (option 0 for continuous loop, 1 for only 1 tag)"},
+ {"410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag in GraphBuffer"},
+ {"410xsim", CmdEM410xSim, 0, "<UID> [clock rate] -- Simulate EM410x tag"},
+ {"410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
+ {"410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
+ {"410xwrite", CmdEM410xWrite, 0, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
+ {"4x05dump", CmdEM4x05dump, 0, "(pwd) -- Read EM4x05/EM4x69 all word data"},
+ {"4x05info", CmdEM4x05info, 0, "(pwd) -- Get info from EM4x05/EM4x69 tag"},
+ {"4x05readword", CmdEM4x05ReadWord, 0, "<Word> (pwd) -- Read EM4x05/EM4x69 word data"},
+ {"4x05writeword", CmdEM4x05WriteWord, 0, "<Word> <data> (pwd) -- Write EM4x05/EM4x69 word data"},
+ {"4x50read", CmdEM4x50Read, 1, "demod data from EM4x50 tag from the graph buffer"},
{NULL, NULL, 0, NULL}
};
int CmdEM410xWatchnSpoof(const char *Cmd);
int CmdEM410xWrite(const char *Cmd);
int CmdEM4x50Read(const char *Cmd);
-int CmdLFEM4X(const char *Cmd);
-int CmdReadWord(const char *Cmd);
-int CmdReadWordPWD(const char *Cmd);
-int CmdWriteWord(const char *Cmd);
-int CmdWriteWordPWD(const char *Cmd);
int EM4x50Read(const char *Cmd, bool verbose);
+int CmdLFEM4X(const char *Cmd);
+bool EM4x05Block0Test(uint32_t *wordData);
+int CmdEM4x05info(const char *Cmd);
+int CmdEM4x05WriteWord(const char *Cmd);
+int CmdEM4x05dump(const char *Cmd);
+int CmdEM4x05ReadWord(const char *Cmd);
+int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *wordData);
+
#endif
if (GetWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == -1) return usage_lf_presco_clone();
if (Q5)
- blocks[0] = T5555_MODULATION_MANCHESTER | 32<<T5555_BITRATE_SHIFT | 4<<T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR;
+ blocks[0] = T5555_MODULATION_MANCHESTER | ((32-2)>>1)<<T5555_BITRATE_SHIFT | 4<<T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR;
if ((sitecode & 0xFF) != sitecode) {
sitecode &= 0xFF;
#include "ui.h"
#include "graph.h"
#include "lfdemod.h"
+#include "cmddata.h" //for g_debugmode
int GraphBuffer[MAX_GRAPH_TRACE_LEN];
int GraphTraceLen;
if (size==0) return 0;
uint16_t ans = countFC(BitStream, size, 1);
if (ans==0) {
- if (verbose) PrintAndLog("DEBUG: No data found");
+ if (verbose || g_debugMode) PrintAndLog("DEBUG: No data found");
return 0;
}
*fc1 = (ans >> 8) & 0xFF;
*rf1 = detectFSKClk(BitStream, size, *fc1, *fc2);
if (*rf1==0) {
- if (verbose) PrintAndLog("DEBUG: Clock detect error");
+ if (verbose || g_debugMode) PrintAndLog("DEBUG: Clock detect error");
return 0;
}
return 1;
printf("\n");
}
+void print_hex_break(const uint8_t *data, const size_t len, uint8_t breaks) {
+
+ int rownum = 0;
+ printf("[%02d] | ", rownum);
+ for (int i = 0; i < len; ++i) {
+
+ printf("%02X ", data[i]);
+
+ // check if a line break is needed
+ if ( breaks > 0 && !((i+1) % breaks) && (i+1 < len) ) {
+ ++rownum;
+ printf("\n[%02d] | ", rownum);
+ }
+ }
+ printf("\n");
+}
+
char *sprint_hex(const uint8_t *data, const size_t len) {
int maxLen = ( len > 1024/3) ? 1024/3 : len;
size_t in_index = 0;
// loop through the out_index to make sure we don't go too far
- for (size_t out_index=0; out_index < max_len; out_index++) {
+ for (size_t out_index=0; out_index < max_len-1; out_index++) {
// set character - (should be binary but verify it isn't more than 1 digit)
if (data[in_index]<10)
sprintf(tmp++, "%u", (unsigned int) data[in_index]);
char *sprint_bin(const uint8_t *data, const size_t len) {
return sprint_bin_break(data, len, 0);
}
+
+char *sprint_hex_ascii(const uint8_t *data, const size_t len) {
+ static char buf[1024];
+ char *tmp = buf;
+ memset(buf, 0x00, 1024);
+ size_t max_len = (len > 1010) ? 1010 : len;
+
+ sprintf(tmp, "%s| ", sprint_hex(data, max_len) );
+
+ size_t i = 0;
+ size_t pos = (max_len * 3)+2;
+ while(i < max_len){
+ char c = data[i];
+ if ( (c < 32) || (c == 127))
+ c = '.';
+ sprintf(tmp+pos+i, "%c", c);
+ ++i;
+ }
+ return buf;
+}
+
+char *sprint_ascii(const uint8_t *data, const size_t len) {
+ static char buf[1024];
+ char *tmp = buf;
+ memset(buf, 0x00, 1024);
+ size_t max_len = (len > 1010) ? 1010 : len;
+ size_t i = 0;
+ while(i < max_len){
+ char c = data[i];
+ tmp[i] = ((c < 32) || (c == 127)) ? '.' : c;
+ ++i;
+ }
+ return buf;
+}
+
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
{
while (len--) {
}
}
+//least significant bit first
+void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest) {
+ for(int i = 0 ; i < len ; ++i) {
+ dest[i] = n & 1;
+ n >>= 1;
+ }
+}
+
+
// aa,bb,cc,dd,ee,ff,gg,hh, ii,jj,kk,ll,mm,nn,oo,pp
// to
// hh,gg,ff,ee,dd,cc,bb,aa, pp,oo,nn,mm,ll,kk,jj,ii
return tmp;
}
+// takes a uint8_t src array, for len items and reverses the byte order in blocksizes (8,16,32,64),
+// returns: the dest array contains the reordered src array.
+void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest){
+ for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){
+ for (size_t i = 0; i < blockSize; i++){
+ dest[i+(blockSize*block)] = src[(blockSize-1-i)+(blockSize*block)];
+ }
+ }
+}
+
//assumes little endian
char * printBits(size_t const size, void const * const ptr)
{
return strtoull(&line[bg], NULL, base);
else
return deflt;
-
- return 0;
}
int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt)
*(target)= GetParity(source + length / 2, ODD, length / 2);
}
+// xor two arrays together for len items. The dst array contains the new xored values.
void xor(unsigned char *dst, unsigned char *src, size_t len) {
for( ; len > 0; len--,dst++,src++)
*dst ^= *src;
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
-#include <time.h>
+#include <time.h> //time, gmtime
#include "data.h" //for FILE_PATH_SIZE
#ifndef ROTR
char * sprint_hex(const uint8_t * data, const size_t len);
char * sprint_bin(const uint8_t * data, const size_t len);
char * sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks);
+char * sprint_hex_ascii(const uint8_t *data, const size_t len);
+char * sprint_ascii(const uint8_t *data, const size_t len);
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t bytes_to_num(uint8_t* src, size_t len);
void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest);
+void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
char * printBits(size_t const size, void const * const ptr);
uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
+void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest);
char param_getchar(const char *line, int paramnum);
int param_getptr(const char *line, int *bg, int *en, int paramnum);
for (uint8_t i = 0; i < bitLen; i++){
ans ^= ((bits >> i) & 1);
}
- //PrintAndLog("DEBUG: ans: %d, ptype: %d",ans,pType);
+ if (g_debugMode) prnt("DEBUG: ans: %d, ptype: %d, bits: %08X",ans,pType,bits);
return (ans == pType);
}
{
uint32_t parityWd = 0;
size_t j = 0, bitCnt = 0;
- for (int word = 0; word < (bLen); word+=pLen){
- for (int bit=0; bit < pLen; bit++){
+ for (int word = 0; word < (bLen); word+=pLen) {
+ for (int bit=0; bit < pLen; bit++) {
parityWd = (parityWd << 1) | BitStream[startIdx+word+bit];
BitStream[j++] = (BitStream[startIdx+word+bit]);
}
+ if (word+pLen >= bLen) break;
+
j--; // overwrite parity with next data
// if parity fails then return 0
switch (pType) {
//search for given preamble in given BitStream and return success=1 or fail=0 and startIndex and length
uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx)
{
+ // Sanity check. If preamble length is bigger than bitstream length.
+ if ( *size <= pLen ) return 0;
+
uint8_t foundCnt=0;
for (int idx=0; idx < *size - pLen; idx++){
if (memcmp(BitStream+idx, preamble, pLen) == 0){
return 0;
}
+// search for given preamble in given BitStream and return success=1 or fail=0 and startIndex (where it was found)
+// does not look for a repeating preamble
+// em4x05/4x69 only sends preamble once, so look for it once in the first pLen bits
+// leave it generic so it could be reused later...
+bool onePreambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t size, size_t *startIdx) {
+ // Sanity check. If preamble length is bigger than bitstream length.
+ if ( size <= pLen ) return false;
+ for (size_t idx = 0; idx < size - pLen; idx++) {
+ if (memcmp(BitStream+idx, preamble, pLen) == 0) {
+ if (g_debugMode) prnt("DEBUG: preamble found at %u", idx);
+ *startIdx = idx;
+ return true;
+ }
+ }
+ return false;
+}
+
+// find start of modulating data (for fsk and psk) in case of beginning noise or slow chip startup.
+size_t findModStart(uint8_t dest[], size_t size, uint8_t threshold_value, uint8_t expWaveSize) {
+ size_t i = 0;
+ size_t waveSizeCnt = 0;
+ uint8_t thresholdCnt = 0;
+ bool isAboveThreshold = dest[i++] >= threshold_value;
+ for (; i < size-20; i++ ) {
+ if(dest[i] < threshold_value && isAboveThreshold) {
+ thresholdCnt++;
+ if (thresholdCnt > 2 && waveSizeCnt < expWaveSize+1) break;
+ isAboveThreshold = false;
+ waveSizeCnt = 0;
+ } else if (dest[i] >= threshold_value && !isAboveThreshold) {
+ thresholdCnt++;
+ if (thresholdCnt > 2 && waveSizeCnt < expWaveSize+1) break;
+ isAboveThreshold = true;
+ waveSizeCnt = 0;
+ } else {
+ waveSizeCnt++;
+ }
+ if (thresholdCnt > 10) break;
+ }
+ if (g_debugMode == 2) prnt("DEBUG: threshold Count reached at %u, count: %u",i, thresholdCnt);
+ return i;
+}
+
//by marshmellow
//takes 1s and 0s and searches for EM410x format - output EM ID
uint8_t Em410xDecode(uint8_t *BitStream, size_t *size, size_t *startIdx, uint32_t *hi, uint64_t *lo)
{
size_t last_transition = 0;
size_t idx = 1;
- //uint32_t maxVal=0;
if (fchigh==0) fchigh=10;
if (fclow==0) fclow=8;
//set the threshold close to 0 (graph) or 128 std to avoid static
size_t preLastSample = 0;
size_t LastSample = 0;
size_t currSample = 0;
- // sync to first lo-hi transition, and threshold
+ if ( size < 1024 ) return 0; // not enough samples
+
+ //find start of modulating data in trace
+ idx = findModStart(dest, size, threshold_value, fchigh);
// Need to threshold first sample
- // skip 160 samples to allow antenna/samples to settle
- if(dest[160] < threshold_value) dest[0] = 0;
+ if(dest[idx] < threshold_value) dest[0] = 0;
else dest[0] = 1;
-
+ idx++;
+
size_t numBits = 0;
// count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8)
// or 10 (fc/10) cycles but in practice due to noise etc we may end up with anywhere
// between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10
// (could also be fc/5 && fc/7 for fsk1 = 4-9)
- for(idx = 161; idx < size-20; idx++) {
+ for(; idx < size-20; idx++) {
// threshold current value
if (dest[idx] < threshold_value) dest[idx] = 0;
//do nothing with extra garbage
} else if (currSample < (fchigh-1)) { //6-8 = 8 sample waves (or 3-6 = 5)
//correct previous 9 wave surrounded by 8 waves (or 6 surrounded by 5)
- if (LastSample > (fchigh-2) && (preLastSample < (fchigh-1) || preLastSample == 0 )){
+ if (LastSample > (fchigh-2) && (preLastSample < (fchigh-1))){
dest[numBits-1]=1;
}
dest[numBits++]=1;
- } else if (currSample > (fchigh) && !numBits) { //12 + and first bit = unusable garbage
- //do nothing with beginning garbage
+ } else if (currSample > (fchigh+1) && numBits < 3) { //12 + and first two bit = unusable garbage
+ //do nothing with beginning garbage and reset.. should be rare..
+ numBits = 0;
} else if (currSample == (fclow+1) && LastSample == (fclow-1)) { // had a 7 then a 9 should be two 8's (or 4 then a 6 should be two 5's)
dest[numBits++]=1;
} else { //9+ = 10 sample waves (or 6+ = 7)
continue;
// else new peak
// if we got less than the small fc + tolerance then set it to the small fc
- if (fcCounter < fcLow+fcTol)
+ // if it is inbetween set it to the last counter
+ if (fcCounter < fcHigh && fcCounter > fcLow)
+ fcCounter = lastFCcnt;
+ else if (fcCounter < fcLow+fcTol)
fcCounter = fcLow;
else //set it to the large fc
fcCounter = fcHigh;
}
}
- if (ii<0) return 0; // oops we went too far
+ if (ii<2) return 0; // oops we went too far
return clk[ii];
}
uint8_t fcLens[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint16_t fcCnts[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t fcLensFnd = 0;
- uint8_t lastFCcnt=0;
+ uint8_t lastFCcnt = 0;
uint8_t fcCounter = 0;
size_t i;
- if (size == 0) return 0;
+ if (size < 180) return 0;
// prime i to first up transition
for (i = 160; i < size-20; i++)
size_t numBits=0;
uint8_t curPhase = *invert;
- size_t i, waveStart=1, waveEnd=0, firstFullWave=0, lastClkBit=0;
- uint8_t fc=0, fullWaveLen=0, tol=1;
- uint16_t errCnt=0, waveLenCnt=0;
- fc = countFC(dest, *size, 0);
+ size_t i=0, waveStart=1, waveEnd=0, firstFullWave=0, lastClkBit=0;
+ uint16_t fc=0, fullWaveLen=0, tol=1;
+ uint16_t errCnt=0, waveLenCnt=0, errCnt2=0;
+ fc = countFC(dest, *size, 1);
+ uint8_t fc2 = fc >> 8;
+ if (fc2 == 10) return -1; //fsk found - quit
+ fc = fc & 0xFF;
if (fc!=2 && fc!=4 && fc!=8) return -1;
//PrintAndLog("DEBUG: FC: %d",fc);
*clock = DetectPSKClock(dest, *size, *clock);
if (*clock == 0) return -1;
- int avgWaveVal=0, lastAvgWaveVal=0;
+
+ //find start of modulating data in trace
+ uint8_t threshold_value = 123; //-5
+ i = findModStart(dest, *size, threshold_value, fc);
+
//find first phase shift
- for (i=0; i<loopCnt; i++){
+ int avgWaveVal=0, lastAvgWaveVal=0;
+ waveStart = i;
+ for (; i<loopCnt; i++) {
+ // find peak
if (dest[i]+fc < dest[i+1] && dest[i+1] >= dest[i+2]){
waveEnd = i+1;
- //PrintAndLog("DEBUG: waveEnd: %d",waveEnd);
+ if (g_debugMode == 2) prnt("DEBUG PSK: waveEnd: %u, waveStart: %u",waveEnd, waveStart);
waveLenCnt = waveEnd-waveStart;
- if (waveLenCnt > fc && waveStart > fc && !(waveLenCnt > fc+2)){ //not first peak and is a large wave but not out of whack
+ if (waveLenCnt > fc && waveStart > fc && !(waveLenCnt > fc+3)){ //not first peak and is a large wave but not out of whack
lastAvgWaveVal = avgWaveVal/(waveLenCnt);
firstFullWave = waveStart;
fullWaveLen=waveLenCnt;
- //if average wave value is > graph 0 then it is an up wave or a 1
- if (lastAvgWaveVal > 123) curPhase ^= 1; //fudge graph 0 a little 123 vs 128
+ //if average wave value is > graph 0 then it is an up wave or a 1 (could cause inverting)
+ if (lastAvgWaveVal > threshold_value) curPhase ^= 1;
break;
}
waveStart = i+1;
//set start of wave as clock align
lastClkBit = firstFullWave;
if (g_debugMode==2) prnt("DEBUG PSK: firstFullWave: %u, waveLen: %u",firstFullWave,fullWaveLen);
- if (g_debugMode==2) prnt("DEBUG: clk: %d, lastClkBit: %u, fc: %u", *clock, lastClkBit,(unsigned int) fc);
+ if (g_debugMode==2) prnt("DEBUG PSK: clk: %d, lastClkBit: %u, fc: %u", *clock, lastClkBit,(unsigned int) fc);
waveStart = 0;
dest[numBits++] = curPhase; //set first read bit
for (i = firstFullWave + fullWaveLen - 1; i < *size-3; i++){
} else if (i+1 > lastClkBit + *clock + tol + fc){
lastClkBit += *clock; //no phase shift but clock bit
dest[numBits++] = curPhase;
+ } else if (waveLenCnt < fc - 1) { //wave is smaller than field clock (shouldn't happen often)
+ errCnt2++;
+ if(errCnt2 > 101) return errCnt2;
}
avgWaveVal = 0;
waveStart = i+1;
int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert);
uint8_t parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType);
uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx);
+bool onePreambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t size, size_t *startIdx);
int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert);
void psk2TOpsk1(uint8_t *BitStream, size_t size);
void psk1TOpsk2(uint8_t *BitStream, size_t size);