+ do {
+ if (ukbhit()) {
+ printf("\naborted via keyboard!\n");
+ break;
+ }
+
+ CmdLFRead("s");
+ getSamples("8201",true); //capture enough to get 2 complete preambles (4096*2+9)
+ } while (!CmdEM410xRead(""));
+
+ return 0;
+}
+
+//currently only supports manchester modulations
+// todo: helptext
+int CmdEM410xWatchnSpoof(const char *Cmd)
+{
+ // loops if the captured ID was in XL-format.
+ CmdEM410xWatch(Cmd);
+ PrintAndLog("# Replaying captured ID: %llu", g_em410xid);
+ CmdLFaskSim("");
+ return 0;
+}
+
+int CmdEM410xWrite(const char *Cmd)
+{
+ uint64_t id = 0xFFFFFFFFFFFFFFFF; // invalid id value
+ int card = 0xFF; // invalid card value
+ uint32_t clock = 0; // invalid clock value
+
+ sscanf(Cmd, "%" PRIx64 " %d %d", &id, &card, &clock);
+
+ // Check ID
+ if (id == 0xFFFFFFFFFFFFFFFF) {
+ PrintAndLog("Error! ID is required.\n");
+ return 0;
+ }
+ if (id >= 0x10000000000) {
+ PrintAndLog("Error! Given EM410x ID is longer than 40 bits.\n");
+ return 0;
+ }
+
+ // Check Card
+ if (card == 0xFF) {
+ PrintAndLog("Error! Card type required.\n");
+ return 0;
+ }
+ if (card < 0) {
+ PrintAndLog("Error! Bad card type selected.\n");
+ return 0;
+ }
+
+ // Check Clock
+ // Default: 64
+ if (clock == 0)
+ clock = 64;
+
+ // Allowed clock rates: 16, 32, 40 and 64
+ if ((clock != 16) && (clock != 32) && (clock != 64) && (clock != 40)) {
+ PrintAndLog("Error! Clock rate %d not valid. Supported clock rates are 16, 32, 40 and 64.\n", clock);
+ return 0;
+ }
+
+ if (card == 1) {
+ PrintAndLog("Writing %s tag with UID 0x%010" PRIx64 " (clock rate: %d)", "T55x7", id, clock);
+ // NOTE: We really should pass the clock in as a separate argument, but to
+ // provide for backwards-compatibility for older firmware, and to avoid
+ // having to add another argument to CMD_EM410X_WRITE_TAG, we just store
+ // the clock rate in bits 8-15 of the card value
+ card = (card & 0xFF) | ((clock << 8) & 0xFF00);
+ } else if (card == 0) {
+ PrintAndLog("Writing %s tag with UID 0x%010" PRIx64, "T5555", id, clock);
+ card = (card & 0xFF) | ((clock << 8) & 0xFF00);
+ } else {
+ PrintAndLog("Error! Bad card type selected.\n");
+ return 0;
+ }
+
+ UsbCommand c = {CMD_EM410X_WRITE_TAG, {card, (uint32_t)(id >> 32), (uint32_t)id}};
+ SendCommand(&c);
+ return 0;
+}
+
+bool EM_EndParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType)
+{
+ if (rows*cols>size) return FALSE;
+ uint8_t colP=0;
+ //assume last col is a parity and do not test
+ for (uint8_t colNum = 0; colNum < cols-1; colNum++) {
+ for (uint8_t rowNum = 0; rowNum < rows; rowNum++) {
+ colP ^= BitStream[(rowNum*cols)+colNum];
+ }
+ if (colP != pType) return FALSE;
+ }
+ return TRUE;
+}
+
+bool EM_ByteParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType)
+{
+ if (rows*cols>size) return FALSE;
+ uint8_t rowP=0;
+ //assume last row is a parity row and do not test
+ for (uint8_t rowNum = 0; rowNum < rows-1; rowNum++) {
+ for (uint8_t colNum = 0; colNum < cols; colNum++) {
+ rowP ^= BitStream[(rowNum*cols)+colNum];
+ }
+ if (rowP != pType) return FALSE;
+ }
+ return TRUE;
+}
+
+// EM word parity test.
+// 9*5 = 45 bits in total
+// 012345678|r1
+// 012345678|r2
+// 012345678|r3
+// 012345678|r4
+// ------------
+//c012345678| 0
+// |- must be zero
+
+bool EMwordparitytest(uint8_t *bits){
+
+ // last row/col parity must be 0
+ if (bits[44] != 0 ) return FALSE;
+
+ // col parity check
+ uint8_t c1 = bytebits_to_byte(bits, 8) ^ bytebits_to_byte(bits+9, 8) ^ bytebits_to_byte(bits+18, 8) ^ bytebits_to_byte(bits+27, 8);
+ uint8_t c2 = bytebits_to_byte(bits+36, 8);
+ if ( c1 != c2 ) return FALSE;
+
+ // row parity check
+ uint8_t rowP = 0;
+ for ( uint8_t i = 0; i < 36; ++i ) {
+
+ rowP ^= bits[i];
+ if ( i>0 && (i % 9) == 0) {
+
+ if ( rowP != EVEN )
+ return FALSE;
+
+ rowP = 0;
+ }
+ }
+ // all checks ok.
+ return TRUE;
+}
+
+
+//////////////// 4050 / 4450 commands
+int usage_lf_em4x50_dump(void) {
+ PrintAndLog("Dump EM4x50/EM4x69. Tag must be on antenna. ");
+ PrintAndLog("");
+ PrintAndLog("Usage: lf em 4x50dump [h] <pwd>");
+ PrintAndLog("Options:");
+ PrintAndLog(" h - this help");
+ PrintAndLog(" pwd - password (hex) (optional)");
+ PrintAndLog("samples:");
+ PrintAndLog(" lf em 4x50dump");
+ PrintAndLog(" lf em 4x50dump 11223344");
+ return 0;
+}
+int usage_lf_em4x50_read(void) {
+ PrintAndLog("Read EM 4x50/EM4x69. Tag must be on antenna. ");
+ PrintAndLog("");
+ PrintAndLog("Usage: lf em 4x50read [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 4x50read 1");
+ PrintAndLog(" lf em 4x50read 1 11223344");
+ return 0;
+}
+int usage_lf_em4x50_write(void) {
+ PrintAndLog("Write EM 4x50/4x69. Tag must be on antenna. ");
+ PrintAndLog("");
+ PrintAndLog("Usage: lf em 4x50write [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 4x50write 1 deadc0de");
+ PrintAndLog(" lf em 4x50write 1 deadc0de 11223344");
+ return 0;
+}
+
+uint32_t OutputEM4x50_Block(uint8_t *BitStream, size_t size, bool verbose, bool pTest)
+{
+ if (size<45) return 0;
+
+ uint32_t code = bytebits_to_byte(BitStream,8);
+ code = code<<8 | bytebits_to_byte(BitStream+9,8);
+ code = code<<8 | bytebits_to_byte(BitStream+18,8);
+ code = code<<8 | bytebits_to_byte(BitStream+27,8);
+
+ if (verbose || g_debugMode){
+ for (uint8_t i = 0; i<5; i++){
+ if (i == 4) PrintAndLog(""); //parity byte spacer
+ PrintAndLog("%d%d%d%d%d%d%d%d %d -> 0x%02x",
+ BitStream[i*9],
+ BitStream[i*9+1],
+ BitStream[i*9+2],
+ BitStream[i*9+3],
+ BitStream[i*9+4],
+ BitStream[i*9+5],
+ BitStream[i*9+6],
+ BitStream[i*9+7],
+ BitStream[i*9+8],
+ bytebits_to_byte(BitStream+i*9,8)
+ );
+ }
+ if (pTest)
+ PrintAndLog("Parity Passed");
+ else
+ PrintAndLog("Parity Failed");
+ }
+ return code;