Add hf mfu cchk/aeschk and options to hf mf cauth/aesauth

This commit is contained in:
Philippe Teuwen
2026-01-19 21:47:49 +01:00
parent 6942c41155
commit a26892a891
14 changed files with 775 additions and 165 deletions
+4 -4
View File
@@ -1864,12 +1864,12 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareUReadBlock((mful_readblock_t *)packet->data.asBytes);
break;
}
case CMD_HF_MIFAREUC_AUTH: {
MifareUC_Auth(packet->oldarg[0], packet->data.asBytes);
case CMD_HF_MIFAREU3P_AUTH: {
MifareU3PassAuth((mful_3passauth_t *)packet->data.asBytes);
break;
}
case CMD_HF_MIFAREULAES_AUTH: {
MifareUL_AES_Auth((mfulaes_keys_t *)packet->data.asBytes);
case CMD_HF_MIFAREU3P_CHKKEY: {
MifareU3PassChkKeys((mful_3passchk_t *)packet->data.asBytes);
break;
}
case CMD_HF_MIFAREU_READCARD: {
+1 -1
View File
@@ -3043,7 +3043,7 @@ static void iso14a_set_ATS_times(const uint8_t *ats) {
}
static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, const iso14a_polling_parameters_t *polling_parameters) {
int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, const iso14a_polling_parameters_t *polling_parameters) {
#define RETRY_TIMEOUT 10
uint32_t save_iso14a_timeout = iso14a_get_timeout();
+1
View File
@@ -161,6 +161,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
bool GetIso14443aCommandFromReader(uint8_t *received, uint16_t received_maxlen, uint8_t *par, int *len);
void iso14443a_antifuzz(uint32_t flags);
int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, const iso14a_polling_parameters_t *polling_parameters);
void ReaderIso14443a(PacketCommandNG *c);
void ReaderTransmit(const uint8_t *frame, uint16_t len, uint32_t *timing);
void ReaderTransmitBitsPar(const uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing);
+173 -44
View File
@@ -256,68 +256,189 @@ void MifareReadSector(uint8_t sector_no, uint8_t key_type, uint8_t *key) {
reply_old(CMD_ACK, retval == PM3_SUCCESS, 0, 0, outbuf, 16 * num_blocks);
}
void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes) {
static int MifareUFastRead0(void) {
uint8_t resp[18] = { 0 }; // 4 pages + crc
uint8_t resp_par[1] = {0};
bool turnOffField = (arg0 == 1);
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
if (iso14443a_select_card(NULL, NULL, NULL, true, 0, true) == 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card");
OnError(0);
return;
};
if (mifare_ultra_auth(keybytes) == 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Authentication failed");
OnError(1);
return;
if (GetATQA(resp, sizeof(resp), resp_par, NULL) == 0) {
return 0;
}
uint8_t read0[4] = {0x30, 0x00, 0x00, 0x00};
AddCrc14A(read0, 2);
ReaderTransmit(read0, sizeof(read0), NULL);
if (turnOffField) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
// Receive 4 pages, 2 Byte CRC
if (ReaderReceive(resp, sizeof(resp), resp_par) != 18) {
return 0;
}
reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
return 1;
}
void MifareUL_AES_Auth(mfulaes_keys_t *packet) {
#define MIFAREU3P_KEY_SIZE 16
#define MIFAREULC_KEY_INDEX 3
// checks one key.
// fast select, tries 5 times to select
//
// return:
// 4 = failed to select
// 3 = failed auth
// 2 = timeout
// 1 = failed auth
// 0 = correct
static uint8_t chkKey3Pass(uint8_t keyno, uint8_t *keybytes, uint32_t *auths, bool check_answer) {
uint8_t i = 0, res = 2;
bool selected = false;
while (i < 5) {
if (MifareUFastRead0() == 0) {
++i;
continue;
}
selected = true;
if (g_dbglevel >= DBG_EXTENDED) Dbhexdump(MIFAREU3P_KEY_SIZE, keybytes, false);
if (keyno == MIFAREULC_KEY_INDEX) {
res = mifare_ultra_3des_auth(keybytes, check_answer) == 1 ? 0 : 1; // 0 = correct, 1 = failed auth
} else {
bool use_schann = false;
res = mifare_ultra_aes_auth(keyno, keybytes, use_schann, check_answer) == 1 ? 0 : 1; // 0 = correct, 1 = failed auth
}
(*auths)++;
break;
}
if (selected == false) {
Dbprintf("chkKey: Failed at fast selecting the card!");
res = 4;
}
return res;
}
void MifareU3PassAuth(mful_3passauth_t *packet) {
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
uint32_t auths = 0;
int res = PM3_ESOFT;
struct rp {
uint32_t auths;
uint32_t ticks;
} PACKED rpayload;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
if (iso14443a_select_card(NULL, NULL, NULL, true, 0, true) == 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card");
OnErrorNG(CMD_HF_MIFAREULAES_AUTH, PM3_ESOFT);
return;
};
uint32_t ti = GetTickCount();
if (mifare_ultra_aes_auth(packet->keyno, packet->key, packet->use_schann) == 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Authentication failed");
OnErrorNG(CMD_HF_MIFAREULAES_AUTH, PM3_ESOFT);
return;
for (uint16_t r = 0; r < 1 + packet->retries; r++) {
WDT_HIT();
if (chkKey3Pass(packet->keyno, packet->key, &auths, packet->check_answer) == 0) {
res = PM3_SUCCESS;
goto out;
}
}
out:
rpayload.auths = auths;
rpayload.ticks = GetTickCountDelta(ti);
if (g_dbglevel >= DBG_ERROR) {
if (res != PM3_SUCCESS) {
Dbprintf("Authentication failed");
}
}
reply_ng(CMD_HF_MIFAREU3P_AUTH, res, (uint8_t *)&rpayload, sizeof(rpayload));
if (packet->turn_off_field) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
reply_ng(CMD_HF_MIFAREULAES_AUTH, PM3_SUCCESS, NULL, 0);
}
void MifareU3PassChkKeys(mful_3passchk_t *packet) {
static uint8_t foundkeys = 0;
uint8_t keysize = packet->segment != 4 ? MIFAREU3P_KEY_SIZE / 4 : MIFAREU3P_KEY_SIZE;
int oldbg = g_dbglevel;
int res = PM3_ESOFT;
struct rp {
uint32_t auths;
uint32_t ticks;
uint8_t key[16];
} PACKED rpayload;
uint32_t auths = 0;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
LEDsoff();
LED_A_ON();
uint32_t ti = GetTickCount();
if (packet->firstchunk) {
clear_trace();
set_tracing(false);
if (iso14443a_select_card(NULL, NULL, NULL, true, 0, true) == 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("ChkKeys_fast: Can't select card (ALL)");
goto out;
}
CHK_TIMEOUT();
}
// clear debug level. We are expecting lots of authentication failures...
g_dbglevel = DBG_NONE;
for (uint16_t i = 0; i < packet->nkeys; ++i) {
// Allow button press / usb cmd to interrupt device
if (BUTTON_PRESS() || data_available()) {
goto out;
}
WDT_HIT();
uint8_t fullkeybytes[MIFAREU3P_KEY_SIZE] = {0};
memcpy(fullkeybytes, packet->ref_key, MIFAREU3P_KEY_SIZE);
if (keysize == MIFAREU3P_KEY_SIZE) {
if (packet->xor_ref_key) {
for (uint8_t j = 0; j < keysize; ++j) {
fullkeybytes[j] ^= packet->data[j + (i * keysize)];
}
} else {
memcpy(fullkeybytes, packet->data + (i * keysize), keysize);
}
} else {
if (packet->xor_ref_key) {
for (uint8_t j = 0; j < keysize; ++j) {
fullkeybytes[j + (packet->segment * keysize)] ^= packet->data[j + (i * keysize)];
}
} else {
memcpy(fullkeybytes + (packet->segment * keysize), packet->data + (i * keysize), keysize);
}
}
if (chkKey3Pass(packet->key_index, fullkeybytes, &auths, packet->check_answer) == 0) {
foundkeys++;
memcpy(rpayload.key, fullkeybytes, MIFAREU3P_KEY_SIZE);
res = PM3_SUCCESS;
goto out;
}
}
out:
rpayload.auths = auths;
rpayload.ticks = GetTickCountDelta(ti);
reply_ng(CMD_HF_MIFAREU3P_CHKKEY, res, (uint8_t *)&rpayload, sizeof(rpayload));
LEDsoff();
if (foundkeys || packet->lastchunk) {
set_tracing(false);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
BigBuf_free();
BigBuf_Clear_ext(false);
}
g_dbglevel = oldbg;
}
// Arg0 = BlockNo,
// Arg1 = UsePwd bool
// datain = PWD bytes,
@@ -344,7 +465,7 @@ void MifareUReadBlock(mful_readblock_t *packet) {
// UL-C authentication
if (useCKey) {
if (mifare_ultra_auth(packet->key) == 0) {
if (mifare_ultra_3des_auth(packet->key, true) == 0) {
OnErrorNG(CMD_HF_MIFAREU_READBL, PM3_ESOFT);
return;
}
@@ -352,7 +473,7 @@ void MifareUReadBlock(mful_readblock_t *packet) {
// UL-AES authentication, hardcode to use keyno 0
if (useAESKey) {
if (mifare_ultra_aes_auth(0, packet->key, packet->use_schann) == 0) {
if (mifare_ultra_aes_auth(0, packet->key, packet->use_schann, true) == 0) {
OnErrorNG(CMD_HF_MIFAREU_READBL, PM3_ESOFT);
return;
}
@@ -427,7 +548,7 @@ void MifareUReadCard(mful_readblock_t *packet) {
// UL-C authentication
if (useCKey) {
if (mifare_ultra_auth(packet->key) == 0) {
if (mifare_ultra_3des_auth(packet->key, true) == 0) {
OnErrorNG(CMD_HF_MIFAREU_READCARD, PM3_ESOFT);
return;
}
@@ -435,7 +556,7 @@ void MifareUReadCard(mful_readblock_t *packet) {
// UL-AES authentication
if (useAESKey) {
if (mifare_ultra_aes_auth(0, packet->key, schann) == 0) {
if (mifare_ultra_aes_auth(0, packet->key, schann, true) == 0) {
OnErrorNG(CMD_HF_MIFAREU_READCARD, PM3_ESOFT);
return;
}
@@ -615,7 +736,7 @@ static void MifareUWriteBlockEx(mful_writeblock_t *packet, bool reply) {
// UL-C authentication
if (useCKey) {
if (mifare_ultra_auth(packet->key) == 0) {
if (mifare_ultra_3des_auth(packet->key, true) == 0) {
OnErrorNG(CMD_HF_MIFAREU_READBL, PM3_ESOFT);
return;
}
@@ -623,7 +744,7 @@ static void MifareUWriteBlockEx(mful_writeblock_t *packet, bool reply) {
// UL-AES authentication
if (useAESKey) {
if (mifare_ultra_aes_auth(0, packet->key, packet->use_schann) == 0) {
if (mifare_ultra_aes_auth(0, packet->key, packet->use_schann, true) == 0) {
OnErrorNG(CMD_HF_MIFAREU_READBL, PM3_ESOFT);
return;
}
@@ -699,7 +820,15 @@ void MifareUWriteBlockCompat(mful_writeblock_t *packet) {
// UL-C authentication
if (useCKey) {
if (mifare_ultra_auth(packet->key) == 0) {
if (mifare_ultra_3des_auth(packet->key, true) == 0) {
OnErrorNG(CMD_HF_MIFAREU_WRITEBL_COMPAT, PM3_ESOFT);
return;
}
}
// UL-AES authentication
if (useAESKey) {
if (mifare_ultra_aes_auth(0, packet->key, packet->use_schann, true) == 0) {
OnErrorNG(CMD_HF_MIFAREU_WRITEBL_COMPAT, PM3_ESOFT);
return;
}
+3 -3
View File
@@ -26,14 +26,14 @@ void MifareReadSector(uint8_t sector_no, uint8_t key_type, uint8_t *key);
void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareUReadBlock(mful_readblock_t *packet);
void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes);
void MifareUL_AES_Auth(mfulaes_keys_t *packet);
void MifareUReadCard(mful_readblock_t *packet);
void MifareUWriteBlockCompat(mful_writeblock_t *packet);
void MifareUWriteBlock(mful_writeblock_t *packet);
void MifareU3PassAuth(mful_3passauth_t *packet);
void MifareU3PassChkKeys(mful_3passchk_t *packet);
void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, bool calibrate, uint8_t *key);
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key, uint8_t forceDetectDist);
+61 -49
View File
@@ -380,12 +380,11 @@ int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack) {
return 1;
}
int mifare_ultra_auth(uint8_t *keybytes) {
int mifare_ultra_3des_auth(uint8_t *keybytes, bool check_answer) {
/// 3des2k
uint8_t random_a[8] = {1, 1, 1, 1, 1, 1, 1, 1};
uint8_t random_a[8] = {1, 1, 1, 1, 1, 1, 1, 2};
uint8_t random_b[8] = {0x00};
uint8_t enc_random_b[8] = {0x00};
uint8_t rnd_ab[16] = {0x00};
uint8_t IV[8] = {0x00};
uint8_t key[16] = {0x00};
@@ -398,77 +397,71 @@ int mifare_ultra_auth(uint8_t *keybytes) {
// REQUEST AUTHENTICATION
len = mifare_sendcmd_short(NULL, CRYPT_NONE, MIFARE_ULC_AUTH_1, 0x00, resp, sizeof(resp), respPar, NULL);
if (len != 11) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]);
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x - expected 11 got " _RED_("%u"), resp[0], len);
return 0;
}
// tag nonce.
memcpy(enc_random_b, resp + 1, 8);
// decrypt nonce.
tdes_nxp_receive((void *)enc_random_b, (void *)random_b, sizeof(random_b), (const void *)key, IV, 2);
tdes_nxp_receive((void *)(resp + 1), (void *)random_b, sizeof(random_b), (const void *)key, IV, 2);
rol(random_b, 8);
memcpy(rnd_ab, random_a, 8);
memcpy(rnd_ab + 8, random_b, 8);
if (g_dbglevel >= DBG_EXTENDED) {
Dbprintf("enc_B: %02x %02x %02x %02x %02x %02x %02x %02x",
enc_random_b[0], enc_random_b[1], enc_random_b[2], enc_random_b[3], enc_random_b[4], enc_random_b[5], enc_random_b[6], enc_random_b[7]);
Dbprintf("enc_B:");
Dbhexdump(8, resp + 1, false);
Dbprintf(" B: %02x %02x %02x %02x %02x %02x %02x %02x",
random_b[0], random_b[1], random_b[2], random_b[3], random_b[4], random_b[5], random_b[6], random_b[7]);
Dbprintf("B:");
Dbhexdump(8, random_b, false);
Dbprintf("rnd_ab: %02x %02x %02x %02x %02x %02x %02x %02x",
rnd_ab[0], rnd_ab[1], rnd_ab[2], rnd_ab[3], rnd_ab[4], rnd_ab[5], rnd_ab[6], rnd_ab[7]);
Dbprintf("rnd_ab: %02x %02x %02x %02x %02x %02x %02x %02x",
rnd_ab[8], rnd_ab[9], rnd_ab[10], rnd_ab[11], rnd_ab[12], rnd_ab[13], rnd_ab[14], rnd_ab[15]);
Dbprintf("rnd_ab:");
Dbhexdump(16, rnd_ab, false);
}
// encrypt out, in, length, key, iv
tdes_nxp_send(rnd_ab, rnd_ab, sizeof(rnd_ab), key, enc_random_b, 2);
// reuse rnd_ab as enc_rnd_ab
if (check_answer) {
tdes_nxp_send((void *)rnd_ab, (void *)rnd_ab, sizeof(rnd_ab), (const void *)key, resp + 1, 2);
} else {
tdes_nxp_send((void *)(rnd_ab + sizeof(random_a)), (void *)(rnd_ab + sizeof(random_a)), sizeof(random_b), (const void *)key, rnd_ab, 2);
// tdes_nxp_send destroys IV, let's restore it
memcpy(rnd_ab, random_a, 8);
}
len = mifare_sendcmd(MIFARE_ULC_AUTH_2, rnd_ab, sizeof(rnd_ab), resp, sizeof(resp), respPar, NULL);
if ((!check_answer) && (len == 11)) {
return 1;
}
if (len != 11) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]);
if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd Error: %02x - expected 11 got " _RED_("%u"), resp[0], len);
return 0;
}
uint8_t enc_resp[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t resp_random_a[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
memcpy(enc_resp, resp + 1, 8);
// reuse random_b as resp_random_a
// decrypt out, in, length, key, iv
tdes_nxp_receive(enc_resp, resp_random_a, 8, key, enc_random_b, 2);
if (memcmp(resp_random_a, random_a, 8) != 0) {
tdes_nxp_receive(resp + 1, random_b, 8, key, rnd_ab + 8, 2);
if (g_dbglevel >= DBG_EXTENDED) {
Dbprintf("e_AB:");
Dbhexdump(16, rnd_ab, false);
Dbprintf("A sent:");
Dbhexdump(8, random_a, false);
Dbprintf("A' recv:");
Dbhexdump(8, random_b, false);
}
rol(random_a, 8);
if (memcmp(random_b, random_a, 8) != 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("failed authentication");
return 0;
}
if (g_dbglevel >= DBG_EXTENDED) {
Dbprintf("e_AB: %02x %02x %02x %02x %02x %02x %02x %02x",
rnd_ab[0], rnd_ab[1], rnd_ab[2], rnd_ab[3],
rnd_ab[4], rnd_ab[5], rnd_ab[6], rnd_ab[7]);
Dbprintf("e_AB: %02x %02x %02x %02x %02x %02x %02x %02x",
rnd_ab[8], rnd_ab[9], rnd_ab[10], rnd_ab[11],
rnd_ab[12], rnd_ab[13], rnd_ab[14], rnd_ab[15]);
Dbprintf("a: %02x %02x %02x %02x %02x %02x %02x %02x",
random_a[0], random_a[1], random_a[2], random_a[3],
random_a[4], random_a[5], random_a[6], random_a[7]);
Dbprintf("b: %02x %02x %02x %02x %02x %02x %02x %02x",
resp_random_a[0], resp_random_a[1], resp_random_a[2], resp_random_a[3],
resp_random_a[4], resp_random_a[5], resp_random_a[6], resp_random_a[7]);
}
return 1;
}
int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes, bool schann) {
int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes, bool schann, bool check_answer) {
/// aes-128
uint8_t random_a[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
uint8_t random_a[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2};
uint8_t random_b[16] = { 0x00 };
uint8_t rnd_ab[32] = { 0x00 };
uint8_t enc_rnd_ab[32] = { 0x00 };
@@ -513,12 +506,20 @@ int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes, bool schann) {
}
// encrypt reader response
memset(IV, 0, 16);
mbedtls_aes_setkey_enc(&actx, key, 128);
mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_ENCRYPT, sizeof(enc_rnd_ab), IV, rnd_ab, enc_rnd_ab);
if (check_answer) {
memset(IV, 0, 16);
mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_ENCRYPT, sizeof(rnd_ab), IV, rnd_ab, enc_rnd_ab);
} else {
memcpy(enc_rnd_ab, rnd_ab, sizeof(rnd_ab));
mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_ENCRYPT, sizeof(random_b), rnd_ab, rnd_ab + sizeof(random_a), enc_rnd_ab + sizeof(random_a));
}
// send & receive
len = mifare_sendcmd(MIFARE_ULAES_AUTH_2, enc_rnd_ab, sizeof(enc_rnd_ab), resp, sizeof(resp), respPar, NULL);
if ((! check_answer) && (len == 19)) {
return 1;
}
if (len != 19) {
if (g_dbglevel >= DBG_INFO) {
Dbprintf("Cmd Error: %02x - expected 19 got " _RED_("%u"), resp[0], len);
@@ -531,7 +532,17 @@ int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes, bool schann) {
uint8_t rec_rnd_a[16] = {0};
mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_DECRYPT, sizeof(rec_rnd_a), IV, resp + 1, rec_rnd_a);
mbedtls_aes_free(&actx);
if (g_dbglevel >= DBG_EXTENDED) {
Dbprintf("e_AB:");
Dbhexdump(32, rnd_ab, false);
Dbprintf("A sent:");
Dbhexdump(16, random_a, false);
Dbprintf("A' recv:");
Dbhexdump(16, rec_rnd_a, false);
}
rol(random_a, 16);
if (memcmp(rec_rnd_a, random_a, 16) != 0) {
if (g_dbglevel >= DBG_INFO) {
Dbprintf("failed authentication");
@@ -544,7 +555,7 @@ int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes, bool schann) {
return 1;
}
// Session key calculation setion
// Session key calculation section
// clear global session variable
init_secure_session();
@@ -555,7 +566,8 @@ int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes, bool schann) {
uint8_t *ra = random_a;
uint8_t *rb = random_b;
// do we need to unroll it?
// we need to unroll randoms
ror(ra, 16);
ror(rb, 16);
uint8_t session_vec[] = {
+2 -2
View File
@@ -104,8 +104,8 @@ int mifare_classic_value(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blo
// Ultralight/NTAG...
int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack);
int mifare_ultra_auth(uint8_t *keybytes);
int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes, bool schann);
int mifare_ultra_3des_auth(uint8_t *keybytes, bool check_answer);
int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes, bool schann, bool check_answer);
int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData);
int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData);
int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData);
@@ -382,8 +382,10 @@ def main():
description=main.__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument('-c', '--challenges', help='Set number of challenges to collect (default:1000)', type=int, default=1000)
parser.add_argument('-t', '--threads', help='Set number of threads to use for key recovery (default:1)', type=int, default=1)
parser.add_argument('-c', '--challenges', help='Set number of challenges to collect (default:1000)',
type=int, default=1000)
parser.add_argument('-t', '--threads', help='Set number of threads to use for key recovery (default:1)',
type=int, default=16)
parser.add_argument('-d', '--debug', action='store_true', help='Enable debug mode')
parser.add_argument('-j', '--json', help='Path to JSON file to load or save collected challenges')
parser.add_argument('-o', '--offline', action='store_true', help='Use offline mode with pre-collected challenges')
+434 -30
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -436,7 +436,9 @@ const static vocabulary_t vocabulary[] = {
{ 1, "hf mfu pwdgen" },
{ 0, "hf mfu otptear" },
{ 0, "hf mfu cauth" },
{ 0, "hf mfu cchk" },
{ 0, "hf mfu aesauth" },
{ 0, "hf mfu aeschk" },
{ 0, "hf mfu setkey" },
{ 0, "hf mfu dump" },
{ 0, "hf mfu incr" },
@@ -920,6 +922,10 @@ const static vocabulary_t vocabulary[] = {
{ 0, "script run ice.py" },
{ 0, "script run intertic.py" },
{ 0, "script run mf_backdoor_dump.py" },
{ 0, "script run mfulaes_mask_recovery.py" },
{ 0, "script run mfulc_counterfeit_recovery.py" },
{ 0, "script run ntag22x_libsuncmac.py" },
{ 0, "script run ntag22x_suncmac_recovery.py" },
{ 0, "script run parity.py" },
{ 0, "script run paxton_convert.py" },
{ 0, "script run paxton_net.py" },
+51 -10
View File
@@ -1411,10 +1411,10 @@
"-x Performs the 'reader attack', nr/ar attack against a reader",
"--sk Fill simulator keys from found keys",
"-v, --verbose verbose output",
"--z1 ULC/ULAES Auth - all zero handshake part 1",
"--z2 ULC/ULAES Auth - all zero handshake part 2"
"--1a1 <hex> <8|16> hex bytes ULC/ULAES Auth reply step1: ek(RndB)",
"--1a2 <hex> <8|16> hex bytes ULC/ULAES Auth reply step2: ek(RndA')"
],
"usage": "hf 14a sim [-hxv] -t <1-14> [-u <hex>] [-n <dec>] [--sk] [--z1] [--z2]"
"usage": "hf 14a sim [-hxv] -t <1-14> [-u <hex>] [-n <dec>] [--sk] [--1a1 <hex>] [--1a2 <hex>]"
},
"hf 14a simaid": {
"command": "hf 14a simaid",
@@ -7183,9 +7183,30 @@
"-i, --idx <0..2> Key index (def: 0)",
"-l Swap entered key's endianness",
"-k Keep field on (only if a key is provided)",
"--schann use secure channel. Must have key"
"--schann use secure channel. Must have key",
"-r, --retries <n> Number of retries (def: 0)",
"-n, --nocheck Skip checking tag answer correctness"
],
"usage": "hf mfu aesauth [-hlk] [--key <hex>] [-i <0..2>] [--schann]"
"usage": "hf mfu aesauth [-hlkn] [--key <hex>] [-i <0..2>] [--schann] [-r <n>]"
},
"hf mfu aeschk": {
"command": "hf mfu aeschk",
"description": "It checks MIFARE Ultralight AES tags keys against a dictionary file with keys Key index 0... DataProtKey (default) Key index 1... UIDRetrKey Key index 2... OriginalityKey",
"notes": [
"hf mfu aeschk -f mfulaes_default_keys.dic"
],
"offline": false,
"options": [
"-h, --help This help",
"-f, --file <fn> filename of dictionary",
"-i, --idx <0..2> Key index (def: 0)",
"-s, --segment <0..3> Segment index (full key if not specified)",
"-r, --retries <0..255> Number of retries (def: 0)",
"-k, --key <hex> Starting key, 16 hex bytes (def: zero key), for segment check",
"-x, --xor XOR starting key with segment candidates (def: override)",
"-n, --nocheck Skip checking tag answer correctness"
],
"usage": "hf mfu aeschk [-hxn] [-f <fn>] [-i <0..2>] [-s <0..3>] [-r <0..255>] [-k <hex>]"
},
"hf mfu amiibo": {
"command": "hf mfu amiibo",
@@ -7217,9 +7238,29 @@
"-h, --help This help",
"--key <hex> Authentication key (16 bytes in hex)",
"-l Swap entered key's endianness",
"-k Keep field on (only if a key is provided)"
"-k Keep field on (only if a key is provided)",
"-r, --retries <n> Number of retries with provided key (def: 0)",
"-n, --nocheck Skip checking tag answer correctness (only if a key is provided)"
],
"usage": "hf mfu cauth [-hlk] [--key <hex>]"
"usage": "hf mfu cauth [-hlkn] [--key <hex>] [-r <n>]"
},
"hf mfu cchk": {
"command": "hf mfu cchk",
"description": "It checks MIFARE Ultralight C tags keys against a dictionary file with keys",
"notes": [
"hf mfu cchk -f mfulc_default_keys.dic"
],
"offline": false,
"options": [
"-h, --help This help",
"-f, --file <fn> filename of dictionary",
"-s, --segment <0..3> Segment index (full key if not specified)",
"-r, --retries <0..255> Number of retries (def: 0)",
"-k, --key <hex> Starting key, 16 hex bytes (def: zero key), for segment check",
"-x, --xor XOR starting key with segment candidates (def: override)",
"-n, --nocheck Skip checking tag answer correctness"
],
"usage": "hf mfu cchk [-hxn] [-f <fn>] [-s <0..3>] [-r <0..255>] [-k <hex>]"
},
"hf mfu dump": {
"command": "hf mfu dump",
@@ -7510,10 +7551,10 @@
"-u, --uid <hex> <4|7|10> hex bytes UID",
"-n, --num <dec> Exit simulation after <numreads> blocks. 0 = infinite",
"-v, --verbose Verbose output",
"--z1 ULC/ULAES Auth - all zero handshake part 1",
"--z2 ULC/ULAES Auth - all zero handshake part 2"
"--1a1 <hex> <8|16> hex bytes ULC/ULAES Auth reply step1: ek(RndB)",
"--1a2 <hex> <8|16> hex bytes ULC/ULAES Auth reply step2: ek(RndA')"
],
"usage": "hf mfu sim [-hv] -t <1..14> [-u <hex>] [-n <dec>] [--z1] [--z2]"
"usage": "hf mfu sim [-hv] -t <1..14> [-u <hex>] [-n <dec>] [--1a1 <hex>] [--1a2 <hex>]"
},
"hf mfu tamper": {
"command": "hf mfu tamper",
+4 -2
View File
@@ -622,8 +622,10 @@ Check column "offline" for their availability.
|`hf mfu keygen `|Y |`Generate DES/3DES/AES MIFARE diversified keys`
|`hf mfu pwdgen `|Y |`Generate pwd from known algos`
|`hf mfu otptear `|N |`Tear-off test on OTP bits`
|`hf mfu cauth `|N |`Ultralight C - Authentication`
|`hf mfu aesauth `|N |`Ultralight AES - Authentication`
|`hf mfu cauth `|N |`Ultralight-C - Authentication`
|`hf mfu cchk `|N |`Ultralight-C - Authentication dictionary check`
|`hf mfu aesauth `|N |`Ultralight-AES - Authentication`
|`hf mfu aeschk `|N |`Ultralight-AES - Authentication dictionary check`
|`hf mfu setkey `|N |`Ultralight C/AES - Set 3DES/AES keys`
|`hf mfu dump `|N |`Dump MIFARE Ultralight family tag to binary file`
|`hf mfu incr `|N |`Increments Ev1/NTAG counter`
+27 -15
View File
@@ -366,17 +366,30 @@ typedef struct {
} PACKED mfc_eload_t;
typedef struct {
bool use_flashmem;
uint16_t keycount;
uint8_t keys[];
} PACKED mfulc_keys_t;
typedef struct {
bool turn_off_field;
bool use_schann;
uint8_t keyno;
uint8_t turn_off_field : 1;
uint8_t check_answer : 1;
uint8_t keyno : 2;
uint8_t use_schann : 1;
uint8_t reserved : 3;
uint16_t retries;
uint8_t key[16];
} PACKED mfulaes_keys_t;
} PACKED mful_3passauth_t;
enum {
MIFAREU3P_KEY_SIZE = 16,
MIFAREU3P_CHKKEY_HEADER = 2 + MIFAREU3P_KEY_SIZE
};
typedef struct {
uint8_t key_index : 2;
uint8_t firstchunk : 1;
uint8_t lastchunk : 1;
uint8_t xor_ref_key : 1;
uint8_t segment : 3;
uint8_t check_answer : 1;
uint8_t nkeys : 7;
uint8_t ref_key[MIFAREU3P_KEY_SIZE];
uint8_t data[PM3_CMD_DATA_SIZE - MIFAREU3P_CHKKEY_HEADER];
} PACKED mful_3passchk_t;
typedef struct {
bool use_schann;
@@ -798,11 +811,10 @@ typedef struct {
#define CMD_HF_MIFARE_MFKEY 0x0631
#define CMD_HF_MIFARE_PERSONALIZE_UID 0x0632
// ultralight-C
#define CMD_HF_MIFAREUC_AUTH 0x0724
// Ultralight AES
#define CMD_HF_MIFAREULAES_AUTH 0x0725
// 0x0726 no longer used
// ultralight-C & AES
#define CMD_HF_MIFAREU3P_AUTH 0x0724
// 0x0725 is free
#define CMD_HF_MIFAREU3P_CHKKEY 0x0726
#define CMD_HF_MIFAREU_SETKEY 0x0727
// mifare desfire
@@ -195,9 +195,10 @@ typedef struct {
#define CMD_HF_MIFARE_SETMOD 0x0624
#define CMD_HF_MIFARE_SNIFF 0x0630
//ultralightC
#define CMD_HF_MIFAREUC_AUTH 0x0724
//0x0725 and 0x0726 no longer used
// ultralight-C & AES
#define CMD_HF_MIFAREU3P_AUTH 0x0724
// 0x0725 is free
#define CMD_HF_MIFAREU3P_CHKKEY 0x0726
#define CMD_HF_MIFAREU_SETKEY 0x0727