+int CmdLegicRfRawWrite(const char *Cmd) {
+
+ char cmdp = param_getchar(Cmd, 0);
+ if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_rawwrite();
+
+ uint32_t address = 0, data = 0, IV = 0;
+ char answer;
+
+ UsbCommand c = { CMD_RAW_WRITER_LEGIC_RF, {0,0,0} };
+ int res = sscanf(Cmd, "%x %x %x", &address, &data, &IV);
+ if(res < 2)
+ return usage_legic_rawwrite();
+
+ // OUT-OF-BOUNDS check
+ if(address > MAX_LENGTH)
+ return usage_legic_rawwrite();
+
+ if ( (IV & 0x7F) != IV ){
+ IV &= 0x7F;
+ PrintAndLog("Truncating IV to 7bits");
+ }
+ if ( (IV & 1) == 0 ){
+ IV |= 0x01; // IV must be odd
+ PrintAndLog("LSB of IV must be SET");
+ }
+ PrintAndLog("Current IV: 0x%02x", IV);
+
+ c.arg[0] = address;
+ c.arg[1] = data;
+ c.arg[2] = IV;
+
+ if (c.arg[0] == 0x05 || c.arg[0] == 0x06) {
+ PrintAndLog("############# DANGER !! #############");
+ PrintAndLog("# changing the DCF is irreversible #");
+ PrintAndLog("#####################################");
+ PrintAndLog("do youe really want to continue? y(es) n(o)");
+ if (scanf(" %c", &answer) > 0 && (answer == 'y' || answer == 'Y')) {
+ SendCommand(&c);
+ return 0;
+ }
+ return -1;
+ }
+
+ clearCommandBuffer();
+ SendCommand(&c);
+ return 0;
+}
+
+//TODO: write a help text (iceman)
+int CmdLegicRfFill(const char *Cmd) {
+ UsbCommand cmd = {CMD_WRITER_LEGIC_RF, {0,0,0} };
+ int res = sscanf(Cmd, " 0x%"llx" 0x%"llx" 0x%"llx, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]);
+ if(res != 3) {
+ PrintAndLog("Please specify the offset, length and value as two hex strings");
+ return -1;
+ }
+
+ int i;
+ UsbCommand c = {CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}};
+ memset(c.d.asBytes, cmd.arg[2], 48);
+
+ for(i = 0; i < 22; i++) {
+ c.arg[0] = i*48;
+
+ clearCommandBuffer();
+ SendCommand(&c);
+ WaitForResponse(CMD_ACK, NULL);
+ }
+ clearCommandBuffer();
+ SendCommand(&cmd);
+ return 0;
+ }
+
+void static calc4(uint8_t *cmd, uint8_t len){
+ crc_t crc;
+ //crc_init_ref(&crc, 4, 0x19 >> 1, 0x5, 0, TRUE, TRUE);
+ crc_init(&crc, 4, 0x19 >> 1, 0x5, 0);
+
+ crc_clear(&crc);
+ crc_update(&crc, 1, 1); /* CMD_READ */
+ crc_update(&crc, cmd[0], 8);
+ crc_update(&crc, cmd[1], 8);
+ printf("crc4 %X\n", reflect(crc_finish(&crc), 4) ) ;
+
+ crc_clear(&crc);
+ crc_update(&crc, 1, 1); /* CMD_READ */
+ crc_update(&crc, cmd[0], 8);
+ crc_update(&crc, cmd[1], 8);
+ printf("crc4 %X\n", crc_finish(&crc), 4 ) ;
+
+ printf("---- old ---\n");
+ crc_update2(&crc, 1, 1); /* CMD_READ */
+ crc_update2(&crc, cmd[0], 8);
+ crc_update2(&crc, cmd[1], 8);
+ printf("crc4 %X \n", reflect(crc_finish(&crc), 4) ) ;
+
+
+ crc_clear(&crc);
+ crc_update2(&crc, 1, 1); /* CMD_READ */
+ crc_update2(&crc, cmd[0], 8);
+ crc_update2(&crc, cmd[1], 8);
+ printf("crc4 %X\n", crc_finish(&crc), 4 ) ;
+}
+
+int CmdLegicCalcCrc8(const char *Cmd){
+
+ uint8_t *data = NULL;
+ uint8_t cmdp = 0, uidcrc = 0, type=0;
+ bool errors = false;
+ int len = 0;
+ int bg, en;
+
+ while(param_getchar(Cmd, cmdp) != 0x00) {
+ switch(param_getchar(Cmd, cmdp)) {
+ case 'b':
+ case 'B':
+ // peek at length of the input string so we can
+ // figure out how many elements to malloc in "data"
+ bg=en=0;
+ if (param_getptr(Cmd, &bg, &en, cmdp+1)) {
+ errors = true;
+ break;
+ }
+ len = (en - bg + 1);
+
+ // check that user entered even number of characters
+ // for hex data string
+ if (len & 1) {
+ errors = true;
+ break;
+ }
+
+ // it's possible for user to accidentally enter "b" parameter
+ // more than once - we have to clean previous malloc
+ if (data) free(data);
+ data = malloc(len >> 1);
+ if ( data == NULL ) {
+ PrintAndLog("Can't allocate memory. exiting");
+ errors = true;
+ break;
+ }
+
+ if (param_gethex(Cmd, cmdp+1, data, len)) {
+ errors = true;
+ break;
+ }
+
+ len >>= 1;
+ cmdp += 2;
+ break;
+ case 'u':
+ case 'U':
+ uidcrc = param_get8ex(Cmd, cmdp+1, 0, 16);
+ cmdp += 2;
+ break;
+ case 'c':
+ case 'C':
+ type = param_get8ex(Cmd, cmdp+1, 0, 10);
+ cmdp += 2;
+ break;
+ case 'h':
+ case 'H':
+ errors = true;
+ break;
+ default:
+ PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
+ errors = true;
+ break;
+ }
+ if (errors) break;
+ }
+ //Validations
+ if (errors){
+ if (data) free(data);
+ return usage_legic_calccrc8();
+ }
+
+ switch (type){
+ case 16:
+ PrintAndLog("Legic crc16: %X", CRC16Legic(data, len, uidcrc));
+ break;
+ case 4:
+ calc4(data, 0);
+ break;
+ default:
+ PrintAndLog("Legic crc8: %X", CRC8Legic(data, len) );
+ break;
+ }
+
+ if (data) free(data);
+ return 0;
+}
+
+static command_t CommandTable[] = {
+ {"help", CmdHelp, 1, "This help"},
+ {"decode", CmdLegicDecode, 0, "Display deobfuscated and decoded LEGIC RF tag data (use after hf legic reader)"},
+ {"read", CmdLegicRFRead, 0, "[offset][length] <iv> -- read bytes from a LEGIC card"},
+ {"save", CmdLegicSave, 0, "<filename> [<length>] -- Store samples"},
+ {"load", CmdLegicLoad, 0, "<filename> -- Restore samples"},
+ {"sim", CmdLegicRfSim, 0, "[phase drift [frame drift [req/resp drift]]] Start tag simulator (use after load or read)"},
+ {"write", CmdLegicRfWrite,0, "<offset> <length> <iv> -- Write sample buffer (user after load or read)"},
+ {"writeraw",CmdLegicRfRawWrite, 0, "<address> <value> <iv> -- Write direct to address"},
+ {"fill", CmdLegicRfFill, 0, "<offset> <length> <value> -- Fill/Write tag with constant value"},
+ {"crc8", CmdLegicCalcCrc8, 1, "Calculate Legic CRC8 over given hexbytes"},
+ {"info", CmdLegicCalcCrc8, 1, "Information"},
+ {NULL, NULL, 0, NULL}
+};
+
+int CmdHFLegic(const char *Cmd) {
+ clearCommandBuffer();
+ CmdsParse(CommandTable, Cmd);
+ return 0;