diff --git a/CHANGELOG.md b/CHANGELOG.md index 76099dcf5..d1036dd33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,10 @@ 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] -- Change `hf mfu sim` deny OTP changes with all zeros (@iceman1001) +- Added `hf mfu aesauth` based on existing UL AES support (@doegox) +- Changed `hf mfu sim` deny OTP changes with all zeros (@iceman1001) - Added missing file in CMakeLists.txt (@iceman1001) -- Major update to `lf em 4x70` internals on ARM side; Enabling improved debugging and reliability (@henrygab) +- Changed `lf em 4x70` internals on ARM side; Enabling improved debugging and reliability (@henrygab) - Improved `pcf7931` generic readability of the code. Unified datatypes and added documentation/explainations (@tinooo) - Improved `lf pcf7931` read code - fixed some checks for more stability (@tinooo) - Changed `trace list -t seos` - improved annotation (@iceman1001) @@ -19,7 +20,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed `mem spiffs tree` - ID is now shown in decimal (@iceman1001) - Added sample wiegand format 56bit (@iceman1001) - Changed Wiegand formats to include number of bits (@iceman1001) -- Fix compilation warning in hitagS (@iceman1001) +- Fixed compilation warning in hitagS (@iceman1001) - Added new wiegand format H800002 (@jmichelp) - Changed `Makefile.platform.sample` file - now have clear instructions for generating images for other proxmark3 hardware (@iceman1001) - Changed `doc/magic_cards_notes.md` - now contains documentation for iKey LLC's MF4 tag (@team-orangeBlue) diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index d19233f0a..bd51e0e1c 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -483,7 +483,7 @@ int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes) { // send & receive len = mifare_sendcmd(MIFARE_ULAES_AUTH_2, enc_rnd_ab, sizeof(enc_rnd_ab), resp, sizeof(resp), respPar, NULL); if (len != 19) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x - expected 19 got " _RED_("%u"), resp[0], len); + if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd Error: %02x - expected 19 got " _RED_("%u"), resp[0], len); return 0; } @@ -492,7 +492,7 @@ int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes) { mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_DECRYPT, sizeof(random_b), IV, resp + 1, random_b); if (memcmp(random_b, random_a, 16) != 0) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("failed authentication"); + if (g_dbglevel >= DBG_INFO) Dbprintf("failed authentication"); return 0; } diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index dc6a982b4..9ef064824 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -3892,6 +3892,69 @@ static int CmdHF14AMfUCAuth(const char *Cmd) { return PM3_SUCCESS; } +//------------------------------------------------------------------------------- +// Ultralight AES Methods +//------------------------------------------------------------------------------- + +// Ultralight AES Authentication +// +static int CmdHF14AMfUAESAuth(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu aesauth", + "Tests AES key on Mifare Ultralight AES tags.\n" + "If no key is specified, null key will be tried.\n" + "Key index 0: DataProtKey (default)\n" + "Key index 1: UIDRetrKey\n" + "Key index 2: OriginalityKey\n", + "hf mfu aesauth\n" + "hf mfu aesauth --key <32 bytes> --index <0..2>" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0(NULL, "key", "", "AES key (32 hex bytes)"), + arg_int0("i", "index", "<0..2>", "Key index, default: 0"), + arg_lit0("k", NULL, "Keep field on (only if a key is provided)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int ak_len = 0; + uint8_t authentication_key[32] = {0}; + uint8_t *authKeyPtr = 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); + + CLIParserFree(ctx); + + if (ak_len == 0) { + // default to null key + ak_len = 32; + } + if (ak_len != 32) { + PrintAndLogEx(WARNING, "Invalid key length"); + return PM3_EINVARG; + } + + if (key_index < 0 || key_index > 2) { + PrintAndLogEx(WARNING, "Invalid key index"); + return PM3_EINVARG; + } + + int result = ulaes_requestAuthentication(authKeyPtr, key_index, !keep_field_on); + + const char *key_type[] = { "DataProtKey", "UIDRetrKey", "OriginalityKey" }; + if (result == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "Authentication with " _YELLOW_("%s") " " _GREEN_("%s") " ( " _GREEN_("ok")" )", + key_type[key_index], sprint_hex_inrow(authKeyPtr, ak_len)); + } else { + PrintAndLogEx(WARNING, "Authentication with " _YELLOW_("%s") " ( " _RED_("fail") " )", + key_type[key_index]); + } + return result; +} + /** A test function to validate that the polarssl-function works the same was as the openssl-implementation. @@ -5915,6 +5978,7 @@ static command_t CommandTable[] = { {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("operations") " -----------------------"}, {"cauth", CmdHF14AMfUCAuth, IfPm3Iso14443a, "Ultralight-C - Authentication"}, {"setpwd", CmdHF14AMfUCSetPwd, IfPm3Iso14443a, "Ultralight-C - Set 3DES key"}, + {"aesauth", CmdHF14AMfUAESAuth, IfPm3Iso14443a, "Ultralight-AES - Authentication"}, {"dump", CmdHF14AMfUDump, IfPm3Iso14443a, "Dump MIFARE Ultralight family tag to binary file"}, {"incr", CmdHF14AMfUIncr, IfPm3Iso14443a, "Increments Ev1/NTAG counter"}, {"info", CmdHF14AMfUInfo, IfPm3Iso14443a, "Tag information"}, diff --git a/client/src/pm3line_vocabulary.h b/client/src/pm3line_vocabulary.h index 2447b924f..b51758eae 100644 --- a/client/src/pm3line_vocabulary.h +++ b/client/src/pm3line_vocabulary.h @@ -430,6 +430,7 @@ const static vocabulary_t vocabulary[] = { { 0, "hf mfu otptear" }, { 0, "hf mfu cauth" }, { 0, "hf mfu setpwd" }, + { 0, "hf mfu aesauth" }, { 0, "hf mfu dump" }, { 0, "hf mfu incr" }, { 0, "hf mfu info" }, diff --git a/doc/commands.json b/doc/commands.json index 584caef94..f3a831927 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -7062,6 +7062,22 @@ ], "usage": "hf mfp wrp [-hv] -a [-d ]" }, + "hf mfu aesauth": { + "command": "hf mfu aesauth", + "description": "Tests AES key on Mifare Ultralight AES tags. If no key is specified, null key will be tried. Key index 0: DataProtKey (default) Key index 1: UIDRetrKey Key index 2: OriginalityKey", + "notes": [ + "hf mfu aesauth", + "hf mfu aesauth --key <32 bytes> --index <0..2>" + ], + "offline": false, + "options": [ + "-h, --help This help", + "--key AES key (32 hex bytes)", + "-i, --index <0..2> Key index, default: 0", + "-k Keep field on (only if a key is provided)" + ], + "usage": "hf mfu aesauth [-hk] [--key ] [-i <0..2>]" + }, "hf mfu amiibo": { "command": "hf mfu amiibo", "description": "Tries to read all memory from amiibo tag and decrypt it", @@ -13230,8 +13246,8 @@ } }, "metadata": { - "commands_extracted": 760, + "commands_extracted": 761, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2025-03-18T06:54:58" + "extracted_on": "2025-03-19T08:33:58" } } diff --git a/doc/commands.md b/doc/commands.md index 960e40a2b..e9f37737a 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -617,6 +617,7 @@ Check column "offline" for their availability. |`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 dump `|N |`Dump MIFARE Ultralight family tag to binary file` |`hf mfu incr `|N |`Increments Ev1/NTAG counter` |`hf mfu info `|N |`Tag information`