Add crypto1 support to hf 14a raw

This commit is contained in:
Philippe Teuwen 2024-09-26 23:39:39 +02:00
commit 2eac5419f0
4 changed files with 63 additions and 12 deletions

View file

@ -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... 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] ## [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) - 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` - 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) - 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) - 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 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 read` -> `lf hitag hts rdbl` to fit rest of client command names (@iceman1001)
- Changed `hf mf info` - Better handling when printing ATS (@iceman1001) - Changed `hf mf info` - Better handling when printing ATS (@iceman1001)
- Changed to also try the MFC_B key when extracting memory (@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) - Added support for 8268/8310 (@douniwan5788)
- Changed scripting string params to accept 1024 chars, Thanks @evildaemond! (@iceman1001) - Changed scripting string params to accept 1024 chars, Thanks @evildaemond! (@iceman1001)
- Added detection for FM11NT021 (@iceman1001) - Added detection for FM11NT021 (@iceman1001)

View file

@ -159,6 +159,11 @@ iso14a_polling_parameters_t REQA_POLLING_PARAMETERS = {
// parity isn't used much // parity isn't used much
static uint8_t parity_array[MAX_PARITY_SIZE] = {0}; 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) { void printHf14aConfig(void) {
DbpString(_CYAN_("HF 14a config")); DbpString(_CYAN_("HF 14a config"));
Dbprintf(" [a] Anticol override.... %s%s%s", Dbprintf(" [a] Anticol override.... %s%s%s",
@ -3151,14 +3156,14 @@ void ReaderIso14443a(PacketCommandNG *c) {
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// notify client selecting status. // 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) { if ((param & ISO14A_NO_SELECT) != ISO14A_NO_SELECT) {
iso14a_card_select_t *card = (iso14a_card_select_t *)buf; iso14a_card_select_t *card = (iso14a_card_select_t *)buf;
arg0 = iso14443a_select_cardEx( arg0 = iso14443a_select_cardEx(
NULL, NULL,
card, card,
NULL, &crypto1_uid,
true, true,
0, 0,
((param & ISO14A_NO_RATS) == ISO14A_NO_RATS), ((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 // TODO: Improve by adding a cmd parser pointer and moving it by struct length to allow combining data with polling params
FpgaDisableTracing(); 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)); reply_mix(CMD_ACK, arg0, card->uidlen, 0, buf, sizeof(iso14a_card_select_t));
if (arg0 == 0) { if (arg0 == 0) {
goto OUT; goto OUT;
@ -3195,7 +3205,20 @@ void ReaderIso14443a(PacketCommandNG *c) {
} }
if ((param & ISO14A_RAW) == ISO14A_RAW) { if ((param & ISO14A_RAW) == ISO14A_RAW) {
if ((param & ISO14A_CRYPTO1MODE) == ISO14A_CRYPTO1MODE) {
// Intercept special Auth command 6xxx<key>CRCA
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) { if ((param & ISO14A_APPEND_CRC) == ISO14A_APPEND_CRC) {
// Don't append crc on empty bytearray... // Don't append crc on empty bytearray...
if (len > 0) { 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) // want to send a specific number of bits (e.g. short commands)
if (lenbits > 0) { if (lenbits > 0) {
@ -3232,6 +3258,9 @@ void ReaderIso14443a(PacketCommandNG *c) {
} else { } else {
GetParity(cmd, lenbits / 8, parity_array); 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 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); reply_mix(CMD_ACK, 0, 0, 0, NULL, 0);
} else { } else {
arg0 = ReaderReceive(buf, sizeof(buf), parity_array); arg0 = ReaderReceive(buf, sizeof(buf), parity_array);
if ((param & ISO14A_CRYPTO1MODE) == ISO14A_CRYPTO1MODE) {
mf_crypto1_decrypt(&crypto1_state, buf, arg0);
}
FpgaDisableTracing(); FpgaDisableTracing();
reply_mix(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); reply_mix(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
} }
} }
} }
CMD_DONE:
if ((param & ISO14A_REQUEST_TRIGGER) == ISO14A_REQUEST_TRIGGER) if ((param & ISO14A_REQUEST_TRIGGER) == ISO14A_REQUEST_TRIGGER)
iso14a_set_trigger(false); iso14a_set_trigger(false);
@ -3296,6 +3329,7 @@ void ReaderIso14443a(PacketCommandNG *c) {
} }
OUT: OUT:
crypto1_auth_state = AUTH_FIRST;
hf_field_off(); hf_field_off();
set_tracing(false); set_tracing(false);
} }

View file

@ -1449,7 +1449,12 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
"Sends raw bytes over ISO14443a. With option to use TOPAZ 14a mode.", "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 -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 -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<key>:\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[] = { void *argtable[] = {
@ -1466,6 +1471,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
arg_lit0(NULL, "ecp", "Use enhanced contactless polling"), arg_lit0(NULL, "ecp", "Use enhanced contactless polling"),
arg_lit0(NULL, "mag", "Use Apple magsafe polling"), arg_lit0(NULL, "mag", "Use Apple magsafe polling"),
arg_lit0(NULL, "topaz", "Use Topaz protocol to send command"), arg_lit0(NULL, "topaz", "Use Topaz protocol to send command"),
arg_lit0(NULL, "crypto1", "Use crypto1 session"),
arg_strx1(NULL, NULL, "<hex>", "Raw bytes to send"), arg_strx1(NULL, NULL, "<hex>", "Raw bytes to send"),
arg_param_end arg_param_end
}; };
@ -1483,10 +1489,11 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
bool use_ecp = arg_get_lit(ctx, 10); bool use_ecp = arg_get_lit(ctx, 10);
bool use_magsafe = arg_get_lit(ctx, 11); bool use_magsafe = arg_get_lit(ctx, 11);
bool topazmode = arg_get_lit(ctx, 12); bool topazmode = arg_get_lit(ctx, 12);
bool crypto1mode = arg_get_lit(ctx, 13);
int datalen = 0; int datalen = 0;
uint8_t data[PM3_CMD_DATA_SIZE_MIX] = {0}; uint8_t data[PM3_CMD_DATA_SIZE_MIX] = {0};
CLIGetHexWithReturn(ctx, 13, data, &datalen); CLIGetHexWithReturn(ctx, 14, data, &datalen);
CLIParserFree(ctx); CLIParserFree(ctx);
bool bTimeout = (timeout) ? true : false; bool bTimeout = (timeout) ? true : false;
@ -1540,6 +1547,14 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
flags |= ISO14A_TOPAZMODE; 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) { if (no_rats) {
flags |= ISO14A_NO_RATS; flags |= ISO14A_NO_RATS;
} }

View file

@ -99,7 +99,8 @@ typedef enum ISO14A_COMMAND {
ISO14A_SEND_CHAINING = (1 << 10), ISO14A_SEND_CHAINING = (1 << 10),
ISO14A_USE_ECP = (1 << 11), ISO14A_USE_ECP = (1 << 11),
ISO14A_USE_MAGSAFE = (1 << 12), ISO14A_USE_MAGSAFE = (1 << 12),
ISO14A_USE_CUSTOM_POLLING = (1 << 13) ISO14A_USE_CUSTOM_POLLING = (1 << 13),
ISO14A_CRYPTO1MODE = (1 << 14)
} iso14a_command_t; } iso14a_command_t;
// Defines a frame that will be used in a polling sequence // Defines a frame that will be used in a polling sequence