From 2eac5419f0f4bf4ddcd5e90bfed5b7e57fb720fe Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Thu, 26 Sep 2024 23:39:39 +0200 Subject: [PATCH] Add crypto1 support to hf 14a raw --- CHANGELOG.md | 9 +++++---- armsrc/iso14443a.c | 44 ++++++++++++++++++++++++++++++++++++++----- client/src/cmdhf14a.c | 19 +++++++++++++++++-- include/mifare.h | 3 ++- 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64c14dd54b..e02c7f65a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,16 +3,17 @@ 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] -- Print LUA and Python versions in `hw version` command (@jmichelp) +- Added crypto1 support to `hf 14a raw` (@doegox) +- Changed `hw version` command to print LUA and Python versions (@jmichelp) - Updated LUA to v5.4.7 which adds utf-8 support (@jmichelp) - Changed `lf search` - it now tries to read and decode paxton id (@iceman1001) - Changed `lf search` - to identify hitag2/s/82xx in chipset detection to preserve their EM4100 or other outputs (@iceman1001) - Added `lf hitag hts reader` - to act as a HitagS / 82xx reader (@iceman1001) -- Changed `lf hitag hts write` -> ´lf hitag hts wdbl` to fit rest of client command names (@iceman1001) -- Changed `lf hitag hts read` -> ´lf hitag hts rdbl` to fit rest of client command names (@iceman1001) +- Changed `lf hitag hts write` -> `lf hitag hts wdbl` to fit rest of client command names (@iceman1001) +- Changed `lf hitag hts read` -> `lf hitag hts rdbl` to fit rest of client command names (@iceman1001) - Changed `hf mf info` - Better handling when printing ATS (@iceman1001) - Changed to also try the MFC_B key when extracting memory (@iceman1001) -- Fix parallel `make -j check` Thanks @elboulangero (@iceman1001) +- Fixed parallel `make -j check` Thanks @elboulangero (@iceman1001) - Added support for 8268/8310 (@douniwan5788) - Changed scripting string params to accept 1024 chars, Thanks @evildaemond! (@iceman1001) - Added detection for FM11NT021 (@iceman1001) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 2013c99e4a..dfbefdde3f 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -159,6 +159,11 @@ iso14a_polling_parameters_t REQA_POLLING_PARAMETERS = { // parity isn't used much static uint8_t parity_array[MAX_PARITY_SIZE] = {0}; +// crypto1 stuff +static uint8_t crypto1_auth_state = AUTH_FIRST; +static uint32_t crypto1_uid; +struct Crypto1State crypto1_state = {0, 0}; + void printHf14aConfig(void) { DbpString(_CYAN_("HF 14a config")); Dbprintf(" [a] Anticol override.... %s%s%s", @@ -3151,14 +3156,14 @@ void ReaderIso14443a(PacketCommandNG *c) { iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); // notify client selecting status. - // if failed selecting, turn off antenna and quite. + // if failed selecting, turn off antenna and quit. if ((param & ISO14A_NO_SELECT) != ISO14A_NO_SELECT) { iso14a_card_select_t *card = (iso14a_card_select_t *)buf; arg0 = iso14443a_select_cardEx( NULL, card, - NULL, + &crypto1_uid, true, 0, ((param & ISO14A_NO_RATS) == ISO14A_NO_RATS), @@ -3167,6 +3172,11 @@ void ReaderIso14443a(PacketCommandNG *c) { // TODO: Improve by adding a cmd parser pointer and moving it by struct length to allow combining data with polling params FpgaDisableTracing(); + if ((param & ISO14A_CRYPTO1MODE) == ISO14A_CRYPTO1MODE) { + crypto1_auth_state = AUTH_FIRST; + crypto1_deinit(&crypto1_state); + } + reply_mix(CMD_ACK, arg0, card->uidlen, 0, buf, sizeof(iso14a_card_select_t)); if (arg0 == 0) { goto OUT; @@ -3195,7 +3205,20 @@ void ReaderIso14443a(PacketCommandNG *c) { } if ((param & ISO14A_RAW) == ISO14A_RAW) { - + if ((param & ISO14A_CRYPTO1MODE) == ISO14A_CRYPTO1MODE) { + // Intercept special Auth command 6xxxCRCA + if ((len == 10) && ((cmd[0] & 0xF0) == 0x60)) { + uint64_t ui64key = bytes_to_num((uint8_t *)&cmd[2], 6); + if (mifare_classic_authex_cmd(&crypto1_state, crypto1_uid, cmd[1], cmd[0], ui64key, crypto1_auth_state, NULL, NULL, NULL, NULL, false, false)) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Auth error"); + } else { + crypto1_auth_state = AUTH_NESTED; + if (g_dbglevel >= DBG_INFO) Dbprintf("Auth succeeded"); + } + reply_mix(CMD_ACK, 0, 0, 0, NULL, 0); + goto CMD_DONE; + } + } if ((param & ISO14A_APPEND_CRC) == ISO14A_APPEND_CRC) { // Don't append crc on empty bytearray... if (len > 0) { @@ -3213,7 +3236,10 @@ void ReaderIso14443a(PacketCommandNG *c) { } } } - + if ((param & ISO14A_CRYPTO1MODE) == ISO14A_CRYPTO1MODE) { + // Force explicit parity + lenbits = len * 8; + } // want to send a specific number of bits (e.g. short commands) if (lenbits > 0) { @@ -3232,6 +3258,9 @@ void ReaderIso14443a(PacketCommandNG *c) { } else { GetParity(cmd, lenbits / 8, parity_array); + if ((param & ISO14A_CRYPTO1MODE) == ISO14A_CRYPTO1MODE) { + mf_crypto1_encrypt(&crypto1_state, cmd, len, parity_array); + } ReaderTransmitBitsPar(cmd, lenbits, parity_array, NULL); // bytes are 8 bit with odd parity } @@ -3278,12 +3307,16 @@ void ReaderIso14443a(PacketCommandNG *c) { reply_mix(CMD_ACK, 0, 0, 0, NULL, 0); } else { arg0 = ReaderReceive(buf, sizeof(buf), parity_array); + + if ((param & ISO14A_CRYPTO1MODE) == ISO14A_CRYPTO1MODE) { + mf_crypto1_decrypt(&crypto1_state, buf, arg0); + } FpgaDisableTracing(); reply_mix(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); } } } - +CMD_DONE: if ((param & ISO14A_REQUEST_TRIGGER) == ISO14A_REQUEST_TRIGGER) iso14a_set_trigger(false); @@ -3296,6 +3329,7 @@ void ReaderIso14443a(PacketCommandNG *c) { } OUT: + crypto1_auth_state = AUTH_FIRST; hf_field_off(); set_tracing(false); } diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index a71c292e1b..0ca1e68943 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -1449,7 +1449,12 @@ static int CmdHF14ACmdRaw(const char *Cmd) { "Sends raw bytes over ISO14443a. With option to use TOPAZ 14a mode.", "hf 14a raw -sc 3000 -> select, crc, where 3000 == 'read block 00'\n" "hf 14a raw -ak -b 7 40 -> send 7 bit byte 0x40\n" - "hf 14a raw --ecp -s -> send ECP before select" + "hf 14a raw --ecp -s -> send ECP before select\n" + "Crypto1 session example, with special auth shortcut 6xxx:\n" + "hf 14a raw --crypto1 -skc 6000FFFFFFFFFFFF\n" + "hf 14a raw --crypto1 -kc 3000\n" + "hf 14a raw --crypto1 -kc 6007FFFFFFFFFFFF\n" + "hf 14a raw --crypto1 -c 3007" ); void *argtable[] = { @@ -1466,6 +1471,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) { arg_lit0(NULL, "ecp", "Use enhanced contactless polling"), arg_lit0(NULL, "mag", "Use Apple magsafe polling"), arg_lit0(NULL, "topaz", "Use Topaz protocol to send command"), + arg_lit0(NULL, "crypto1", "Use crypto1 session"), arg_strx1(NULL, NULL, "", "Raw bytes to send"), arg_param_end }; @@ -1483,10 +1489,11 @@ static int CmdHF14ACmdRaw(const char *Cmd) { bool use_ecp = arg_get_lit(ctx, 10); bool use_magsafe = arg_get_lit(ctx, 11); bool topazmode = arg_get_lit(ctx, 12); + bool crypto1mode = arg_get_lit(ctx, 13); int datalen = 0; uint8_t data[PM3_CMD_DATA_SIZE_MIX] = {0}; - CLIGetHexWithReturn(ctx, 13, data, &datalen); + CLIGetHexWithReturn(ctx, 14, data, &datalen); CLIParserFree(ctx); bool bTimeout = (timeout) ? true : false; @@ -1540,6 +1547,14 @@ static int CmdHF14ACmdRaw(const char *Cmd) { flags |= ISO14A_TOPAZMODE; } + if (crypto1mode) { + flags |= ISO14A_CRYPTO1MODE; + if (numbits > 0 || topazmode || use_ecp || use_magsafe) { + PrintAndLogEx(FAILED, "crypto1 mode cannot be used with other modes or partial bytes"); + return PM3_EINVARG; + } + } + if (no_rats) { flags |= ISO14A_NO_RATS; } diff --git a/include/mifare.h b/include/mifare.h index 02f0b49a3d..cd24a5f4f0 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -99,7 +99,8 @@ typedef enum ISO14A_COMMAND { ISO14A_SEND_CHAINING = (1 << 10), ISO14A_USE_ECP = (1 << 11), ISO14A_USE_MAGSAFE = (1 << 12), - ISO14A_USE_CUSTOM_POLLING = (1 << 13) + ISO14A_USE_CUSTOM_POLLING = (1 << 13), + ISO14A_CRYPTO1MODE = (1 << 14) } iso14a_command_t; // Defines a frame that will be used in a polling sequence