mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-07-09 10:11:54 +00:00
support for Ultralight AES auth in hf mfu info/rdbl/wrbl/dump/ndefread/wipe/setkey
This commit is contained in:
@@ -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 support for Ultralight AES auth in `hf mfu info/rdbl/wrbl/dump/ndefread/wipe/setkey` (@doegox)
|
||||
- Added Ultralight AES basic DataProtKey emulation support (@doegox)
|
||||
- Changed `mem info` and how the signature handling is done (@iceman1001)
|
||||
- Added `client/resources/pm3_generic_private_key.pem` in order to self-sign a modded device (@iceman1001)
|
||||
|
||||
+2
-2
@@ -1848,8 +1848,8 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
MifareUReadCard(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFAREUC_SETPWD: {
|
||||
MifareUSetPwd(packet->oldarg[0], packet->data.asBytes);
|
||||
case CMD_HF_MIFAREU_SETKEY: {
|
||||
MifareUSetKey(packet->oldarg[0], packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_READSC: {
|
||||
|
||||
+85
-53
@@ -323,8 +323,9 @@ void MifareUL_AES_Auth(bool turn_off_field, uint8_t keyno, uint8_t *keybytes) {
|
||||
void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
uint8_t blockNo = arg0;
|
||||
uint8_t dataout[16] = {0x00};
|
||||
bool useKey = (arg1 == 1); //UL_C
|
||||
bool usePwd = (arg1 == 2); //UL_EV1/NTAG
|
||||
bool useCKey = (arg1 == 1); // UL_C
|
||||
bool usePwd = (arg1 == 2); // UL_EV1/NTAG
|
||||
bool useAESKey = (arg1 == 3); // UL_AES
|
||||
|
||||
LEDsoff();
|
||||
LED_A_ON();
|
||||
@@ -340,7 +341,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
}
|
||||
|
||||
// UL-C authentication
|
||||
if (useKey) {
|
||||
if (useCKey) {
|
||||
uint8_t key[16] = {0x00};
|
||||
memcpy(key, datain, sizeof(key));
|
||||
|
||||
@@ -350,6 +351,17 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
}
|
||||
}
|
||||
|
||||
// UL-AES authentication
|
||||
if (useAESKey) {
|
||||
uint8_t key[16] = {0x00};
|
||||
memcpy(key, datain, sizeof(key));
|
||||
|
||||
if (mifare_ultra_aes_auth(0, key) == 0) {
|
||||
OnError(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// UL-EV1 / NTAG authentication
|
||||
if (usePwd) {
|
||||
uint8_t pwd[4] = {0x00};
|
||||
@@ -395,8 +407,9 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
|
||||
// params
|
||||
uint8_t blockNo = arg0;
|
||||
uint16_t blocks = arg1;
|
||||
bool useKey = (arg2 == 1); // UL_C
|
||||
bool useCKey = (arg2 == 1); // UL_C
|
||||
bool usePwd = (arg2 == 2); // UL_EV1/NTAG
|
||||
bool useAESKey = (arg2 == 3); // UL_AES
|
||||
uint32_t countblocks = 0;
|
||||
uint8_t *dataout = BigBuf_calloc(CARD_MEMORY_SIZE);
|
||||
if (dataout == NULL) {
|
||||
@@ -413,7 +426,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
|
||||
}
|
||||
|
||||
// UL-C authentication
|
||||
if (useKey) {
|
||||
if (useCKey) {
|
||||
uint8_t key[16] = {0x00};
|
||||
memcpy(key, datain, sizeof(key));
|
||||
|
||||
@@ -423,6 +436,17 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
|
||||
}
|
||||
}
|
||||
|
||||
// UL-AES authentication
|
||||
if (useAESKey) {
|
||||
uint8_t key[16] = {0x00};
|
||||
memcpy(key, datain, sizeof(key));
|
||||
|
||||
if (mifare_ultra_aes_auth(0, key) == 0) {
|
||||
OnError(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// UL-EV1 / NTAG authentication
|
||||
if (usePwd) {
|
||||
uint8_t pwd[4] = {0x00};
|
||||
@@ -571,8 +595,9 @@ void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) {
|
||||
// : 4/16 next bytes is authentication key.
|
||||
static void MifareUWriteBlockEx(uint8_t arg0, uint8_t arg1, uint8_t *datain, bool reply) {
|
||||
uint8_t blockNo = arg0;
|
||||
bool useKey = (arg1 == 1); //UL_C
|
||||
bool usePwd = (arg1 == 2); //UL_EV1/NTAG
|
||||
bool useCKey = (arg1 == 1); // UL_C
|
||||
bool usePwd = (arg1 == 2); // UL_EV1/NTAG
|
||||
bool useAESKey = (arg1 == 3); // UL_AES
|
||||
uint8_t blockdata[4] = {0x00};
|
||||
|
||||
memcpy(blockdata, datain, 4);
|
||||
@@ -591,7 +616,7 @@ static void MifareUWriteBlockEx(uint8_t arg0, uint8_t arg1, uint8_t *datain, boo
|
||||
};
|
||||
|
||||
// UL-C authentication
|
||||
if (useKey) {
|
||||
if (useCKey) {
|
||||
uint8_t key[16] = {0x00};
|
||||
memcpy(key, datain + 4, sizeof(key));
|
||||
|
||||
@@ -601,6 +626,17 @@ static void MifareUWriteBlockEx(uint8_t arg0, uint8_t arg1, uint8_t *datain, boo
|
||||
}
|
||||
}
|
||||
|
||||
// UL-AES authentication
|
||||
if (useAESKey) {
|
||||
uint8_t key[16] = {0x00};
|
||||
memcpy(key, datain + 4, sizeof(key));
|
||||
|
||||
if (mifare_ultra_aes_auth(0, key) == 0) {
|
||||
OnError(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// UL-EV1 / NTAG authentication
|
||||
if (usePwd) {
|
||||
uint8_t pwd[4] = {0x00};
|
||||
@@ -646,8 +682,9 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
// : 4/16 next bytes is authentication key.
|
||||
void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
uint8_t blockNo = arg0;
|
||||
bool useKey = (arg1 == 1); //UL_C
|
||||
bool usePwd = (arg1 == 2); //UL_EV1/NTAG
|
||||
bool useCKey = (arg1 == 1); // UL_C
|
||||
bool usePwd = (arg1 == 2); // UL_EV1/NTAG
|
||||
bool useAESKey = (arg1 == 3); // UL_AES
|
||||
uint8_t blockdata[16] = {0x00};
|
||||
|
||||
memcpy(blockdata, datain, 16);
|
||||
@@ -666,7 +703,7 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
};
|
||||
|
||||
// UL-C authentication
|
||||
if (useKey) {
|
||||
if (useCKey) {
|
||||
uint8_t key[16] = {0x00};
|
||||
memcpy(key, datain + 16, sizeof(key));
|
||||
|
||||
@@ -676,6 +713,17 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
}
|
||||
}
|
||||
|
||||
// UL-AES authentication
|
||||
if (useAESKey) {
|
||||
uint8_t key[16] = {0x00};
|
||||
memcpy(key, datain + 16, sizeof(key));
|
||||
|
||||
if (mifare_ultra_aes_auth(0, key) == 0) {
|
||||
OnError(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// UL-EV1 / NTAG authentication
|
||||
if (usePwd) {
|
||||
uint8_t pwd[4] = {0x00};
|
||||
@@ -707,12 +755,15 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
set_tracing(false);
|
||||
}
|
||||
|
||||
void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
||||
void MifareUSetKey(uint8_t arg0, uint8_t *datain) {
|
||||
|
||||
uint8_t pwd[16] = {0x00};
|
||||
uint8_t blockdata[4] = {0x00};
|
||||
uint8_t key[16] = {0x00};
|
||||
if (arg0 < 1 || arg0 > 3) {
|
||||
OnError(0);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(pwd, datain, 16);
|
||||
memcpy(key, datain, 16);
|
||||
|
||||
LED_A_ON();
|
||||
LED_B_OFF();
|
||||
@@ -728,45 +779,26 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
||||
return;
|
||||
};
|
||||
|
||||
blockdata[0] = pwd[7];
|
||||
blockdata[1] = pwd[6];
|
||||
blockdata[2] = pwd[5];
|
||||
blockdata[3] = pwd[4];
|
||||
if (mifare_ultra_writeblock(44, blockdata) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
OnError(44);
|
||||
return;
|
||||
};
|
||||
uint8_t start_block = 4; // just to be safe
|
||||
switch (arg0) {
|
||||
case 1: // UL-C
|
||||
start_block = 44;
|
||||
break;
|
||||
case 2: // UL-AES DataProtKey
|
||||
start_block = 48;
|
||||
break;
|
||||
case 3: // UL-AES UIDRetrKey
|
||||
start_block = 52;
|
||||
break;
|
||||
}
|
||||
|
||||
blockdata[0] = pwd[3];
|
||||
blockdata[1] = pwd[2];
|
||||
blockdata[2] = pwd[1];
|
||||
blockdata[3] = pwd[0];
|
||||
if (mifare_ultra_writeblock(45, blockdata) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
OnError(45);
|
||||
return;
|
||||
};
|
||||
|
||||
blockdata[0] = pwd[15];
|
||||
blockdata[1] = pwd[14];
|
||||
blockdata[2] = pwd[13];
|
||||
blockdata[3] = pwd[12];
|
||||
if (mifare_ultra_writeblock(46, blockdata) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
OnError(46);
|
||||
return;
|
||||
};
|
||||
|
||||
blockdata[0] = pwd[11];
|
||||
blockdata[1] = pwd[10];
|
||||
blockdata[2] = pwd[9];
|
||||
blockdata[3] = pwd[8];
|
||||
if (mifare_ultra_writeblock(47, blockdata) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
OnError(47);
|
||||
return;
|
||||
};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (mifare_ultra_writeblock(start_block + i, key + (i * 4)) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
OnError(start_block + i);
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
if (mifare_ultra_halt()) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Halt error");
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ void MifareG4WriteBlk(uint8_t blockno, uint8_t *pwd, uint8_t *data, uint8_t work
|
||||
void MifareSetMod(uint8_t *datain);
|
||||
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);
|
||||
|
||||
void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
|
||||
void MifareUSetKey(uint8_t arg0, uint8_t *datain);
|
||||
void OnSuccessMagic(void);
|
||||
void OnErrorMagic(uint8_t reason);
|
||||
|
||||
|
||||
+345
-156
@@ -706,6 +706,12 @@ static int ul_auth_select(iso14a_card_select_t *card, uint64_t tagtype, bool has
|
||||
PrintAndLogEx(WARNING, "Authentication Failed UL-C");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else if (hasAuthKey && (tagtype & MFU_TT_UL_AES)) {
|
||||
//will select card automatically and close connection on error
|
||||
if (ulaes_requestAuthentication(authkey, 0, false) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "Authentication Failed UL-AES");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
if (hasAuthKey) {
|
||||
if (ulev1_requestAuthentication(authkey, pack, packSize) == PM3_EWRONGANSWER) {
|
||||
@@ -1888,7 +1894,7 @@ int mfu_get_version_uid(uint8_t *version, uint8_t *uid) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int mfu_fingerprint(uint64_t tagtype, bool hasAuthKey, const uint8_t *authkey, int ak_len) {
|
||||
static int mfu_fingerprint(uint64_t tagtype, bool has_auth_key, const uint8_t *authkey, int ak_len) {
|
||||
|
||||
uint8_t dbg_curr = DBG_NONE;
|
||||
uint8_t *data = NULL;
|
||||
@@ -1912,10 +1918,11 @@ static int mfu_fingerprint(uint64_t tagtype, bool hasAuthKey, const uint8_t *aut
|
||||
|
||||
uint8_t pages = (maxbytes / MFU_BLOCK_SIZE);
|
||||
uint8_t keytype = 0;
|
||||
|
||||
if (hasAuthKey) {
|
||||
if (tagtype & MFU_TT_UL_C)
|
||||
if (has_auth_key) {
|
||||
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)
|
||||
keytype = 1; // UL_C auth
|
||||
else if ((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)
|
||||
keytype = 3; // UL_AES auth
|
||||
else
|
||||
keytype = 2; // UL_EV1/NTAG auth
|
||||
}
|
||||
@@ -2008,23 +2015,21 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int mfu_write_block(const uint8_t *data, uint8_t datalen, bool has_auth_key, bool has_pwd, const uint8_t *auth_key_ptr, uint8_t blockno) {
|
||||
static int mfu_write_block(const uint8_t *data, uint8_t datalen, uint8_t keytype, const uint8_t *auth_key_ptr, uint8_t blockno) {
|
||||
|
||||
// 4 or 16.
|
||||
uint8_t cmd[32];
|
||||
memcpy(cmd, data, datalen);
|
||||
|
||||
size_t cmdlen = datalen;
|
||||
// 0 - no pwd/key, no authentication
|
||||
// 1 - 3des key (16 bytes)
|
||||
// 2 - pwd (4 bytes)
|
||||
uint8_t keytype = 0;
|
||||
size_t cmdlen = datalen;
|
||||
if (has_auth_key) {
|
||||
keytype = 1;
|
||||
// 3 - AES key (16 bytes)
|
||||
if ((keytype == 1)||(keytype == 3)) {
|
||||
memcpy(cmd + datalen, auth_key_ptr, 16);
|
||||
cmdlen += 16;
|
||||
} else if (has_pwd) {
|
||||
keytype = 2;
|
||||
} else if (keytype == 2) {
|
||||
memcpy(cmd + datalen, auth_key_ptr, 4);
|
||||
cmdlen += 4;
|
||||
}
|
||||
@@ -2314,7 +2319,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
uint8_t data[16] = {0x00};
|
||||
iso14a_card_select_t card;
|
||||
int status;
|
||||
uint8_t *authkeyptr = authenticationkey;
|
||||
uint8_t *auth_key_ptr = authenticationkey;
|
||||
uint8_t pwd[4] = {0, 0, 0, 0};
|
||||
uint8_t *key = pwd;
|
||||
uint8_t pack[4] = {0, 0, 0, 0};
|
||||
@@ -2330,11 +2335,19 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
ul_print_type(tagtype, 6);
|
||||
|
||||
// Swap endianness
|
||||
if (swap_endian && has_auth_key) {
|
||||
authkeyptr = SwapEndian64(authenticationkey, ak_len, (ak_len == 16) ? 8 : 4);
|
||||
if (swap_endian) {
|
||||
if (ak_len == 16) {
|
||||
if (((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
} else if (((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 16);
|
||||
}
|
||||
} else if (ak_len == 4) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||
}
|
||||
}
|
||||
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
@@ -2371,7 +2384,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
locked = true;
|
||||
}
|
||||
|
||||
mfu_fingerprint(tagtype, has_auth_key, authkeyptr, ak_len);
|
||||
mfu_fingerprint(tagtype, has_auth_key, auth_key_ptr, ak_len);
|
||||
|
||||
DropField();
|
||||
|
||||
@@ -2440,7 +2453,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
}
|
||||
DropField();
|
||||
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
@@ -2451,7 +2464,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
if ((tagtype & (MFU_TT_UL_EV1_48 | MFU_TT_UL_EV1_128 | MFU_TT_UL_EV1))) {
|
||||
if (ulev1_print_counters() != 3) {
|
||||
// failed - re-select
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
@@ -2461,7 +2474,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
if ((tagtype & (MFU_TT_NTAG_213 | MFU_TT_NTAG_213_F | MFU_TT_NTAG_213_C | MFU_TT_NTAG_213_TT | MFU_TT_NTAG_215 | MFU_TT_NTAG_216))) {
|
||||
if (ntag_print_counter()) {
|
||||
// failed - re-select
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
@@ -2519,7 +2532,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
ulev1_print_signature(tagtype, card.uid, ulev1_signature, 48);
|
||||
} else {
|
||||
// re-select
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
@@ -2538,7 +2551,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
ulev1_print_version(version);
|
||||
} else {
|
||||
locked = true;
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
@@ -2569,7 +2582,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
authlim = (ulev1_conf[4] & 0x07);
|
||||
// add pwd / pack if used from cli
|
||||
if (has_auth_key) {
|
||||
memcpy(ulev1_conf + 8, authkeyptr, 4);
|
||||
memcpy(ulev1_conf + 8, auth_key_ptr, 4);
|
||||
memcpy(ulev1_conf + 12, pack, 2);
|
||||
}
|
||||
ulev1_print_configuration(tagtype, ulev1_conf, startconfigblock);
|
||||
@@ -2595,7 +2608,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
@@ -2610,7 +2623,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
@@ -2625,7 +2638,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
@@ -2640,7 +2653,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
@@ -2654,7 +2667,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
PrintAndLogEx(SUCCESS, "Password... " _GREEN_("%s") " pack... " _GREEN_("%02X%02X"), sprint_hex_inrow(key, 4), pack[0], pack[1]);
|
||||
break;
|
||||
} else {
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
@@ -2673,7 +2686,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
out:
|
||||
DropField();
|
||||
|
||||
mfu_fingerprint(tagtype, has_auth_key, authkeyptr, ak_len);
|
||||
mfu_fingerprint(tagtype, has_auth_key, auth_key_ptr, ak_len);
|
||||
|
||||
if (locked) {
|
||||
PrintAndLogEx(INFO, "\nTag appears to be locked, try using a key to get more info");
|
||||
@@ -2703,7 +2716,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) {
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("k", "key", "<hex>", "Authentication key (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
|
||||
arg_str0("k", "key", "<hex>", "Authentication key (UL-C/UL-AES 16 bytes, EV1/NTAG 4 bytes)"),
|
||||
arg_lit0("l", NULL, "Swap entered key's endianness"),
|
||||
arg_int1("b", "block", "<dec>", "Block number to write"),
|
||||
arg_str1("d", "data", "<hex>", "Block data (4 or 16 hex bytes, 16 hex bytes will do a compatibility write)"),
|
||||
@@ -2768,11 +2781,15 @@ static int CmdHF14AMfUWrBl(const char *Cmd) {
|
||||
|
||||
// Swap endianness
|
||||
if (swap_endian) {
|
||||
if (has_auth_key)
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, 16, 8);
|
||||
|
||||
if (has_pwd)
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, 4, 4);
|
||||
if (ak_len == 16) {
|
||||
if (((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
} else if (((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 16);
|
||||
}
|
||||
} else if (ak_len == 4) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||
}
|
||||
}
|
||||
|
||||
if (blockno <= 3)
|
||||
@@ -2780,10 +2797,26 @@ static int CmdHF14AMfUWrBl(const char *Cmd) {
|
||||
else
|
||||
PrintAndLogEx(INFO, "Block: %0d (0x%02X) [ %s]", blockno, blockno, sprint_hex(data, datalen));
|
||||
|
||||
if (ak_len) {
|
||||
PrintAndLogEx(INFO, "Using %s " _GREEN_("%s"), (ak_len == 16) ? "3des" : "pwd", sprint_hex(authenticationkey, ak_len));
|
||||
if (has_auth_key) {
|
||||
if (((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)) {
|
||||
PrintAndLogEx(INFO, "Using %s... " _GREEN_("%s"), "3des", sprint_hex_inrow(authenticationkey, ak_len));
|
||||
} else if (((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) {
|
||||
PrintAndLogEx(INFO, "Using %s... " _GREEN_("%s"), "aes", sprint_hex_inrow(authenticationkey, ak_len));
|
||||
}
|
||||
} else if (has_pwd) {
|
||||
PrintAndLogEx(INFO, "Using %s... " _GREEN_("%s"), "pwd", sprint_hex_inrow(authenticationkey, ak_len));
|
||||
}
|
||||
|
||||
uint8_t keytype = 0;
|
||||
if (has_auth_key || has_pwd) {
|
||||
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) {
|
||||
keytype = 1; // UL_C auth
|
||||
} else if ((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES) {
|
||||
keytype = 3; // UL_AES auth
|
||||
} else {
|
||||
keytype = 2; // UL_EV1/NTAG auth
|
||||
}
|
||||
}
|
||||
|
||||
// Send write Block.
|
||||
uint8_t *d = data;
|
||||
@@ -2792,7 +2825,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) {
|
||||
// Comp write may take 16bytes, but only write 4bytes. See UL-C datasheet
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
|
||||
res = mfu_write_block(d, 4, has_auth_key, has_pwd, auth_key_ptr, blockno + i);
|
||||
res = mfu_write_block(d, 4, keytype, auth_key_ptr, blockno + i);
|
||||
if (res == PM3_SUCCESS) {
|
||||
d += 4;
|
||||
} else {
|
||||
@@ -2807,7 +2840,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) {
|
||||
}
|
||||
|
||||
} else {
|
||||
res = mfu_write_block(data, datalen, has_auth_key, has_pwd, auth_key_ptr, blockno);
|
||||
res = mfu_write_block(data, datalen, keytype, auth_key_ptr, blockno);
|
||||
switch (res) {
|
||||
case PM3_SUCCESS: {
|
||||
PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
|
||||
@@ -2844,7 +2877,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) {
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("k", "key", "<hex>", "Authentication key (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
|
||||
arg_str0("k", "key", "<hex>", "Authentication key (UL-C/UL-AES 16 bytes, EV1/NTAG 4 bytes)"),
|
||||
arg_lit0("l", NULL, "Swap entered key's endianness"),
|
||||
arg_int1("b", "block", "<dec>", "Block number to read"),
|
||||
arg_lit0(NULL, "force", "Force operation even if address is out of range"),
|
||||
@@ -2876,7 +2909,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t *authKeyPtr = authenticationkey;
|
||||
uint8_t *auth_key_ptr = authenticationkey;
|
||||
|
||||
// start with getting tagtype
|
||||
uint64_t tagtype = GetHF14AMfU_Type();
|
||||
@@ -2897,30 +2930,45 @@ static int CmdHF14AMfURdBl(const char *Cmd) {
|
||||
|
||||
// Swap endianness
|
||||
if (swap_endian) {
|
||||
if (has_auth_key)
|
||||
authKeyPtr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
|
||||
if (has_pwd)
|
||||
authKeyPtr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||
if (ak_len == 16) {
|
||||
if (((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
} else if (((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 16);
|
||||
}
|
||||
} else if (ak_len == 4) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||
}
|
||||
}
|
||||
|
||||
if (ak_len) {
|
||||
PrintAndLogEx(INFO, "Using %s... " _GREEN_("%s"), (ak_len == 16) ? "3des" : "pwd", sprint_hex_inrow(authenticationkey, ak_len));
|
||||
if (has_auth_key) {
|
||||
if (((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)) {
|
||||
PrintAndLogEx(INFO, "Using %s... " _GREEN_("%s"), "3des", sprint_hex_inrow(authenticationkey, ak_len));
|
||||
} else if (((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) {
|
||||
PrintAndLogEx(INFO, "Using %s... " _GREEN_("%s"), "aes", sprint_hex_inrow(authenticationkey, ak_len));
|
||||
}
|
||||
} else if (has_pwd) {
|
||||
PrintAndLogEx(INFO, "Using %s... " _GREEN_("%s"), "pwd", sprint_hex_inrow(authenticationkey, ak_len));
|
||||
}
|
||||
|
||||
//Read Block
|
||||
uint8_t keytype = 0;
|
||||
uint8_t datalen = 0;
|
||||
if (has_auth_key) {
|
||||
keytype = 1;
|
||||
datalen = 16;
|
||||
} else if (has_pwd) {
|
||||
keytype = 2;
|
||||
datalen = 4;
|
||||
if (has_auth_key || has_pwd) {
|
||||
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) {
|
||||
keytype = 1; // UL_C auth
|
||||
datalen = 16;
|
||||
} else if ((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES) {
|
||||
keytype = 3; // UL_AES auth
|
||||
datalen = 16;
|
||||
} else {
|
||||
keytype = 2; // UL_EV1/NTAG auth
|
||||
datalen = 4;
|
||||
}
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockno, keytype, 0, authKeyPtr, datalen);
|
||||
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockno, keytype, 0, auth_key_ptr, datalen);
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
uint8_t isOK = resp.oldarg[0] & 0xff;
|
||||
@@ -3150,7 +3198,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
"Dump MIFARE Ultralight/NTAG tag to files (bin/json)\n"
|
||||
"It autodetects card type."
|
||||
"Supports:\n"
|
||||
"Ultralight, Ultralight-C, Ultralight EV1\n"
|
||||
"Ultralight, Ultralight C, Ultralight AES, Ultralight EV1\n"
|
||||
"NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216\n",
|
||||
"hf mfu dump -f myfile\n"
|
||||
"hf mfu dump -k AABBCCDD -> dump whole tag using pwd AABBCCDD\n"
|
||||
@@ -3162,7 +3210,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
|
||||
arg_str0("k", "key", "<hex>", "Key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
|
||||
arg_str0("k", "key", "<hex>", "Key for authentication (UL-C/UL-AES 16 bytes, EV1/NTAG 4 bytes)"),
|
||||
arg_lit0("l", NULL, "Swap entered key's endianness"),
|
||||
arg_int0("p", "page", "<dec>", "Manually set start page number to start from"),
|
||||
arg_int0("q", "qty", "<dec>", "Manually set number of pages to dump"),
|
||||
@@ -3178,7 +3226,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
|
||||
int ak_len = 0;
|
||||
uint8_t authenticationkey[16] = {0x00};
|
||||
uint8_t *authKeyPtr = authenticationkey;
|
||||
uint8_t *auth_key_ptr = authenticationkey;
|
||||
CLIGetHexWithReturn(ctx, 2, authenticationkey, &ak_len);
|
||||
bool swap_endian = arg_get_lit(ctx, 3);
|
||||
int start_page = arg_get_int_def(ctx, 4, 0);
|
||||
@@ -3209,22 +3257,24 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
|
||||
uint8_t card_mem_size = 0;
|
||||
|
||||
// Swap endianness
|
||||
if (swap_endian) {
|
||||
if (has_auth_key) {
|
||||
authKeyPtr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
}
|
||||
|
||||
if (has_pwd) {
|
||||
authKeyPtr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t tagtype = GetHF14AMfU_Type();
|
||||
if (tagtype == MFU_TT_UL_ERROR) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// Swap endianness
|
||||
if (swap_endian) {
|
||||
if (ak_len == 16) {
|
||||
if (((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
} else if (((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 16);
|
||||
}
|
||||
} else if (ak_len == 4) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||
}
|
||||
}
|
||||
|
||||
//get number of pages to read
|
||||
if (manual_pages == false) {
|
||||
for (uint8_t idx = 1; idx < ARRAYLEN(UL_TYPES_ARRAY); idx++) {
|
||||
@@ -3242,6 +3292,8 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
if (has_auth_key || has_pwd) {
|
||||
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)
|
||||
keytype = 1; // UL_C auth
|
||||
else if ((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)
|
||||
keytype = 3; // UL_AES auth
|
||||
else
|
||||
keytype = 2; // UL_EV1/NTAG auth
|
||||
}
|
||||
@@ -3256,7 +3308,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFAREU_READCARD, start_page, pages, keytype, authKeyPtr, ak_len);
|
||||
SendCommandMIX(CMD_HF_MIFAREU_READCARD, start_page, pages, keytype, auth_key_ptr, ak_len);
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
@@ -3292,7 +3344,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
|
||||
if (is_partial) {
|
||||
|
||||
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) {
|
||||
if (((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) || ((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) {
|
||||
if (card_mem_size != (pages + 4)) {
|
||||
PrintAndLogEx(INFO, "Partial dump, got " _RED_("%d") " bytes - card mem size is %u bytes", pages * MFU_BLOCK_SIZE, card_mem_size * MFU_BLOCK_SIZE);
|
||||
PrintAndLogEx(HINT, "Hint: Try using a key");
|
||||
@@ -3312,11 +3364,11 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
|
||||
// not ul_c and not std ul then attempt to collect info like
|
||||
// VERSION, SIGNATURE, COUNTERS, TEARING, PACK,
|
||||
if (!(tagtype & MFU_TT_UL_C || tagtype & MFU_TT_UL || tagtype & MFU_TT_MY_D_MOVE || tagtype & MFU_TT_MY_D_MOVE_LEAN)) {
|
||||
if (!(tagtype & MFU_TT_UL_C || tagtype & MFU_TT_UL_AES || tagtype & MFU_TT_UL || tagtype & MFU_TT_MY_D_MOVE || tagtype & MFU_TT_MY_D_MOVE_LEAN)) {
|
||||
// attempt to read pack
|
||||
bool has_key = (has_auth_key || has_pwd);
|
||||
uint8_t get_pack[] = {0, 0};
|
||||
if (ul_auth_select(&card, tagtype, has_key, authKeyPtr, get_pack, sizeof(get_pack)) != PM3_SUCCESS) {
|
||||
if (ul_auth_select(&card, tagtype, has_key, auth_key_ptr, get_pack, sizeof(get_pack)) != PM3_SUCCESS) {
|
||||
//reset pack
|
||||
get_pack[0] = 0;
|
||||
get_pack[1] = 0;
|
||||
@@ -3332,7 +3384,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
|
||||
if (has_auth_key) {
|
||||
uint8_t dummy_pack[] = {0, 0};
|
||||
ul_auth_select(&card, tagtype, has_auth_key, authKeyPtr, dummy_pack, sizeof(dummy_pack));
|
||||
ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, dummy_pack, sizeof(dummy_pack));
|
||||
} else {
|
||||
ul_select(&card);
|
||||
}
|
||||
@@ -3352,7 +3404,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
|
||||
if (has_auth_key) {
|
||||
uint8_t dummy_pack[] = {0, 0};
|
||||
ul_auth_select(&card, tagtype, has_auth_key, authKeyPtr, dummy_pack, sizeof(dummy_pack));
|
||||
ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, dummy_pack, sizeof(dummy_pack));
|
||||
} else {
|
||||
ul_select(&card);
|
||||
}
|
||||
@@ -3360,7 +3412,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
|
||||
if (has_auth_key) {
|
||||
uint8_t dummy_pack[] = {0, 0};
|
||||
ul_auth_select(&card, tagtype, has_auth_key, authKeyPtr, dummy_pack, sizeof(dummy_pack));
|
||||
ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, dummy_pack, sizeof(dummy_pack));
|
||||
} else {
|
||||
ul_select(&card);
|
||||
}
|
||||
@@ -3371,7 +3423,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
|
||||
if (has_auth_key) {
|
||||
uint8_t dummy_pack[] = {0, 0};
|
||||
ul_auth_select(&card, tagtype, has_auth_key, authKeyPtr, dummy_pack, sizeof(dummy_pack));
|
||||
ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, dummy_pack, sizeof(dummy_pack));
|
||||
} else {
|
||||
ul_select(&card);
|
||||
}
|
||||
@@ -3384,20 +3436,30 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
// format and add keys to block dump output
|
||||
// only add keys if not partial read, and complete pages read
|
||||
|
||||
// UL-C add a working known key
|
||||
if (has_auth_key && (tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) { // add 4 pages of key
|
||||
// UL-C/UL-AES add a working known key
|
||||
if (has_auth_key && ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C || (tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) { // add 4 pages of key
|
||||
|
||||
// if we didn't swapendian before - do it now for the sprint_hex call
|
||||
// NOTE: default entry is bigendian (unless swapped), sprint_hex outputs little endian
|
||||
// need to swap to keep it the same
|
||||
if (swap_endian == false) {
|
||||
authKeyPtr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
} else {
|
||||
authKeyPtr = authenticationkey;
|
||||
}
|
||||
auth_key_ptr = authenticationkey;
|
||||
|
||||
memcpy(data + pages * MFU_BLOCK_SIZE, authKeyPtr, ak_len);
|
||||
pages += ak_len / MFU_BLOCK_SIZE;
|
||||
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) {
|
||||
if (swap_endian == false) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
}
|
||||
memcpy(data + pages * MFU_BLOCK_SIZE, auth_key_ptr, ak_len);
|
||||
pages += ak_len / MFU_BLOCK_SIZE;
|
||||
}
|
||||
if (((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES) && (pages >= 0x2F)) {
|
||||
if (swap_endian == false) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 16);
|
||||
}
|
||||
memcpy(data + 0x30 * MFU_BLOCK_SIZE, auth_key_ptr, ak_len);
|
||||
if (pages < 0x34) {
|
||||
pages = 0x34;
|
||||
}
|
||||
}
|
||||
|
||||
// fix
|
||||
if (is_partial && pages == card_mem_size) {
|
||||
@@ -3410,9 +3472,9 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
// NOTE: default entry is bigendian (unless swapped), sprint_hex outputs little endian
|
||||
// need to swap to keep it the same
|
||||
if (swap_endian == false) {
|
||||
authKeyPtr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||
} else {
|
||||
authKeyPtr = authenticationkey;
|
||||
auth_key_ptr = authenticationkey;
|
||||
}
|
||||
|
||||
memcpy(data + (pages * MFU_BLOCK_SIZE) - 8, authenticationkey, ak_len);
|
||||
@@ -3632,9 +3694,9 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
|
||||
int ak_len = 0;
|
||||
uint8_t authkey[16] = {0x00};
|
||||
uint8_t *p_authkey = authkey;
|
||||
CLIGetHexWithReturn(ctx, 2, authkey, &ak_len);
|
||||
uint8_t authenticationkey[16] = {0x00};
|
||||
uint8_t *auth_key_ptr = authenticationkey;
|
||||
CLIGetHexWithReturn(ctx, 2, authenticationkey, &ak_len);
|
||||
|
||||
bool swap_endian = arg_get_lit(ctx, 3);
|
||||
bool write_special = arg_get_lit(ctx, 4);
|
||||
@@ -3695,24 +3757,43 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint64_t tagtype = GetHF14AMfU_Type();
|
||||
if (tagtype == MFU_TT_UL_ERROR) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if ((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES) {
|
||||
PrintAndLogEx(ERR, "Sorry, UL-AES not yet supported");
|
||||
free(dump);
|
||||
return PM3_ENOTIMPL;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename);
|
||||
|
||||
mfu_print_dump(mem, pages, 0, dense_output);
|
||||
|
||||
// Swap endianness
|
||||
if (swap_endian && has_key) {
|
||||
if (ak_len == 16)
|
||||
p_authkey = SwapEndian64(authkey, ak_len, 8);
|
||||
else
|
||||
p_authkey = SwapEndian64(authkey, ak_len, 4);
|
||||
if (swap_endian) {
|
||||
if (ak_len == 16) {
|
||||
if (((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
} else if (((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 16);
|
||||
}
|
||||
} else if (ak_len == 4) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t data[20] = {0};
|
||||
uint8_t keytype = 0;
|
||||
// set key - only once
|
||||
if (has_key) {
|
||||
keytype = (ak_len == 16) ? 1 : 2;
|
||||
memcpy(data + 4, p_authkey, ak_len);
|
||||
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)
|
||||
keytype = 1; // UL_C auth
|
||||
else if ((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)
|
||||
keytype = 3; // UL_AES auth
|
||||
else
|
||||
keytype = 2; // UL_EV1/NTAG auth
|
||||
memcpy(data + 4, auth_key_ptr, ak_len);
|
||||
}
|
||||
|
||||
// write version, signature, pack
|
||||
@@ -3726,7 +3807,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||
// pwd
|
||||
if (has_key || read_key) {
|
||||
|
||||
memcpy(data, p_authkey, 4);
|
||||
memcpy(data, auth_key_ptr, 4);
|
||||
if (read_key) {
|
||||
// try reading key from dump and use.
|
||||
memcpy(data, mem->data + (bytes_read - MFU_DUMP_PREFIX_LENGTH - 8), 4);
|
||||
@@ -3740,8 +3821,8 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||
|
||||
// copy the new key
|
||||
keytype = 2;
|
||||
memcpy(authkey, data, 4);
|
||||
memcpy(data + 4, authkey, 4);
|
||||
memcpy(authenticationkey, data, 4);
|
||||
memcpy(data + 4, authenticationkey, 4);
|
||||
}
|
||||
|
||||
// pack
|
||||
@@ -3794,7 +3875,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||
|
||||
PrintAndLogEx(INFO, "Restoring configuration blocks");
|
||||
|
||||
PrintAndLogEx(INFO, "Authentication with keytype[%x] %s\n", (uint8_t)(keytype & 0xff), sprint_hex(p_authkey, 4));
|
||||
PrintAndLogEx(INFO, "Authentication with keytype[%x] %s\n", (uint8_t)(keytype & 0xff), sprint_hex(auth_key_ptr, 4));
|
||||
|
||||
#if defined ICOPYX
|
||||
// otp, uid, lock, dynlockbits, cfg0, cfg1, pwd, pack
|
||||
@@ -3915,7 +3996,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) {
|
||||
|
||||
int ak_len = 0;
|
||||
uint8_t authenticationkey[16] = {0x00};
|
||||
uint8_t *authKeyPtr = authenticationkey;
|
||||
uint8_t *auth_key_ptr = authenticationkey;
|
||||
CLIGetHexWithReturn(ctx, 1, authenticationkey, &ak_len);
|
||||
bool swap_endian = arg_get_lit(ctx, 2);
|
||||
bool keep_field_on = arg_get_lit(ctx, 3);
|
||||
@@ -3928,7 +4009,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) {
|
||||
|
||||
// Swap endianness
|
||||
if (swap_endian && ak_len) {
|
||||
authKeyPtr = SwapEndian64(authenticationkey, 16, 8);
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, 16, 8);
|
||||
}
|
||||
|
||||
int isok;
|
||||
@@ -3937,14 +4018,14 @@ static int CmdHF14AMfUCAuth(const char *Cmd) {
|
||||
if (ak_len == 0) {
|
||||
|
||||
PrintAndLogEx(INFO, "Called with no key, checking default keys...");
|
||||
isok = try_default_3des_keys(false, &authKeyPtr);
|
||||
isok = try_default_3des_keys(false, &auth_key_ptr);
|
||||
} else {
|
||||
// try user-supplied
|
||||
isok = ulc_authentication(authKeyPtr, !keep_field_on);
|
||||
isok = ulc_authentication(auth_key_ptr, !keep_field_on);
|
||||
}
|
||||
|
||||
if (isok == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Authentication 3DES key... " _GREEN_("%s") " ( " _GREEN_("ok")" )", sprint_hex_inrow(authKeyPtr, 16));
|
||||
PrintAndLogEx(SUCCESS, "Authentication 3DES key... " _GREEN_("%s") " ( " _GREEN_("ok")" )", sprint_hex_inrow(auth_key_ptr, 16));
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Authentication ( " _RED_("fail") " )");
|
||||
}
|
||||
@@ -3973,6 +4054,7 @@ static int CmdHF14AMfUAESAuth(const char *Cmd) {
|
||||
arg_param_begin,
|
||||
arg_str0(NULL, "key", "<hex>", "AES key (16 hex bytes)"),
|
||||
arg_int0("i", "idx", "<0..2>", "Key index (def: 0)"),
|
||||
arg_lit0("l", NULL, "Swap entered key's endianness"),
|
||||
arg_lit0("k", NULL, "Keep field on (only if a key is provided)"),
|
||||
arg_param_end
|
||||
};
|
||||
@@ -3980,10 +4062,11 @@ static int CmdHF14AMfUAESAuth(const char *Cmd) {
|
||||
|
||||
int ak_len = 0;
|
||||
uint8_t authentication_key[16] = {0};
|
||||
uint8_t *authKeyPtr = authentication_key;
|
||||
uint8_t *auth_key_ptr = authentication_key;
|
||||
CLIGetHexWithReturn(ctx, 1, authentication_key, &ak_len);
|
||||
int key_index = arg_get_int_def(ctx, 2, 0);
|
||||
bool keep_field_on = arg_get_lit(ctx, 3);
|
||||
bool swap_endian = arg_get_lit(ctx, 3);
|
||||
bool keep_field_on = arg_get_lit(ctx, 4);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
@@ -4001,11 +4084,16 @@ static int CmdHF14AMfUAESAuth(const char *Cmd) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
int result = ulaes_requestAuthentication(authKeyPtr, key_index, !keep_field_on);
|
||||
// Swap endianness
|
||||
if (swap_endian && ak_len) {
|
||||
auth_key_ptr = SwapEndian64(authentication_key, ak_len, 16);
|
||||
}
|
||||
|
||||
int result = ulaes_requestAuthentication(auth_key_ptr, key_index, !keep_field_on);
|
||||
if (result == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Authentication with " _YELLOW_("%s") " " _GREEN_("%s") " ( " _GREEN_("ok")" )"
|
||||
, key_type[key_index]
|
||||
, sprint_hex_inrow(authKeyPtr, ak_len)
|
||||
, sprint_hex_inrow(auth_key_ptr, ak_len)
|
||||
);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Authentication with " _YELLOW_("%s") " ( " _RED_("fail") " )", key_type[key_index]);
|
||||
@@ -4111,39 +4199,77 @@ static int CmdTestDES(const char * cmd)
|
||||
**/
|
||||
|
||||
//
|
||||
// Mifare Ultralight C - Set password
|
||||
// Mifare Ultralight C/AES - Set keys
|
||||
//
|
||||
static int CmdHF14AMfUCSetPwd(const char *Cmd) {
|
||||
static int CmdHF14AMfUSetKey(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfu setpwd",
|
||||
"Set the 3DES key on MIFARE Ultralight-C tag. ",
|
||||
"hf mfu setpwd --key 000102030405060708090a0b0c0d0e0f"
|
||||
CLIParserInit(&ctx, "hf mfu setkey",
|
||||
"Set the 3DES key on MIFARE Ultralight C tag and the AES keys on Ultralight AES. \n"
|
||||
"Note: AUTH0 must allow unauthenticated writes to the key blocks\n"
|
||||
"UL-AES:\n"
|
||||
" New Key index 0... DataProtKey (default)\n"
|
||||
" New Key index 1... UIDRetrKey\n",
|
||||
"hf mfu setkey --key 49454D4B41455242214E4143554F5946\n"
|
||||
"hf mfu setkey --key <16 hex bytes> --idx <0..1>"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("k", "key", "<hex>", "New key (16 hex bytes)"),
|
||||
arg_int0("i", "idx", "<0..1>", "New key index (def: 0), only for UL-AES"),
|
||||
arg_lit0("l", NULL, "Swap entered keys' endianness"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
int k_len = 0;
|
||||
uint8_t key[16] = {0x00};
|
||||
CLIGetHexWithReturn(ctx, 1, key, &k_len);
|
||||
int ak_len = 0;
|
||||
uint8_t authenticationkey[16] = {0x00};
|
||||
uint8_t *auth_key_ptr = authenticationkey;
|
||||
CLIGetHexWithReturn(ctx, 1, authenticationkey, &ak_len);
|
||||
int key_index = arg_get_int_def(ctx, 2, 0);
|
||||
bool swap_endian = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (k_len != 16) {
|
||||
if (ak_len != 16) {
|
||||
PrintAndLogEx(WARNING, "Key must be 16 hex bytes");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (key_index < 0 || key_index > 1) {
|
||||
PrintAndLogEx(WARNING, "Invalid key index");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint64_t tagtype = GetHF14AMfU_Type();
|
||||
if (tagtype == MFU_TT_UL_ERROR) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if ((tagtype & (MFU_TT_UL_C | MFU_TT_UL_AES)) == 0) {
|
||||
PrintAndLogEx(WARNING, "Tag is not Ultralight C or Ultralight AES");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// Swap endianness
|
||||
// Beware, inverse condition! Key not used for authentication here
|
||||
// if key not swapped by user, we need to swap it to write it in memory
|
||||
if (!swap_endian) {
|
||||
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
} else if ((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 16);
|
||||
}
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFAREUC_SETPWD, 0, 0, 0, key, sizeof(key));
|
||||
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) {
|
||||
SendCommandMIX(CMD_HF_MIFAREU_SETKEY, 1, 0, 0, auth_key_ptr, sizeof(authenticationkey));
|
||||
} else if ((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES) {
|
||||
SendCommandMIX(CMD_HF_MIFAREU_SETKEY, key_index + 2, 0, 0, auth_key_ptr, sizeof(authenticationkey));
|
||||
}
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
if ((resp.oldarg[0] & 0xff) == 1) {
|
||||
PrintAndLogEx(INFO, "Ultralight-C new key... " _GREEN_("%s"), sprint_hex_inrow(key, sizeof(key)));
|
||||
PrintAndLogEx(INFO, "New key... " _GREEN_("%s"), sprint_hex_inrow(authenticationkey, sizeof(authenticationkey)));
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xFF));
|
||||
return PM3_ESOFT;
|
||||
@@ -5185,15 +5311,15 @@ static int CmdHF14AMfuEv1CounterTearoff(const char *Cmd) {
|
||||
|
||||
int CmdHF14MfuNDEFRead(const char *Cmd) {
|
||||
|
||||
int keylen;
|
||||
int ak_len;
|
||||
int maxsize = 16, status;
|
||||
bool hasAuthKey = false;
|
||||
bool swapEndian = false;
|
||||
bool has_auth_key = false;
|
||||
bool swap_endian = false;
|
||||
|
||||
iso14a_card_select_t card;
|
||||
uint8_t data[16] = {0x00};
|
||||
uint8_t key[16] = {0x00};
|
||||
uint8_t *p_key = key;
|
||||
uint8_t authenticationkey[16] = {0x00};
|
||||
uint8_t *auth_key_ptr = authenticationkey;
|
||||
uint8_t pack[4] = {0, 0, 0, 0};
|
||||
|
||||
CLIParserContext *ctx;
|
||||
@@ -5213,20 +5339,20 @@ int CmdHF14MfuNDEFRead(const char *Cmd) {
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIGetHexWithReturn(ctx, 1, key, &keylen);
|
||||
swapEndian = arg_get_lit(ctx, 2);
|
||||
CLIGetHexWithReturn(ctx, 1, authenticationkey, &ak_len);
|
||||
swap_endian = arg_get_lit(ctx, 2);
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
bool verbose = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
switch (keylen) {
|
||||
switch (ak_len) {
|
||||
case 0:
|
||||
break;
|
||||
case 4:
|
||||
case 16:
|
||||
hasAuthKey = true;
|
||||
has_auth_key = true;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n");
|
||||
@@ -5243,10 +5369,20 @@ int CmdHF14MfuNDEFRead(const char *Cmd) {
|
||||
// Is tag UL/NTAG?
|
||||
|
||||
// Swap endianness
|
||||
if (swapEndian && hasAuthKey) p_key = SwapEndian64(key, keylen, (keylen == 16) ? 8 : 4);
|
||||
if (swap_endian) {
|
||||
if (ak_len == 16) {
|
||||
if (((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
} else if (((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 16);
|
||||
}
|
||||
} else if (ak_len == 4) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Select and Auth
|
||||
if (ul_auth_select(&card, tagtype, hasAuthKey, p_key, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT;
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT;
|
||||
|
||||
// read pages 0,1,2,3 (should read 4pages)
|
||||
status = ul_read(0, data, sizeof(data));
|
||||
@@ -5677,7 +5813,8 @@ static int CmdHF14AMfuWipe(const char *Cmd) {
|
||||
"you will need to call it with password in order to wipe the config and sett default pwd/pack\n"
|
||||
"Abort by pressing a key\n"
|
||||
"New password.... FFFFFFFF\n"
|
||||
"New 3-DES key... 49454D4B41455242214E4143554F5946\n",
|
||||
"New 3-DES key... 49454D4B41455242214E4143554F5946\n"
|
||||
"New AES keys... 00000000000000000000000000000000\n",
|
||||
"hf mfu wipe\n"
|
||||
"hf mfu wipe -k 49454D4B41455242214E4143554F5946\n"
|
||||
);
|
||||
@@ -5710,22 +5847,24 @@ static int CmdHF14AMfuWipe(const char *Cmd) {
|
||||
|
||||
uint8_t card_mem_size = 0;
|
||||
|
||||
// Swap endianness
|
||||
if (swap_endian) {
|
||||
if (has_auth_key) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
}
|
||||
|
||||
if (has_pwd) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t tagtype = GetHF14AMfU_Type();
|
||||
if (tagtype == MFU_TT_UL_ERROR) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// Swap endianness
|
||||
if (swap_endian) {
|
||||
if (ak_len == 16) {
|
||||
if (((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||
} else if (((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 16);
|
||||
}
|
||||
} else if (ak_len == 4) {
|
||||
auth_key_ptr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// number of pages to WRITE
|
||||
for (uint8_t idx = 1; idx < ARRAYLEN(UL_TYPES_ARRAY); idx++) {
|
||||
if ((tagtype & UL_TYPES_ARRAY[idx]) == UL_TYPES_ARRAY[idx]) {
|
||||
@@ -5752,6 +5891,17 @@ static int CmdHF14AMfuWipe(const char *Cmd) {
|
||||
|
||||
DropField();
|
||||
|
||||
uint8_t keytype = 0;
|
||||
if (has_auth_key || has_pwd) {
|
||||
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) {
|
||||
keytype = 1; // UL_C auth
|
||||
} else if ((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES) {
|
||||
keytype = 3; // UL_AES auth
|
||||
} else {
|
||||
keytype = 2; // UL_EV1/NTAG auth
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Start wiping...");
|
||||
PrintAndLogEx(INFO, "-----+-----------------------------");
|
||||
// time to wipe card
|
||||
@@ -5793,7 +5943,18 @@ static int CmdHF14AMfuWipe(const char *Cmd) {
|
||||
|
||||
// UL_AES specific
|
||||
if ((tagtype & MFU_TT_UL_AES)) {
|
||||
// default config?
|
||||
// default config? TODO:
|
||||
|
||||
switch (i) {
|
||||
case 41:
|
||||
memcpy(data, "\x00\x00\x00\x3C", 4);
|
||||
break;
|
||||
case 42:
|
||||
memcpy(data, "\x8C\x05\x00\x00", 4);
|
||||
break;
|
||||
case 48:
|
||||
goto ulaes;
|
||||
}
|
||||
}
|
||||
|
||||
// UL / NTAG with PWD/PACK
|
||||
@@ -5840,11 +6001,11 @@ static int CmdHF14AMfuWipe(const char *Cmd) {
|
||||
/*
|
||||
int res = PM3_SUCCESS;
|
||||
if (res == PM3_ESOFT) {
|
||||
res = mfu_write_block(data, MFU_BLOCK_SIZE, has_auth_key, has_pwd, auth_key_ptr, i);
|
||||
res = mfu_write_block(data, MFU_BLOCK_SIZE, keytype, auth_key_ptr, i);
|
||||
}
|
||||
*/
|
||||
|
||||
int res = mfu_write_block(data, MFU_BLOCK_SIZE, has_auth_key, has_pwd, auth_key_ptr, i);
|
||||
int res = mfu_write_block(data, MFU_BLOCK_SIZE, keytype, auth_key_ptr, i);
|
||||
|
||||
PrintAndLogEx(INFO, " %3d | %s" NOLF, i, sprint_hex(data, MFU_BLOCK_SIZE));
|
||||
switch (res) {
|
||||
@@ -5872,17 +6033,18 @@ ulc:
|
||||
// UL-C - set 3-DES key
|
||||
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) {
|
||||
|
||||
uint8_t key[16] = {
|
||||
uint8_t defaultkey[16] = {
|
||||
0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42,
|
||||
0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46
|
||||
};
|
||||
uint8_t *def_key_ptr = SwapEndian64(defaultkey, 16, 8);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFAREUC_SETPWD, 0, 0, 0, key, sizeof(key));
|
||||
SendCommandMIX(CMD_HF_MIFAREU_SETKEY, 1, 0, 0, def_key_ptr, sizeof(defaultkey));
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
if ((resp.oldarg[0] & 0xff) == 1) {
|
||||
PrintAndLogEx(INFO, "Ultralight-C new key... " _GREEN_("%s"), sprint_hex_inrow(key, sizeof(key)));
|
||||
PrintAndLogEx(INFO, "Ultralight C new key... " _GREEN_("%s"), sprint_hex_inrow(defaultkey, sizeof(defaultkey)));
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xFF));
|
||||
return PM3_ESOFT;
|
||||
@@ -5893,9 +6055,36 @@ ulc:
|
||||
}
|
||||
}
|
||||
|
||||
ulaes:
|
||||
// UL_AES specific
|
||||
if ((tagtype & MFU_TT_UL_AES)) {
|
||||
// Set AES key
|
||||
if ((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES) {
|
||||
// Set AES keys
|
||||
uint8_t defaultkey[16] = { 0 };
|
||||
uint8_t *def_key_ptr = SwapEndian64(defaultkey, 16, 16);
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFAREU_SETKEY, 2, 0, 0, def_key_ptr, sizeof(defaultkey));
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
if ((resp.oldarg[0] & 0xff) != 1) {
|
||||
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xFF));
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFAREU_SETKEY, 3, 0, 0, def_key_ptr, sizeof(defaultkey));
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
if ((resp.oldarg[0] & 0xff) == 1) {
|
||||
PrintAndLogEx(INFO, "Ultralight AES new key... " _GREEN_("%s"), sprint_hex_inrow(defaultkey, sizeof(defaultkey)));
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xFF));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6037,9 +6226,9 @@ static command_t CommandTable[] = {
|
||||
{"otptear", CmdHF14AMfuOtpTearoff, IfPm3Iso14443a, "Tear-off test on OTP bits"},
|
||||
// {"tear_cnt", CmdHF14AMfuEv1CounterTearoff, IfPm3Iso14443a, "Tear-off test on Ev1/NTAG Counter bits"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("operations") " -----------------------"},
|
||||
{"cauth", CmdHF14AMfUCAuth, IfPm3Iso14443a, "Ultralight-C - Authentication"},
|
||||
{"setpwd", CmdHF14AMfUCSetPwd, IfPm3Iso14443a, "Ultralight-C - Set 3DES key"},
|
||||
{"aesauth", CmdHF14AMfUAESAuth, IfPm3Iso14443a, "Ultralight-AES - Authentication"},
|
||||
{"cauth", CmdHF14AMfUCAuth, IfPm3Iso14443a, "Ultralight C - Authentication"},
|
||||
{"aesauth", CmdHF14AMfUAESAuth, IfPm3Iso14443a, "Ultralight AES - Authentication"},
|
||||
{"setkey", CmdHF14AMfUSetKey, IfPm3Iso14443a, "Ultralight C/AES - Set 3DES/AES keys"},
|
||||
{"dump", CmdHF14AMfUDump, IfPm3Iso14443a, "Dump MIFARE Ultralight family tag to binary file"},
|
||||
{"incr", CmdHF14AMfUIncr, IfPm3Iso14443a, "Increments Ev1/NTAG counter"},
|
||||
{"info", CmdHF14AMfUInfo, IfPm3Iso14443a, "Tag information"},
|
||||
|
||||
@@ -434,8 +434,8 @@ const static vocabulary_t vocabulary[] = {
|
||||
{ 1, "hf mfu pwdgen" },
|
||||
{ 0, "hf mfu otptear" },
|
||||
{ 0, "hf mfu cauth" },
|
||||
{ 0, "hf mfu setpwd" },
|
||||
{ 0, "hf mfu aesauth" },
|
||||
{ 0, "hf mfu setkey" },
|
||||
{ 0, "hf mfu dump" },
|
||||
{ 0, "hf mfu incr" },
|
||||
{ 0, "hf mfu info" },
|
||||
|
||||
+33
-26
@@ -1382,21 +1382,22 @@
|
||||
"hf 14a sim -t 10 -> ST25TA IKEA Rothult",
|
||||
"hf 14a sim -t 11 -> Javacard (JCOP)",
|
||||
"hf 14a sim -t 12 -> 4K Seos card",
|
||||
"hf 14a sim -t 13 -> MIFARE Ultralight C"
|
||||
"hf 14a sim -t 13 -> MIFARE Ultralight C",
|
||||
"hf 14a sim -t 14 -> MIFARE Ultralight AES"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-t, --type <1-12> Simulation type to use",
|
||||
"-t, --type <1-14> Simulation type to use",
|
||||
"-u, --uid <hex> <4|7|10> hex bytes UID",
|
||||
"-n, --num <dec> Exit simulation after <numreads> blocks have been read by reader. 0 = infinite",
|
||||
"-x Performs the 'reader attack', nr/ar attack against a reader",
|
||||
"--sk Fill simulator keys from found keys",
|
||||
"-v, --verbose verbose output",
|
||||
"--c1 UL-C Auth - all zero handshake part 1",
|
||||
"--c2 UL-C Auth - all zero handshake part 2"
|
||||
"--z1 ULC/ULAES Auth - all zero handshake part 1",
|
||||
"--z2 ULC/ULAES Auth - all zero handshake part 2"
|
||||
],
|
||||
"usage": "hf 14a sim [-hxv] -t <1-12> [-u <hex>] [-n <dec>] [--sk] [--c1] [--c2]"
|
||||
"usage": "hf 14a sim [-hxv] -t <1-14> [-u <hex>] [-n <dec>] [--sk] [--z1] [--z2]"
|
||||
},
|
||||
"hf 14a simaid": {
|
||||
"command": "hf 14a simaid",
|
||||
@@ -1533,9 +1534,10 @@
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help"
|
||||
"-h, --help This help",
|
||||
"-o, --old for old cards"
|
||||
],
|
||||
"usage": "hf 14b mobib [-h]"
|
||||
"usage": "hf 14b mobib [-ho]"
|
||||
},
|
||||
"hf 14b ndefread": {
|
||||
"command": "hf 14b ndefread",
|
||||
@@ -7159,9 +7161,10 @@
|
||||
"-h, --help This help",
|
||||
"--key <hex> AES key (16 hex bytes)",
|
||||
"-i, --idx <0..2> Key index (def: 0)",
|
||||
"-l Swap entered key's endianness",
|
||||
"-k Keep field on (only if a key is provided)"
|
||||
],
|
||||
"usage": "hf mfu aesauth [-hk] [--key <hex>] [-i <0..2>]"
|
||||
"usage": "hf mfu aesauth [-hlk] [--key <hex>] [-i <0..2>]"
|
||||
},
|
||||
"hf mfu amiibo": {
|
||||
"command": "hf mfu amiibo",
|
||||
@@ -7199,7 +7202,7 @@
|
||||
},
|
||||
"hf mfu dump": {
|
||||
"command": "hf mfu dump",
|
||||
"description": "Dump MIFARE Ultralight/NTAG tag to files (bin/json) It autodetects card type.Supports: Ultralight, Ultralight-C, Ultralight EV1 NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216",
|
||||
"description": "Dump MIFARE Ultralight/NTAG tag to files (bin/json) It autodetects card type.Supports: Ultralight, Ultralight C, Ultralight AES, Ultralight EV1 NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216",
|
||||
"notes": [
|
||||
"hf mfu dump -f myfile",
|
||||
"hf mfu dump -k AABBCCDD -> dump whole tag using pwd AABBCCDD",
|
||||
@@ -7211,7 +7214,7 @@
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-f, --file <fn> Specify a filename for dump file",
|
||||
"-k, --key <hex> Key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)",
|
||||
"-k, --key <hex> Key for authentication (UL-C/UL-AES 16 bytes, EV1/NTAG 4 bytes)",
|
||||
"-l Swap entered key's endianness",
|
||||
"-p, --page <dec> Manually set start page number to start from",
|
||||
"-q, --qty <dec> Manually set number of pages to dump",
|
||||
@@ -7405,7 +7408,7 @@
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-k, --key <hex> Authentication key (UL-C 16 bytes, EV1/NTAG 4 bytes)",
|
||||
"-k, --key <hex> Authentication key (UL-C/UL-AES 16 bytes, EV1/NTAG 4 bytes)",
|
||||
"-l Swap entered key's endianness",
|
||||
"-b, --block <dec> Block number to read",
|
||||
"--force Force operation even if address is out of range"
|
||||
@@ -7434,18 +7437,21 @@
|
||||
],
|
||||
"usage": "hf mfu restore [-hlservz] -f <fn> [-k <hex>]"
|
||||
},
|
||||
"hf mfu setpwd": {
|
||||
"command": "hf mfu setpwd",
|
||||
"description": "Set the 3DES key on MIFARE Ultralight-C tag.",
|
||||
"hf mfu setkey": {
|
||||
"command": "hf mfu setkey",
|
||||
"description": "Set the 3DES key on MIFARE Ultralight C tag and the AES keys on Ultralight AES. Note: AUTH0 must allow unauthenticated writes to the key blocks UL-AES: New Key index 0... DataProtKey (default) New Key index 1... UIDRetrKey",
|
||||
"notes": [
|
||||
"hf mfu setpwd --key 000102030405060708090a0b0c0d0e0f"
|
||||
"hf mfu setkey --key 49454D4B41455242214E4143554F5946",
|
||||
"hf mfu setkey --key <16 hex bytes> --idx <0..1>"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-k, --key <hex> New key (16 hex bytes)"
|
||||
"-k, --key <hex> New key (16 hex bytes)",
|
||||
"-i, --idx <0..1> New key index (def: 0), only for UL-AES",
|
||||
"-l Swap entered keys' endianness"
|
||||
],
|
||||
"usage": "hf mfu setpwd [-h] [-k <hex>]"
|
||||
"usage": "hf mfu setkey [-hl] [-k <hex>] [-i <0..1>]"
|
||||
},
|
||||
"hf mfu setuid": {
|
||||
"command": "hf mfu setuid",
|
||||
@@ -7462,24 +7468,25 @@
|
||||
},
|
||||
"hf mfu sim": {
|
||||
"command": "hf mfu sim",
|
||||
"description": "Simulate MIFARE Ultralight family type based upon ISO/IEC 14443 type A tag with 4,7 or 10 byte UID from emulator memory. See `hf mfu eload` first. The UID from emulator memory will be used if not specified. See `hf 14a sim -h` to see available types. You want 2, 7 or 13 usually.",
|
||||
"description": "Simulate MIFARE Ultralight family type based upon ISO/IEC 14443 type A tag with 4,7 or 10 byte UID from emulator memory. See `hf mfu eload` first. The UID from emulator memory will be used if not specified. See `hf 14a sim -h` to see available types. You want 2, 7, 13 or 14 usually.",
|
||||
"notes": [
|
||||
"hf mfu sim -t 2 --uid 11223344556677 -> MIFARE Ultralight",
|
||||
"hf mfu sim -t 7 --uid 11223344556677 -n 5 -> MFU EV1 / NTAG 215 Amiibo",
|
||||
"hf mfu sim -t 7 -> MFU EV1 / NTAG 215 Amiibo",
|
||||
"hf mfu sim -t 13 -> MIFARE Ultralight-C"
|
||||
"hf mfu sim -t 13 -> MIFARE Ultralight C",
|
||||
"hf mfu sim -t 14 -> MIFARE Ultralight AES"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-t, --type <1..13> Simulation type to use",
|
||||
"-t, --type <1..14> Simulation type to use",
|
||||
"-u, --uid <hex> <4|7|10> hex bytes UID",
|
||||
"-n, --num <dec> Exit simulation after <numreads> blocks. 0 = infinite",
|
||||
"-v, --verbose Verbose output",
|
||||
"--c1 UL-C Auth - all zero handshake part 1",
|
||||
"--c2 UL-C Auth - all zero handshake part 2"
|
||||
"--z1 ULC/ULAES Auth - all zero handshake part 1",
|
||||
"--z2 ULC/ULAES Auth - all zero handshake part 2"
|
||||
],
|
||||
"usage": "hf mfu sim [-hv] -t <1..13> [-u <hex>] [-n <dec>] [--c1] [--c2]"
|
||||
"usage": "hf mfu sim [-hv] -t <1..14> [-u <hex>] [-n <dec>] [--z1] [--z2]"
|
||||
},
|
||||
"hf mfu tamper": {
|
||||
"command": "hf mfu tamper",
|
||||
@@ -7517,7 +7524,7 @@
|
||||
},
|
||||
"hf mfu wipe": {
|
||||
"command": "hf mfu wipe",
|
||||
"description": "Wipe card to zeros. It will ignore block0,1,2,3 you will need to call it with password in order to wipe the config and sett default pwd/pack Abort by pressing a key New password.... FFFFFFFF New 3-DES key... 49454D4B41455242214E4143554F5946",
|
||||
"description": "Wipe card to zeros. It will ignore block0,1,2,3 you will need to call it with password in order to wipe the config and sett default pwd/pack Abort by pressing a key New password.... FFFFFFFF New 3-DES key... 49454D4B41455242214E4143554F5946 New AES keys... 00000000000000000000000000000000",
|
||||
"notes": [
|
||||
"hf mfu wipe",
|
||||
"hf mfu wipe -k 49454D4B41455242214E4143554F5946"
|
||||
@@ -7541,7 +7548,7 @@
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-k, --key <hex> Authentication key (UL-C 16 bytes, EV1/NTAG 4 bytes)",
|
||||
"-k, --key <hex> Authentication key (UL-C/UL-AES 16 bytes, EV1/NTAG 4 bytes)",
|
||||
"-l Swap entered key's endianness",
|
||||
"-b, --block <dec> Block number to write",
|
||||
"-d, --data <hex> Block data (4 or 16 hex bytes, 16 hex bytes will do a compatibility write)",
|
||||
@@ -13659,6 +13666,6 @@
|
||||
"metadata": {
|
||||
"commands_extracted": 784,
|
||||
"extracted_by": "PM3Help2JSON v1.00",
|
||||
"extracted_on": "2025-09-25T17:48:12"
|
||||
"extracted_on": "2025-10-03T23:59:38"
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -620,9 +620,9 @@ 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 setpwd `|N |`Ultralight-C - Set 3DES key`
|
||||
|`hf mfu aesauth `|N |`Ultralight-AES - Authentication`
|
||||
|`hf mfu cauth `|N |`Ultralight C - Authentication`
|
||||
|`hf mfu aesauth `|N |`Ultralight AES - Authentication`
|
||||
|`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`
|
||||
|`hf mfu info `|N |`Tag information`
|
||||
|
||||
+1
-1
@@ -751,7 +751,7 @@ typedef struct {
|
||||
// Ultralight AES
|
||||
#define CMD_HF_MIFAREULAES_AUTH 0x0725
|
||||
// 0x0726 no longer used
|
||||
#define CMD_HF_MIFAREUC_SETPWD 0x0727
|
||||
#define CMD_HF_MIFAREU_SETKEY 0x0727
|
||||
|
||||
// mifare desfire
|
||||
#define CMD_HF_DESFIRE_READBL 0x0728
|
||||
|
||||
@@ -198,7 +198,7 @@ typedef struct {
|
||||
//ultralightC
|
||||
#define CMD_HF_MIFAREUC_AUTH 0x0724
|
||||
//0x0725 and 0x0726 no longer used
|
||||
#define CMD_HF_MIFAREUC_SETPWD 0x0727
|
||||
#define CMD_HF_MIFAREU_SETKEY 0x0727
|
||||
|
||||
|
||||
// mifare desfire
|
||||
|
||||
Reference in New Issue
Block a user