Compare commits
43 Commits
mbedtls_2.
...
patch-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebe0a16ad8 | ||
|
|
a0efc7aa02 | ||
|
|
8bf5a99bca | ||
|
|
a469fdd24b | ||
|
|
0c71b6cc32 | ||
|
|
c731c945d6 | ||
|
|
27dcbb49ec | ||
|
|
03a7109efd | ||
|
|
b822e0e046 | ||
|
|
dfd07ccd69 | ||
|
|
16c43bea2d | ||
|
|
3d8b165033 | ||
|
|
2b4d110836 | ||
|
|
836e0fa206 | ||
|
|
a592b349cb | ||
|
|
76adb58feb | ||
|
|
592b7af837 | ||
|
|
e0269bde74 | ||
|
|
03a8704e17 | ||
|
|
01154712a9 | ||
|
|
70694ff281 | ||
|
|
269983db27 | ||
|
|
cfdef9e92e | ||
|
|
c56d3dd42e | ||
|
|
09dc29dd9d | ||
|
|
16783000f0 | ||
|
|
451de246b7 | ||
|
|
af59e27643 | ||
|
|
30fc94da4c | ||
|
|
2f17034254 | ||
|
|
8fa51075fb | ||
|
|
5fdd9ac392 | ||
|
|
228668e7a3 | ||
|
|
7d151057c2 | ||
|
|
6e28a431cb | ||
|
|
65e4d8e1fa | ||
|
|
929ddf0830 | ||
|
|
925e672e54 | ||
|
|
71504daea2 | ||
|
|
2e347393e1 | ||
|
|
a99eb7bf5b | ||
|
|
e45924b450 | ||
|
|
3a920f4e0c |
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Added '--gap' option to lf em 410x sim for more control over sim data (@mwalker)
|
||||
- Changed `hf fido` - refactored load/save json objects (@iceman1001)
|
||||
- Moved / renamed `fido2.json` -> `client/resource/fido2_defparams.json` (@iceman1001)
|
||||
- Added openocd shikra support based on @ninjastyle82 patch to deprecated iceman fork (@iceman1001)
|
||||
|
||||
@@ -102,7 +102,7 @@ static bool get_input_data_from_file(uint32_t *tag, char *inputfile) {
|
||||
|
||||
rdv40_spiffs_read_as_filetype(inputfile, mem, size, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
|
||||
now = size / 9;
|
||||
now = (size + 1) / 9;
|
||||
for (int i = 0; i < now; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
tag[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8);
|
||||
|
||||
@@ -472,6 +472,7 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password)
|
||||
// Perform the PACE protocol by replaying given APDUs
|
||||
//-----------------------------------------------------------------------------
|
||||
void EPA_PACE_Replay(PacketCommandNG *c) {
|
||||
|
||||
uint32_t timings[ARRAYLEN(apdu_lengths_replay)] = {0};
|
||||
|
||||
// if an APDU has been passed, save it
|
||||
|
||||
@@ -319,7 +319,7 @@ void BootROM(void) {
|
||||
|
||||
if ((common_area.command == COMMON_AREA_COMMAND_ENTER_FLASH_MODE) ||
|
||||
(!common_area.flags.button_pressed && BUTTON_PRESS()) ||
|
||||
(*(uint32_t*)_osimage_entry == 0xffffffffU)) {
|
||||
(*(uint32_t *)_osimage_entry == 0xffffffffU)) {
|
||||
flash_mode();
|
||||
} else {
|
||||
// clear button status, even if button still pressed
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
#include "cmddata.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h> // for CmdNorm INT_MIN && INT_MAX
|
||||
#include <math.h> // pow
|
||||
#include <ctype.h> // tolower
|
||||
#include <limits.h> // for CmdNorm INT_MIN && INT_MAX
|
||||
#include <math.h> // pow
|
||||
#include <ctype.h> // tolower
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // for command_t
|
||||
#include "ui.h" // for show graph controls
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "mifare/ndef.h"
|
||||
#include "cliparser.h"
|
||||
#include "cmdlft55xx.h" // print...
|
||||
#include "crypto/asn1utils.h" // ASN1 decode / print
|
||||
#include "crypto/asn1utils.h" // ASN1 decode / print
|
||||
|
||||
uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];
|
||||
size_t DemodBufferLen = 0;
|
||||
|
||||
@@ -474,13 +474,13 @@ static int CmdFlashMemInfo(const char *Cmd) {
|
||||
|
||||
// load private
|
||||
res = mbedtls_pk_parse_keyfile(&pkctx, path, NULL);
|
||||
free(path);
|
||||
//res = mbedtls_pk_parse_public_keyfile(&pkctx, path);
|
||||
if (res == 0) {
|
||||
PrintAndLogEx(NORMAL, " ( " _GREEN_("ok") " )");
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " ( " _RED_("fail") " )");
|
||||
mbedtls_pk_free(&pkctx);
|
||||
free(path);
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
@@ -489,7 +489,6 @@ static int CmdFlashMemInfo(const char *Cmd) {
|
||||
PrintAndLogEx(FAILED, "failed to allocate rsa context memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
free(path);
|
||||
got_private = true;
|
||||
} else {
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
bool APDUInFramingEnable = true;
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
static int waitCmd(bool i_select, uint32_t timeout);
|
||||
static int waitCmd(bool i_select, uint32_t timeout, bool verbose);
|
||||
|
||||
static const manufactureName manufactureMapping[] = {
|
||||
// ID, "Vendor Country"
|
||||
@@ -1187,7 +1187,6 @@ static int CmdHF14AAPDU(const char *Cmd) {
|
||||
}
|
||||
|
||||
static int CmdHF14ACmdRaw(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14a raw",
|
||||
"Sends raw bytes over ISO14443a. With option to use TOPAZ 14a mode.",
|
||||
@@ -1205,13 +1204,13 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
|
||||
arg_lit0("r", NULL, "do not read response"),
|
||||
arg_lit0("s", NULL, "active signal field ON with select"),
|
||||
arg_int0("t", "timeout", "<ms>", "timeout in milliseconds"),
|
||||
arg_lit0("v", "verbose", "Verbose output"),
|
||||
arg_lit0(NULL, "topaz", "use Topaz protocol to send command"),
|
||||
arg_strx1(NULL, NULL, "<hex>", "raw bytes to send"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
|
||||
bool active = arg_get_lit(ctx, 1);
|
||||
uint16_t numbits = (uint16_t)arg_get_int_def(ctx, 2, 0);
|
||||
bool crc = arg_get_lit(ctx, 3);
|
||||
@@ -1220,11 +1219,12 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
|
||||
bool reply = (arg_get_lit(ctx, 6) == false);
|
||||
bool active_select = arg_get_lit(ctx, 7);
|
||||
uint32_t timeout = (uint32_t)arg_get_int_def(ctx, 8, 0);
|
||||
bool topazmode = arg_get_lit(ctx, 9);
|
||||
bool verbose = arg_get_lit(ctx, 9);
|
||||
bool topazmode = arg_get_lit(ctx, 10);
|
||||
|
||||
int datalen = 0;
|
||||
uint8_t data[PM3_CMD_DATA_SIZE];
|
||||
CLIGetHexWithReturn(ctx, 10, data, &datalen);
|
||||
CLIGetHexWithReturn(ctx, 11, data, &datalen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
bool bTimeout = (timeout) ? true : false;
|
||||
@@ -1290,14 +1290,14 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
|
||||
if (reply) {
|
||||
int res = 0;
|
||||
if (active_select)
|
||||
res = waitCmd(true, timeout);
|
||||
res = waitCmd(true, timeout, verbose);
|
||||
if (res == PM3_SUCCESS && datalen > 0)
|
||||
waitCmd(false, timeout);
|
||||
waitCmd(false, timeout, verbose);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int waitCmd(bool i_select, uint32_t timeout) {
|
||||
static int waitCmd(bool i_select, uint32_t timeout, bool verbose) {
|
||||
PacketResponseNG resp;
|
||||
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, timeout + 1500)) {
|
||||
@@ -1305,16 +1305,24 @@ static int waitCmd(bool i_select, uint32_t timeout) {
|
||||
if (i_select) {
|
||||
len = (resp.oldarg[1] & 0xFFFF);
|
||||
if (len) {
|
||||
PrintAndLogEx(SUCCESS, "Card selected. UID[%u]:", len);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, "Card selected. UID[%u]:", len);
|
||||
} else {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Can't select card.");
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len);
|
||||
}
|
||||
}
|
||||
|
||||
if (!len)
|
||||
if (len == 0) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint8_t *data = resp.data.asBytes;
|
||||
|
||||
|
||||
@@ -1051,8 +1051,6 @@ static bool emrtd_connect(bool *use_14b) {
|
||||
}
|
||||
|
||||
static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BAC_available, bool *BAC, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool *use_14b) {
|
||||
uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 };
|
||||
int resplen = 0;
|
||||
|
||||
// Select MRTD applet
|
||||
if (emrtd_select_file(EMRTD_P1_SELECT_BY_NAME, EMRTD_AID_MRTD, *use_14b) == false) {
|
||||
@@ -1069,6 +1067,8 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA
|
||||
// Select EF_DG1
|
||||
emrtd_select_file(EMRTD_P1_SELECT_BY_EF, dg_table[EF_DG1].fileid, *use_14b);
|
||||
|
||||
int resplen = 0;
|
||||
uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 };
|
||||
if (emrtd_read_file(response, &resplen, NULL, NULL, NULL, false, *use_14b) == false) {
|
||||
*BAC = true;
|
||||
PrintAndLogEx(INFO, "Authentication is enforced. Will attempt external authentication.");
|
||||
@@ -1090,7 +1090,6 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1760,6 +1759,7 @@ static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *has
|
||||
case 0x30: {
|
||||
// iceman: if these two calls fails, feels like we should have a better check in place
|
||||
bool res = emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hashidstr, &hashidstrlen, 0x02, 0x00, false, false, 0);
|
||||
(void)res;
|
||||
res = emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hash, &hashlen, 0x04, 0x00, false, false, 0);
|
||||
(void)res;
|
||||
if (hashlen <= 64) {
|
||||
|
||||
@@ -1217,11 +1217,10 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||
mbedtls_des3_context ctx;
|
||||
mbedtls_des3_set2key_dec(&ctx, key);
|
||||
|
||||
uint8_t dec_data[8] = {0};
|
||||
|
||||
// decrypt user supplied data
|
||||
if (have_data) {
|
||||
|
||||
uint8_t dec_data[8] = {0};
|
||||
if (use_sc) {
|
||||
Decrypt(enc_data, dec_data);
|
||||
} else {
|
||||
|
||||
@@ -870,13 +870,13 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||
snprintf(exp, size, "DELETE FILE");
|
||||
break;
|
||||
case MFDES_AUTHENTICATE:
|
||||
snprintf(exp, size, "AUTH NATIVE (keyNo %d)", cmd[pos + 1]);
|
||||
snprintf(exp, size, "AUTH NATIVE (keyNo %d)", cmd[pos + 4]);
|
||||
break; // AUTHENTICATE_NATIVE
|
||||
case MFDES_AUTHENTICATE_ISO:
|
||||
snprintf(exp, size, "AUTH ISO (keyNo %d)", cmd[pos + 1]);
|
||||
snprintf(exp, size, "AUTH ISO (keyNo %d)", cmd[pos + 4]);
|
||||
break; // AUTHENTICATE_STANDARD
|
||||
case MFDES_AUTHENTICATE_AES:
|
||||
snprintf(exp, size, "AUTH AES (keyNo %d)", cmd[pos + 1]);
|
||||
snprintf(exp, size, "AUTH AES (keyNo %d)", cmd[pos + 4]);
|
||||
break;
|
||||
case MFDES_AUTHENTICATE_EV2F:
|
||||
snprintf(exp, size, "AUTH EV2 First");
|
||||
|
||||
@@ -833,11 +833,11 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp
|
||||
}
|
||||
}
|
||||
// else {
|
||||
/*
|
||||
cmd[0] = AUTHENTICATE;
|
||||
cmd[1] = payload->keyno;
|
||||
len = DesfireAPDU(cmd, 2, resp);
|
||||
*/
|
||||
/*
|
||||
cmd[0] = AUTHENTICATE;
|
||||
cmd[1] = payload->keyno;
|
||||
len = DesfireAPDU(cmd, 2, resp);
|
||||
*/
|
||||
//}
|
||||
|
||||
if (!recv_len) {
|
||||
@@ -1260,7 +1260,7 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
|
||||
// C4 01 A0B08090E0F0C0D02030001060704050 03
|
||||
// 19 bytes
|
||||
//uint8_t csPkt[30] = {0x00};
|
||||
csPkt[0] = 0xC4;
|
||||
csPkt[0] = MFDES_CHANGE_KEY;
|
||||
memcpy(&csPkt[1], data, 18);
|
||||
|
||||
desfire_crc32(csPkt, 19, data + 1 + cmdcnt);
|
||||
@@ -1280,8 +1280,18 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
|
||||
cmdcnt += 2;
|
||||
break;
|
||||
case AS_NEW:
|
||||
desfire_crc32_append(data, cmdcnt);
|
||||
if (new_algo == MFDES_ALGO_AES) {
|
||||
// AES Checksum must cover : C4<KeyNo> <PrevKey XOR Newkey> <NewKeyVer>
|
||||
// C4 01 A0B08090E0F0C0D02030001060704050 03
|
||||
csPkt[0] = 0xC4;
|
||||
memcpy(&csPkt[1], data, 18);
|
||||
desfire_crc32(csPkt, 19, data + 1 + cmdcnt);
|
||||
} else {
|
||||
desfire_crc32_append(data + 1, cmdcnt);
|
||||
}
|
||||
cmdcnt += 4;
|
||||
// desfire_crc32_append(data, cmdcnt);
|
||||
// cmdcnt += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1293,7 +1303,6 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
|
||||
memcpy(&data[1], p, cmdcnt);
|
||||
apdu.data = data;
|
||||
|
||||
|
||||
uint32_t recv_len = 0;
|
||||
uint16_t sw = 0;
|
||||
|
||||
@@ -1303,13 +1312,22 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
|
||||
int res = send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, true);
|
||||
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, _RED_(" Can't change key -> %s"), GetErrorString(res, &sw));
|
||||
PrintAndLogEx(WARNING, _RED_("can't change key -> %s"), GetErrorString(res, &sw));
|
||||
DropFieldDesfire();
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t sn = recv_len;
|
||||
|
||||
if (new_algo == MFDES_ALGO_AES)
|
||||
{
|
||||
// AES expects us to Calculate CMAC for status byte : OK 0x00 (0x91 00)
|
||||
// As such if we get this far without an error, we should be good
|
||||
// Since we are dropping the field, we dont need to maintain the CMAC etc.
|
||||
// Setting sn = 1 will allow the post process to just exit (as status only)
|
||||
sn = 1;
|
||||
}
|
||||
|
||||
p = mifare_cryto_postprocess_data(tag, data, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY);
|
||||
|
||||
// Should be finished processing the changekey so lets ensure the field is dropped.
|
||||
@@ -1319,9 +1337,11 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
|
||||
/*
|
||||
Note in my testing on an EV1, the AES password did change, with the number of returned bytes was 8, expected 9 <status><8 byte cmac>
|
||||
As such !p is true and the code reports "Error on changing key"; so comment back to user until its fixed.
|
||||
|
||||
Note: as at 19 May 2021, with the sn = 1 patch above, this should no longer be reachable!
|
||||
*/
|
||||
if (new_algo == MFDES_ALGO_AES) {
|
||||
PrintAndLogEx(WARNING, "AES password may have been changed, please check new password with the auth command.");
|
||||
PrintAndLogEx(WARNING, "AES Key may have been changed, please check new password with the auth command.");
|
||||
}
|
||||
|
||||
return PM3_ESOFT;
|
||||
@@ -1890,10 +1910,21 @@ static int handler_desfire_readdata(mfdes_data_t *data, MFDES_FILE_TYPE_T type,
|
||||
uint16_t sw = 0;
|
||||
uint32_t resplen = 0;
|
||||
|
||||
size_t plen = apdu.Lc;
|
||||
uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)data, &plen, 0, MDCM_PLAIN | CMAC_COMMAND);
|
||||
apdu.Lc = (uint8_t)plen;
|
||||
apdu.data = p;
|
||||
// we need the CMD 0xBD <data> to calc the CMAC
|
||||
uint8_t tmp_data[8]; // Since the APDU is hardcoded to 7 bytes of payload 7+1 = 8 is enough.
|
||||
tmp_data[0] = 0xBD;
|
||||
memcpy(&tmp_data[1], data, 7);
|
||||
|
||||
// size_t plen = apdu.Lc;
|
||||
// uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)data, &plen, 0, MDCM_PLAIN | CMAC_COMMAND);
|
||||
// apdu.Lc = (uint8_t)plen;
|
||||
// apdu.data = p;
|
||||
|
||||
size_t plen = 8;
|
||||
uint8_t *p = mifare_cryto_preprocess_data(tag, tmp_data, &plen, 0, MDCM_PLAIN | CMAC_COMMAND);
|
||||
// apdu data does not need the cmd, so use the original read command data.
|
||||
apdu.Lc = 7;
|
||||
apdu.data = (uint8_t *)data;
|
||||
|
||||
int res = send_desfire_cmd(&apdu, false, data->data, &resplen, &sw, 0, true);
|
||||
if (res != PM3_SUCCESS) {
|
||||
@@ -1953,11 +1984,12 @@ static int handler_desfire_writedata(mfdes_data_t *data, MFDES_FILE_TYPE_T type,
|
||||
uint32_t recvlen = 0;
|
||||
int res = PM3_SUCCESS;
|
||||
uint16_t sw = 0;
|
||||
uint8_t tmp[59] = {0};
|
||||
uint8_t tmp[60] = {0};
|
||||
mfdes_data_t sdata;
|
||||
sAPDU apdu = {0x90, MFDES_WRITE_DATA, 0x00, 0x00, 0, (uint8_t *) &sdata}; // 0x3D
|
||||
tmp[0] = data->fileno;
|
||||
apdu.data = tmp;
|
||||
tmp[0] = MFDES_WRITE_DATA;
|
||||
tmp[1] = data->fileno;
|
||||
apdu.data = &tmp[1]; // tmp[0] is holding the OPCODE for macd calc, so we dont want it in the apdu
|
||||
if (type == MFDES_RECORD_FILE) apdu.INS = MFDES_WRITE_RECORD;
|
||||
|
||||
while (datatowrite) {
|
||||
@@ -1967,21 +1999,34 @@ static int handler_desfire_writedata(mfdes_data_t *data, MFDES_FILE_TYPE_T type,
|
||||
else
|
||||
datasize = datatowrite;
|
||||
|
||||
tmp[1] = offset & 0xFF;
|
||||
tmp[2] = (offset >> 8) & 0xFF;
|
||||
tmp[3] = (offset >> 16) & 0xFF;
|
||||
tmp[4] = datasize & 0xFF;
|
||||
tmp[5] = (datasize >> 8) & 0xFF;
|
||||
tmp[6] = (datasize >> 16) & 0xFF;
|
||||
// Build packet to pre-process (using CMD FN OFFSET LEN DATA)
|
||||
tmp[2] = offset & 0xFF;
|
||||
tmp[3] = (offset >> 8) & 0xFF;
|
||||
tmp[4] = (offset >> 16) & 0xFF;
|
||||
tmp[5] = datasize & 0xFF;
|
||||
tmp[6] = (datasize >> 8) & 0xFF;
|
||||
tmp[7] = (datasize >> 16) & 0xFF;
|
||||
memcpy(&tmp[8], (uint8_t *)&data->data[offset], datasize);
|
||||
|
||||
// size_t plen = datasize;
|
||||
// uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)&data->data[pos], &plen, 0, cs | MAC_COMMAND | CMAC_COMMAND | ENC_COMMAND);
|
||||
size_t plen = datasize + 8;
|
||||
uint8_t *p = mifare_cryto_preprocess_data(tag, tmp, &plen, 8, cs | MAC_COMMAND | CMAC_COMMAND | ENC_COMMAND);
|
||||
|
||||
size_t plen = datasize;
|
||||
uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)&data->data[pos], &plen, 0, cs | MAC_COMMAND | CMAC_COMMAND | ENC_COMMAND);
|
||||
if (plen != -1) datasize = (uint8_t)plen;
|
||||
memcpy(&tmp[7], p, datasize);
|
||||
// Copy actual data as needed to create APDU Format
|
||||
if (plen != -1) {
|
||||
memcpy(&tmp[8], &p[8], plen - 8);
|
||||
apdu.Lc = plen - 1; //need to drop the OpCode from plen
|
||||
}
|
||||
|
||||
apdu.Lc = datasize + 1 + 3 + 3;
|
||||
/*
|
||||
// we dont want to change the value of datasize, so delt with above without change
|
||||
// Doing so can create wrong offsets and endless loop.
|
||||
if (plen != -1) datasize = (uint8_t)plen;
|
||||
memcpy(&tmp[7], p, datasize);
|
||||
|
||||
apdu.Lc = datasize + 1 + 3 + 3;
|
||||
*/
|
||||
|
||||
res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
|
||||
if (res != PM3_SUCCESS) {
|
||||
@@ -2019,8 +2064,8 @@ static int handler_desfire_deletefile(uint8_t file_no) {
|
||||
return res;
|
||||
}
|
||||
|
||||
static int handler_desfire_clearrecordfile(uint8_t file_no) {
|
||||
if (file_no > 0x1F)
|
||||
static int handler_desfire_clear_record_file(uint8_t file_no) {
|
||||
if (file_no > 0x1F)
|
||||
return PM3_EINVARG;
|
||||
|
||||
sAPDU apdu = {0x90, MFDES_CLEAR_RECORD_FILE, 0x00, 0x00, 1, &file_no}; // 0xEB
|
||||
@@ -2639,7 +2684,7 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
int res = handler_desfire_clearrecordfile(fno);
|
||||
int res = handler_desfire_clear_record_file(fno);
|
||||
if (res == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Successfully cleared record file.");
|
||||
} else {
|
||||
@@ -4063,18 +4108,9 @@ static int CmdHF14ADesBruteApps(const char *Cmd) {
|
||||
}
|
||||
|
||||
static int CmdHF14ADesChangeKey(const char *Cmd) {
|
||||
//DropFieldDesfire();
|
||||
// NR DESC KEYLENGHT
|
||||
// ------------------------
|
||||
// 1 = DES 8
|
||||
// 2 = 3DES 16
|
||||
// 3 = 3K 3DES 24
|
||||
// 4 = AES 16
|
||||
uint8_t keylength = 8;
|
||||
uint8_t newkeylength = 8;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfdes changekey",
|
||||
"Changes MIFARE DESFire Key\n"
|
||||
"Change MIFARE DESFire Key.\n"
|
||||
"Make sure to select aid or authenticate aid before running this command.",
|
||||
"hf mfdes changekey -n 0 -t 1 -k 0000000000000000 -u 1 -j 0102030405060708 -> DES, keynumber 0"
|
||||
);
|
||||
@@ -4105,6 +4141,14 @@ static int CmdHF14ADesChangeKey(const char *Cmd) {
|
||||
uint8_t aesversion = arg_get_int_def(ctx, 6, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
//DropFieldDesfire();
|
||||
// NR DESC KEYLENGHT
|
||||
// ------------------------
|
||||
// 1 = DES 8
|
||||
// 2 = 3DES 16
|
||||
// 3 = 3K 3DES 24
|
||||
// 4 = AES 16
|
||||
uint8_t keylength = 8;
|
||||
if (cmdAuthAlgo == MFDES_ALGO_AES) {
|
||||
keylength = 16;
|
||||
} else if (cmdAuthAlgo == MFDES_ALGO_3DES) {
|
||||
@@ -4115,6 +4159,7 @@ static int CmdHF14ADesChangeKey(const char *Cmd) {
|
||||
keylength = 24;
|
||||
}
|
||||
|
||||
uint8_t newkeylength = 8;
|
||||
if (newcmdAuthAlgo == MFDES_ALGO_AES) {
|
||||
newkeylength = 16;
|
||||
} else if (newcmdAuthAlgo == MFDES_ALGO_3DES) {
|
||||
@@ -4126,37 +4171,36 @@ static int CmdHF14ADesChangeKey(const char *Cmd) {
|
||||
}
|
||||
|
||||
if (res_klen || (keylen < 8) || (keylen > 24)) {
|
||||
PrintAndLogEx(ERR, "Specified key must have %d bytes length.", keylen);
|
||||
PrintAndLogEx(ERR, "Specified key must have %d bytes length", keylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (res_newklen || (newkeylen < 8) || (newkeylen > 24)) {
|
||||
PrintAndLogEx(ERR, "Specified key must have %d bytes length.", newkeylen);
|
||||
PrintAndLogEx(ERR, "Specified new key must have %d bytes length", newkeylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (keylen != keylength) {
|
||||
PrintAndLogEx(WARNING, "Key must include %d HEX symbols", keylength);
|
||||
PrintAndLogEx(WARNING, "Key must include %d hex symbols, got %d", keylength, keylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (newkeylen != newkeylength) {
|
||||
PrintAndLogEx(WARNING, "New key must include %d HEX symbols", keylength);
|
||||
PrintAndLogEx(WARNING, "New key must include %d hex symbols, got %d", keylength, newkeylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "changing key number 0x%02x", cmdKeyNo);
|
||||
PrintAndLogEx(INFO, "old key: %s (%s)", sprint_hex_inrow(key, keylen), getEncryptionAlgoStr(cmdAuthAlgo));
|
||||
PrintAndLogEx(INFO, "new key: %s (%s)", sprint_hex_inrow(newkey, newkeylen), getEncryptionAlgoStr(newcmdAuthAlgo));
|
||||
PrintAndLogEx(INFO, "changing key number " _YELLOW_("0x%02x"), cmdKeyNo);
|
||||
PrintAndLogEx(INFO, "old key: %s ( %s )", sprint_hex_inrow(key, keylen), getEncryptionAlgoStr(cmdAuthAlgo));
|
||||
PrintAndLogEx(INFO, "new key: %s ( %s )", sprint_hex_inrow(newkey, newkeylen), getEncryptionAlgoStr(newcmdAuthAlgo));
|
||||
|
||||
int error = mifare_desfire_change_key(cmdKeyNo, newkey, newcmdAuthAlgo, key, cmdAuthAlgo, aesversion);
|
||||
if (error == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, " Successfully changed key.");
|
||||
int res = mifare_desfire_change_key(cmdKeyNo, newkey, newcmdAuthAlgo, key, cmdAuthAlgo, aesversion);
|
||||
if (res == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Change key ( " _GREEN_("ok") " )");
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, " Error on changing key.");
|
||||
return PM3_ESOFT;
|
||||
PrintAndLogEx(FAILED, "Change key ( " _RED_("fail") " )");
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ uint8_t default_3des_keys[][16] = {
|
||||
|
||||
uint8_t default_pwd_pack[][4] = {
|
||||
{0xFF, 0xFF, 0xFF, 0xFF}, // PACK 0x00,0x00 -- factory default
|
||||
{0x4E, 0x45, 0x78, 0x54},
|
||||
};
|
||||
|
||||
uint32_t UL_TYPES_ARRAY[] = {
|
||||
|
||||
@@ -268,7 +268,7 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) {
|
||||
break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, " --= %s " _YELLOW_("%uK") " bytes ( " _YELLOW_("%2.1f%%") " used )"
|
||||
PrintAndLogEx(NORMAL, " --= %s " _YELLOW_("%uK") " bytes ( " _YELLOW_("%2.0f%%") " used )"
|
||||
, asBuff
|
||||
, mem_avail
|
||||
, mem_avail == 0 ? 0.0f : (float)mem_used / (mem_avail * 1024) * 100
|
||||
|
||||
@@ -48,13 +48,13 @@ static int CmdHelp(const char *Cmd);
|
||||
*/
|
||||
|
||||
// Construct the graph for emulating an EM410X tag
|
||||
static void em410x_construct_emul_graph(uint8_t *uid, uint8_t clock) {
|
||||
static void em410x_construct_emul_graph(uint8_t *uid, uint8_t clock, uint8_t gap) {
|
||||
|
||||
// clear our graph
|
||||
ClearGraph(true);
|
||||
|
||||
// write 16 zero bit sledge
|
||||
for (uint8_t i = 0; i < 20; i++)
|
||||
for (uint8_t i = 0; i < gap; i++)
|
||||
AppendGraph(false, clock, 0);
|
||||
|
||||
// write 9 start bits
|
||||
@@ -403,13 +403,15 @@ static int CmdEM410xSim(const char *Cmd) {
|
||||
"Enables simulation of EM 410x card.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf em 410x sim --id 0F0368568B\n"
|
||||
"lf em 410x sim --id 0F0368568B --clk 32"
|
||||
"lf em 410x sim --id 0F0368568B --clk 32\n"
|
||||
"lf em 410x sim --id 0F0368568B --gap 0"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_0(NULL, "clk", "<dec>", "<32|64> clock (default 64)"),
|
||||
arg_str1(NULL, "id", "<hex>", "ID number (5 hex bytes)"),
|
||||
arg_u64_0(NULL, "gap", "<dec>", "gap (0's) between ID repeats (default 20)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
@@ -417,6 +419,7 @@ static int CmdEM410xSim(const char *Cmd) {
|
||||
// clock is 64 in EM410x tags
|
||||
int clk = arg_get_u32_def(ctx, 1, 64);
|
||||
int uid_len = 0;
|
||||
int gap = arg_get_u32_def(ctx, 3, 20);
|
||||
uint8_t uid[5] = {0};
|
||||
CLIGetHexWithReturn(ctx, 2, uid, &uid_len);
|
||||
CLIParserFree(ctx);
|
||||
@@ -427,7 +430,7 @@ static int CmdEM410xSim(const char *Cmd) {
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Starting simulating UID "_YELLOW_("%s")" clock: "_YELLOW_("%d"), sprint_hex_inrow(uid, sizeof(uid)), clk);
|
||||
em410x_construct_emul_graph(uid, clk);
|
||||
em410x_construct_emul_graph(uid, clk, gap);
|
||||
CmdLFSim("");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
@@ -447,13 +450,14 @@ static int CmdEM410xBrute(const char *Cmd) {
|
||||
arg_u64_0(NULL, "clk", "<dec>", "<32|64> clock (default 64)"),
|
||||
arg_u64_0(NULL, "delay", "<dec>", "pause delay in milliseconds between UIDs simulation (default 1000ms)"),
|
||||
arg_str1("f", "file", "<hex>", "file with UIDs in HEX format, one per line"),
|
||||
arg_u64_0(NULL, "gap", "<dec>", "gap (0's) between ID repeats (default 20)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
// clock default 64 in EM410x
|
||||
uint32_t clk = arg_get_u32_def(ctx, 1, 64);
|
||||
|
||||
int gap = arg_get_u32_def(ctx, 4, 20);
|
||||
// default pause time: 1 second
|
||||
uint32_t delay = arg_get_u32_def(ctx, 2, 1000);
|
||||
|
||||
@@ -548,7 +552,7 @@ static int CmdEM410xBrute(const char *Cmd) {
|
||||
, sprint_hex_inrow(testuid, sizeof(testuid))
|
||||
);
|
||||
|
||||
em410x_construct_emul_graph(testuid, clk);
|
||||
em410x_construct_emul_graph(testuid, clk, gap);
|
||||
|
||||
lfsim_upload_gb();
|
||||
|
||||
|
||||
@@ -1852,14 +1852,11 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
||||
PrintAndLogEx(INFO, "Old protection word => " _YELLOW_("%08X"), search_value);
|
||||
char bitstring[9] = {0};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bitstring[i] = (bitflips & (0xF << ((7 - i) * 4))) ? 'x' : '.';
|
||||
bitstring[i] = (bitflips & (0xFU << ((7 - i) * 4))) ? 'x' : '.';
|
||||
}
|
||||
// compute number of bits flipped
|
||||
|
||||
PrintAndLogEx(INFO, "Bitflips: %2u events => %s", bitcount32(bitflips), bitstring);
|
||||
PrintAndLogEx(INFO, "New protection word => " _CYAN_("%08X") "\n", word14b);
|
||||
|
||||
|
||||
PrintAndLogEx(INFO, "Try " _YELLOW_("`lf em 4x05_dump`"));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
#include "commonutil.h"
|
||||
#include "pmflash.h"
|
||||
#include "cmdflashmemspiffs.h"
|
||||
|
||||
#define BYTES2UINT32(x) ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3]))
|
||||
#include "em4x50.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
@@ -465,12 +464,12 @@ int CmdEM4x50Chk(const char *Cmd) {
|
||||
}
|
||||
|
||||
size_t datalen = 0;
|
||||
uint8_t data[FLASH_MEM_MAX_SIZE] = {0x0};
|
||||
uint8_t data[100000] = {0x0};
|
||||
uint8_t *keys = data;
|
||||
uint32_t key_count = 0;
|
||||
|
||||
int res = loadFileDICTIONARY(filename, data, &datalen, 4, &key_count);
|
||||
if (res || !key_count)
|
||||
if ((res != PM3_SUCCESS) || (key_count == 0))
|
||||
return PM3_EFILE;
|
||||
|
||||
PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button");
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
#define LOCKBIT_0 BITMASK(6)
|
||||
#define LOCKBIT_1 BITMASK(7)
|
||||
|
||||
#define BYTES2UINT16(x) ((x[1] << 8) | (x[0]))
|
||||
#define BYTES2UINT32(x) ((x[3] << 24) | (x[2] << 16) | (x[1] << 8) | (x[0]))
|
||||
|
||||
#define INDEX_TO_BLOCK(x) (((32-x)/2)-1)
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
@@ -65,7 +65,7 @@ int ExecuteCryptoTests(bool verbose, bool ignore_time, bool include_slow_tests)
|
||||
PrintAndLogEx(WARNING, "Repeat timing test " _RED_("%d"), i + 1);
|
||||
}
|
||||
if (res && !ignore_time) TestFail = true;
|
||||
*/
|
||||
*/
|
||||
|
||||
res = mbedtls_ctr_drbg_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
@@ -285,7 +285,7 @@ void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t le
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *buffer = malloc(padded_data_length(len, kbs));
|
||||
uint8_t *buffer = calloc(padded_data_length(len, kbs), sizeof(uint8_t));
|
||||
|
||||
memcpy(buffer, data, len);
|
||||
|
||||
@@ -315,8 +315,8 @@ void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len)
|
||||
|
||||
cmac_generate_subkeys(key, MCD_SEND);
|
||||
|
||||
uint8_t *buffer = malloc(kbs2);
|
||||
uint8_t *ivect = malloc(kbs);
|
||||
uint8_t *buffer = calloc(kbs2, sizeof(uint8_t));
|
||||
uint8_t *ivect = calloc(kbs, sizeof(uint8_t));
|
||||
|
||||
memset(ivect, 0, kbs);
|
||||
|
||||
@@ -556,7 +556,7 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
void *res = data;
|
||||
void *edata = NULL;
|
||||
tag->crypto_buffer_size = *nbytes * 2;
|
||||
tag->crypto_buffer = (uint8_t *)malloc(tag->crypto_buffer_size);
|
||||
tag->crypto_buffer = (uint8_t *)calloc(tag->crypto_buffer_size, sizeof(uint8_t));
|
||||
|
||||
uint8_t first_cmac_byte = 0x00;
|
||||
|
||||
@@ -592,7 +592,7 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
}
|
||||
|
||||
size_t edl = enciphered_data_length(tag, *nbytes, communication_settings);
|
||||
edata = malloc(edl);
|
||||
edata = calloc(edl, sizeof(uint8_t));
|
||||
|
||||
memcpy(edata, data, *nbytes);
|
||||
memset((uint8_t *)edata + *nbytes, 0, edl - *nbytes);
|
||||
|
||||
@@ -217,6 +217,7 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) {
|
||||
|
||||
char *cmd = NULL;
|
||||
bool execCommand = (script_cmd != NULL);
|
||||
bool fromInteractive = false;
|
||||
uint16_t script_cmd_len = 0;
|
||||
if (execCommand) {
|
||||
script_cmd_len = strlen(script_cmd);
|
||||
@@ -309,10 +310,10 @@ check_script:
|
||||
} else {
|
||||
// If there is a script command
|
||||
if (execCommand) {
|
||||
prompt_ctx = PROXPROMPT_CTX_SCRIPTCMD;
|
||||
prompt_ctx = stdinOnPipe ? PROXPROMPT_CTX_STDIN : PROXPROMPT_CTX_SCRIPTCMD;
|
||||
|
||||
cmd = str_dup(script_cmd);
|
||||
if (cmd != NULL)
|
||||
if ((cmd != NULL) && (! fromInteractive))
|
||||
printprompt = true;
|
||||
|
||||
uint16_t len = strlen(script_cmd) + 1;
|
||||
@@ -329,8 +330,6 @@ check_script:
|
||||
|
||||
// if there is a pipe from stdin
|
||||
if (stdinOnPipe) {
|
||||
prompt_ctx = PROXPROMPT_CTX_STDIN;
|
||||
|
||||
// clear array
|
||||
memset(script_cmd_buf, 0, sizeof(script_cmd_buf));
|
||||
// get
|
||||
@@ -338,13 +337,15 @@ check_script:
|
||||
PrintAndLogEx(ERR, "STDIN unexpected end, exit...");
|
||||
break;
|
||||
}
|
||||
execCommand = true;
|
||||
stayInCommandLoop = true;
|
||||
fromInteractive = false;
|
||||
script_cmd = script_cmd_buf;
|
||||
script_cmd_len = strlen(script_cmd);
|
||||
strcreplace(script_cmd, script_cmd_len, ';', '\0');
|
||||
// remove linebreaks
|
||||
strcleanrn(script_cmd_buf, sizeof(script_cmd_buf));
|
||||
|
||||
cmd = str_dup(script_cmd_buf);
|
||||
if (cmd != NULL)
|
||||
printprompt = true;
|
||||
|
||||
strcleanrn(script_cmd, script_cmd_len);
|
||||
goto check_script;
|
||||
} else {
|
||||
#ifdef HAVE_READLINE
|
||||
rl_event_hook = check_comm;
|
||||
@@ -358,7 +359,17 @@ check_script:
|
||||
memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !session.supports_colors);
|
||||
g_pendingPrompt = true;
|
||||
#ifdef HAVE_READLINE
|
||||
cmd = readline(prompt_filtered);
|
||||
script_cmd = readline(prompt_filtered);
|
||||
if (script_cmd != NULL) {
|
||||
execCommand = true;
|
||||
stayInCommandLoop = true;
|
||||
fromInteractive = true;
|
||||
script_cmd_len = strlen(script_cmd);
|
||||
strcreplace(script_cmd, script_cmd_len, ';', '\0');
|
||||
// remove linebreaks
|
||||
strcleanrn(script_cmd, script_cmd_len);
|
||||
goto check_script;
|
||||
}
|
||||
#else
|
||||
printf("%s", prompt_filtered);
|
||||
cmd = NULL;
|
||||
|
||||
@@ -305,7 +305,7 @@ char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t brea
|
||||
*(tmp++) = c;
|
||||
|
||||
// check if a line break is needed and we have room to print it in our array
|
||||
if (breaks) {
|
||||
if (breaks > 1) {
|
||||
if (((i + 1) % breaks) == 0) {
|
||||
|
||||
*(tmp++) = '\n';
|
||||
@@ -826,7 +826,9 @@ int binarraytohex(char *target, const size_t targetlen, char *source, size_t src
|
||||
x += (source[s] << (3 - i));
|
||||
i++;
|
||||
if (i == 4) {
|
||||
if (t >= targetlen - 2) return r;
|
||||
if (t >= targetlen - 2) {
|
||||
return r;
|
||||
}
|
||||
sprintf(target + t, "%X", x);
|
||||
t++;
|
||||
r += 4;
|
||||
@@ -835,16 +837,20 @@ int binarraytohex(char *target, const size_t targetlen, char *source, size_t src
|
||||
}
|
||||
} else {
|
||||
if (i > 0) {
|
||||
if (t >= targetlen - 5) return r;
|
||||
w = 0;
|
||||
if (t >= targetlen - 5) {
|
||||
return r;
|
||||
}
|
||||
sprintf(target + t, "%X[%i]", x, i);
|
||||
t += 4;
|
||||
r += i;
|
||||
x = 0;
|
||||
i = 0;
|
||||
w = 1;
|
||||
}
|
||||
if (w == 0) {
|
||||
if (t >= targetlen - 2) return r;
|
||||
if (t >= targetlen - 2) {
|
||||
return r;
|
||||
}
|
||||
sprintf(target + t, " ");
|
||||
t++;
|
||||
}
|
||||
|
||||
@@ -1206,6 +1206,47 @@ static bool Unpack_pw39(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool Pack_bc40(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||
|
||||
memset(packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
if (card->FacilityCode > 0xFFF) return false; // Can't encode FC.
|
||||
if (card->CardNumber > 0xFFFFF) return false; // Can't encode CN.
|
||||
if (card->IssueLevel > 0) return false; // Not used in this format
|
||||
if (card->OEM > 0x7F) return false; // Not used in this format
|
||||
|
||||
packed->Length = 39; // Set number of bits
|
||||
|
||||
set_linear_field(packed, card->OEM, 0, 7);
|
||||
|
||||
// cost center 12
|
||||
set_linear_field(packed, card->FacilityCode, 7, 12);
|
||||
set_linear_field(packed, card->CardNumber, 19, 19);
|
||||
|
||||
set_bit_by_position(packed,
|
||||
oddparity32(get_linear_field(packed, 19, 19))
|
||||
, 39);
|
||||
|
||||
if (preamble)
|
||||
return add_HID_header(packed);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Unpack_bc40(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||
memset(card, 0, sizeof(wiegand_card_t));
|
||||
|
||||
if (packed->Length != 39) return false; // Wrong length? Stop here.
|
||||
|
||||
card->OEM = get_linear_field(packed, 0, 7);
|
||||
card->FacilityCode = get_linear_field(packed, 7, 12);
|
||||
card->CardNumber = get_linear_field(packed, 19, 19);
|
||||
|
||||
card->ParityValid =
|
||||
(get_bit_by_position(packed, 39) == oddparity32(get_linear_field(packed, 19, 19)));
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
|
||||
void print_desc_wiegand(cardformat_t *fmt, wiegand_message_t *packed) {
|
||||
@@ -1324,6 +1365,7 @@ static const cardformat_t FormatTable[] = {
|
||||
{"P10001", Pack_P10001, Unpack_P10001, "HID P10001 Honeywell 40-bit", {1, 1, 0, 1, 0}}, // from cardinfo.barkweb.com.au
|
||||
{"Casi40", Pack_CasiRusco40, Unpack_CasiRusco40, "Casi-Rusco 40-bit", {1, 0, 0, 0, 0}}, // from cardinfo.barkweb.com.au
|
||||
{"C1k48s", Pack_C1k48s, Unpack_C1k48s, "HID Corporate 1000 48-bit std", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
|
||||
{"BC40", Pack_bc40, Unpack_bc40, "Bundy TimeClock 40-bit", {1, 1, 0, 1, 1}}, // from
|
||||
{NULL, NULL, NULL, NULL, {0, 0, 0, 0, 0}} // Must null terminate array
|
||||
};
|
||||
|
||||
@@ -1341,7 +1383,7 @@ void HIDListFormats(void) {
|
||||
++i;
|
||||
}
|
||||
PrintAndLogEx(INFO, "------------------------------------------------------------");
|
||||
PrintAndLogEx(INFO, "Available card formats: " _YELLOW_("%u"), ARRAYLEN(FormatTable));
|
||||
PrintAndLogEx(INFO, "Available card formats: " _YELLOW_("%" PRIu64), ARRAYLEN(FormatTable));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -176,19 +176,19 @@ bool add_HID_header(wiegand_message_t *data) {
|
||||
return false;
|
||||
|
||||
if (data->Length >= 64) {
|
||||
data->Top |= 1 << (data->Length - 64); // leading 1: start bit
|
||||
data->Top |= 0x09e00000; // Extended-length header
|
||||
data->Top |= 1U << (data->Length - 64); // leading 1: start bit
|
||||
} else if (data->Length > 37) {
|
||||
data->Mid |= 1 << (data->Length - 32); // leading 1: start bit
|
||||
data->Top |= 0x09e00000; // Extended-length header
|
||||
data->Mid |= 1U << (data->Length - 32); // leading 1: start bit
|
||||
} else if (data->Length == 37) {
|
||||
// No header bits added to 37-bit cards
|
||||
} else if (data->Length >= 32) {
|
||||
data->Mid |= 0x20; // Bit 37; standard header
|
||||
data->Mid |= 1 << (data->Length - 32); // leading 1: start bit
|
||||
data->Mid |= 1U << (data->Length - 32); // leading 1: start bit
|
||||
} else {
|
||||
data->Mid |= 0x20; // Bit 37; standard header
|
||||
data->Bot |= 1 << data->Length; // leading 1: start bit
|
||||
data->Bot |= 1U << data->Length; // leading 1: start bit
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
|
||||
- Android phone
|
||||
- [Termux](https://play.google.com/store/apps/details?id=com.termux)
|
||||
- Proxmark3 RDV4
|
||||
- Blueshark Standalone Module (Bluetooth ONLY)
|
||||
- Proxmark with BTADDON compiled Firmware (Bluetooth ONLY) (https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md#platform_extras)
|
||||
|
||||
|
||||
## Notes
|
||||
^[Top](#top)
|
||||
|
||||
@@ -131,6 +131,15 @@ extern bool tearoff_enabled;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// convert 2 bytes to U16
|
||||
#ifndef BYTES2UINT16
|
||||
# define BYTES2UINT16(x) ((x[1] << 8) | (x[0]))
|
||||
#endif
|
||||
// convert 4 bytes to U32
|
||||
#ifndef BYTES2UINT32
|
||||
# define BYTES2UINT32(x) ((x[3] << 24) | (x[2] << 16) | (x[1] << 8) | (x[0]))
|
||||
#endif
|
||||
|
||||
#define EVEN 0
|
||||
#define ODD 1
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#ifndef EM4X50_H__
|
||||
#define EM4X50_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define EM4X50_NO_WORDS 34
|
||||
|
||||
// special words
|
||||
@@ -45,8 +47,6 @@
|
||||
#define TIMEOUT_CMD 3000
|
||||
#define DUMP_FILESIZE 136
|
||||
|
||||
#define BYTES2UINT32(x) ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3]))
|
||||
|
||||
typedef struct {
|
||||
bool addr_given;
|
||||
bool pwd_given;
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
# define FLASH_MEM_MAX_4K_SECTOR 0x3F000
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef FLASH_MEM_ID_LEN
|
||||
# define FLASH_MEM_ID_LEN 8
|
||||
#endif
|
||||
@@ -79,4 +78,9 @@ typedef struct {
|
||||
uint8_t signature[FLASH_MEM_SIGNATURE_LEN];
|
||||
} PACKED rdv40_validation_t;
|
||||
|
||||
// SPIFFS current allocates 128kb of the 256kb available.
|
||||
#ifndef FLASH_SPIFFS_ALLOCATED_SIZE
|
||||
# define FLASH_SPIFFS_ALLOCATED_SIZE (1024 * 128)
|
||||
#endif
|
||||
|
||||
#endif // __PMFLASH_H
|
||||
|
||||
@@ -41,12 +41,12 @@
|
||||
#define SSC_CLOCK_MODE_SELECT(x) ((x) << 0)
|
||||
#define SSC_FRAME_MODE_BITS_IN_WORD(x) (((x)-1) << 0)
|
||||
|
||||
#define MC_FLASH_COMMAND_KEY ((0x5a) << 24)
|
||||
#define MC_FLASH_COMMAND_KEY ((0x5A) << 24)
|
||||
#define MC_FLASH_MODE_FLASH_WAIT_STATES(x) ((x) << 8)
|
||||
#define MC_FLASH_MODE_MASTER_CLK_IN_MHZ(x) (((x)+((x)/2)) << 16)
|
||||
#define MC_FLASH_COMMAND_PAGEN(x) ((x) << 8)
|
||||
|
||||
#define RST_CONTROL_KEY (0xa5 << 24)
|
||||
#define RST_CONTROL_KEY (0xA5U << 24)
|
||||
|
||||
#define PMC_MAIN_OSC_STARTUP_DELAY(x) ((x) << 8)
|
||||
#define PMC_PLL_DIVISOR(x) (x)
|
||||
|
||||
@@ -97,7 +97,10 @@ static int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile) {
|
||||
|
||||
memcpy(ring_buffer, fpga_config + current_in, bytes_to_copy);
|
||||
int cmp_bytes = LZ4_compress_HC_continue(lz4_streamhc, ring_buffer, outbuf, bytes_to_copy, outsize_max);
|
||||
|
||||
if (cmp_bytes < 0 ){
|
||||
fprintf(stderr, "(lz4 - zlib_compress) error, got negative number of bytes from LZ4_compress_HC_continue call. got %d ", cmp_bytes);
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
fwrite(&cmp_bytes, sizeof(int), 1, outfile);
|
||||
fwrite(outbuf, sizeof(char), cmp_bytes, outfile);
|
||||
|
||||
@@ -118,7 +121,7 @@ static int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile) {
|
||||
fprintf(stdout, "compressed %u input bytes to %d output bytes\n", total_size, current_out);
|
||||
|
||||
if (current_out == 0) {
|
||||
fprintf(stderr, "Error in lz4");
|
||||
fprintf(stderr, "error in lz4");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
return (EXIT_SUCCESS);
|
||||
@@ -204,18 +207,27 @@ static int bitparse_find_section(FILE *infile, char section_name, unsigned int *
|
||||
break;
|
||||
}
|
||||
unsigned int current_length = 0;
|
||||
int tmp;
|
||||
switch (current_name) {
|
||||
case 'e':
|
||||
/* Four byte length field */
|
||||
current_length += fgetc(infile) << 24;
|
||||
current_length += fgetc(infile) << 16;
|
||||
current_length += fgetc(infile) << 8;
|
||||
current_length += fgetc(infile) << 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
tmp = fgetc(infile);
|
||||
if (tmp < 0 ) {
|
||||
break;
|
||||
}
|
||||
current_length += tmp << (24 - (i * 8));
|
||||
}
|
||||
numbytes += 4;
|
||||
break;
|
||||
default: /* Fall through, two byte length field */
|
||||
current_length += fgetc(infile) << 8;
|
||||
current_length += fgetc(infile) << 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
tmp = fgetc(infile);
|
||||
if (tmp < 0 ) {
|
||||
break;
|
||||
}
|
||||
current_length += tmp << (8 - (i * 8));
|
||||
}
|
||||
numbytes += 2;
|
||||
break;
|
||||
}
|
||||
@@ -290,6 +302,7 @@ static int FpgaGatherVersion(FILE *infile, char *infile_name, char *dst, int len
|
||||
for (uint16_t i = 0; i < fpga_info_len; i++) {
|
||||
char c = (char)fgetc(infile);
|
||||
if (i < sizeof(tempstr)) {
|
||||
if (c == ' ') c = '0';
|
||||
tempstr[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
MYSRCPATHS = ../../common ../../common/crapto1
|
||||
MYSRCS = crypto1.c crapto1.c bucketsort.c iso14443crc.c sleep.c
|
||||
MYSRCS = crypto1.c crapto1.c bucketsort.c iso14443crc.c sleep.c util_posix.c
|
||||
MYINCLUDES = -I../../include -I../../common
|
||||
MYCFLAGS =
|
||||
MYDEFS =
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
#define __STDC_FORMAT_MACROS
|
||||
|
||||
#if !defined(_WIN64)
|
||||
#if defined(_WIN32) || defined(__WIN32__)
|
||||
# define _USE_32BIT_TIME_T 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
@@ -13,11 +7,11 @@
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include "crapto1/crapto1.h"
|
||||
#include "protocol.h"
|
||||
#include "iso14443crc.h"
|
||||
#include "util_posix.h"
|
||||
|
||||
#define AEND "\x1b[0m"
|
||||
#define _RED_(s) "\x1b[31m" s AEND
|
||||
@@ -74,11 +68,11 @@ uint8_t cmds[8][2] = {
|
||||
{MIFARE_CMD_TRANSFER, 0}
|
||||
};
|
||||
|
||||
int global_counter = 0;
|
||||
int global_found = 0;
|
||||
int global_found_candidate = 0;
|
||||
uint64_t global_candiate_key = 0;
|
||||
size_t thread_count = 2;
|
||||
//static int global_counter = 0;
|
||||
static int global_found = 0;
|
||||
static int global_found_candidate = 0;
|
||||
static uint64_t global_candiate_key = 0;
|
||||
static int thread_count = 2;
|
||||
|
||||
static int param_getptr(const char *line, int *bg, int *en, int paramnum) {
|
||||
int i;
|
||||
@@ -390,7 +384,7 @@ static void *brute_thread(void *arguments) {
|
||||
|
||||
nt = count << 16 | prng_successor(count, 16);
|
||||
|
||||
if (!candidate_nonce(args->xored, nt, args->ev1))
|
||||
if (candidate_nonce(args->xored, nt, args->ev1) == false)
|
||||
continue;
|
||||
|
||||
p64 = prng_successor(nt, 64);
|
||||
@@ -420,14 +414,17 @@ static void *brute_thread(void *arguments) {
|
||||
|
||||
// check if cmd exists
|
||||
uint8_t isOK = checkValidCmd(decrypted);
|
||||
(void)isOK;
|
||||
if (isOK == false) {
|
||||
printf(_RED_("<-- not a valid cmd\n"));
|
||||
pthread_mutex_unlock(&print_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add a crc-check.
|
||||
isOK = checkCRC(decrypted);
|
||||
if (isOK == false) {
|
||||
printf(_RED_("<-- not a valid cmd\n"));
|
||||
printf(_RED_("<-- not a valid crc\n"));
|
||||
pthread_mutex_unlock(&print_lock);
|
||||
free(revstate);
|
||||
continue;
|
||||
} else {
|
||||
printf("<-- valid cmd\n");
|
||||
@@ -440,7 +437,6 @@ static void *brute_thread(void *arguments) {
|
||||
lfsr_rollback_word(revstate, nr_enc, 1);
|
||||
lfsr_rollback_word(revstate, uid ^ nt, 0);
|
||||
crypto1_get_lfsr(revstate, &key);
|
||||
free(revstate);
|
||||
|
||||
if (args->ev1) {
|
||||
// if it was EV1, we know for sure xxxAAAAAAAA recovery
|
||||
@@ -450,11 +446,13 @@ static void *brute_thread(void *arguments) {
|
||||
printf("\nKey candidate [ " _GREEN_("....%08" PRIx64) " ]\n\n", key & 0xFFFFFFFF);
|
||||
__sync_fetch_and_add(&global_found, 1);
|
||||
}
|
||||
__sync_fetch_and_add(&global_candiate_key, key);
|
||||
//release lock
|
||||
pthread_mutex_unlock(&print_lock);
|
||||
__sync_fetch_and_add(&global_candiate_key, key);
|
||||
free(revstate);
|
||||
break;
|
||||
}
|
||||
free(revstate);
|
||||
}
|
||||
free(args);
|
||||
return NULL;
|
||||
@@ -463,7 +461,7 @@ static void *brute_thread(void *arguments) {
|
||||
static void *brute_key_thread(void *arguments) {
|
||||
|
||||
struct thread_key_args *args = (struct thread_key_args *) arguments;
|
||||
uint64_t key;
|
||||
uint64_t key = args->part_key;
|
||||
uint8_t local_enc[args->enc_len];
|
||||
memcpy(local_enc, args->enc, args->enc_len);
|
||||
|
||||
@@ -473,7 +471,7 @@ static void *brute_key_thread(void *arguments) {
|
||||
break;
|
||||
}
|
||||
|
||||
key = (count << 32 | args->part_key);
|
||||
key |= (count << 32);
|
||||
|
||||
// Init cipher with key
|
||||
struct Crypto1State *pcs = crypto1_create(key);
|
||||
@@ -489,13 +487,13 @@ static void *brute_key_thread(void *arguments) {
|
||||
for (int i = 0; i < args->enc_len; i++)
|
||||
dec[i] = crypto1_byte(pcs, 0x00, 0) ^ local_enc[i];
|
||||
|
||||
crypto1_deinit(pcs);
|
||||
crypto1_destroy(pcs);
|
||||
|
||||
// check if cmd exists
|
||||
uint8_t isOK = checkValidCmdByte(dec, args->enc_len);
|
||||
if (isOK == false) {
|
||||
if (checkValidCmdByte(dec, args->enc_len) == false) {
|
||||
continue;
|
||||
}
|
||||
__sync_fetch_and_add(&global_found, 1);
|
||||
|
||||
// lock this section to avoid interlacing prints from different threats
|
||||
pthread_mutex_lock(&print_lock);
|
||||
@@ -503,7 +501,6 @@ static void *brute_key_thread(void *arguments) {
|
||||
printf("dec: %s\n", sprint_hex_inrow_ex(dec, args->enc_len, 0));
|
||||
printf("\nValid Key found [ " _GREEN_("%012" PRIx64) " ]\n\n", key);
|
||||
pthread_mutex_unlock(&print_lock);
|
||||
__sync_fetch_and_add(&global_found, 1);
|
||||
break;
|
||||
}
|
||||
free(args);
|
||||
@@ -568,7 +565,7 @@ int main(int argc, char *argv[]) {
|
||||
printf("next encrypted cmd... %s\n", sprint_hex_inrow_ex(enc, enc_len, 0));
|
||||
}
|
||||
|
||||
clock_t t1 = clock();
|
||||
uint64_t t1 = msclock();
|
||||
uint16_t nt_par = parity_from_err(nt_enc, nt_par_err);
|
||||
uint16_t ar_par = parity_from_err(ar_enc, ar_par_err);
|
||||
uint16_t at_par = parity_from_err(at_enc, at_par_err);
|
||||
@@ -582,7 +579,7 @@ int main(int argc, char *argv[]) {
|
||||
thread_count = 2;
|
||||
#endif /* _WIN32 */
|
||||
|
||||
printf("\nBruteforce using " _YELLOW_("%zu") " threads\n", thread_count);
|
||||
printf("\nBruteforce using " _YELLOW_("%d") " threads\n", thread_count);
|
||||
printf("looking for the last bytes of the encrypted tagnonce\n");
|
||||
|
||||
pthread_t threads[thread_count];
|
||||
@@ -591,7 +588,7 @@ int main(int argc, char *argv[]) {
|
||||
pthread_mutex_init(&print_lock, NULL);
|
||||
|
||||
// one thread T0 for none EV1.
|
||||
struct thread_args *a = malloc(sizeof(struct thread_args));
|
||||
struct thread_args *a = calloc(1, sizeof(struct thread_args));
|
||||
a->xored = xored;
|
||||
a->thread = 0;
|
||||
a->idx = 0;
|
||||
@@ -600,7 +597,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// the rest of available threads to EV1 scenario
|
||||
for (int i = 0; i < thread_count - 1; ++i) {
|
||||
struct thread_args *b = malloc(sizeof(struct thread_args));
|
||||
struct thread_args *b = calloc(1, sizeof(struct thread_args));
|
||||
b->xored = xored;
|
||||
b->thread = i + 1;
|
||||
b->idx = i;
|
||||
@@ -612,8 +609,8 @@ int main(int argc, char *argv[]) {
|
||||
for (int i = 0; i < thread_count; ++i)
|
||||
pthread_join(threads[i], NULL);
|
||||
|
||||
t1 = clock() - t1;
|
||||
printf("execution time %.2f sec\n", (float)t1 / 1000000.0);
|
||||
t1 = msclock() - t1;
|
||||
printf("execution time " _YELLOW_("%.2f") " sec\n", (float)t1 / 1000.0);
|
||||
|
||||
|
||||
if (!global_found && !global_found_candidate) {
|
||||
@@ -631,11 +628,11 @@ int main(int argc, char *argv[]) {
|
||||
global_found_candidate = 0;
|
||||
|
||||
printf("\n----------- " _CYAN_("Phase 2") " ------------------------\n");
|
||||
printf("uid.......... %08x\n", uid);
|
||||
printf("partial key.. %08x\n", (uint32_t)(global_candiate_key & 0xFFFFFFFF));
|
||||
printf("nt enc....... %08x\n", nt_enc);
|
||||
printf("nr enc....... %08x\n", nr_enc);
|
||||
printf("next encrypted cmd: %s\n", sprint_hex_inrow_ex(enc, enc_len, 0));
|
||||
printf("uid.................. %08x\n", uid);
|
||||
printf("partial key.......... %08x\n", (uint32_t)(global_candiate_key & 0xFFFFFFFF));
|
||||
printf("nt enc............... %08x\n", nt_enc);
|
||||
printf("nr enc............... %08x\n", nr_enc);
|
||||
printf("next encrypted cmd... %s\n", sprint_hex_inrow_ex(enc, enc_len, 0));
|
||||
printf("\nlooking for the upper 16 bits of key\n");
|
||||
fflush(stdout);
|
||||
|
||||
|
||||
@@ -9,12 +9,6 @@
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
|
||||
#if !defined(_WIN64)
|
||||
#if defined(_WIN32) || defined(__WIN32__)
|
||||
# define _USE_32BIT_TIME_T 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
@@ -23,10 +17,16 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "ctype.h"
|
||||
#include <time.h>
|
||||
#include "crapto1/crapto1.h"
|
||||
#include "protocol.h"
|
||||
#include "iso14443crc.h"
|
||||
#include <util_posix.h>
|
||||
|
||||
#define AEND "\x1b[0m"
|
||||
#define _RED_(s) "\x1b[31m" s AEND
|
||||
#define _GREEN_(s) "\x1b[32m" s AEND
|
||||
#define _YELLOW_(s) "\x1b[33m" s AEND
|
||||
#define _CYAN_(s) "\x1b[36m" s AEND
|
||||
|
||||
// a global mutex to prevent interlaced printing from different threads
|
||||
pthread_mutex_t print_lock;
|
||||
@@ -41,26 +41,24 @@ typedef struct thread_args {
|
||||
uint32_t part_key;
|
||||
uint32_t nt_enc;
|
||||
uint32_t nr_enc;
|
||||
uint16_t enc_len;
|
||||
uint8_t enc[ENC_LEN]; // next encrypted command + a full read/write
|
||||
} targs;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
uint8_t cmds[] = {
|
||||
ISO14443A_CMD_READBLOCK,
|
||||
ISO14443A_CMD_WRITEBLOCK,
|
||||
MIFARE_AUTH_KEYA,
|
||||
MIFARE_AUTH_KEYB,
|
||||
MIFARE_CMD_INC,
|
||||
MIFARE_CMD_DEC,
|
||||
MIFARE_CMD_RESTORE,
|
||||
MIFARE_CMD_TRANSFER
|
||||
uint8_t cmds[8][2] = {
|
||||
{ISO14443A_CMD_READBLOCK, 18},
|
||||
{ISO14443A_CMD_WRITEBLOCK, 18},
|
||||
{MIFARE_AUTH_KEYA, 0},
|
||||
{MIFARE_AUTH_KEYB, 0},
|
||||
{MIFARE_CMD_INC, 6},
|
||||
{MIFARE_CMD_DEC, 6},
|
||||
{MIFARE_CMD_RESTORE, 6},
|
||||
{MIFARE_CMD_TRANSFER, 0}
|
||||
};
|
||||
|
||||
int global_counter = 0;
|
||||
int global_fin_flag = 0;
|
||||
int global_found = 0;
|
||||
int global_found_candidate = 0;
|
||||
size_t thread_count = 2;
|
||||
static int global_found = 0;
|
||||
static int thread_count = 2;
|
||||
|
||||
static int param_getptr(const char *line, int *bg, int *en, int paramnum) {
|
||||
int i;
|
||||
@@ -174,67 +172,71 @@ static char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const si
|
||||
return buf;
|
||||
}
|
||||
|
||||
static bool checkValidCmdByte(uint8_t *cmd, uint16_t n) {
|
||||
|
||||
bool ok = false;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
if (cmd[0] == cmds[i][0]) {
|
||||
|
||||
if (n >= 4)
|
||||
ok = CheckCrc14443(CRC_14443_A, cmd, 4);
|
||||
|
||||
if (cmds[i][1] > 0 && n >= cmds[i][1])
|
||||
ok = CheckCrc14443(CRC_14443_A, cmd + 4, cmds[i][1]);
|
||||
|
||||
if (ok) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void *brute_thread(void *arguments) {
|
||||
|
||||
//int shift = (int)arg;
|
||||
struct thread_args *args = (struct thread_args *) arguments;
|
||||
|
||||
uint64_t key; // recovered key candidate
|
||||
int found = 0;
|
||||
struct Crypto1State mpcs = {0, 0};
|
||||
struct Crypto1State *pcs = &mpcs;
|
||||
|
||||
uint8_t local_enc[ENC_LEN] = {0};
|
||||
memcpy(local_enc, args->enc, sizeof(local_enc));
|
||||
uint64_t key = args->part_key;
|
||||
uint8_t local_enc[args->enc_len];
|
||||
memcpy(local_enc, args->enc, args->enc_len);
|
||||
|
||||
for (uint64_t count = args->idx; count < 0xFFFF; count += thread_count) {
|
||||
|
||||
found = global_found;
|
||||
if (found) {
|
||||
if (__atomic_load_n(&global_found, __ATOMIC_ACQUIRE) == 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
key = (count << 32 | args->part_key);
|
||||
key |= count << 32;
|
||||
|
||||
// Init cipher with key
|
||||
pcs = crypto1_create(key);
|
||||
struct Crypto1State *pcs = crypto1_create(key);
|
||||
|
||||
// NESTED decrypt nt with help of new key
|
||||
// if (args->use_nested)
|
||||
// crypto1_word(pcs, args->nt_enc ^ args->uid, 1) ^ args->nt_enc;
|
||||
// else
|
||||
crypto1_word(pcs, args->nt_enc ^ args->uid, 1);
|
||||
|
||||
crypto1_word(pcs, args->nr_enc, 1);
|
||||
crypto1_word(pcs, 0, 0);
|
||||
crypto1_word(pcs, 0, 0);
|
||||
|
||||
// decrypt 22 bytes
|
||||
uint8_t dec[ENC_LEN] = {0};
|
||||
for (int i = 0; i < ENC_LEN; i++)
|
||||
uint8_t dec[args->enc_len];
|
||||
for (int i = 0; i < args->enc_len; i++)
|
||||
dec[i] = crypto1_byte(pcs, 0x00, 0) ^ local_enc[i];
|
||||
|
||||
crypto1_deinit(pcs);
|
||||
crypto1_destroy(pcs);
|
||||
|
||||
if (CheckCrc14443(CRC_14443_A, dec, 4)) {
|
||||
|
||||
// check crc-16 in the end
|
||||
|
||||
if (CheckCrc14443(CRC_14443_A, dec + 4, 18)) {
|
||||
|
||||
// lock this section to avoid interlacing prints from different threats
|
||||
pthread_mutex_lock(&print_lock);
|
||||
printf("\nValid Key found: [%012" PRIx64 "]\n", key);
|
||||
|
||||
printf("enc: %s\n", sprint_hex_inrow_ex(local_enc, ENC_LEN, 0));
|
||||
printf(" xx crcA crcA\n");
|
||||
printf("dec: %s\n", sprint_hex_inrow_ex(dec, ENC_LEN, 0));
|
||||
pthread_mutex_unlock(&print_lock);
|
||||
|
||||
__sync_fetch_and_add(&global_found, 1);
|
||||
}
|
||||
if (checkValidCmdByte(dec, args->enc_len) == false) {
|
||||
continue;
|
||||
}
|
||||
__sync_fetch_and_add(&global_found, 1);
|
||||
|
||||
// lock this section to avoid interlacing prints from different threats
|
||||
pthread_mutex_lock(&print_lock);
|
||||
printf("\nenc: %s\n", sprint_hex_inrow_ex(local_enc, args->enc_len, 0));
|
||||
printf("dec: %s\n", sprint_hex_inrow_ex(dec, args->enc_len, 0));
|
||||
printf("\nValid Key found [ " _GREEN_("%012" PRIx64) " ]\n\n", key);
|
||||
pthread_mutex_unlock(&print_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
free(args);
|
||||
return NULL;
|
||||
}
|
||||
@@ -245,7 +247,7 @@ static int usage(void) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
printf("Mifare classic nested auth key recovery. Phase 2.\n");
|
||||
printf("Mifare classic nested auth key recovery Phase 2\n");
|
||||
if (argc < 3) return usage();
|
||||
|
||||
uint32_t uid = 0; // serial number
|
||||
@@ -263,13 +265,13 @@ int main(int argc, char *argv[]) {
|
||||
param_gethex_to_eol(argv[5], 0, enc, sizeof(enc), &enc_len);
|
||||
|
||||
printf("-------------------------------------------------\n");
|
||||
printf("uid.......... %08x\n", uid);
|
||||
printf("partial key.. %08x\n", part_key);
|
||||
printf("nt enc....... %08x\n", nt_enc);
|
||||
printf("nr enc....... %08x\n", nr_enc);
|
||||
printf("next encrypted cmd: %s\n", sprint_hex_inrow_ex(enc, ENC_LEN, 0));
|
||||
printf("uid.................. %08x\n", uid);
|
||||
printf("partial key.......... %08x\n", part_key);
|
||||
printf("nt enc............... %08x\n", nt_enc);
|
||||
printf("nr enc............... %08x\n", nr_enc);
|
||||
printf("next encrypted cmd... %s\n", sprint_hex_inrow_ex(enc, enc_len, 0));
|
||||
|
||||
clock_t t1 = clock();
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
#if !defined(_WIN32) || !defined(__WIN32__)
|
||||
thread_count = sysconf(_SC_NPROCESSORS_CONF);
|
||||
@@ -277,7 +279,7 @@ int main(int argc, char *argv[]) {
|
||||
thread_count = 2;
|
||||
#endif /* _WIN32 */
|
||||
|
||||
printf("\nBruteforce using %zu threads to find upper 16bits of key\n", thread_count);
|
||||
printf("\nBruteforce using %d threads to find upper 16bits of key\n", thread_count);
|
||||
|
||||
pthread_t threads[thread_count];
|
||||
|
||||
@@ -286,14 +288,15 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// threads
|
||||
for (int i = 0; i < thread_count; ++i) {
|
||||
struct thread_args *a = malloc(sizeof(struct thread_args));
|
||||
struct thread_args *a = calloc(1, sizeof(struct thread_args));
|
||||
a->thread = i;
|
||||
a->idx = i;
|
||||
a->uid = uid;
|
||||
a->part_key = part_key;
|
||||
a->nt_enc = nt_enc;
|
||||
a->nr_enc = nr_enc;
|
||||
memcpy(a->enc, enc, sizeof(a->enc));
|
||||
a->enc_len = enc_len;
|
||||
memcpy(a->enc, enc, enc_len);
|
||||
pthread_create(&threads[i], NULL, brute_thread, (void *)a);
|
||||
}
|
||||
|
||||
@@ -301,13 +304,13 @@ int main(int argc, char *argv[]) {
|
||||
for (int i = 0; i < thread_count; ++i)
|
||||
pthread_join(threads[i], NULL);
|
||||
|
||||
if (!global_found && !global_found_candidate) {
|
||||
if (global_found == false) {
|
||||
printf("\nFailed to find a key\n\n");
|
||||
}
|
||||
|
||||
t1 = clock() - t1;
|
||||
t1 = msclock() - t1;
|
||||
if (t1 > 0)
|
||||
printf("Execution time: %.0f ticks\n", (float)t1);
|
||||
printf("execution time " _YELLOW_("%.2f") " sec\n", (float)t1 / 1000.0);
|
||||
|
||||
// clean up mutex
|
||||
pthread_mutex_destroy(&print_lock);
|
||||
|
||||
137
tools/mf_nonce_brute/util_posix.c
Normal file
137
tools/mf_nonce_brute/util_posix.c
Normal file
@@ -0,0 +1,137 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// 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
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// utilities requiring Posix library functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// ensure availability even with -std=c99; must be included before
|
||||
#if !defined(_WIN32)
|
||||
//#define _POSIX_C_SOURCE 199309L // need nanosleep()
|
||||
#define _POSIX_C_SOURCE 200112L // need localtime_r()
|
||||
#else
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "util_posix.h"
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
// Timer functions
|
||||
#if !defined (_WIN32)
|
||||
#include <errno.h>
|
||||
|
||||
static void nsleep(uint64_t n) {
|
||||
struct timespec timeout;
|
||||
timeout.tv_sec = n / 1000000000;
|
||||
timeout.tv_nsec = n % 1000000000;
|
||||
while (nanosleep(&timeout, &timeout) && errno == EINTR);
|
||||
}
|
||||
|
||||
void msleep(uint32_t n) {
|
||||
nsleep(1000000 * (uint64_t)n);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#ifndef CLOCK_MONOTONIC
|
||||
#define CLOCK_MONOTONIC (1)
|
||||
#endif
|
||||
#ifndef CLOCK_REALTIME
|
||||
#define CLOCK_REALTIME (2)
|
||||
#endif
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
/* clock_gettime is not implemented on OSX prior to 10.12 */
|
||||
int _civet_clock_gettime(int clk_id, struct timespec *t);
|
||||
|
||||
int _civet_clock_gettime(int clk_id, struct timespec *t) {
|
||||
memset(t, 0, sizeof(*t));
|
||||
if (clk_id == CLOCK_REALTIME) {
|
||||
struct timeval now;
|
||||
int rv = gettimeofday(&now, NULL);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
t->tv_sec = now.tv_sec;
|
||||
t->tv_nsec = now.tv_usec * 1000;
|
||||
return 0;
|
||||
|
||||
} else if (clk_id == CLOCK_MONOTONIC) {
|
||||
static uint64_t clock_start_time = 0;
|
||||
static mach_timebase_info_data_t timebase_info = {0, 0};
|
||||
|
||||
uint64_t now = mach_absolute_time();
|
||||
|
||||
if (clock_start_time == 0) {
|
||||
|
||||
mach_timebase_info(&timebase_info);
|
||||
clock_start_time = now;
|
||||
}
|
||||
|
||||
now = (uint64_t)((double)(now - clock_start_time)
|
||||
* (double)timebase_info.numer
|
||||
/ (double)timebase_info.denom);
|
||||
|
||||
t->tv_sec = now / 1000000000;
|
||||
t->tv_nsec = now % 1000000000;
|
||||
return 0;
|
||||
}
|
||||
return -1; // EINVAL - Clock ID is unknown
|
||||
}
|
||||
|
||||
/* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */
|
||||
#ifdef __CLOCK_AVAILABILITY
|
||||
/* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be declared
|
||||
* but it may be NULL at runtime. So we need to check before using it. */
|
||||
int _civet_safe_clock_gettime(int clk_id, struct timespec *t);
|
||||
|
||||
int _civet_safe_clock_gettime(int clk_id, struct timespec *t) {
|
||||
if (clock_gettime) {
|
||||
return clock_gettime(clk_id, t);
|
||||
}
|
||||
return _civet_clock_gettime(clk_id, t);
|
||||
}
|
||||
#define clock_gettime _civet_safe_clock_gettime
|
||||
#else
|
||||
#define clock_gettime _civet_clock_gettime
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// a milliseconds timer for performance measurement
|
||||
uint64_t msclock(void) {
|
||||
#if defined(_WIN32)
|
||||
#include <sys/types.h>
|
||||
|
||||
// WORKAROUND FOR MinGW (some versions - use if normal code does not compile)
|
||||
// It has no _ftime_s and needs explicit inclusion of timeb.h
|
||||
#include <sys/timeb.h>
|
||||
struct _timeb t;
|
||||
_ftime(&t);
|
||||
return 1000 * (uint64_t)t.time + t.millitm;
|
||||
|
||||
// NORMAL CODE (use _ftime_s)
|
||||
//struct _timeb t;
|
||||
//if (_ftime_s(&t)) {
|
||||
// return 0;
|
||||
//} else {
|
||||
// return 1000 * t.time + t.millitm;
|
||||
//}
|
||||
#else
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
return (1000 * (uint64_t)t.tv_sec + t.tv_nsec / 1000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
26
tools/mf_nonce_brute/util_posix.h
Normal file
26
tools/mf_nonce_brute/util_posix.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// 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
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// utilities requiring Posix library functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef UTIL_POSIX_H__
|
||||
#define UTIL_POSIX_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
# define sleep(n) Sleep(1000 *(n))
|
||||
# define msleep(n) Sleep((n))
|
||||
#else
|
||||
void msleep(uint32_t n); // sleep n milliseconds
|
||||
#endif // _WIN32
|
||||
|
||||
uint64_t msclock(void); // a milliseconds clock
|
||||
|
||||
#endif
|
||||
@@ -275,8 +275,8 @@ while true; do
|
||||
if $TESTALL || $TESTMFNONCEBRUTE; then
|
||||
echo -e "\n${C_BLUE}Testing mf_nonce_brute:${C_NC} ${MFNONCEBRUTEBIN:=./tools/mf_nonce_brute/mf_nonce_brute}"
|
||||
if ! CheckFileExist "mf_nonce_brute exists" "$MFNONCEBRUTEBIN"; then break; fi
|
||||
# if ! CheckExecute slow "mf_nonce_brute test" "$MFNONCEBRUTEBIN 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a" "Key found \[.*ffffffffffff.*\]"; then break; fi
|
||||
if ! CheckExecute slow "mf_nonce_brute test" "$MFNONCEBRUTEBIN 96519578 d7e3c6ac 0011 cd311951 9da49e49 0010 2bb22e00 0100 a4f7f398" "Key found \[.*3b7e4fd575ad.*\]"; then break; fi
|
||||
if ! CheckExecute slow "mf_nonce_brute test" "$MFNONCEBRUTEBIN 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a" "Key found \[.*ffffffffffff.*\]"; then break; fi
|
||||
# if ! CheckExecute slow "mf_nonce_brute test" "$MFNONCEBRUTEBIN 96519578 d7e3c6ac 0011 cd311951 9da49e49 0010 2bb22e00 0100 a4f7f398" "Key found \[.*3b7e4fd575ad.*\]"; then break; fi
|
||||
fi
|
||||
# hitag2crack not yet part of "all"
|
||||
# if $TESTALL || $TESTHITAG2CRACK; then
|
||||
@@ -351,6 +351,12 @@ while true; do
|
||||
if ! CheckExecute "proxmark help text ISO7816" "$CLIENTBIN -t 2>&1" "ISO7816"; then break; fi
|
||||
if ! CheckExecute "proxmark help text hardnested" "$CLIENTBIN -t 2>&1" "hardnested"; then break; fi
|
||||
if ! CheckExecute "proxmark full help dump" "$CLIENTBIN --fulltext 2>&1" "Full help dump done"; then break; fi
|
||||
if ! CheckExecute "proxmark multi cmds 1/2" "$CLIENTBIN -c 'rem foo;rem bar'" "remark: foo"; then break; fi
|
||||
if ! CheckExecute "proxmark multi cmds 2/2" "$CLIENTBIN -c 'rem foo;rem bar'" "remark: bar"; then break; fi
|
||||
if ! CheckExecute "proxmark multi stdin 1/4" "echo 'rem foo;rem bar;quit' |$CLIENTBIN" "remark: foo"; then break; fi
|
||||
if ! CheckExecute "proxmark multi stdin 2/4" "echo 'rem foo;rem bar;quit' |$CLIENTBIN" "remark: bar"; then break; fi
|
||||
if ! CheckExecute "proxmark multi stdin 3/4" "echo -e 'rem foo\nrem bar;quit' |$CLIENTBIN" "remark: foo"; then break; fi
|
||||
if ! CheckExecute "proxmark multi stdin 4/4" "echo -e 'rem foo\nrem bar;quit' |$CLIENTBIN" "remark: bar"; then break; fi
|
||||
|
||||
echo -e "\n${C_BLUE}Testing data manipulation:${C_NC}"
|
||||
if ! CheckExecute "reveng readline test" "$CLIENTBIN -c 'reveng -h;reveng -D'" "CRC-64/GO-ISO"; then break; fi
|
||||
|
||||
Reference in New Issue
Block a user