Merge branch 'master' into allin
update 201127
This commit is contained in:
@@ -10,3 +10,5 @@ AEA684A6DAB23278 # AA1
|
||||
F0E1D2C3B4A59687 # Kd from PicoPass 2k documentation
|
||||
5CBCF1DA45D5FB4F # PicoPass Default Exchange Key
|
||||
31ad7ebd2f282168 # From HID multiclassSE reader
|
||||
6EFD46EFCBB3C875 # From pastebin: https://pastebin.com/uHqpjiuU
|
||||
E033CA419AEE43F9 # From pastebin: https://pastebin.com/uHqpjiuU
|
||||
@@ -1275,4 +1275,7 @@ AABAFFCC7612
|
||||
# gamefactory
|
||||
# ozdilek
|
||||
#
|
||||
17D071403C20
|
||||
17D071403C20
|
||||
#
|
||||
534F4C415249
|
||||
534f4c303232
|
||||
@@ -1178,11 +1178,11 @@ static int CmdHF14AAPDU(const char *Cmd) {
|
||||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "( " _YELLOW_("%s%s%s")" )",
|
||||
activateField ? "select" : "",
|
||||
leaveSignalON ? ", keep" : "",
|
||||
decodeTLV ? ", TLV" : ""
|
||||
);
|
||||
PrintAndLogEx(SUCCESS, "( " _YELLOW_("%s%s%s")" )",
|
||||
activateField ? "select" : "",
|
||||
leaveSignalON ? ", keep" : "",
|
||||
decodeTLV ? ", TLV" : ""
|
||||
);
|
||||
PrintAndLogEx(SUCCESS, ">>> %s", sprint_hex_inrow(data, datalen));
|
||||
|
||||
if (decodeAPDU) {
|
||||
@@ -1217,7 +1217,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
|
||||
"Sends an raw bytes over ISO14443a. With option to use TOPAZ 14a mode.",
|
||||
"hf 14a raw -sc 3000 -> select, crc, where 3000 == 'read block 00'\n"
|
||||
"hf 14a raw -ak -b 7 40 -> send 7 bit byte 0x40\n"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
@@ -1344,13 +1344,13 @@ static int waitCmd(bool i_select, uint32_t timeout) {
|
||||
|
||||
if (i_select == false && len >= 3) {
|
||||
bool crc = check_crc(CRC_14443_A, data, len);
|
||||
|
||||
|
||||
char s[16];
|
||||
sprintf(s,
|
||||
(crc) ? _GREEN_("%02X %02X") : _RED_("%02X %02X"),
|
||||
data[len - 2],
|
||||
data[len - 1]
|
||||
);
|
||||
sprintf(s,
|
||||
(crc) ? _GREEN_("%02X %02X") : _RED_("%02X %02X"),
|
||||
data[len - 2],
|
||||
data[len - 1]
|
||||
);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "%s[ %s ]", sprint_hex(data, len - 2), s);
|
||||
} else {
|
||||
|
||||
@@ -1725,7 +1725,7 @@ static int CmdHF15Write(const char *Cmd) {
|
||||
AddCrc15(req, reqlen);
|
||||
reqlen += 2;
|
||||
|
||||
PrintAndLogEx(INFO, "iso15693 writing to page %02d (0x%02X) | data ", pagenum, pagenum);
|
||||
PrintAndLogEx(INFO, "iso15693 writing to page %02d (0x%02X) | data [ %s ] ", pagenum, pagenum, sprint_hex(req, reqlen));
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5444,7 +5444,7 @@ static command_t CommandTable[] = {
|
||||
{"esave", CmdHF14AMfESave, IfPm3Iso14443a, "Save to file emul dump"},
|
||||
{"eset", CmdHF14AMfESet, IfPm3Iso14443a, "Set simulator memory block"},
|
||||
{"eview", CmdHF14AMfEView, IfPm3Iso14443a, "View emul memory"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic") " -----------------------"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen1") " -----------------------"},
|
||||
{"cgetblk", CmdHF14AMfCGetBlk, IfPm3Iso14443a, "Read block"},
|
||||
{"cgetsc", CmdHF14AMfCGetSc, IfPm3Iso14443a, "Read sector"},
|
||||
{"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump"},
|
||||
|
||||
@@ -395,9 +395,9 @@ static char *getCardSizeStr(uint8_t fsize) {
|
||||
|
||||
// is LSB set?
|
||||
if (fsize & 1)
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _GREEN_("%d - %d bytes") ")", fsize, usize, lsize);
|
||||
snprintf(retStr, sizeof(buf), "0x%02X ( " _GREEN_("%d - %d bytes") " )", fsize, usize, lsize);
|
||||
else
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _GREEN_("%d bytes") ")", fsize, lsize);
|
||||
snprintf(retStr, sizeof(buf), "0x%02X ( " _GREEN_("%d bytes") " )", fsize, lsize);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -407,14 +407,14 @@ static char *getProtocolStr(uint8_t id, bool hw) {
|
||||
char *retStr = buf;
|
||||
|
||||
if (id == 0x04) {
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("ISO 14443-3 MIFARE, 14443-4") ")", id);
|
||||
snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("ISO 14443-3 MIFARE, 14443-4") " )", id);
|
||||
} else if (id == 0x05) {
|
||||
if (hw)
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("ISO 14443-2, 14443-3") ")", id);
|
||||
snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("ISO 14443-2, 14443-3") " )", id);
|
||||
else
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("ISO 14443-3, 14443-4") ")", id);
|
||||
snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") " )", id);
|
||||
} else {
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("Unknown") ")", id);
|
||||
snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("Unknown") " )", id);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
@@ -425,19 +425,21 @@ static char *getVersionStr(uint8_t major, uint8_t minor) {
|
||||
char *retStr = buf;
|
||||
|
||||
if (major == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire MF3ICD40") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire MF3ICD40") " )", major, minor);
|
||||
else if (major == 0x01 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV1") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV1") " )", major, minor);
|
||||
else if (major == 0x12 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV2") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV2") " )", major, minor);
|
||||
else if (major == 0x42 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV2") " )", major, minor);
|
||||
else if (major == 0x33 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV3") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV3") " )", major, minor);
|
||||
else if (major == 0x30 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire Light") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire Light") " )", major, minor);
|
||||
else if (major == 0x10 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("NTAG413DNA") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("NTAG413DNA") " )", major, minor);
|
||||
else
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("Unknown") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x ( " _YELLOW_("Unknown") " )", major, minor);
|
||||
return buf;
|
||||
|
||||
//04 01 01 01 00 1A 05
|
||||
@@ -1180,7 +1182,7 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
|
||||
key 8b
|
||||
cpy 8b
|
||||
crc 2b
|
||||
padding
|
||||
padding
|
||||
*/
|
||||
|
||||
// Variable length ciphered key data 24-42 bytes plus padding..
|
||||
@@ -1188,11 +1190,11 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
|
||||
sAPDU apdu = {0x90, MFDES_CHANGE_KEY, 0x00, 0x00, 0x01, data}; // 0xC4
|
||||
|
||||
size_t cmdcnt = 0;
|
||||
|
||||
|
||||
uint8_t new_key_length = 16;
|
||||
switch (new_algo) {
|
||||
case MFDES_ALGO_DES:
|
||||
// double
|
||||
// double
|
||||
memcpy(data + cmdcnt + 1, new_key, new_key_length);
|
||||
memcpy(data + cmdcnt + 1 + new_key_length, new_key, new_key_length);
|
||||
break;
|
||||
@@ -1381,15 +1383,43 @@ static int handler_desfire_signature(uint8_t *signature, size_t *signature_len)
|
||||
return res;
|
||||
}
|
||||
|
||||
// --- KEY SETTING
|
||||
static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) {
|
||||
// --- KEY VERSION
|
||||
static int desfire_print_keyversion(uint8_t key_idx, uint8_t key_version) {
|
||||
PrintAndLogEx(SUCCESS, " Key [%u] Version : %d (0x%02x)", key_idx, key_version, key_version);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int handler_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) {
|
||||
if (num_versions == NULL) {
|
||||
PrintAndLogEx(DEBUG, "NUM_VERSIONS=NULL");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64
|
||||
uint32_t recv_len = 0;
|
||||
uint16_t sw = 0;
|
||||
int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0, true);
|
||||
|
||||
if (res != PM3_SUCCESS)
|
||||
return res;
|
||||
|
||||
if (sw != status(MFDES_S_OPERATION_OK))
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// --- KEY SETTING Application Master Key
|
||||
static int desfire_print_amk_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) {
|
||||
PrintAndLogEx(SUCCESS, " AID Key settings : 0x%02x", key_settings);
|
||||
// 2 MSB denotes
|
||||
const char *str = " Max key number and type : %d, " _YELLOW_("%s");
|
||||
|
||||
if (algo == MFDES_ALGO_DES) PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "(3)DES");
|
||||
else if (algo == MFDES_ALGO_AES) PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "AES");
|
||||
else if (algo == MFDES_ALGO_3K3DES) PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "3K3DES");
|
||||
if (algo == MFDES_ALGO_DES)
|
||||
PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "(3)DES");
|
||||
else if (algo == MFDES_ALGO_AES)
|
||||
PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "AES");
|
||||
else if (algo == MFDES_ALGO_3K3DES)
|
||||
PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "3K3DES");
|
||||
|
||||
//PrintAndLogEx(SUCCESS, " Max number of keys in AID : %d", num_keys & 0x3F);
|
||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||
@@ -1408,14 +1438,69 @@ static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys, int
|
||||
PrintAndLogEx(SUCCESS, " -- All keys (except AMK,see Bit0) within this application are frozen");
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(SUCCESS, " -- Authentication with the specified key is necessary to change any key.\nA change key and a PICC master key (CMK) can only be changed after authentication with the master key.\nFor keys other then the master or change key, an authentication with the same key is needed.");
|
||||
PrintAndLogEx(SUCCESS,
|
||||
" -- Authentication with the specified key is necessary to change any key.\n"
|
||||
"A change key and a PICC master key (CMK) can only be changed after authentication with the master key.\n"
|
||||
"For keys other then the master or change key, an authentication with the same key is needed."
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO");
|
||||
PrintAndLogEx(SUCCESS, " [0x04] AMK required for create/delete : %s", (key_settings & (1 << 2)) ? "NO" : "YES");
|
||||
PrintAndLogEx(SUCCESS, " [0x02] Directory list access with AMK : %s", (key_settings & (1 << 1)) ? "NO" : "YES");
|
||||
PrintAndLogEx(SUCCESS, " [0x01] AMK is changeable : %s", (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO");
|
||||
PrintAndLogEx(SUCCESS, " [1000] AMK Configuration changeable : %s", (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)");
|
||||
PrintAndLogEx(SUCCESS, " [0100] AMK required for create/delete : %s", (key_settings & (1 << 2)) ? "NO" : "YES");
|
||||
PrintAndLogEx(SUCCESS, " [0010] Directory list access with AMK : %s", (key_settings & (1 << 1)) ? "NO" : "YES");
|
||||
PrintAndLogEx(SUCCESS, " [0001] AMK is changeable : %s", (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// --- KEY SETTING PICC Master Key (CMK)
|
||||
static int desfire_print_piccmk_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) {
|
||||
//PrintAndLogEx(INFO, "--- " _CYAN_("PICC Master Key (CMK) settings"));
|
||||
// number of Master keys (0x01)
|
||||
PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F));
|
||||
const char *str = " Operation of PICC master key : " _YELLOW_("%s");
|
||||
|
||||
if (algo == MFDES_ALGO_DES)
|
||||
PrintAndLogEx(SUCCESS, str, "(3)DES");
|
||||
else if (algo == MFDES_ALGO_AES)
|
||||
PrintAndLogEx(SUCCESS, str, "AES");
|
||||
else if (algo == MFDES_ALGO_3K3DES)
|
||||
PrintAndLogEx(SUCCESS, str, "3K3DES");
|
||||
|
||||
uint8_t cmk_num_versions = 0;
|
||||
if (handler_desfire_keyversion(0, &cmk_num_versions) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions, cmk_num_versions);
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, " ----------------------------------------------------------");
|
||||
|
||||
// Authentication tests
|
||||
int res = test_desfire_authenticate();
|
||||
if (res == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
|
||||
|
||||
res = test_desfire_authenticate_iso();
|
||||
if (res == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
|
||||
|
||||
res = test_desfire_authenticate_aes();
|
||||
if (res == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
|
||||
|
||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||
PrintAndLogEx(INFO, " Key setting: 0x%02X [%c%c%c%c]",
|
||||
key_settings,
|
||||
(key_settings & (1 << 3)) ? '1' : '0',
|
||||
(key_settings & (1 << 2)) ? '1' : '0',
|
||||
(key_settings & (1 << 1)) ? '1' : '0',
|
||||
(key_settings & (1 << 0)) ? '1' : '0'
|
||||
);
|
||||
|
||||
PrintAndLogEx(SUCCESS, " [1...] CMK Configuration changeable : %s", (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)");
|
||||
PrintAndLogEx(SUCCESS, " [.1..] CMK required for create/delete : %s", (key_settings & (1 << 2)) ? _GREEN_("NO") : "YES");
|
||||
PrintAndLogEx(SUCCESS, " [..1.] Directory list access with CMK : %s", (key_settings & (1 << 1)) ? _GREEN_("NO") : "YES");
|
||||
PrintAndLogEx(SUCCESS, " [...1] CMK is changeable : %s", (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)");
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1445,31 +1530,6 @@ static int handler_desfire_getkeysettings(uint8_t *key_settings, uint8_t *num_ke
|
||||
return res;
|
||||
}
|
||||
|
||||
// --- KEY VERSION
|
||||
static int desfire_print_keyversion(uint8_t key_idx, uint8_t key_version) {
|
||||
PrintAndLogEx(SUCCESS, " Key [%u] Version : %d (0x%02x)", key_idx, key_version, key_version);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int handler_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) {
|
||||
if (num_versions == NULL) {
|
||||
PrintAndLogEx(DEBUG, "NUM_VERSIONS=NULL");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64
|
||||
uint32_t recv_len = 0;
|
||||
uint16_t sw = 0;
|
||||
int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0, true);
|
||||
|
||||
if (res != PM3_SUCCESS)
|
||||
return res;
|
||||
|
||||
if (sw != status(MFDES_S_OPERATION_OK))
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int handler_desfire_getuid(uint8_t *uid) {
|
||||
if (uid == NULL) {
|
||||
PrintAndLogEx(DEBUG, "UID=NULL");
|
||||
@@ -1585,14 +1645,14 @@ static int handler_desfire_select_application(uint8_t *aid) {
|
||||
sAPDU apdu = {0x90, MFDES_SELECT_APPLICATION, 0x00, 0x00, 0x03, aid}; //0x5a
|
||||
uint32_t recv_len = 0;
|
||||
uint16_t sw = 0;
|
||||
|
||||
|
||||
int res = send_desfire_cmd(&apdu, !tag->rf_field_on, NULL, &recv_len, &sw, sizeof(dfname_t), true);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING,
|
||||
_RED_(" Can't select AID 0x%X -> %s"),
|
||||
(aid[2] << 16) + (aid[1] << 8) + aid[0],
|
||||
GetErrorString(res, &sw)
|
||||
);
|
||||
_RED_(" Can't select AID 0x%X -> %s"),
|
||||
(aid[2] << 16) + (aid[1] << 8) + aid[0],
|
||||
GetErrorString(res, &sw)
|
||||
);
|
||||
DropFieldDesfire();
|
||||
return res;
|
||||
}
|
||||
@@ -1672,17 +1732,17 @@ static int handler_desfire_createapp(aidhdr_t *aidhdr, bool usename, bool usefid
|
||||
apdu.Lc = apdu.Lc - sizeof(aidhdr->fid);
|
||||
}
|
||||
uint8_t *data = NULL;
|
||||
|
||||
|
||||
// skip over FID if not used.
|
||||
if (usefid == false && usename) {
|
||||
data = calloc(apdu.Lc, sizeof(uint8_t));
|
||||
apdu.data = data;
|
||||
|
||||
|
||||
memcpy(data, aidhdr->aid, sizeof(aidhdr->aid));
|
||||
data[3] = aidhdr->keysetting1;
|
||||
data[4] = aidhdr->keysetting2;
|
||||
memcpy(data + 5, aidhdr->name, sizeof(aidhdr->name));
|
||||
|
||||
|
||||
PrintAndLogEx(INFO, "new data: %s", sprint_hex_inrow(data, apdu.Lc));
|
||||
}
|
||||
|
||||
@@ -2006,6 +2066,8 @@ static int handler_desfire_create_backup_file(mfdes_file_t *file) {
|
||||
static int getKeySettings(uint8_t *aid) {
|
||||
if (aid == NULL) return PM3_EINVARG;
|
||||
|
||||
uint8_t num_keys = 0;
|
||||
uint8_t key_setting = 0;
|
||||
int res = 0;
|
||||
if (memcmp(aid, "\x00\x00\x00", 3) == 0) {
|
||||
|
||||
@@ -2013,50 +2075,15 @@ static int getKeySettings(uint8_t *aid) {
|
||||
//PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
|
||||
|
||||
// KEY Settings - AMK
|
||||
uint8_t num_keys = 0;
|
||||
uint8_t key_setting = 0;
|
||||
mifare_des_authalgo_t algo = MFDES_ALGO_DES;
|
||||
res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys);
|
||||
|
||||
if (res == PM3_SUCCESS) {
|
||||
// number of Master keys (0x01)
|
||||
PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F));
|
||||
|
||||
PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_setting & (1 << 3)) ? _GREEN_("YES") : "NO");
|
||||
PrintAndLogEx(SUCCESS, " [0x04] CMK required for create/delete : %s", (key_setting & (1 << 2)) ? _GREEN_("YES") : "NO");
|
||||
PrintAndLogEx(SUCCESS, " [0x02] Directory list access with CMK : %s", (key_setting & (1 << 1)) ? _GREEN_("YES") : "NO");
|
||||
PrintAndLogEx(SUCCESS, " [0x01] CMK is changeable : %s", (key_setting & (1 << 0)) ? _GREEN_("YES") : "NO");
|
||||
desfire_print_piccmk_keysetting(key_setting, num_keys, algo);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
|
||||
PrintAndLogEx(WARNING, _RED_(" Can't read PICC Master key settings"));
|
||||
}
|
||||
|
||||
const char *str = " Operation of PICC master key : " _YELLOW_("%s");
|
||||
|
||||
if (algo == MFDES_ALGO_DES) PrintAndLogEx(SUCCESS, str, "(3)DES");
|
||||
else if (algo == MFDES_ALGO_AES) PrintAndLogEx(SUCCESS, str, "AES");
|
||||
else if (algo == MFDES_ALGO_3K3DES) PrintAndLogEx(SUCCESS, str, "3K3DES");
|
||||
|
||||
uint8_t cmk_num_versions = 0;
|
||||
if (handler_desfire_keyversion(0, &cmk_num_versions) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions, cmk_num_versions);
|
||||
PrintAndLogEx(INFO, " ----------------------------------------------------------");
|
||||
}
|
||||
|
||||
// Authentication tests
|
||||
res = test_desfire_authenticate();
|
||||
if (res == PM3_ETIMEOUT) return res;
|
||||
PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
|
||||
|
||||
res = test_desfire_authenticate_iso();
|
||||
if (res == PM3_ETIMEOUT) return res;
|
||||
PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
|
||||
|
||||
res = test_desfire_authenticate_aes();
|
||||
if (res == PM3_ETIMEOUT) return res;
|
||||
PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
|
||||
|
||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||
|
||||
} else {
|
||||
|
||||
// AID - APPLICATION MASTER KEYS
|
||||
@@ -2065,12 +2092,10 @@ static int getKeySettings(uint8_t *aid) {
|
||||
if (res != PM3_SUCCESS) return res;
|
||||
|
||||
// KEY Settings - AMK
|
||||
uint8_t num_keys = 0;
|
||||
uint8_t key_setting = 0;
|
||||
mifare_des_authalgo_t algo = MFDES_ALGO_DES;
|
||||
res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys);
|
||||
if (res == PM3_SUCCESS) {
|
||||
desfire_print_keysetting(key_setting, num_keys, algo);
|
||||
desfire_print_amk_keysetting(key_setting, num_keys, algo);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
|
||||
}
|
||||
@@ -2393,7 +2418,7 @@ static int CmdHF14ADesCreateApp(const char *Cmd) {
|
||||
if (usefid)
|
||||
memcpy(aidhdr.fid, fid, sizeof(aidhdr.fid));
|
||||
|
||||
if (usename)
|
||||
if (usename)
|
||||
memcpy(aidhdr.name, name, sizeof(aidhdr.name));
|
||||
|
||||
PrintAndLogEx(INFO, "Creating AID using:");
|
||||
@@ -2405,14 +2430,14 @@ static int CmdHF14ADesCreateApp(const char *Cmd) {
|
||||
if (usename)
|
||||
PrintAndLogEx(INFO, "DF Name %s", aidhdr.name);
|
||||
|
||||
/*
|
||||
uint8_t rootaid[3] = {0x00, 0x00, 0x00};
|
||||
int res = handler_desfire_select_application(rootaid);
|
||||
if (res != PM3_SUCCESS) {
|
||||
DropFieldDesfire();
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
uint8_t rootaid[3] = {0x00, 0x00, 0x00};
|
||||
int res = handler_desfire_select_application(rootaid);
|
||||
if (res != PM3_SUCCESS) {
|
||||
DropFieldDesfire();
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
int res = handler_desfire_createapp(&aidhdr, usename, usefid);
|
||||
DropFieldDesfire();
|
||||
@@ -3436,6 +3461,8 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||
PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), info.details[12], info.details[13]);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information"));
|
||||
PrintAndLogEx(INFO, " raw: %s", sprint_hex_inrow(info.versionHW, sizeof(info.versionHW)));
|
||||
|
||||
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(info.versionHW[0]));
|
||||
PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), info.versionHW[1]);
|
||||
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), info.versionHW[2]);
|
||||
@@ -3444,6 +3471,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(info.versionHW[6], true));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Software Information"));
|
||||
PrintAndLogEx(INFO, " raw: %s", sprint_hex_inrow(info.versionSW, sizeof(info.versionSW)));
|
||||
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(info.versionSW[0]));
|
||||
PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), info.versionSW[1]);
|
||||
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), info.versionSW[2]);
|
||||
@@ -3670,7 +3698,7 @@ static int CmdHF14ADesDump(const char *Cmd) {
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
DropFieldDesfire();
|
||||
|
||||
|
||||
@@ -1882,7 +1882,7 @@ uint32_t static em4x05_Sniff_GetBlock(char *bits, bool fwd) {
|
||||
if (parity != (bits[35] - '0'))
|
||||
parityerror = true;
|
||||
|
||||
if (parityerror)
|
||||
if (parityerror)
|
||||
PrintAndLogEx(ERR, "parity error : ");
|
||||
|
||||
if (!fwd) {
|
||||
|
||||
@@ -179,68 +179,56 @@ static int CmdKeriDemod(const char *Cmd) {
|
||||
return demodKeri(true);
|
||||
}
|
||||
|
||||
static int CmdKeriRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 10000);
|
||||
return demodKeri(true);
|
||||
}
|
||||
|
||||
static int CmdKeriClone(const char *Cmd) {
|
||||
|
||||
bool q5 = false, em = false;
|
||||
|
||||
uint8_t keritype[2] = {'i'}; // default to internalid
|
||||
int typeLen = 0;
|
||||
uint32_t fc = 0;
|
||||
uint32_t cid = 0;
|
||||
uint32_t internalid = 0;
|
||||
uint32_t blocks[3] = {
|
||||
T55x7_TESTMODE_DISABLED |
|
||||
T55x7_X_MODE |
|
||||
T55x7_MODULATION_PSK1 |
|
||||
T55x7_PSKCF_RF_2 |
|
||||
2 << T55x7_MAXBLOCK_SHIFT,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
// dynamic bitrate used
|
||||
blocks[0] |= 0xF << 18;
|
||||
|
||||
static int CmdKeriReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf keri clone",
|
||||
"clone a KERI tag to a T55x7, Q5/T5555 or EM4305/4469 tag",
|
||||
"lf keri clone -t i --id 12345\n"
|
||||
"lf keri clone -t m --fc 6 --id 12345\n");
|
||||
CLIParserInit(&ctx, "lf keri reader",
|
||||
"read a keri tag",
|
||||
"lf keri reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
do {
|
||||
lf_read(false, 10000);
|
||||
demodKeri(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdKeriClone(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf keri clone",
|
||||
"clone a KERI tag to a T55x7, Q5/T5555 or EM4305/4469 tag",
|
||||
"lf keri clone -t i --cn 12345 -> Internal ID\n"
|
||||
"lf keri clone -t m --fc 6 --cn 12345 -> MS ID\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("q", "q5", "specify writing to Q5/T5555 tag"),
|
||||
arg_str0("t", "type", "<m|i>", "Type m - MS, i - Internal ID"),
|
||||
arg_int0(NULL, "fc", "<dec>", "Facility Code"),
|
||||
arg_int1(NULL, "id", "<dec>", "Keri ID"),
|
||||
arg_lit0(NULL, "em", "specify writing to EM4305/4469 tag"),
|
||||
arg_int1(NULL, "cn", "<dec>", "KERI card ID"),
|
||||
arg_lit0(NULL, "q5", "specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
if (arg_get_lit(ctx, 1)) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
q5 = true;
|
||||
}
|
||||
if (arg_get_lit(ctx, 5)) {
|
||||
blocks[0] = EM4305_KERI_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
em = true;
|
||||
}
|
||||
uint8_t keritype[2] = {'i'}; // default to internalid
|
||||
int typeLen = sizeof(keritype);
|
||||
CLIGetStrWithReturn(ctx, 1, keritype, &typeLen);
|
||||
|
||||
typeLen = sizeof(keritype);
|
||||
CLIGetStrWithReturn(ctx, 2, keritype, &typeLen);
|
||||
|
||||
fc = arg_get_int_def(ctx, 3, 0);
|
||||
cid = arg_get_int_def(ctx, 4, 0);
|
||||
uint32_t fc = arg_get_int_def(ctx, 2, 0);
|
||||
uint32_t cid = arg_get_int_def(ctx, 3, 0);
|
||||
bool q5 = arg_get_lit(ctx, 4);
|
||||
bool em = arg_get_lit(ctx, 5);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
@@ -249,6 +237,7 @@ static int CmdKeriClone(const char *Cmd) {
|
||||
}
|
||||
|
||||
// Setup card data/build internal id
|
||||
uint32_t internalid = 0;
|
||||
switch (keritype[0]) {
|
||||
case 'i' : // Internal ID
|
||||
// MSB is ONE
|
||||
@@ -262,6 +251,24 @@ static int CmdKeriClone(const char *Cmd) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t blocks[3];
|
||||
blocks[0] = T55x7_TESTMODE_DISABLED | T55x7_X_MODE | T55x7_MODULATION_PSK1 | T55x7_PSKCF_RF_2 | 2 << T55x7_MAXBLOCK_SHIFT;
|
||||
// dynamic bitrate used
|
||||
blocks[0] |= 0xF << 18;
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
if (em) {
|
||||
blocks[0] = EM4305_KERI_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
|
||||
// Prepare and write to card
|
||||
// 3 LSB is ONE
|
||||
uint64_t data = ((uint64_t)internalid << 3) + 7;
|
||||
@@ -288,19 +295,18 @@ static int CmdKeriSim(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf keri sim",
|
||||
"Enables simulation of KERI card with card number.",
|
||||
"lf keri sim --id 112233"
|
||||
"Enables simulation of KERI card with internal ID.\n"
|
||||
"You supply a KERI card id and it will converted to a KERI internal ID.",
|
||||
"lf keri sim --cn 112233"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int1(NULL, "id", "<dec>", "KERI Internal ID"),
|
||||
arg_u64_1(NULL, "id", "<dec>", "KERI card ID"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint64_t internalid = arg_get_int_def(ctx, 1, 0);
|
||||
|
||||
uint64_t internalid = arg_get_u64_def(ctx, 1, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
internalid |= 0x80000000;
|
||||
@@ -314,7 +320,7 @@ static int CmdKeriSim(const char *Cmd) {
|
||||
bs[j++] = ((internalid >> i) & 1);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating KERI - Internal Id: %" PRIu64, internalid);
|
||||
PrintAndLogEx(SUCCESS, "Simulating KERI - Internal Id " _YELLOW_("%" PRIu64), internalid);
|
||||
|
||||
lf_psksim_t *payload = calloc(1, sizeof(lf_psksim_t) + sizeof(bs));
|
||||
payload->carrier = 2;
|
||||
@@ -322,8 +328,6 @@ static int CmdKeriSim(const char *Cmd) {
|
||||
payload->clock = 32;
|
||||
memcpy(payload->data, bs, sizeof(bs));
|
||||
|
||||
PrintAndLogEx(INFO, "Simulating");
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + sizeof(bs));
|
||||
free(payload);
|
||||
@@ -338,11 +342,11 @@ static int CmdKeriSim(const char *Cmd) {
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdKeriDemod, AlwaysAvailable, "Demodulate an KERI tag from the GraphBuffer"},
|
||||
{"read", CmdKeriRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdKeriClone, IfPm3Lf, "clone KERI tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdKeriSim, IfPm3Lf, "simulate KERI tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdKeriDemod, AlwaysAvailable, "Demodulate an KERI tag from the GraphBuffer"},
|
||||
{"reader", CmdKeriReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdKeriClone, IfPm3Lf, "clone KERI tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdKeriSim, IfPm3Lf, "simulate KERI tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -9,22 +9,20 @@
|
||||
// PSK1, RF/32, 64 bits long, at 74 kHz
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfmotorola.h"
|
||||
|
||||
#include <ctype.h> //tolower
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include <ctype.h> // tolower
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "common.h"
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "cmdlf.h" // cmdlfconfig
|
||||
#include "cliparser.h" // cli parse input
|
||||
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "cmdlf.h" // cmdlfconfig
|
||||
#include "cliparser.h" // cli parse input
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
@@ -124,7 +122,22 @@ static int CmdMotorolaDemod(const char *Cmd) {
|
||||
return demodMotorola(true);
|
||||
}
|
||||
|
||||
static int CmdMotorolaRead(const char *Cmd) {
|
||||
static int CmdMotorolaReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf motorola reader",
|
||||
"read a Motorola tag",
|
||||
"lf motorola reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// Motorola Flexpass seem to work at 74 kHz
|
||||
// and take about 4400 samples to befor modulating
|
||||
sample_config sc = {
|
||||
@@ -138,61 +151,86 @@ static int CmdMotorolaRead(const char *Cmd) {
|
||||
};
|
||||
lf_config(&sc);
|
||||
|
||||
// 64 * 32 * 2 * n-ish
|
||||
lf_read(false, 5000);
|
||||
do {
|
||||
// 64 * 32 * 2 * n-ish
|
||||
lf_read(false, 5000);
|
||||
demodMotorola(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
// reset back to 125 kHz
|
||||
sc.divisor = LF_DIVISOR_125;
|
||||
sc.samples_to_skip = 0;
|
||||
lf_config(&sc);
|
||||
return demodMotorola(true);
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdMotorolaClone(const char *Cmd) {
|
||||
|
||||
uint32_t blocks[3] = {0};
|
||||
uint8_t data[8];
|
||||
int datalen = 0;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf motorola clone",
|
||||
"clone Motorola UID to T55x7 or Q5/T5555 tag\n"
|
||||
"clone Motorola UID to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
|
||||
"defaults to 64 bit format",
|
||||
"lf motorola clone -r a0000000a0002021"
|
||||
"lf motorola clone --raw a0000000a0002021\n"
|
||||
"lf motorola clone --q5 --raw a0000000a0002021 -> encode for Q5/T5555 tag\n"
|
||||
"lf motorola clone --em --raw a0000000a0002021 -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx1("r", "raw", "<hex>", "raw bytes"),
|
||||
arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_strx1("r", "raw", "<hex>", "raw hex bytes. 8 bytes"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
CLIGetHexWithReturn(ctx, 1, data, &datalen);
|
||||
bool is_t5555 = arg_get_lit(ctx, 2);
|
||||
|
||||
int raw_len = 0;
|
||||
uint8_t raw[8];
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
//TODO add selection of chip for Q5 or T55x7
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Target chip " _YELLOW_("%s"), (is_t5555) ? "Q5/T5555" : "T55x7");
|
||||
//TODO add selection of chip for Q5 or T55x7
|
||||
uint32_t blocks[3] = {0};
|
||||
|
||||
blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT);
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_MOTOROLA_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
blocks[1] = bytes_to_num(raw, 4);
|
||||
blocks[2] = bytes_to_num(raw + 4, 4);
|
||||
|
||||
// config for Motorola 64 format (RF/32;PSK1 with RF/2; Maxblock=2)
|
||||
PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit tag");
|
||||
PrintAndLogEx(INFO, "Using raw " _GREEN_("%s"), sprint_hex_inrow(data, datalen));
|
||||
|
||||
if (is_t5555)
|
||||
blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
else
|
||||
blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT);
|
||||
|
||||
|
||||
blocks[1] = bytes_to_num(data, 4);
|
||||
blocks[2] = bytes_to_num(data + 4, 4);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit to " _YELLOW_("%s") " with raw " _GREEN_("%s")
|
||||
, cardtype
|
||||
, sprint_hex_inrow(raw, sizeof(raw))
|
||||
);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf motorola read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf motorola reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -205,11 +243,11 @@ static int CmdMotorolaSim(const char *Cmd) {
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdMotorolaDemod, AlwaysAvailable, "Demodulate an MOTOROLA tag from the GraphBuffer"},
|
||||
{"read", CmdMotorolaRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdMotorolaClone, IfPm3Lf, "clone MOTOROLA tag to T55x7"},
|
||||
{"sim", CmdMotorolaSim, IfPm3Lf, "simulate MOTOROLA tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdMotorolaDemod, AlwaysAvailable, "Demodulate an MOTOROLA tag from the GraphBuffer"},
|
||||
{"reader", CmdMotorolaReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdMotorolaClone, IfPm3Lf, "clone MOTOROLA tag to T55x7"},
|
||||
{"sim", CmdMotorolaSim, IfPm3Lf, "simulate MOTOROLA tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -266,5 +304,5 @@ int detectMotorola(uint8_t *dest, size_t *size) {
|
||||
}
|
||||
|
||||
int readMotorolaUid(void) {
|
||||
return (CmdMotorolaRead("") == PM3_SUCCESS);
|
||||
return (CmdMotorolaReader("") == PM3_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -9,20 +9,21 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfnexwatch.h"
|
||||
#include <inttypes.h> // PRIu
|
||||
#include <inttypes.h> // PRIu
|
||||
#include <string.h>
|
||||
#include <ctype.h> // tolower
|
||||
#include <stdlib.h> // free, alloc
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include <ctype.h> // tolower
|
||||
#include <stdlib.h> // free, alloc
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h" // preamblesearch
|
||||
#include "cmddata.h" // preamblesearch
|
||||
#include "cmdlf.h"
|
||||
#include "lfdemod.h"
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
typedef enum {
|
||||
SCRAMBLE,
|
||||
@@ -31,49 +32,6 @@ typedef enum {
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_nexwatch_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Nexwatch tag to a T55x7 tag.");
|
||||
PrintAndLogEx(NORMAL, "You can use raw hex values or create a credential based on id, mode");
|
||||
PrintAndLogEx(NORMAL, "and type of credential (Nexkey/Quadrakey)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf nexwatch clone [h] [b <raw hex>] [c <id>] [m <mode>] [n|q]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " r <raw hex> : raw hex data. 12 bytes max");
|
||||
PrintAndLogEx(NORMAL, " c <id> : card id (decimal)");
|
||||
PrintAndLogEx(NORMAL, " m <mode> : mode (decimal) (0-15, defaults to 1)");
|
||||
PrintAndLogEx(NORMAL, " n : Nexkey credential");
|
||||
PrintAndLogEx(NORMAL, " q : Quadrakey credential");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf nexwatch clone r 5600000000213C9F8F150C"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf nexwatch clone c 521512301 m 1 n") " -- Nexkey credential");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf nexwatch clone c 521512301 m 1 q") " -- Quadrakey credential");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_nexwatch_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of Nexwatch card");
|
||||
PrintAndLogEx(NORMAL, "You can use raw hex values or create a credential based on id, mode");
|
||||
PrintAndLogEx(NORMAL, "and type of credential (Nexkey/Quadrakey)");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf nexwatch sim [h] <r raw hex> [c <id>] [m <mode>] [n|q]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " r <raw hex> : raw hex data. 16 bytes max");
|
||||
PrintAndLogEx(NORMAL, " c <id> : card id (decimal)");
|
||||
PrintAndLogEx(NORMAL, " m <mode> : mode (decimal) (0-15, defaults to 1)");
|
||||
PrintAndLogEx(NORMAL, " n : Nexkey credential");
|
||||
PrintAndLogEx(NORMAL, " q : Quadrakey credential");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf nexwatch sim r 5600000000213C9F8F150C"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf nexwatch sim c 521512301 m 1 n") " -- Nexkey credential");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf nexwatch sim c 521512301 m 1 q") " -- Quadrakey credential");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// scramble parity (1234) -> (4231)
|
||||
static uint8_t nexwatch_parity_swap(uint8_t parity) {
|
||||
uint8_t a = (((parity >> 3) & 1));
|
||||
@@ -263,168 +221,230 @@ static int CmdNexWatchDemod(const char *Cmd) {
|
||||
return demodNexWatch(true);
|
||||
}
|
||||
|
||||
//by marshmellow
|
||||
//see ASKDemod for what args are accepted
|
||||
static int CmdNexWatchRead(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
lf_read(false, 20000);
|
||||
return demodNexWatch(true);
|
||||
static int CmdNexWatchReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf nexwatch reader",
|
||||
"read a nexwatch tag",
|
||||
"lf nexwatch reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
do {
|
||||
lf_read(false, 20000);
|
||||
demodNexWatch(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdNexWatchClone(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf nexwatch clone",
|
||||
"clone a Nexwatch tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
|
||||
"You can use raw hex values or create a credential based on id, mode\n"
|
||||
"and type of credential (Nexkey / Quadrakey)",
|
||||
"lf nexwatch clone --raw 5600000000213C9F8F150C00\n"
|
||||
"lf nexwatch clone --cn 521512301 -m 1 -n -> Nexkey credential\n"
|
||||
"lf nexwatch clone --cn 521512301 -m 1 -q -> Quadrakey credential\n"
|
||||
);
|
||||
|
||||
// 56000000 00213C9F 8F150C00
|
||||
uint32_t blocks[4];
|
||||
bool use_raw = false;
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
int datalen = 0;
|
||||
uint8_t magic = 0xBE;
|
||||
uint32_t cn = 0;
|
||||
uint8_t rawhex[12] = {0x56, 0};
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes"),
|
||||
arg_u64_0(NULL, "cn", "<dec>", "card id"),
|
||||
arg_u64_0("m", "mode", "<dec>", "mode (decimal) (0-15, defaults to 1)"),
|
||||
arg_lit0("n", NULL, "Nexkey credential"),
|
||||
arg_lit0("q", NULL, "Quadrakey credential"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_nexwatch_clone();
|
||||
case 'r': {
|
||||
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen);
|
||||
if (res != 0)
|
||||
errors = true;
|
||||
int raw_len = 0;
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t raw[12] = {0x56, 0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
use_raw = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
cn = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
uint32_t scrambled;
|
||||
nexwatch_scamble(SCRAMBLE, &cn, &scrambled);
|
||||
num_to_bytes(scrambled, 4, rawhex + 5);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
uint8_t mode = param_get8ex(Cmd, cmdp + 1, 1, 10);
|
||||
mode &= 0x0F;
|
||||
rawhex[9] |= (mode << 4);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
magic = 0x88;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
case 'q': {
|
||||
magic = 0xBE;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
uint32_t cn = arg_get_u32_def(ctx, 2, -1);
|
||||
uint32_t mode = arg_get_u32_def(ctx, 3, -1);
|
||||
bool use_nexkey = arg_get_lit(ctx, 4);
|
||||
bool use_quadrakey = arg_get_lit(ctx, 5);
|
||||
bool q5 = arg_get_lit(ctx, 6);
|
||||
bool em = arg_get_lit(ctx, 7);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (use_nexkey && use_quadrakey) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Nexkey and Quadrakey at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (errors || cmdp == 0) return usage_lf_nexwatch_clone();
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// 56000000 00213C9F 8F150C00
|
||||
bool use_raw = (raw_len != 0);
|
||||
|
||||
if (use_raw && cn != -1) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Raw and Card id at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (cn != -1) {
|
||||
uint32_t scrambled;
|
||||
nexwatch_scamble(SCRAMBLE, &cn, &scrambled);
|
||||
num_to_bytes(scrambled, 4, raw + 5);
|
||||
}
|
||||
|
||||
if (mode != -1) {
|
||||
if (mode > 15) {
|
||||
mode = 1;
|
||||
}
|
||||
mode &= 0x0F;
|
||||
raw[9] |= (mode << 4);
|
||||
}
|
||||
|
||||
uint8_t magic = 0xBE;
|
||||
if (use_nexkey)
|
||||
magic = 0x88;
|
||||
|
||||
if (use_quadrakey)
|
||||
magic = 0xBE;
|
||||
|
||||
uint32_t blocks[4];
|
||||
|
||||
//Nexwatch - compat mode, PSK, data rate 40, 3 data blocks
|
||||
blocks[0] = T55x7_MODULATION_PSK1 | T55x7_BITRATE_RF_32 | 3 << T55x7_MAXBLOCK_SHIFT;
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_NEXWATCH_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
if (use_raw == false) {
|
||||
uint8_t parity = nexwatch_parity(rawhex + 5) & 0xF;
|
||||
rawhex[9] |= parity;
|
||||
rawhex[10] |= nexwatch_checksum(magic, cn, parity);
|
||||
uint8_t parity = nexwatch_parity(raw + 5) & 0xF;
|
||||
raw[9] |= parity;
|
||||
raw[10] |= nexwatch_checksum(magic, cn, parity);
|
||||
}
|
||||
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
|
||||
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone NexWatch to T55x7 with raw hex");
|
||||
PrintAndLogEx(INFO, "Preparing to clone NexWatch to " _YELLOW_("%s") " raw " _YELLOW_("%s"), cardtype, sprint_hex_inrow(raw, sizeof(raw)));
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nexwatch read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nexwatch reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdNexWatchSim(const char *Cmd) {
|
||||
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
bool use_raw = false;
|
||||
uint8_t rawhex[12] = {0x56, 0};
|
||||
int rawlen = sizeof(rawhex);
|
||||
uint8_t magic = 0xBE;
|
||||
uint32_t cn = 0;
|
||||
uint8_t bs[128];
|
||||
memset(bs, 0, sizeof(bs));
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf nexwatch sim",
|
||||
"Enables simulation of secura card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n"
|
||||
"You can use raw hex values or create a credential based on id, mode\n"
|
||||
"and type of credential (Nexkey/Quadrakey)",
|
||||
"lf nexwatch sim --raw 5600000000213C9F8F150C00\n"
|
||||
"lf nexwatch sim --cn 521512301 -m 1 -n -> Nexkey credential\n"
|
||||
"lf nexwatch sim --cn 521512301 -m 1 -q -> Quadrakey credential"
|
||||
);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_nexwatch_clone();
|
||||
case 'r': {
|
||||
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &rawlen);
|
||||
if (res != 0)
|
||||
errors = true;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes"),
|
||||
arg_u64_0(NULL, "cn", "<dec>", "card id"),
|
||||
arg_u64_0("m", "mode", "<dec>", "mode (decimal) (0-15, defaults to 1)"),
|
||||
arg_lit0("n", NULL, "Nexkey credential"),
|
||||
arg_lit0("q", NULL, "Quadrakey credential"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
use_raw = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
cn = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
uint32_t scrambled;
|
||||
nexwatch_scamble(SCRAMBLE, &cn, &scrambled);
|
||||
num_to_bytes(scrambled, 4, rawhex + 5);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
uint8_t mode = param_get8ex(Cmd, cmdp + 1, 1, 10);
|
||||
mode &= 0x0F;
|
||||
rawhex[9] |= (mode << 4);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
magic = 0x88;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
case 'q': {
|
||||
magic = 0xBE;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
int raw_len = 0;
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t raw[12] = {0x56, 0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
uint32_t cn = arg_get_u32_def(ctx, 2, -1);
|
||||
uint32_t mode = arg_get_u32_def(ctx, 3, -1);
|
||||
bool use_nexkey = arg_get_lit(ctx, 4);
|
||||
bool use_quadrakey = arg_get_lit(ctx, 5);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (use_nexkey && use_quadrakey) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Nexkey and Quadrakey at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (errors || cmdp == 0) return usage_lf_nexwatch_sim();
|
||||
bool use_raw = (raw_len != 0);
|
||||
|
||||
if (use_raw && cn != -1) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Raw and Card id at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (cn != -1) {
|
||||
uint32_t scrambled;
|
||||
nexwatch_scamble(SCRAMBLE, &cn, &scrambled);
|
||||
num_to_bytes(scrambled, 4, raw + 5);
|
||||
}
|
||||
|
||||
if (mode != -1) {
|
||||
if (mode > 15) {
|
||||
mode = 1;
|
||||
}
|
||||
mode &= 0x0F;
|
||||
raw[9] |= (mode << 4);
|
||||
}
|
||||
|
||||
uint8_t magic = 0xBE;
|
||||
if (use_nexkey)
|
||||
magic = 0x88;
|
||||
|
||||
if (use_quadrakey)
|
||||
magic = 0xBE;
|
||||
|
||||
if (use_raw == false) {
|
||||
uint8_t parity = nexwatch_parity(rawhex + 5) & 0xF;
|
||||
rawhex[9] |= parity;
|
||||
rawhex[10] |= nexwatch_checksum(magic, cn, parity);
|
||||
uint8_t parity = nexwatch_parity(raw + 5) & 0xF;
|
||||
raw[9] |= parity;
|
||||
raw[10] |= nexwatch_checksum(magic, cn, parity);
|
||||
}
|
||||
|
||||
// hex to bits.
|
||||
uint32_t rawblocks[3];
|
||||
for (size_t i = 0; i < ARRAYLEN(rawblocks); i++) {
|
||||
rawblocks[i] = bytes_to_num(rawhex + (i * sizeof(uint32_t)), sizeof(uint32_t));
|
||||
num_to_bytebits(rawblocks[i], sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8));
|
||||
uint8_t bs[96];
|
||||
memset(bs, 0, sizeof(bs));
|
||||
|
||||
// hex to bits. (3 * 32 == 96)
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
uint32_t tmp = bytes_to_num(raw + (i * sizeof(uint32_t)), sizeof(uint32_t));
|
||||
num_to_bytebits(tmp, sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8));
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating NexWatch - raw: %s", sprint_hex_inrow(rawhex, rawlen));
|
||||
PrintAndLogEx(SUCCESS, "Simulating NexWatch - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw)));
|
||||
|
||||
lf_psksim_t *payload = calloc(1, sizeof(lf_psksim_t) + sizeof(bs));
|
||||
payload->carrier = 2;
|
||||
@@ -447,11 +467,11 @@ static int CmdNexWatchSim(const char *Cmd) {
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdNexWatchDemod, AlwaysAvailable, "Demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer"},
|
||||
{"read", CmdNexWatchRead, IfPm3Lf, "Attempt to Read and Extract tag data from the antenna"},
|
||||
{"clone", CmdNexWatchClone, IfPm3Lf, "clone NexWatch tag to T55x7"},
|
||||
{"sim", CmdNexWatchSim, IfPm3Lf, "simulate NexWatch tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdNexWatchDemod, AlwaysAvailable, "Demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer"},
|
||||
{"reader", CmdNexWatchReader, IfPm3Lf, "Attempt to Read and Extract tag data from the antenna"},
|
||||
{"clone", CmdNexWatchClone, IfPm3Lf, "clone NexWatch tag to T55x7"},
|
||||
{"sim", CmdNexWatchSim, IfPm3Lf, "simulate NexWatch tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,52 +8,23 @@
|
||||
// ASK/Manchester, STT, RF/32, 96 bits long (some bits unknown)
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfnoralsy.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_noralsy_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Noralsy tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf noralsy clone [h] <card id> <year> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <card id> : Noralsy card ID");
|
||||
PrintAndLogEx(NORMAL, " <year> : Tag allocation year");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf noralsy clone 112233"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_noralsy_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of Noralsy card with specified card number.");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf noralsy sim [h] <card id> <year>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <card id> : Noralsy card ID");
|
||||
PrintAndLogEx(NORMAL, " <year> : Tag allocation year");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf noralsy sim 112233"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t noralsy_chksum(uint8_t *bits, uint8_t len) {
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 0; i < len; i += 4)
|
||||
@@ -136,28 +107,72 @@ static int CmdNoralsyDemod(const char *Cmd) {
|
||||
return demodNoralsy(true);
|
||||
}
|
||||
|
||||
static int CmdNoralsyRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 8000);
|
||||
return demodNoralsy(true);
|
||||
static int CmdNoralsyReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf noralsy reader",
|
||||
"read a noralsy tag",
|
||||
"lf noralsy reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
do {
|
||||
lf_read(false, 8000);
|
||||
demodNoralsy(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdNoralsyClone(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf noralsy clone",
|
||||
"clone a noralsy tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf noralsy clone --cn 112233\n"
|
||||
"lf noralsy clone --cn 112233 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf noralsy clone --cn 112233 --em -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "cn", "<dec>", "Noralsy card ID"),
|
||||
arg_u64_0("y", "year", "<dec>", "tag allocation year"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint32_t id = arg_get_u32_def(ctx, 1, 0);
|
||||
uint16_t year = arg_get_u32_def(ctx, 2, 2000);
|
||||
bool q5 = arg_get_lit(ctx, 3);
|
||||
bool em = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint16_t year = 0;
|
||||
uint32_t id = 0;
|
||||
uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0};
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_noralsy_clone();
|
||||
|
||||
id = param_get32ex(Cmd, 0, 0, 10);
|
||||
year = param_get32ex(Cmd, 1, 2000, 10);
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
//Q5
|
||||
bool q5 = tolower(param_getchar(Cmd, 2) == 'q');
|
||||
if (q5)
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_NORALSY_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
uint8_t *bits = calloc(96, sizeof(uint8_t));
|
||||
if (getnoralsyBits(id, year, bits) != PM3_SUCCESS) {
|
||||
@@ -172,36 +187,50 @@ static int CmdNoralsyClone(const char *Cmd) {
|
||||
|
||||
free(bits);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Noralsy to " _YELLOW_("%s") " with CardId: %u", (q5) ? "Q5/T5555" : "T55x7", id);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Noralsy to " _YELLOW_("%s") " with Card id: " _GREEN_("%u"), cardtype, id);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf noralsy read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf noralsy reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdNoralsySim(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf noralsy sim",
|
||||
"Enables simulation of Noralsy card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n",
|
||||
"lf noralsy sim --cn 1337\n"
|
||||
"lf noralsy sim --cn 1337 --year 2010"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "cn", "<dec>", "Noralsy card ID"),
|
||||
arg_u64_0("y", "year", "<dec>", "tag allocation year"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
uint32_t id = arg_get_u32_def(ctx, 1, 0);
|
||||
uint16_t year = arg_get_u32_def(ctx, 2, 2000);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint8_t bs[96];
|
||||
memset(bs, 0, sizeof(bs));
|
||||
|
||||
uint16_t year = 0;
|
||||
uint32_t id = 0;
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h')
|
||||
return usage_lf_noralsy_sim();
|
||||
|
||||
id = param_get32ex(Cmd, 0, 0, 10);
|
||||
year = param_get32ex(Cmd, 1, 2000, 10);
|
||||
|
||||
if (getnoralsyBits(id, year, bs) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Noralsy - CardId: %u", id);
|
||||
PrintAndLogEx(SUCCESS, "Simulating Noralsy - CardId: " _YELLOW_("%u") " year " _YELLOW_("%u"), id, year);
|
||||
|
||||
lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs));
|
||||
payload->encoding = 1;
|
||||
@@ -225,11 +254,11 @@ static int CmdNoralsySim(const char *Cmd) {
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdNoralsyDemod, AlwaysAvailable, "Demodulate an Noralsy tag from the GraphBuffer"},
|
||||
{"read", CmdNoralsyRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdNoralsyClone, IfPm3Lf, "clone Noralsy tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdNoralsySim, IfPm3Lf, "simulate Noralsy tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdNoralsyDemod, AlwaysAvailable, "Demodulate an Noralsy tag from the GraphBuffer"},
|
||||
{"reader", CmdNoralsyReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdNoralsyClone, IfPm3Lf, "clone Noralsy tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdNoralsySim, IfPm3Lf, "simulate Noralsy tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -272,7 +301,6 @@ int getnoralsyBits(uint32_t id, uint16_t year, uint8_t *bits) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// by iceman
|
||||
// find Noralsy preamble in already demoded data
|
||||
int detectNoralsy(uint8_t *dest, size_t *size) {
|
||||
if (*size < 96) return -1; //make sure buffer has data
|
||||
|
||||
@@ -25,40 +25,14 @@
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone
|
||||
#include "parity.h"
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_pac_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a PAC/Stanley tag to a T55x7 tag.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf pac clone [h] [c <card id>] [b <raw hex>]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " c <card id> : 8 byte card ID");
|
||||
PrintAndLogEx(NORMAL, " b <raw hex> : raw hex data. 16 bytes max");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf pac clone c CD4F5552 "));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf pac clone b FF2049906D8511C593155B56D5B2649F "));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_lf_pac_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of PAC/Stanley card with specified card number.");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "The card ID is 8 byte number. Larger values are truncated.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf pac sim <Card-ID>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " <Card ID> : 8 byte PAC/Stanley card id");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf pac sim 12345678"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// PAC_8byte format: preamble (8 mark/idle bits), ascii STX (02), ascii '2' (32), ascii '0' (30), ascii bytes 0..7 (cardid), then xor checksum of cardid bytes
|
||||
// all bytes following 8 bit preamble are one start bit (0), 7 data bits (lsb first), odd parity bit, and one stop bit (1)
|
||||
static int demodbuf_to_pacid(uint8_t *src, const size_t src_size, uint8_t *dst, const size_t dst_size) {
|
||||
static int pac_buf_to_cardid(uint8_t *src, const size_t src_size, uint8_t *dst, const size_t dst_size) {
|
||||
const size_t byteLength = 10; // start bit, 7 data bits, parity bit, stop bit
|
||||
const size_t startIndex = 8 + (3 * byteLength) + 1; // skip 8 bits preamble, STX, '2', '0', and first start bit
|
||||
const size_t dataLength = 9;
|
||||
@@ -93,35 +67,33 @@ static int demodbuf_to_pacid(uint8_t *src, const size_t src_size, uint8_t *dst,
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
// convert a 16 byte array of raw demod data (FF204990XX...) to 8 bytes of PAC_8byte ID
|
||||
// performs no parity or checksum validation
|
||||
static void pacRawToCardId(uint8_t* outCardId, const uint8_t* rawBytes) {
|
||||
static void pac_raw_to_cardid(const uint8_t* src, uint8_t *dst) {
|
||||
for (int i = 4; i < 12; i++) {
|
||||
uint8_t shift = 7 - (i + 3) % 4 * 2;
|
||||
size_t index = i + (i - 1) / 4;
|
||||
|
||||
outCardId[i - 4] = reflect8((((rawBytes[index] << 8) | (rawBytes[index + 1])) >> shift) & 0xFE);
|
||||
dst[i - 4] = reflect8((((src[index] << 8) | (src[index + 1])) >> shift) & 0xFE);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// convert 8 bytes of PAC_8byte ID to 16 byte array of raw data (FF204990XX...)
|
||||
static void pacCardIdToRaw(uint8_t *outRawBytes, const char *cardId) {
|
||||
static void pac_cardid_to_raw(const char *src, uint8_t *dst) {
|
||||
uint8_t idbytes[10];
|
||||
|
||||
// prepend PAC_8byte card type "20"
|
||||
idbytes[0] = '2';
|
||||
idbytes[1] = '0';
|
||||
for (size_t i = 0; i < 8; i++)
|
||||
idbytes[i + 2] = toupper(cardId[i]);
|
||||
idbytes[i + 2] = toupper(src[i]);
|
||||
|
||||
// initialise array with start and stop bits
|
||||
for (size_t i = 0; i < 16; i++)
|
||||
outRawBytes[i] = 0x40 >> (i + 3) % 5 * 2;
|
||||
dst[i] = 0x40 >> (i + 3) % 5 * 2;
|
||||
|
||||
outRawBytes[0] = 0xFF; // mark + stop
|
||||
outRawBytes[1] = 0x20; // start + reflect8(STX)
|
||||
dst[0] = 0xFF; // mark + stop
|
||||
dst[1] = 0x20; // start + reflect8(STX)
|
||||
|
||||
uint8_t checksum = 0;
|
||||
for (size_t i = 2; i < 13; i++) {
|
||||
@@ -138,8 +110,8 @@ static void pacCardIdToRaw(uint8_t *outRawBytes, const char *cardId) {
|
||||
}
|
||||
pattern <<= shift;
|
||||
|
||||
outRawBytes[index] |= pattern >> 8 & 0xFF;
|
||||
outRawBytes[index + 1] |= pattern & 0xFF;
|
||||
dst[index] |= pattern >> 8 & 0xFF;
|
||||
dst[index + 1] |= pattern & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +148,7 @@ int demodPac(bool verbose) {
|
||||
|
||||
const size_t idLen = 9; // 8 bytes + null terminator
|
||||
uint8_t cardid[idLen];
|
||||
int retval = demodbuf_to_pacid(DemodBuffer, DemodBufferLen, cardid, sizeof(cardid));
|
||||
int retval = pac_buf_to_cardid(DemodBuffer, DemodBufferLen, cardid, sizeof(cardid));
|
||||
|
||||
if (retval == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "PAC/Stanley - Card: " _GREEN_("%s") ", Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4);
|
||||
@@ -189,93 +161,183 @@ static int CmdPacDemod(const char *Cmd) {
|
||||
return demodPac(true);
|
||||
}
|
||||
|
||||
static int CmdPacRead(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
lf_read(false, 4096 * 2 + 20);
|
||||
return demodPac(true);
|
||||
static int CmdPacReader(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pac reader",
|
||||
"read a pac tag",
|
||||
"lf pac reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
do {
|
||||
lf_read(false, 4096 * 2 + 20);
|
||||
demodPac(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdPacClone(const char *Cmd) {
|
||||
|
||||
uint32_t blocks[5];
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
int datalen = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pac clone",
|
||||
"clone a PAC/Stanley tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf pac clone --cn CD4F5552\n"
|
||||
"lf pac clone --cn CD4F5552 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf pac clone --cn CD4F5552 --em -> encode for EM4305/4469\n"
|
||||
"lf pac clone --raw FF2049906D8511C593155B56D5B2649F"
|
||||
);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_pac_clone();
|
||||
case 'c': {
|
||||
// skip first block, 4*4 = 16 bytes left
|
||||
uint8_t rawhex[16] = {0};
|
||||
char cardid[9];
|
||||
int res = param_getstr(Cmd, cmdp + 1, cardid, sizeof(cardid));
|
||||
if (res < 8)
|
||||
errors = true;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0(NULL, "cn", "<dec>", "8 byte PAC/Stanley card ID"),
|
||||
arg_str0("r", "raw", "<hex>", "raw hex data. 16 bytes max"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
pacCardIdToRaw(rawhex, cardid);
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
// skip first block, 4*4 = 16 bytes left
|
||||
uint8_t rawhex[16] = {0};
|
||||
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen);
|
||||
if (res != 0)
|
||||
errors = true;
|
||||
uint8_t cnstr[9];
|
||||
int cnlen = 9;
|
||||
memset(cnstr, 0x00, sizeof(cnstr));
|
||||
CLIGetStrWithReturn(ctx, 1, cnstr, &cnlen);
|
||||
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
// skip first block, 4*4 = 16 bytes left
|
||||
int raw_len = 0;
|
||||
uint8_t raw[16] = {0};
|
||||
CLIGetHexWithReturn(ctx, 2, raw, &raw_len);
|
||||
|
||||
bool q5 = arg_get_lit(ctx, 3);
|
||||
bool em = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (cnlen && raw_len) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both CardID and raw hex at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (errors || cmdp == 0) return usage_lf_pac_clone();
|
||||
if (cnlen && cnlen < 8) {
|
||||
PrintAndLogEx(FAILED, "Card ID must be 8 or 9 hex digits (%d)", cnlen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
//Pac - compat mode, NRZ, data rate 32, 3 data blocks
|
||||
if (cnlen == 8 || cnlen == 9) {
|
||||
pac_cardid_to_raw((char*)cnstr, raw);
|
||||
} else {
|
||||
pac_raw_to_cardid(raw, cnstr);
|
||||
}
|
||||
|
||||
uint32_t blocks[5];
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Pac - compat mode, NRZ, data rate 32, 3 data blocks
|
||||
blocks[0] = T55x7_MODULATION_DIRECT | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT;
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_DIRECT | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_PAC_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone PAC/Stanley tag to " _YELLOW_("%s") " with ID " _GREEN_("%s") " raw " _GREEN_("%s")
|
||||
, cardtype
|
||||
, cnstr
|
||||
, sprint_hex_inrow(raw, sizeof(raw))
|
||||
);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone PAC/Stanley tag to T55x7 with raw hex");
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pac read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pac reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdPacSim(const char *Cmd) {
|
||||
|
||||
// NRZ sim.
|
||||
char cardid[9] = { 0 };
|
||||
uint8_t rawBytes[16] = { 0 };
|
||||
uint32_t rawBlocks[4];
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pac_sim();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pac sim",
|
||||
"Enables simulation of PAC/Stanley card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n"
|
||||
"The card ID is 8 byte number. Larger values are truncated.",
|
||||
"lf pac sim --cn CD4F5552\n"
|
||||
"lf pac sim --raw FF2049906D8511C593155B56D5B2649F"
|
||||
);
|
||||
|
||||
int res = param_getstr(Cmd, 0, cardid, sizeof(cardid));
|
||||
if (res < 8) return usage_lf_pac_sim();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0(NULL, "cn", "<dec>", "8 byte PAC/Stanley card ID"),
|
||||
arg_str0("r", "raw", "<hex>", "raw hex data. 16 bytes max"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint8_t bs[128];
|
||||
pacCardIdToRaw(rawBytes, cardid);
|
||||
for (size_t i = 0; i < ARRAYLEN(rawBlocks); i++) {
|
||||
rawBlocks[i] = bytes_to_num(rawBytes + (i * sizeof(uint32_t)), sizeof(uint32_t));
|
||||
num_to_bytebits(rawBlocks[i], sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8));
|
||||
uint8_t cnstr[10];
|
||||
int cnlen = 9;
|
||||
memset(cnstr, 0x00, sizeof(cnstr));
|
||||
CLIGetStrWithReturn(ctx, 1, cnstr, &cnlen);
|
||||
|
||||
// skip first block, 4*4 = 16 bytes left
|
||||
int raw_len = 0;
|
||||
uint8_t raw[16] = {0};
|
||||
CLIGetHexWithReturn(ctx, 2, raw, &raw_len);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cnlen && raw_len) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both CardID and raw hex at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating PAC/Stanley - ID " _YELLOW_("%s")" raw "_YELLOW_("%08X%08X%08X%08X"), cardid, rawBlocks[0], rawBlocks[1], rawBlocks[2], rawBlocks[3]);
|
||||
if (cnlen && cnlen < 8) {
|
||||
PrintAndLogEx(FAILED, "Card ID must be 8 or 9 hex digits (%d)", cnlen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (cnlen == 8 || cnlen == 9) {
|
||||
pac_cardid_to_raw((char*)cnstr, raw);
|
||||
} else {
|
||||
pac_raw_to_cardid(raw, cnstr);
|
||||
}
|
||||
|
||||
uint8_t bs[128];
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
uint32_t tmp = bytes_to_num(raw + (i * sizeof(uint32_t)), sizeof(uint32_t));
|
||||
num_to_bytebits(tmp, sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8));
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating PAC/Stanley - ID " _YELLOW_("%s")" raw " _YELLOW_("%s")
|
||||
, cnstr
|
||||
, sprint_hex_inrow(raw, sizeof(raw))
|
||||
);
|
||||
|
||||
// NRZ sim.
|
||||
lf_nrzsim_t *payload = calloc(1, sizeof(lf_nrzsim_t) + sizeof(bs));
|
||||
payload->invert = 0;
|
||||
payload->separator = 0;
|
||||
@@ -297,11 +359,11 @@ static int CmdPacSim(const char *Cmd) {
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdPacDemod, AlwaysAvailable, "Demodulate a PAC tag from the GraphBuffer"},
|
||||
{"read", CmdPacRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdPacClone, IfPm3Lf, "clone PAC tag to T55x7"},
|
||||
{"sim", CmdPacSim, IfPm3Lf, "simulate PAC tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdPacDemod, AlwaysAvailable, "Demodulate a PAC tag from the GraphBuffer"},
|
||||
{"reader", CmdPacReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdPacClone, IfPm3Lf, "clone PAC tag to T55x7"},
|
||||
{"sim", CmdPacSim, IfPm3Lf, "simulate PAC tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Marshmellow
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
@@ -8,13 +9,11 @@
|
||||
// FSK2a, rf/50, 96 bits (completely known)
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfparadox.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
@@ -25,40 +24,11 @@
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "crc.h" // maxim
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_paradox_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Paradox tag to a T55x7 tag.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf paradox clone [h] [b <raw hex>]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " b <raw hex> : raw hex data. 12 bytes max");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf paradox clone b 0f55555695596a6a9999a59a"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
static int usage_lf_paradox_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of Paradox card with specified card number.");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf paradox sim [h] <Facility-Code> <Card-Number>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " <Facility-Code> : 8-bit value facility code");
|
||||
PrintAndLogEx(NORMAL, " <Card Number> : 16-bit value card number");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf paradox sim 123 11223"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
const uint8_t paradox_lut[] = {
|
||||
0xDB, 0xFC, 0x3F, 0xC5, 0x50, 0x14, 0x05, 0x47,
|
||||
0x9F, 0xED, 0x7D, 0x59, 0x22, 0x84, 0x21, 0x4E,
|
||||
@@ -71,9 +41,9 @@ const uint8_t paradox_lut[] = {
|
||||
|
||||
#define PARADOX_PREAMBLE_LEN 8
|
||||
|
||||
//by marshmellow
|
||||
//Paradox Prox demod - FSK2a RF/50 with preamble of 00001111 (then manchester encoded)
|
||||
//print full Paradox Prox ID and some bit format details if found
|
||||
// by marshmellow
|
||||
// Paradox Prox demod - FSK2a RF/50 with preamble of 00001111 (then manchester encoded)
|
||||
// print full Paradox Prox ID and some bit format details if found
|
||||
|
||||
int demodParadox(bool verbose) {
|
||||
(void) verbose; // unused so far
|
||||
@@ -204,91 +174,141 @@ static int CmdParadoxDemod(const char *Cmd) {
|
||||
return demodParadox(true);
|
||||
}
|
||||
|
||||
//by marshmellow
|
||||
//see ASKDemod for what args are accepted
|
||||
static int CmdParadoxRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 10000);
|
||||
return demodParadox(true);
|
||||
static int CmdParadoxReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf paradox reader",
|
||||
"read a Paradox tag",
|
||||
"lf Paradox reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
do {
|
||||
lf_read(false, 10000);
|
||||
demodParadox(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdParadoxClone(const char *Cmd) {
|
||||
|
||||
uint32_t blocks[4];
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
int datalen = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf paradox clone",
|
||||
"clone a paradox tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf paradox clone --raw 0f55555695596a6a9999a59a\n"
|
||||
"lf paradox clone -r 0f55555695596a6a9999a59a --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf paradox clone -r 0f55555695596a6a9999a59a --em -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_paradox_clone();
|
||||
case 'b': {
|
||||
// skip first block, 3*4 =12 bytes left
|
||||
uint8_t rawhex[12] = {0};
|
||||
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen);
|
||||
if (res != 0)
|
||||
errors = true;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
int raw_len = 0;
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t raw[12] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (errors || cmdp == 0) return usage_lf_paradox_clone();
|
||||
if (raw_len != 12) {
|
||||
PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
//Securakey - compat mode, ASK/Man, data rate 40, 3 data blocks
|
||||
uint32_t blocks[4];
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Paradox - FSK2a, data rate 50, 3 data blocks
|
||||
blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 3 << T55x7_MAXBLOCK_SHIFT;
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_INVERT_OUTPUT | T5555_MODULATION_FSK2 | T5555_SET_BITRATE(50) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Paradox to T55x7 with raw hex");
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_PARADOX_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Paradox to " _YELLOW_("%s") " with raw hex", cardtype);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf paradox read`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdParadoxSim(const char *Cmd) {
|
||||
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
/*
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_paradox_sim();
|
||||
|
||||
uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf paradox sim",
|
||||
"Enables simulation of paradox card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf paradox sim --raw 0f55555695596a6a9999a59a"
|
||||
);
|
||||
|
||||
uint8_t bs[96];
|
||||
memset(bs, 0x00, sizeof(bs));
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<hex>", " raw hex data. 12 bytes"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int raw_len = 0;
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t raw[12] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (raw_len != 12) {
|
||||
PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Paradox - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw)));
|
||||
|
||||
uint8_t bs[sizeof(raw) * 8];
|
||||
bytes_to_bytebits(raw, sizeof(raw), bs);
|
||||
|
||||
// Paradox uses: fcHigh: 10, fcLow: 8, clk: 50, invert: 1 FSK2a
|
||||
uint8_t clk = 50, invert = 1, high = 10, low = 8;
|
||||
|
||||
if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_paradox_sim();
|
||||
|
||||
facilitycode = (fc & 0x000000FF);
|
||||
cardnumber = (cn & 0x0000FFFF);
|
||||
|
||||
// if ( GetParadoxBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) {
|
||||
// PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
PrintAndLogEx(NORMAL, "Simulating Paradox - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber);
|
||||
uint8_t clk = 50, high = 10, low = 8;
|
||||
|
||||
lf_fsksim_t *payload = calloc(1, sizeof(lf_fsksim_t) + sizeof(bs));
|
||||
payload->fchigh = high;
|
||||
payload->fclow = low;
|
||||
payload->separator = invert;
|
||||
payload->separator = 0;
|
||||
payload->clock = clk;
|
||||
memcpy(payload->data, bs, sizeof(bs));
|
||||
|
||||
@@ -302,15 +322,29 @@ static int CmdParadoxSim(const char *Cmd) {
|
||||
PrintAndLogEx(INFO, "Done");
|
||||
if (resp.status != PM3_EOPABORTED)
|
||||
return resp.status;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;}
|
||||
/*
|
||||
|
||||
if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_paradox_sim();
|
||||
|
||||
facilitycode = (fc & 0x000000FF);
|
||||
cardnumber = (cn & 0x0000FFFF);
|
||||
|
||||
// if ( GetParadoxBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) {
|
||||
// PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
PrintAndLogEx(NORMAL, "Simulating Paradox - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber);
|
||||
|
||||
*/
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdParadoxDemod, AlwaysAvailable, "Demodulate a Paradox FSK tag from the GraphBuffer"},
|
||||
{"read", CmdParadoxRead, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
|
||||
{"clone", CmdParadoxClone, IfPm3Lf, "clone paradox tag to T55x7"},
|
||||
{"sim", CmdParadoxSim, IfPm3Lf, "simulate paradox tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdParadoxDemod, AlwaysAvailable, "Demodulate a Paradox FSK tag from the GraphBuffer"},
|
||||
{"reader", CmdParadoxReader, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
|
||||
{"clone", CmdParadoxClone, IfPm3Lf, "clone paradox tag"},
|
||||
{"sim", CmdParadoxSim, IfPm3Lf, "simulate paradox tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,51 +8,64 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfpresco.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_presco_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Presco tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf presco clone [h] d <Card-ID> c <hex-ID> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " d <Card-ID> : 9 digit presco card ID");
|
||||
PrintAndLogEx(NORMAL, " c <hex-ID> : 8 digit hex card number");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf presco clone d 123456789"));
|
||||
// find presco preamble 0x10D in already demoded data
|
||||
static int detectPresco(uint8_t *dest, size_t *size) {
|
||||
if (*size < 128 * 2) return -1; //make sure buffer has data
|
||||
size_t startIdx = 0;
|
||||
uint8_t preamble[] = {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
|
||||
return -2; //preamble not found
|
||||
if (*size != 128) return -3; //wrong demoded size
|
||||
//return start position
|
||||
return (int)startIdx;
|
||||
}
|
||||
|
||||
// convert base 12 ID to sitecode & usercode & 8 bit other unknown code
|
||||
static int getWiegandFromPrintedPresco(void *arr, uint32_t *fullcode) {
|
||||
char *s = (char*)arr;
|
||||
uint8_t val = 0;
|
||||
for (int i = 0; i < strlen(s); ++i) {
|
||||
// Get value from number string.
|
||||
if (s[i] == '*')
|
||||
val = 10;
|
||||
if (s[i] == '#')
|
||||
val = 11;
|
||||
if (s[i] >= 0x30 && s[i] <= 0x39)
|
||||
val = s[i] - 0x30;
|
||||
|
||||
*fullcode += val;
|
||||
|
||||
// last digit is only added, not multipled.
|
||||
if (i < strlen(s) - 1)
|
||||
*fullcode *= 12;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_presco_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of presco card with specified card number.");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf presco sim [h] d <Card-ID> or c <hex-ID>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " d <Card-ID> : 9 digit presco card number");
|
||||
PrintAndLogEx(NORMAL, " c <hex-ID> : 8 digit hex card number");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf presco sim d 123456789"));
|
||||
// calc not certain - intended to get bitstream for programming / sim
|
||||
static int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits) {
|
||||
num_to_bytebits(0x10D00000, 32, prescoBits);
|
||||
num_to_bytebits(0x00000000, 32, prescoBits + 32);
|
||||
num_to_bytebits(0x00000000, 32, prescoBits + 64);
|
||||
num_to_bytebits(fullcode, 32, prescoBits + 96);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -85,15 +98,16 @@ int demodPresco(bool verbose) {
|
||||
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
|
||||
uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32);
|
||||
uint32_t raw4 = bytebits_to_byte(DemodBuffer + 96, 32);
|
||||
uint32_t cardid = raw4;
|
||||
PrintAndLogEx(SUCCESS, "Presco - Card: " _GREEN_("%08X") ", Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4);
|
||||
uint32_t fullcode = raw4;
|
||||
uint32_t usercode = fullcode & 0x0000FFFF;
|
||||
uint32_t sitecode = (fullcode >> 24) & 0x000000FF;
|
||||
|
||||
uint32_t sitecode = 0, usercode = 0, fullcode = 0;
|
||||
bool Q5 = false;
|
||||
char cmd[12] = {0};
|
||||
sprintf(cmd, "H %08X", cardid);
|
||||
getWiegandFromPresco(cmd, &sitecode, &usercode, &fullcode, &Q5);
|
||||
PrintAndLogEx(SUCCESS, "SiteCode: " _GREEN_("%u") " UserCode: " _GREEN_("%u") " FullCode: " _GREEN_("%08X"), sitecode, usercode, fullcode);
|
||||
PrintAndLogEx(SUCCESS, "Presco Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08X") " Raw: " _YELLOW_("%08X%08X%08X%08X")
|
||||
, sitecode
|
||||
, usercode
|
||||
, fullcode
|
||||
, raw1, raw2, raw3, raw4
|
||||
);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -103,35 +117,108 @@ static int CmdPrescoDemod(const char *Cmd) {
|
||||
}
|
||||
|
||||
//see ASKDemod for what args are accepted
|
||||
static int CmdPrescoRead(const char *Cmd) {
|
||||
// Presco Number: 123456789 --> Sitecode 30 | usercode 8665
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 12000);
|
||||
return demodPresco(true);
|
||||
static int CmdPrescoReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf presco reader",
|
||||
"read a presco tag",
|
||||
"lf presco reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
do {
|
||||
lf_read(false, 12000);
|
||||
demodPresco(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// takes base 12 ID converts to hex
|
||||
// Or takes 8 digit hex ID
|
||||
static int CmdPrescoClone(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf presco clone",
|
||||
"clone a presco tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf presco clone -d 018363467\n"
|
||||
"lf presco clone -d 018363467 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf presco clone -d 018363467 --em -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("c", NULL, "<hex>", "8 digit hex card number"),
|
||||
arg_str0("d", NULL, "<digits>", "9 digit presco card ID"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int hex_len = 0;
|
||||
uint8_t hex[4] = {0,0,0,0};
|
||||
CLIGetHexWithReturn(ctx, 1, hex, &hex_len);
|
||||
|
||||
uint8_t idstr[11];
|
||||
int slen = 9;
|
||||
memset(idstr, 0x00, sizeof(idstr));
|
||||
CLIGetStrWithReturn(ctx, 2, idstr, &slen);
|
||||
|
||||
bool q5 = arg_get_lit(ctx, 3);
|
||||
bool em = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t fullcode = 0;
|
||||
|
||||
if (hex_len) {
|
||||
fullcode = bytes_to_num(hex, hex_len);
|
||||
} else {
|
||||
//param get string int param_getstr(const char *line, int paramnum, char * str)
|
||||
if (slen < 2) {
|
||||
PrintAndLogEx(ERR, "Must contain atleast 2 digits");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
getWiegandFromPrintedPresco(idstr, &fullcode);
|
||||
}
|
||||
|
||||
uint32_t usercode = fullcode & 0x0000FFFF; //% 65566
|
||||
uint32_t sitecode = (fullcode >> 24) & 0x000000FF; // /= 16777216;
|
||||
|
||||
bool Q5 = false;
|
||||
uint32_t sitecode = 0, usercode = 0, fullcode = 0;
|
||||
uint32_t blocks[5] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT | T55x7_ST_TERMINATOR, 0, 0, 0, 0};
|
||||
|
||||
// get wiegand from printed number.
|
||||
if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG) return usage_lf_presco_clone();
|
||||
|
||||
if (Q5)
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_PRESCO_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
if ((sitecode & 0xFF) != sitecode) {
|
||||
sitecode &= 0xFF;
|
||||
PrintAndLogEx(INFO, "Facility-Code Truncated to 8-bits (Presco): %u", sitecode);
|
||||
PrintAndLogEx(INFO, "Site code truncated to 8-bits (Presco): %u", sitecode);
|
||||
}
|
||||
|
||||
if ((usercode & 0xFFFF) != usercode) {
|
||||
usercode &= 0xFFFF;
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (Presco): %u", usercode);
|
||||
PrintAndLogEx(INFO, "User code truncated to 16-bits (Presco): %u", usercode);
|
||||
}
|
||||
|
||||
blocks[1] = 0x10D00000; //preamble
|
||||
@@ -139,25 +226,84 @@ static int CmdPrescoClone(const char *Cmd) {
|
||||
blocks[3] = 0x00000000;
|
||||
blocks[4] = fullcode;
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Presco to " _YELLOW_("%s") " with SiteCode: %u, UserCode: %u, FullCode: %08x", (Q5) ? "Q5/T5555" : "T55x7", sitecode, usercode, fullcode);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Presco to " _GREEN_("%s") " with Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08x")
|
||||
, cardtype
|
||||
, sitecode
|
||||
, usercode
|
||||
, fullcode
|
||||
);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
// takes base 12 ID converts to hex
|
||||
// Or takes 8 digit hex ID
|
||||
static int CmdPrescoSim(const char *Cmd) {
|
||||
uint32_t sitecode = 0, usercode = 0, fullcode = 0;
|
||||
bool Q5 = false;
|
||||
// get wiegand from printed number.
|
||||
if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG)
|
||||
return usage_lf_presco_sim();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf presco sim",
|
||||
"Enables simulation of presco card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n"
|
||||
"Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated.",
|
||||
"lf presco sim -d 018363467"
|
||||
);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Presco - SiteCode: %u, UserCode: %u, FullCode: %08X", sitecode, usercode, fullcode);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("c", NULL, "<hex>", "8 digit hex card number"),
|
||||
arg_str0("d", NULL, "<digits>", "9 digit presco card ID"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int hex_len = 0;
|
||||
uint8_t hex[4] = {0,0,0,0};
|
||||
CLIGetHexWithReturn(ctx, 1, hex, &hex_len);
|
||||
|
||||
uint8_t idstr[11];
|
||||
int slen = 9;
|
||||
memset(idstr, 0x00, sizeof(idstr));
|
||||
CLIGetStrWithReturn(ctx, 2, idstr, &slen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint32_t fullcode = 0;
|
||||
|
||||
if (hex_len) {
|
||||
fullcode = bytes_to_num(hex, hex_len);
|
||||
} else {
|
||||
if (slen < 2) {
|
||||
PrintAndLogEx(ERR, "Must contain atleast 2 digits");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
getWiegandFromPrintedPresco(idstr, &fullcode);
|
||||
}
|
||||
|
||||
uint32_t usercode = fullcode & 0x0000FFFF;
|
||||
uint32_t sitecode = (fullcode >> 24) & 0x000000FF;
|
||||
|
||||
if ((sitecode & 0xFF) != sitecode) {
|
||||
sitecode &= 0xFF;
|
||||
PrintAndLogEx(INFO, "Site code truncated to 8-bits (Presco): %u", sitecode);
|
||||
}
|
||||
|
||||
if ((usercode & 0xFFFF) != usercode) {
|
||||
usercode &= 0xFFFF;
|
||||
PrintAndLogEx(INFO, "User code truncated to 16-bits (Presco): %u", usercode);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Presco - Site Code: " _GREEN_("%u") " User Code: " _GREEN_("%u") " Full Code: " _GREEN_("%08X")
|
||||
, sitecode
|
||||
, usercode
|
||||
, fullcode)
|
||||
;
|
||||
|
||||
uint8_t bs[128];
|
||||
getPrescoBits(fullcode, bs);
|
||||
@@ -185,9 +331,9 @@ static int CmdPrescoSim(const char *Cmd) {
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdPrescoDemod, AlwaysAvailable, "demodulate Presco tag from the GraphBuffer"},
|
||||
{"read", CmdPrescoRead, IfPm3Lf, "Attempt to read and Extract tag data"},
|
||||
{"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"},
|
||||
{"reader", CmdPrescoReader, IfPm3Lf, "Attempt to read and Extract tag data"},
|
||||
{"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -201,86 +347,3 @@ int CmdLFPresco(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
// find presco preamble 0x10D in already demoded data
|
||||
int detectPresco(uint8_t *dest, size_t *size) {
|
||||
if (*size < 128 * 2) return -1; //make sure buffer has data
|
||||
size_t startIdx = 0;
|
||||
uint8_t preamble[] = {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
|
||||
return -2; //preamble not found
|
||||
if (*size != 128) return -3; //wrong demoded size
|
||||
//return start position
|
||||
return (int)startIdx;
|
||||
}
|
||||
|
||||
// convert base 12 ID to sitecode & usercode & 8 bit other unknown code
|
||||
int getWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode, uint32_t *fullcode, bool *Q5) {
|
||||
|
||||
bool hex = false, errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
char id[11];
|
||||
int stringlen = 0;
|
||||
memset(id, 0x00, sizeof(id));
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return PM3_EINVARG;
|
||||
case 'c':
|
||||
hex = true;
|
||||
//get hex
|
||||
*fullcode = param_get32ex(Cmd, cmdp + 1, 0, 16);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'd':
|
||||
//param get string int param_getstr(const char *line, int paramnum, char * str)
|
||||
stringlen = param_getstr(Cmd, cmdp + 1, id, sizeof(id));
|
||||
if (stringlen < 2) return PM3_EINVARG;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'q':
|
||||
*Q5 = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Validations
|
||||
if (errors || cmdp == 0) return PM3_EINVARG;
|
||||
|
||||
if (!hex) {
|
||||
uint8_t val = 0;
|
||||
for (int index = 0; index < strlen(id); ++index) {
|
||||
// Get value from number string.
|
||||
if (id[index] == '*')
|
||||
val = 10;
|
||||
if (id[index] == '#')
|
||||
val = 11;
|
||||
if (id[index] >= 0x30 && id[index] <= 0x39)
|
||||
val = id[index] - 0x30;
|
||||
|
||||
*fullcode += val;
|
||||
|
||||
// last digit is only added, not multipled.
|
||||
if (index < strlen(id) - 1)
|
||||
*fullcode *= 12;
|
||||
}
|
||||
}
|
||||
|
||||
*usercode = *fullcode & 0x0000FFFF; //% 65566
|
||||
*sitecode = (*fullcode >> 24) & 0x000000FF; // /= 16777216;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// calc not certain - intended to get bitstream for programming / sim
|
||||
int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits) {
|
||||
num_to_bytebits(0x10D00000, 32, prescoBits);
|
||||
num_to_bytebits(0x00000000, 32, prescoBits + 32);
|
||||
num_to_bytebits(0x00000000, 32, prescoBits + 64);
|
||||
num_to_bytebits(fullcode, 32, prescoBits + 96);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -12,11 +12,6 @@
|
||||
#include "common.h"
|
||||
|
||||
int CmdLFPresco(const char *Cmd);
|
||||
|
||||
int demodPresco(bool verbose);
|
||||
int detectPresco(uint8_t *dest, size_t *size);
|
||||
int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits);
|
||||
int getWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode, uint32_t *fullcode, bool *Q5);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
@@ -27,43 +26,11 @@
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "crc.h"
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cliparser.h"
|
||||
#include "cmdlfem4x05.h" // EM Defines
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_pyramid_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Farpointe/Pyramid tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated. ");
|
||||
PrintAndLogEx(NORMAL, "Currently only works on 26bit");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf pyramid clone [h] <Facility-Code> <Card-Number> [Q5]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " <Facility-Code> : 8-bit value facility code");
|
||||
PrintAndLogEx(NORMAL, " <Card Number> : 16-bit value card number");
|
||||
PrintAndLogEx(NORMAL, " Q5 : optional - specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf pyramid clone 123 11223"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_pyramid_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of Farpointe/Pyramid card with specified card number.");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.");
|
||||
PrintAndLogEx(NORMAL, "Currently work only on 26bit");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf pyramid sim [h] <Facility-Code> <Card-Number>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " <Facility-Code> : 8-bit value facility code");
|
||||
PrintAndLogEx(NORMAL, " <Card Number> : 16-bit value card number");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf pyramid sim 123 11223"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
//Pyramid Prox demod - FSK RF/50 with preamble of 0000000000000001 (always a 128 bit data stream)
|
||||
//print full Farpointe Data/Pyramid Prox ID and some bit format details if found
|
||||
int demodPyramid(bool verbose) {
|
||||
@@ -215,26 +182,71 @@ static int CmdPyramidDemod(const char *Cmd) {
|
||||
return demodPyramid(true);
|
||||
}
|
||||
|
||||
static int CmdPyramidRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 15000);
|
||||
return demodPyramid(true);
|
||||
static int CmdPyramidReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pyramid reader",
|
||||
"read a Farpointe/Pyramid tag",
|
||||
"lf pyramid reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
do {
|
||||
lf_read(false, 15000);
|
||||
demodPyramid(true);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdPyramidClone(const char *Cmd) {
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pyramid_clone();
|
||||
uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0;
|
||||
if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_pyramid_clone();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pyramid clone",
|
||||
"clone a Farpointe/Pyramid tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
|
||||
"The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n"
|
||||
"Currently only works on 26bit",
|
||||
"lf pyramid clone --fc 123 --cn 11223\n"
|
||||
"lf pyramid clone --fc 123 --cn 11223 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf pyramid clone --fc 123 --cn 11223 --em -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "fc", "<dec>", "8-bit value facility code"),
|
||||
arg_u64_1(NULL, "cn", "<dec>", "16-bit value card number"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint32_t fc = arg_get_u32_def(ctx, 1, 0);
|
||||
uint32_t cn = arg_get_u32_def(ctx, 2, 0);
|
||||
bool q5 = arg_get_lit(ctx, 3);
|
||||
bool em = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t blocks[5];
|
||||
uint8_t *bs = calloc(128, sizeof(uint8_t));
|
||||
if (bs == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
facilitycode = (fc & 0x000000FF);
|
||||
cardnumber = (cn & 0x0000FFFF);
|
||||
uint32_t facilitycode = (fc & 0x000000FF);
|
||||
uint32_t cardnumber = (cn & 0x0000FFFF);
|
||||
|
||||
if (getPyramidBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
@@ -243,11 +255,18 @@ static int CmdPyramidClone(const char *Cmd) {
|
||||
|
||||
//Pyramid - compat mode, FSK2a, data rate 50, 4 data blocks
|
||||
blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 4 << T55x7_MAXBLOCK_SHIFT;
|
||||
char cardtype[16] = {"T55x7"};
|
||||
|
||||
// Q5
|
||||
bool q5 = tolower(param_getchar(Cmd, 2)) == 'q';
|
||||
if (q5)
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 4 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_PYRAMID_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
blocks[1] = bytebits_to_byte(bs, 32);
|
||||
blocks[2] = bytebits_to_byte(bs + 32, 32);
|
||||
@@ -256,36 +275,53 @@ static int CmdPyramidClone(const char *Cmd) {
|
||||
|
||||
free(bs);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to " _YELLOW_("%s") " with Facility Code: %u, Card Number: %u", (q5) ? "Q5/T5555" : "T55x7", facilitycode, cardnumber);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to " _YELLOW_("%s") " with Facility Code: %u, Card Number: %u", cardtype, facilitycode, cardnumber);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pyramid read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pyramid reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdPyramidSim(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pyramid sim",
|
||||
"Enables simulation of Farpointe/Pyramid card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n"
|
||||
"The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n"
|
||||
"Currently work only on 26bit",
|
||||
"lf pyramid sim --fc 123 --cn 1337"
|
||||
);
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pyramid_sim();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "fc", "<dec>", "8-bit value facility code"),
|
||||
arg_u64_1(NULL, "cn", "<dec>", "16-bit value card number"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
uint32_t fc = arg_get_u32_def(ctx, 1, 0);
|
||||
uint32_t cn = arg_get_u32_def(ctx, 2, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint32_t facilitycode = (fc & 0x000000FF);
|
||||
uint32_t cardnumber = (cn & 0x0000FFFF);
|
||||
|
||||
uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0;
|
||||
|
||||
uint8_t bs[128];
|
||||
memset(bs, 0x00, sizeof(bs));
|
||||
|
||||
if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_pyramid_sim();
|
||||
|
||||
facilitycode = (fc & 0x000000FF);
|
||||
cardnumber = (cn & 0x0000FFFF);
|
||||
|
||||
if (getPyramidBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Farpointe/Pyramid - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber);
|
||||
PrintAndLogEx(SUCCESS, "Simulating Farpointe/Pyramid - Facility Code: " _YELLOW_("%u") ", CardNumber: " _YELLOW_("%u"), facilitycode, cardnumber);
|
||||
|
||||
// Pyramid uses: fcHigh: 10, fcLow: 8, clk: 50, invert: 0
|
||||
lf_fsksim_t *payload = calloc(1, sizeof(lf_fsksim_t) + sizeof(bs));
|
||||
@@ -309,11 +345,11 @@ static int CmdPyramidSim(const char *Cmd) {
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdPyramidDemod, AlwaysAvailable, "demodulate a Pyramid FSK tag from the GraphBuffer"},
|
||||
{"read", CmdPyramidRead, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"clone", CmdPyramidClone, IfPm3Lf, "clone pyramid tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdPyramidSim, IfPm3Lf, "simulate pyramid tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdPyramidDemod, AlwaysAvailable, "demodulate a Pyramid FSK tag from the GraphBuffer"},
|
||||
{"reader", CmdPyramidReader, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"clone", CmdPyramidClone, IfPm3Lf, "clone pyramid tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdPyramidSim, IfPm3Lf, "simulate pyramid tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,10 +8,8 @@
|
||||
// ASK/Manchester, RF/40, 96 bits long (unknown cs)
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfsecurakey.h"
|
||||
|
||||
#include <string.h> // memcpy
|
||||
#include <ctype.h> // tolower
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
@@ -22,22 +20,11 @@
|
||||
#include "parity.h" // for wiegand parity test
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "cliparser.h"
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_securakey_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Securakey tag to a T55x7 tag.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf securakey clone [h] [b <raw hex>]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " b <raw hex> : raw hex data. 12 bytes max");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf securakey clone b 7FCB400001ADEA5344300000"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
//see ASKDemod for what args are accepted
|
||||
int demodSecurakey(bool verbose) {
|
||||
(void) verbose; // unused so far
|
||||
@@ -118,9 +105,11 @@ int demodSecurakey(bool verbose) {
|
||||
if (bitLen <= 32)
|
||||
PrintAndLogEx(SUCCESS, "Wiegand: " _GREEN_("%08X") " parity (%s)", (lWiegand << (bitLen / 2)) | rWiegand, parity ? _GREEN_("ok") : _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "\nHow the FC translates to printed FC is unknown");
|
||||
PrintAndLogEx(INFO, "How the checksum is calculated is unknown");
|
||||
PrintAndLogEx(INFO, "Help the community identify this format further\n by sharing your tag on the pm3 forum or with forum members");
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "\nHow the FC translates to printed FC is unknown");
|
||||
PrintAndLogEx(INFO, "How the checksum is calculated is unknown");
|
||||
PrintAndLogEx(INFO, "Help the community identify this format further\nby sharing your tag on the pm3 forum or discord");
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -129,68 +118,160 @@ static int CmdSecurakeyDemod(const char *Cmd) {
|
||||
return demodSecurakey(true);
|
||||
}
|
||||
|
||||
static int CmdSecurakeyRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 8000);
|
||||
return demodSecurakey(true);
|
||||
static int CmdSecurakeyReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf securakey reader",
|
||||
"read a Securakey tag",
|
||||
"lf securakey reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
do {
|
||||
lf_read(false, 8000);
|
||||
demodSecurakey(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdSecurakeyClone(const char *Cmd) {
|
||||
|
||||
uint32_t blocks[4];
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
int datalen = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf securakey clone",
|
||||
"clone a Securakey tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf securakey clone --raw 7FCB400001ADEA5344300000\n"
|
||||
"lf securakey clone --q5 --raw 7FCB400001ADEA5344300000 -> encode for Q5/T5555 tag\n"
|
||||
"lf securakey clone --em --raw 7FCB400001ADEA5344300000 -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_securakey_clone();
|
||||
case 'b': {
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t rawhex[12] = {0};
|
||||
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen);
|
||||
if (res != 0)
|
||||
errors = true;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
int raw_len = 0;
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t raw[12] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (errors || cmdp == 0) return usage_lf_securakey_clone();
|
||||
if (raw_len != 12) {
|
||||
PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t blocks[4];
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
//Securakey - compat mode, ASK/Man, data rate 40, 3 data blocks
|
||||
blocks[0] = T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_40 | 3 << T55x7_MAXBLOCK_SHIFT;
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(40) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Securakey to T55x7 with raw hex");
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_SECURAKEY_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Securakey to " _YELLOW_("%s") " with raw hex", cardtype);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf securakey read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf securakey reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdSecurakeySim(const char *Cmd) {
|
||||
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf securakey sim",
|
||||
"Enables simulation of secura card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf securakey sim --raw 7FCB400001ADEA5344300000"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<hex>", " raw hex data. 12 bytes"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int raw_len = 0;
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t raw[12] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (raw_len != 12) {
|
||||
PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating SecuraKey - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw)));
|
||||
|
||||
uint8_t bs[sizeof(raw) * 8];
|
||||
bytes_to_bytebits(raw, sizeof(raw), bs);
|
||||
|
||||
lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs));
|
||||
payload->encoding = 1;
|
||||
payload->invert = 0;
|
||||
payload->separator = 0;
|
||||
payload->clock = 40;
|
||||
memcpy(payload->data, bs, sizeof(bs));
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + sizeof(bs));
|
||||
free(payload);
|
||||
|
||||
PacketResponseNG resp;
|
||||
WaitForResponse(CMD_LF_ASK_SIMULATE, &resp);
|
||||
|
||||
PrintAndLogEx(INFO, "Done");
|
||||
if (resp.status != PM3_EOPABORTED)
|
||||
return resp.status;
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdSecurakeyDemod, AlwaysAvailable, "Demodulate an Securakey tag from the GraphBuffer"},
|
||||
{"read", CmdSecurakeyRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdSecurakeyClone, IfPm3Lf, "clone Securakey tag to T55x7"},
|
||||
{"sim", CmdSecurakeySim, IfPm3Lf, "simulate Securakey tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdSecurakeyDemod, AlwaysAvailable, "Demodulate an Securakey tag from the GraphBuffer"},
|
||||
{"reader", CmdSecurakeyReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdSecurakeyClone, IfPm3Lf, "clone Securakey tag to T55x7"},
|
||||
{"sim", CmdSecurakeySim, IfPm3Lf, "simulate Securakey tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -1027,7 +1027,7 @@ static void T55xx_Print_DownlinkMode(uint8_t downlink_mode) {
|
||||
}
|
||||
|
||||
// Define prototype to call from within detect.
|
||||
static int CmdT55xxWakeUp (const char *Cmd);
|
||||
static int CmdT55xxWakeUp(const char *Cmd);
|
||||
|
||||
static int CmdT55xxDetect(const char *Cmd) {
|
||||
|
||||
@@ -1054,7 +1054,7 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||
return usage_t55xx_detect();
|
||||
case 'p':
|
||||
password = param_get32ex(Cmd, cmdp + 1, 0, 16);
|
||||
sprintf (wakecmd,"p %08x q",(uint32_t)(password & 0xFFFFFFFF));
|
||||
sprintf(wakecmd, "p %08x q", (uint32_t)(password & 0xFFFFFFFF));
|
||||
usepwd = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
@@ -1077,7 +1077,7 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||
}
|
||||
if (errors) return usage_t55xx_detect();
|
||||
|
||||
|
||||
|
||||
// detect called so clear data blocks
|
||||
T55x7_ClearAllBlockData();
|
||||
|
||||
@@ -1096,11 +1096,11 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||
if (usewake) {
|
||||
// call wake
|
||||
if (try_with_pwd)
|
||||
CmdT55xxWakeUp (wakecmd);
|
||||
CmdT55xxWakeUp(wakecmd);
|
||||
else
|
||||
CmdT55xxWakeUp ("q");
|
||||
CmdT55xxWakeUp("q");
|
||||
// sleep 90 ms
|
||||
nanosleep (&sleepperiod, &sleepperiod);
|
||||
nanosleep(&sleepperiod, &sleepperiod);
|
||||
}
|
||||
|
||||
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, (try_with_pwd && usepwd), password, m) == false)
|
||||
@@ -1117,11 +1117,11 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||
if (usewake) {
|
||||
// call wake
|
||||
if (try_with_pwd)
|
||||
CmdT55xxWakeUp (wakecmd);
|
||||
CmdT55xxWakeUp(wakecmd);
|
||||
else
|
||||
CmdT55xxWakeUp ("q");
|
||||
CmdT55xxWakeUp("q");
|
||||
// sleep 90 ms
|
||||
nanosleep (&sleepperiod, &sleepperiod);
|
||||
nanosleep(&sleepperiod, &sleepperiod);
|
||||
}
|
||||
|
||||
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) {
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
// Low frequency TI commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfti.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "commonutil.h"
|
||||
#include "comms.h"
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "ui.h"
|
||||
#include "proxgui.h"
|
||||
#include "graph.h"
|
||||
#include "cmdlfti.h"
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
@@ -277,10 +277,27 @@ static int CmdTIDemod(const char *Cmd) {
|
||||
}
|
||||
|
||||
// read a TI tag and return its ID
|
||||
static int CmdTIRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_TI_READ, NULL, 0);
|
||||
static int CmdTIReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf ti reader",
|
||||
"read a TI tag",
|
||||
"lf ti reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
do {
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_TI_READ, NULL, 0);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -300,15 +317,15 @@ static int CmdTIWrite(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_LF_TI_WRITE, arg0, arg1, arg2, NULL, 0);
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf ti read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf ti reader`") " to verify");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdTIDemod, AlwaysAvailable, "Demodulate raw bits for TI-type LF tag from the GraphBuffer"},
|
||||
{"read", CmdTIRead, IfPm3Lf, "Read and decode a TI 134 kHz tag"},
|
||||
{"write", CmdTIWrite, IfPm3Lf, "Write new data to a r/w TI 134 kHz tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdTIDemod, AlwaysAvailable, "Demodulate raw bits for TI-type LF tag from the GraphBuffer"},
|
||||
{"reader", CmdTIReader, IfPm3Lf, "Read and decode a TI 134 kHz tag"},
|
||||
{"write", CmdTIWrite, IfPm3Lf, "Write new data to a r/w TI 134 kHz tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -9,13 +9,10 @@
|
||||
// ASK/Manchester, RF/32, 64 bits (complete)
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfviking.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
@@ -23,36 +20,10 @@
|
||||
#include "cmdlf.h"
|
||||
#include "lfdemod.h"
|
||||
#include "commonutil.h" // num_to_bytes
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_viking_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Viking AM tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf viking clone <Card ID - 8 hex digits> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " <Card Number> : 8 digit hex viking card number");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf viking clone 1A337"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf viking clone 1A337 Q5") " - encode for Q5/T5555 tag");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_viking_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of viking card with specified card number.");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "Per viking format, the card number is 8 digit hex number. Larger values are truncated.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf viking sim <Card-Number>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " <Card Number> : 8 digit hex viking card number");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf viking sim 1A337"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
//see ASKDemod for what args are accepted
|
||||
int demodViking(bool verbose) {
|
||||
(void) verbose; // unused so far
|
||||
@@ -88,40 +59,90 @@ static int CmdVikingDemod(const char *Cmd) {
|
||||
}
|
||||
|
||||
//see ASKDemod for what args are accepted
|
||||
static int CmdVikingRead(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
lf_read(false, 10000);
|
||||
return demodViking(true);
|
||||
static int CmdVikingReader(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf viking reader",
|
||||
"read a Viking AM tag",
|
||||
"lf viking reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
do {
|
||||
lf_read(false, 10000);
|
||||
demodViking(true);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdVikingClone(const char *Cmd) {
|
||||
uint32_t id = 0;
|
||||
uint64_t rawID = 0;
|
||||
bool Q5 = false;
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_viking_clone();
|
||||
|
||||
id = param_get32ex(Cmd, 0, 0, 16);
|
||||
if (id == 0) return usage_lf_viking_clone();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf viking clone",
|
||||
"clone a Viking AM tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf viking clone --cn 01A337\n"
|
||||
"lf viking clone --cn 01A337 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf viking clone --cn 112233 --em -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
cmdp = tolower(param_getchar(Cmd, 1));
|
||||
if (cmdp == 'q')
|
||||
Q5 = true;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0(NULL, "cn", "<hex>", "8 digit hex viking card number"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
rawID = getVikingBits(id);
|
||||
int raw_len = 0;
|
||||
uint8_t raw[4] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint32_t id = bytes_to_num(raw, raw_len);
|
||||
if (id == 0) {
|
||||
PrintAndLogEx(ERR, "Cardnumber can't be zero");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint64_t rawID = getVikingBits(id);
|
||||
|
||||
struct p {
|
||||
bool Q5;
|
||||
bool EM;
|
||||
uint8_t blocks[8];
|
||||
} PACKED payload;
|
||||
payload.Q5 = Q5;
|
||||
payload.Q5 = q5;
|
||||
payload.EM = em;
|
||||
|
||||
num_to_bytes(rawID, 8, &payload.blocks[0]);
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
if (q5)
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
else if (em)
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Viking tag on " _YELLOW_("%s") " - ID " _YELLOW_("%08X")" raw " _YELLOW_("%s")
|
||||
, (Q5) ? "Q5/T5555" : "T55x7"
|
||||
, cardtype
|
||||
, id
|
||||
, sprint_hex(payload.blocks, sizeof(payload.blocks))
|
||||
, sprint_hex(payload.blocks, sizeof(payload.blocks))
|
||||
);
|
||||
|
||||
clearCommandBuffer();
|
||||
@@ -133,20 +154,40 @@ static int CmdVikingClone(const char *Cmd) {
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf viking read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf viking reader`") " to verify");
|
||||
return resp.status;
|
||||
}
|
||||
|
||||
static int CmdVikingSim(const char *Cmd) {
|
||||
uint32_t id = 0;
|
||||
uint64_t rawID = 0;
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_viking_sim();
|
||||
|
||||
id = param_get32ex(Cmd, 0, 0, 16);
|
||||
if (id == 0) return usage_lf_viking_sim();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf viking sim",
|
||||
"Enables simulation of viking card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n"
|
||||
"Per viking format, the card number is 8 digit hex number. Larger values are truncated.",
|
||||
"lf viking sim --cn 01A337"
|
||||
);
|
||||
|
||||
rawID = getVikingBits(id);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0(NULL, "cn", "<hex>", "8 digit hex viking card number"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int raw_len = 0;
|
||||
uint8_t raw[4] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
uint32_t id = bytes_to_num(raw, raw_len);
|
||||
if (id == 0) {
|
||||
PrintAndLogEx(ERR, "Cardnumber can't be zero");
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint64_t rawID = getVikingBits(id);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Viking - ID " _YELLOW_("%08X") " raw " _YELLOW_("%08X%08X"), id, (uint32_t)(rawID >> 32), (uint32_t)(rawID & 0xFFFFFFFF));
|
||||
|
||||
@@ -176,7 +217,7 @@ static int CmdVikingSim(const char *Cmd) {
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdVikingDemod, AlwaysAvailable, "Demodulate a Viking tag from the GraphBuffer"},
|
||||
{"read", CmdVikingRead, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
|
||||
{"reader", CmdVikingReader, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
|
||||
{"clone", CmdVikingClone, IfPm3Lf, "clone Viking tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdVikingSim, IfPm3Lf, "simulate Viking tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
@@ -201,7 +242,7 @@ uint64_t getVikingBits(uint32_t id) {
|
||||
ret |= checksum;
|
||||
return ret;
|
||||
}
|
||||
// by marshmellow
|
||||
|
||||
// find viking preamble 0xF200 in already demoded data
|
||||
int detectViking(uint8_t *src, size_t *size) {
|
||||
//make sure buffer has data
|
||||
|
||||
@@ -27,41 +27,14 @@
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // write verify
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
#define BL0CK1 0x56495332
|
||||
#ifndef VISA2k_BL0CK1
|
||||
#define VISA2k_BL0CK1 0x56495332
|
||||
#endif
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_visa2k_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Visa2000 tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf visa2000 clone [h] <card ID> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <card ID> : Visa2k card ID");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, " <em4305> : specify writing to EM4305/4469 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233 q5") " -- encode for Q5/T5555");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233 em4305") " -- encode for EM4305/4469");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_visa2k_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of visa2k card with specified card number.");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf visa2000 sim [h] <card ID>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <card ID> : Visa2k card ID");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 sim 112233"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t visa_chksum(uint32_t id) {
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 0; i < 32; i += 4)
|
||||
@@ -165,47 +138,76 @@ static int CmdVisa2kDemod(const char *Cmd) {
|
||||
}
|
||||
|
||||
// 64*96*2=12288 samples just in case we just missed the first preamble we can still catch 2 of them
|
||||
static int CmdVisa2kRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 20000);
|
||||
return demodVisa2k(true);
|
||||
static int CmdVisa2kReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf visa2000 reader",
|
||||
"read a visa2000 tag",
|
||||
"lf visa2000 reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
do {
|
||||
lf_read(false, 20000);
|
||||
demodVisa2k(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdVisa2kClone(const char *Cmd) {
|
||||
|
||||
uint64_t id = 0;
|
||||
uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_64 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, BL0CK1, 0};
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf visa2000 clone",
|
||||
"clone a Visa2000 tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf visa2000 clone --cn 112233\n"
|
||||
"lf visa2000 clone --cn 112233 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf visa2000 clone --cn 112233 --em -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h')
|
||||
return usage_lf_visa2k_clone();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "cn", "<dec>", "Visa2k card ID"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
id = param_get32ex(Cmd, 0, 0, 10);
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
bool q5 = tolower(param_getchar(Cmd, 1)) == 'q';
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
bool em = tolower(param_getchar(Cmd, 1)) == 'e';
|
||||
if (em) {
|
||||
blocks[0] = EM4305_VISA2000_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
uint32_t id = arg_get_u32_def(ctx, 1, 0);
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_64 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, VISA2k_BL0CK1, 0};
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_VISA2000_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
blocks[2] = id;
|
||||
blocks[3] = (visa_parity(id) << 4) | visa_chksum(id);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: %"PRIu64, cardtype, id);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: %"PRIu32, cardtype, id);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res;
|
||||
@@ -215,22 +217,31 @@ static int CmdVisa2kClone(const char *Cmd) {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf visa2000 read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf visa2000 reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdVisa2kSim(const char *Cmd) {
|
||||
|
||||
uint32_t id = 0;
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h')
|
||||
return usage_lf_visa2k_sim();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf visa2000 sim",
|
||||
"Enables simulation of visa2k card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n",
|
||||
"lf visa2000 sim --cn 1337"
|
||||
);
|
||||
|
||||
id = param_get32ex(Cmd, 0, 0, 10);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "cn", "<dec>", "Visa2k card ID"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
uint32_t id = arg_get_u32_def(ctx, 1, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Visa2000 - CardId: %u", id);
|
||||
PrintAndLogEx(SUCCESS, "Simulating Visa2000 - CardId:" _YELLOW_("%u"), id);
|
||||
|
||||
uint32_t blocks[3] = { BL0CK1, id, (visa_parity(id) << 4) | visa_chksum(id) };
|
||||
uint32_t blocks[3] = { VISA2k_BL0CK1, id, (visa_parity(id) << 4) | visa_chksum(id) };
|
||||
|
||||
uint8_t bs[96];
|
||||
for (int i = 0; i < 3; ++i)
|
||||
@@ -257,11 +268,11 @@ static int CmdVisa2kSim(const char *Cmd) {
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdVisa2kDemod, AlwaysAvailable, "demodulate an VISA2000 tag from the GraphBuffer"},
|
||||
{"read", CmdVisa2kRead, IfPm3Lf, "attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdVisa2kClone, IfPm3Lf, "clone Visa2000 tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdVisa2kSim, IfPm3Lf, "simulate Visa2000 tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdVisa2kDemod, AlwaysAvailable, "demodulate an VISA2000 tag from the GraphBuffer"},
|
||||
{"reader", CmdVisa2kReader, IfPm3Lf, "attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdVisa2kClone, IfPm3Lf, "clone Visa2000 tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdVisa2kSim, IfPm3Lf, "simulate Visa2000 tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ static int lf_search_plus(const char *Cmd) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int CmdAuto(const char *Cmd) {
|
||||
static int CmdAuto(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "auto",
|
||||
"Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE",
|
||||
@@ -136,7 +136,7 @@ static int CmdAuto(const char *Cmd) {
|
||||
|
||||
PrintAndLogEx(INFO, "lf search");
|
||||
int ret = CmdLFfind("");
|
||||
if (ret == PM3_SUCCESS)
|
||||
if (ret == PM3_SUCCESS)
|
||||
return ret;
|
||||
|
||||
PrintAndLogEx(INFO, "hf search");
|
||||
@@ -193,7 +193,7 @@ static int CmdHints(const char *Cmd) {
|
||||
PrintAndLogEx(ERR, "you can't turn off and on at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
||||
if (turn_off) {
|
||||
session.show_hints = false;
|
||||
} else if (turn_on) {
|
||||
|
||||
@@ -116,7 +116,7 @@ static void asn1_tag_dump_str_time(const struct tlv *tlv, const struct asn1_tag
|
||||
if (longyear == false)
|
||||
PrintAndLogEx(NORMAL, "20" NOLF);
|
||||
|
||||
PrintAndLogEx(NORMAL, "%s-" NOLF, sprint_hex(tlv->value, startindx) );
|
||||
PrintAndLogEx(NORMAL, "%s-" NOLF, sprint_hex(tlv->value, startindx));
|
||||
|
||||
if (len < startindx + 2)
|
||||
break;
|
||||
@@ -276,7 +276,7 @@ static void asn1_tag_dump_object_id(const struct tlv *tlv, const struct asn1_tag
|
||||
asn1_buf.p = (uint8_t *)tlv->value;
|
||||
char pstr[300];
|
||||
mbedtls_oid_get_numeric_string(pstr, sizeof(pstr), &asn1_buf);
|
||||
|
||||
|
||||
PrintAndLogEx(INFO, "%*s %s" NOLF, (level * 4), " ", pstr);
|
||||
|
||||
char *jsondesc = asn1_oid_description(pstr, true);
|
||||
|
||||
@@ -462,9 +462,9 @@ static void emv_tag_dump_bitmask(const struct tlv *tlv, const struct emv_tag *ta
|
||||
if (val & 0x80) {
|
||||
PrintAndLogEx(INFO, "%*s" NOLF, (level * 4), " ");
|
||||
PrintAndLogEx(NORMAL, " %s - '%s'",
|
||||
bitstrings[bit - 1],
|
||||
(bits->bit == EMV_BIT(byte, bit)) ? bits->name : "Unknown"
|
||||
);
|
||||
bitstrings[bit - 1],
|
||||
(bits->bit == EMV_BIT(byte, bit)) ? bits->name : "Unknown"
|
||||
);
|
||||
}
|
||||
if (bits->bit == EMV_BIT(byte, bit))
|
||||
bits ++;
|
||||
@@ -535,10 +535,10 @@ static void emv_tag_dump_numeric(const struct tlv *tlv, const struct emv_tag *ta
|
||||
static void emv_tag_dump_yymmdd(const struct tlv *tlv, const struct emv_tag *tag, int level) {
|
||||
PrintAndLogEx(INFO, "%*s" NOLF, (level * 4), " ");
|
||||
PrintAndLogEx(NORMAL, " Date: 20%02lu.%lu.%lu",
|
||||
emv_value_numeric(tlv, 0, 2),
|
||||
emv_value_numeric(tlv, 2, 4),
|
||||
emv_value_numeric(tlv, 4, 6)
|
||||
);
|
||||
emv_value_numeric(tlv, 0, 2),
|
||||
emv_value_numeric(tlv, 2, 4),
|
||||
emv_value_numeric(tlv, 4, 6)
|
||||
);
|
||||
}
|
||||
|
||||
static uint32_t emv_get_binary(const unsigned char *S) {
|
||||
@@ -749,12 +749,12 @@ static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *t
|
||||
|
||||
PrintAndLogEx(INFO, "%*s" NOLF, (level * 4), " ");
|
||||
PrintAndLogEx(NORMAL, " %02x %02x: '%s' '%s' and '%s' if this CVM is unsuccessful",
|
||||
tlv->value[i],
|
||||
tlv->value[i + 1],
|
||||
method,
|
||||
condition,
|
||||
(tlv->value[i] & 0x40) ? "continue" : "fail"
|
||||
);
|
||||
tlv->value[i],
|
||||
tlv->value[i + 1],
|
||||
method,
|
||||
condition,
|
||||
(tlv->value[i] & 0x40) ? "continue" : "fail"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -778,7 +778,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
||||
if (sdad_tlv) {
|
||||
PrintAndLogEx(INFO, "* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA...");
|
||||
|
||||
const struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true);
|
||||
struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true);
|
||||
if (!atc_db) {
|
||||
PrintAndLogEx(ERR, "Error: Can't recover IDN (ICC Dynamic Number)");
|
||||
emv_pk_free(pk);
|
||||
@@ -804,9 +804,10 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
||||
emv_pk_free(pk);
|
||||
emv_pk_free(issuer_pk);
|
||||
emv_pk_free(icc_pk);
|
||||
atc_db = NULL;
|
||||
tlvdb_free(atc_db);
|
||||
return 9;
|
||||
}
|
||||
|
||||
} else {
|
||||
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||
if (dac_db) {
|
||||
|
||||
@@ -541,7 +541,7 @@ int FIDO2MakeCredentionalParseRes(json_t *root, uint8_t *data, size_t dataLen, b
|
||||
res = CborGetArrayBinStringValue(&mapsmt, der, sizeof(der), &derLen);
|
||||
cbor_check(res);
|
||||
if (verbose2) {
|
||||
PrintAndLogEx(INFO, "DER certificate[%zu]:", derLen);
|
||||
PrintAndLogEx(INFO, "DER certificate[%zu]:", derLen);
|
||||
PrintAndLogEx(INFO, "------------------DER-------------------");
|
||||
PrintAndLogEx(INFO, "%s", sprint_hex(der, derLen));
|
||||
PrintAndLogEx(INFO, "----------------DER---------------------");
|
||||
|
||||
@@ -468,9 +468,9 @@ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[]) {
|
||||
|
||||
mbedtls_des_setkey_enc(&ctx_e, key64_stdformat);
|
||||
mbedtls_des_crypt_ecb(&ctx_e, key64_negated, result);
|
||||
PrintAndLogEx(NORMAL, "\n");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "-- High security custom key (Kcus) --");
|
||||
PrintAndLogEx(SUCCESS, "Standard format %s", sprint_hex(key64_stdformat, 8));
|
||||
PrintAndLogEx(SUCCESS, "Standard format " _GREEN_("%s"), sprint_hex(key64_stdformat, 8));
|
||||
PrintAndLogEx(SUCCESS, "iClass format %s", sprint_hex(key64, 8));
|
||||
|
||||
if (master_key != NULL)
|
||||
|
||||
@@ -212,23 +212,23 @@ void print_buffer(const uint8_t *data, const size_t len, int level) {
|
||||
// (16 * 3) + (16) + + 1
|
||||
memset(buf, 0, sizeof(buf));
|
||||
sprintf(buf, "%*s%02x: ", (level * 4), " ", i);
|
||||
|
||||
hex_to_buffer((uint8_t *)(buf + strlen(buf)), data + i, 16, (sizeof(buf) - strlen(buf) - 1), 0, 1, true);
|
||||
|
||||
hex_to_buffer((uint8_t *)(buf + strlen(buf)), data + i, 16, (sizeof(buf) - strlen(buf) - 1), 0, 1, true);
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "| %s", sprint_ascii(data + i, 16));
|
||||
PrintAndLogEx(INFO, "%s", buf);
|
||||
}
|
||||
|
||||
|
||||
// the last odd bytes
|
||||
uint8_t mod = len % 16;
|
||||
|
||||
|
||||
if (mod) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
sprintf(buf, "%*s%02x: ", (level * 4), " ", i);
|
||||
hex_to_buffer((uint8_t *)(buf + strlen(buf)), data + i, mod, (sizeof(buf) - strlen(buf) - 1), 0, 1, true);
|
||||
|
||||
|
||||
// add the spaces...
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%*s", ((16 - mod) * 3) , " ");
|
||||
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%*s", ((16 - mod) * 3), " ");
|
||||
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "| %s", sprint_ascii(data + i, mod));
|
||||
PrintAndLogEx(INFO, "%s", buf);
|
||||
}
|
||||
@@ -446,6 +446,25 @@ void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest) {
|
||||
}
|
||||
}
|
||||
|
||||
void bytes_to_bytebits(void* src, size_t srclen, void* dest) {
|
||||
|
||||
uint8_t *s = (uint8_t*)src;
|
||||
uint8_t *d = (uint8_t*)dest;
|
||||
|
||||
uint32_t i = srclen * 8;
|
||||
while (srclen--) {
|
||||
uint8_t b = s[srclen];
|
||||
d[--i] = (b >> 0) & 1;
|
||||
d[--i] = (b >> 1) & 1;
|
||||
d[--i] = (b >> 2) & 1;
|
||||
d[--i] = (b >> 3) & 1;
|
||||
d[--i] = (b >> 4) & 1;
|
||||
d[--i] = (b >> 5) & 1;
|
||||
d[--i] = (b >> 6) & 1;
|
||||
d[--i] = (b >> 7) & 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
|
||||
|
||||
@@ -56,6 +56,7 @@ void print_blocks(uint32_t *data, size_t len);
|
||||
int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen);
|
||||
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);
|
||||
void bytes_to_bytebits(void* src, size_t srclen, void* dest);
|
||||
|
||||
// Swap endian on arrays up to 64bytes.
|
||||
uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
|
||||
|
||||
Reference in New Issue
Block a user