support for Ultralight AES auth in hf mfu info/rdbl/wrbl/dump/ndefread/wipe/setkey

This commit is contained in:
Philippe Teuwen
2025-10-04 02:00:23 +02:00
parent ae6f2c1b4c
commit 4aac77aaa2
10 changed files with 473 additions and 244 deletions
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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