diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index acf079f70..f14b2d50f 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -279,6 +279,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/mifare/mifare4.c ${PM3_ROOT}/client/src/mifare/mifaredefault.c ${PM3_ROOT}/client/src/mifare/mifarehost.c + ${PM3_ROOT}/client/src/mifare/gen4.c ${PM3_ROOT}/client/src/nfc/ndef.c ${PM3_ROOT}/client/src/mifare/lrpcrypto.c ${PM3_ROOT}/client/src/mifare/desfirecrypto.c diff --git a/client/Makefile b/client/Makefile index 94ad5079b..0d4f73928 100644 --- a/client/Makefile +++ b/client/Makefile @@ -703,6 +703,7 @@ SRCS = mifare/aiddesfire.c \ mifare/mifare4.c \ mifare/mifaredefault.c \ mifare/mifarehost.c \ + mifare/gen4.c \ nfc/ndef.c \ pm3.c \ pm3_binlib.c \ diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index a3c20193d..85d24bba9 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -39,6 +39,7 @@ #include "cmdhw.h" // set_fpga_mode #include "loclass/cipherutils.h" // BitstreamOut_t #include "proxendian.h" +#include "mifare/gen4.h" static int CmdHelp(const char *Cmd); diff --git a/client/src/mifare/gen4.c b/client/src/mifare/gen4.c new file mode 100644 index 000000000..7dfff509f --- /dev/null +++ b/client/src/mifare/gen4.c @@ -0,0 +1,197 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// Common functionality for low/high-frequency GALLAGHER tag encoding & decoding. +//----------------------------------------------------------------------------- +#include "gen4.h" + +#include +#include +#include +#include + +#include "commonutil.h" +#include "util.h" +#include "ui.h" +#include "mifaredefault.h" +#include "comms.h" +#include "cmdhf14a.h" +#include "protocols.h" +#include "mfkey.h" +#include "util_posix.h" +#include "cmdparser.h" + +static int mfG4ExCommand(uint8_t cmd, uint8_t *pwd, uint8_t *data, size_t datalen, uint8_t *response, size_t *responselen, bool verbose) { + struct p { + uint8_t cmdheader; + uint8_t pwd[4]; + uint8_t command; + uint8_t data[32]; + } PACKED payload; + memset(&payload, 0, sizeof(payload)); + + if (datalen > sizeof(payload.data)) { + return PM3_EINVARG; + } + + payload.cmdheader = 0xCF; + payload.command = cmd; + if (pwd != NULL) { + memcpy(payload.pwd, pwd, sizeof(payload.pwd)); + } + if (data != NULL && datalen > 0) { + memcpy(payload.data, data, datalen); + } + + int resplen = 0; + + clearCommandBuffer(); + SendCommandOLD(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_RAW | ISO14A_NO_RATS | ISO14A_APPEND_CRC, 6 + datalen, 0, (uint8_t *)&payload, 6 + datalen); + + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + if (resp.oldarg[0] != 2) { + if (verbose) PrintAndLogEx(ERR, "No card in the field."); + return PM3_ETIMEOUT; + } + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + if (verbose) { + PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]); + PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]); + } + } else { + if (verbose) PrintAndLogEx(ERR, "No card in the field."); + return PM3_ETIMEOUT; + } + + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + resplen = resp.oldarg[0]; + + if (!resplen) { + if (verbose) PrintAndLogEx(ERR, "No card response."); + return PM3_EFAILED; + } + + resplen = resplen - 2; // 14A CRC + if (resplen < 0) + resplen = 0; + + if (resplen > 40) { + if (verbose) PrintAndLogEx(ERR, "Buffer too small(%d).", resplen); + return PM3_EOVFLOW; + } + + if (response != NULL) + memcpy(response, resp.data.asBytes, resplen); + + if (responselen != NULL) + *responselen = resplen; + + return PM3_SUCCESS; + } else { + if (verbose) PrintAndLogEx(ERR, "Reply timeout."); + return PM3_ETIMEOUT; + } +} + +int mfG4GetConfig(uint8_t *pwd, uint8_t *data, size_t *datalen, bool verbose) { + uint8_t resp[40] = {0}; + size_t resplen = 0; + + int res = mfG4ExCommand(GEN4_CMD_DUMP_CONFIG, pwd, NULL, 0, resp, &resplen, verbose); + if (res != PM3_SUCCESS) { + return res; + } + + if (data != NULL) + memcpy(data, resp, resplen); + + if (datalen != NULL) + *datalen = resplen; + + return PM3_SUCCESS; +} + +int mfG4GetFactoryTest(uint8_t *pwd, uint8_t *data, size_t *datalen, bool verbose) { + uint8_t resp[40] = {0}; + size_t resplen = 0; + + int res = mfG4ExCommand(GEN4_CMD_FACTORY_TEST, pwd, NULL, 0, resp, &resplen, verbose); + if (res != PM3_SUCCESS) { + return res; + } + + if (data != NULL) + memcpy(data, resp, resplen); + + if (datalen != NULL) + *datalen = resplen; + + return PM3_SUCCESS; +} + +int mfG4GetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data, uint8_t workFlags) { + struct p { + uint8_t blockno; + uint8_t pwd[4]; + uint8_t workFlags; + } PACKED payload; + payload.blockno = blockno; + memcpy(payload.pwd, pwd, sizeof(payload.pwd)); + payload.workFlags = workFlags; + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_G4_RDBL, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_RDBL, &resp, 1500)) { + if (resp.status != PM3_SUCCESS) { + return PM3_EUNDEF; + } + memcpy(data, resp.data.asBytes, MFBLOCK_SIZE); + } else { + PrintAndLogEx(WARNING, "command execute timeout"); + return PM3_ETIMEOUT; + } + return PM3_SUCCESS; +} + +int mfG4SetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data, uint8_t workFlags) { + struct p { + uint8_t blockno; + uint8_t pwd[4]; + uint8_t data[MFBLOCK_SIZE]; + uint8_t workFlags; + } PACKED payload; + payload.blockno = blockno; + memcpy(payload.pwd, pwd, sizeof(payload.pwd)); + memcpy(payload.data, data, sizeof(payload.data)); + payload.workFlags = workFlags; + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_G4_WRBL, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_WRBL, &resp, 1500)) { + if (resp.status != PM3_SUCCESS) { + return PM3_EUNDEF; + } + } else { + PrintAndLogEx(WARNING, "command execute timeout"); + return PM3_ETIMEOUT; + } + return PM3_SUCCESS; +} diff --git a/client/src/mifare/gen4.h b/client/src/mifare/gen4.h index 3a2ab0947..3cdc7daf1 100644 --- a/client/src/mifare/gen4.h +++ b/client/src/mifare/gen4.h @@ -18,6 +18,8 @@ #ifndef __GEN4_H #define __GEN4_H +#include "common.h" + #define GEN4_CMD_CONFIG_GTU 0x32 #define GEN4_CMD_CONFIG_ATS 0x34 #define GEN4_CMD_CONFIG_ATQA_SAK 0x35 @@ -34,4 +36,10 @@ #define GEN4_CMD_SET_CONFIG_PERMANENT 0xF1 #define GEN4_CMD_CHANGE_PASSWORD 0xFE +int mfG4GetConfig(uint8_t *pwd, uint8_t *data, size_t *datalen, bool verbose); +int mfG4GetFactoryTest(uint8_t *pwd, uint8_t *data, size_t *datalen, bool verbose); + +int mfG4GetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data, uint8_t workFlags); +int mfG4SetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data, uint8_t workFlags); + #endif diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index 7ff786832..13d925fdd 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -1175,170 +1175,6 @@ int mfGen3Freeze(void) { } } -static int mfG4ExCommand(uint8_t cmd, uint8_t *pwd, uint8_t *data, size_t datalen, uint8_t *response, size_t *responselen, bool verbose) { - struct p { - uint8_t cmdheader; - uint8_t pwd[4]; - uint8_t command; - uint8_t data[32]; - } PACKED payload; - memset(&payload, 0, sizeof(payload)); - - if (datalen > sizeof(payload.data)) { - return PM3_EINVARG; - } - - payload.cmdheader = 0xCF; - payload.command = cmd; - if (pwd != NULL) { - memcpy(payload.pwd, pwd, sizeof(payload.pwd)); - } - if (data != NULL && datalen > 0) { - memcpy(payload.data, data, datalen); - } - - int resplen = 0; - - clearCommandBuffer(); - SendCommandOLD(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_RAW | ISO14A_NO_RATS | ISO14A_APPEND_CRC, 6 + datalen, 0, (uint8_t *)&payload, 6 + datalen); - - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - if (resp.oldarg[0] != 2) { - if (verbose) PrintAndLogEx(ERR, "No card in the field."); - return PM3_ETIMEOUT; - } - - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); - if (verbose) { - PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]); - PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]); - } - } else { - if (verbose) PrintAndLogEx(ERR, "No card in the field."); - return PM3_ETIMEOUT; - } - - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - resplen = resp.oldarg[0]; - - if (!resplen) { - if (verbose) PrintAndLogEx(ERR, "No card response."); - return PM3_EFAILED; - } - - resplen = resplen - 2; // 14A CRC - if (resplen < 0) - resplen = 0; - - if (resplen > 40) { - if (verbose) PrintAndLogEx(ERR, "Buffer too small(%d).", resplen); - return PM3_EOVFLOW; - } - - if (response != NULL) - memcpy(response, resp.data.asBytes, resplen); - - if (responselen != NULL) - *responselen = resplen; - - return PM3_SUCCESS; - } else { - if (verbose) PrintAndLogEx(ERR, "Reply timeout."); - return PM3_ETIMEOUT; - } -} - -int mfG4GetConfig(uint8_t *pwd, uint8_t *data, size_t *datalen, bool verbose) { - uint8_t resp[40] = {0}; - size_t resplen = 0; - - int res = mfG4ExCommand(GEN4_CMD_DUMP_CONFIG, pwd, NULL, 0, resp, &resplen, verbose); - if (res != PM3_SUCCESS) { - return res; - } - - if (data != NULL) - memcpy(data, resp, resplen); - - if (datalen != NULL) - *datalen = resplen; - - return PM3_SUCCESS; -} - -int mfG4GetFactoryTest(uint8_t *pwd, uint8_t *data, size_t *datalen, bool verbose) { - uint8_t resp[40] = {0}; - size_t resplen = 0; - - int res = mfG4ExCommand(GEN4_CMD_FACTORY_TEST, pwd, NULL, 0, resp, &resplen, verbose); - if (res != PM3_SUCCESS) { - return res; - } - - if (data != NULL) - memcpy(data, resp, resplen); - - if (datalen != NULL) - *datalen = resplen; - - return PM3_SUCCESS; -} - -int mfG4GetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data, uint8_t workFlags) { - struct p { - uint8_t blockno; - uint8_t pwd[4]; - uint8_t workFlags; - } PACKED payload; - payload.blockno = blockno; - memcpy(payload.pwd, pwd, sizeof(payload.pwd)); - payload.workFlags = workFlags; - - clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_G4_RDBL, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_RDBL, &resp, 1500)) { - if (resp.status != PM3_SUCCESS) { - return PM3_EUNDEF; - } - memcpy(data, resp.data.asBytes, MFBLOCK_SIZE); - } else { - PrintAndLogEx(WARNING, "command execute timeout"); - return PM3_ETIMEOUT; - } - return PM3_SUCCESS; -} - -int mfG4SetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data, uint8_t workFlags) { - struct p { - uint8_t blockno; - uint8_t pwd[4]; - uint8_t data[MFBLOCK_SIZE]; - uint8_t workFlags; - } PACKED payload; - payload.blockno = blockno; - memcpy(payload.pwd, pwd, sizeof(payload.pwd)); - memcpy(payload.data, data, sizeof(payload.data)); - payload.workFlags = workFlags; - - clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_G4_WRBL, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_WRBL, &resp, 1500)) { - if (resp.status != PM3_SUCCESS) { - return PM3_EUNDEF; - } - } else { - PrintAndLogEx(WARNING, "command execute timeout"); - return PM3_ETIMEOUT; - } - return PM3_SUCCESS; -} - - // variables uint32_t cuid = 0; // uid part used for crypto1. diff --git a/client/src/mifare/mifarehost.h b/client/src/mifare/mifarehost.h index dedf7f5ea..6f131f924 100644 --- a/client/src/mifare/mifarehost.h +++ b/client/src/mifare/mifarehost.h @@ -96,12 +96,6 @@ int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid); int mfGen3Block(uint8_t *block, int blockLen, uint8_t *newBlock); int mfGen3Freeze(void); -int mfG4GetConfig(uint8_t *pwd, uint8_t *data, size_t *datalen, bool verbose); -int mfG4GetFactoryTest(uint8_t *pwd, uint8_t *data, size_t *datalen, bool verbose); - -int mfG4GetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data, uint8_t workFlags); -int mfG4SetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data, uint8_t workFlags); - int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len); int detect_classic_prng(void);