mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
Merge branch 'master' into master
Signed-off-by: Jarek Barwinski <116510448+jareckib@users.noreply.github.com>
This commit is contained in:
@@ -45,6 +45,13 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.4-dev liblua5.4-0 lua5.4 sed libssl-dev
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install setuptools
|
||||
python3 -m pip install ansicolors sslcrypto
|
||||
if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
|
||||
@@ -3,6 +3,23 @@ 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]
|
||||
- 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)
|
||||
- Added `make commands` to regenerate commands documentation files and autocompletion data independently of `make style` (@doegox)
|
||||
- Added texecom identification, thanks @en4rab ! (@iceman1001)
|
||||
- Added `hf 15 slixprotectpage` command
|
||||
- Fixed `hf mf gload` - missing parameter (@iceman1001)
|
||||
- Changed `hf mf gload` - now handles 1k ev1 sized dumps (@iceman1001)
|
||||
- Changed wiegand format unpack functions to clear struct later (@iceman1001)
|
||||
- Changed `wiegand decode` - now accepts new padding format (@iceman1001)
|
||||
- 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)
|
||||
- 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)
|
||||
- Changed `hf mf cload` - now accepts MFC Ev1 sized dumps (@iceman1001)
|
||||
- Changed `hf mfu info` - now properly identify ULEv1 AES 50pF (@iceman1001)
|
||||
- Changed `hf mf info` - now differentiates between full USCUID and cut down ZUID chips (@nvx)
|
||||
|
||||
@@ -204,6 +204,7 @@ help:
|
||||
@echo "+ fpga_compress - Make tools/fpga_compress"
|
||||
@echo
|
||||
@echo "+ style - Apply some automated source code formatting rules"
|
||||
@echo "+ commands - Regenerate commands documentation files and autocompletion data
|
||||
@echo "+ check - Run offline tests. Set CHECKARGS to pass arguments to the test script"
|
||||
@echo "+ .../check - Run offline tests against specific target. See above."
|
||||
@echo "+ miscchecks - Detect various encoding issues in source code"
|
||||
@@ -303,7 +304,7 @@ endif
|
||||
# easy printing of MAKE VARIABLES
|
||||
print-%: ; @echo $* = $($*)
|
||||
|
||||
style:
|
||||
style: commands
|
||||
# Make sure astyle is installed
|
||||
@command -v astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 )
|
||||
# Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, *.cpp. *.lua, *.py, *.pl, Makefile, *.v, pm3
|
||||
@@ -317,13 +318,14 @@ style:
|
||||
--keep-one-line-blocks --max-continuation-indent=60 \
|
||||
--style=google --pad-oper --unpad-paren --pad-header \
|
||||
--align-pointer=name {} \;
|
||||
|
||||
commands:
|
||||
# Update commands.md
|
||||
[ -x client/proxmark3 ] && client/proxmark3 -m | tr -d '\r' > doc/commands.md
|
||||
# Make sure python3 is installed
|
||||
@command -v python3 >/dev/null || ( echo "Please install 'python3' package first" ; exit 1 )
|
||||
# Update commands.json, patch port in case it was run under Windows
|
||||
[ -x client/proxmark3 ] && client/proxmark3 --fulltext | sed 's#com[0-9]#/dev/ttyACM0#'|python3 client/pyscripts/pm3_help2json.py - - | tr -d '\r' > doc/commands.json
|
||||
|
||||
# Update the readline autocomplete autogenerated code
|
||||
[ -x client/proxmark3 ] && client/proxmark3 --fulltext | python3 client/pyscripts/pm3_help2list.py - - | tr -d '\r' > client/src/pm3line_vocabulary.h
|
||||
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
# If you want to use it, copy this file as Makefile.platform and adjust it to your needs
|
||||
# Run 'make PLATFORM=' to get an exhaustive list of possible parameters for this file.
|
||||
|
||||
# By default PM3 RDV4 image is generated.
|
||||
# Comment the line below and uncomment further down according to which device you have
|
||||
PLATFORM=PM3RDV4
|
||||
|
||||
# For PM3 Easy:
|
||||
# uncomment the line below
|
||||
#PLATFORM=PM3GENERIC
|
||||
|
||||
# For ICOPY-X and PM3 Max:
|
||||
# uncomment the two lines below
|
||||
#PLATFORM=PM3ICOPY3
|
||||
#PLATFORM_EXTRAS=FLASH
|
||||
|
||||
|
||||
# If you want more than one PLATFORM_EXTRAS option, separate them by spaces:
|
||||
#PLATFORM_EXTRAS=BTADDON
|
||||
#PLATFORM_EXTRAS=FLASH
|
||||
@@ -10,6 +22,7 @@ PLATFORM=PM3RDV4
|
||||
#PLATFORM_EXTRAS=BTADDON FLASH
|
||||
#STANDALONE=LF_SAMYRUN
|
||||
|
||||
|
||||
# Uncomment the line below to set the correct LED order on board Proxmark3 Easy
|
||||
# Only available with PLATFORM=PM3GENERIC
|
||||
#LED_ORDER=PM3EASY
|
||||
|
||||
+4
-2
@@ -321,9 +321,10 @@ bool RAMFUNC LogTraceBits(const uint8_t *btBytes, uint16_t bitLen, uint32_t time
|
||||
// Emulator memory
|
||||
int emlSet(const uint8_t *data, uint32_t offset, uint32_t length) {
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
if (!mem) {
|
||||
if (mem == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
if (offset + length <= CARD_MEMORY_SIZE) {
|
||||
memcpy(mem + offset, data, length);
|
||||
return PM3_SUCCESS;
|
||||
@@ -335,9 +336,10 @@ int emlSet(const uint8_t *data, uint32_t offset, uint32_t length) {
|
||||
|
||||
int emlGet(uint8_t *out, uint32_t offset, uint32_t length) {
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
if (!mem) {
|
||||
if (mem == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
if (offset + length <= CARD_MEMORY_SIZE) {
|
||||
memcpy(out, mem + offset, length);
|
||||
return PM3_SUCCESS;
|
||||
|
||||
@@ -311,7 +311,7 @@ void WriteTagToFlash(uint32_t uid, size_t size) {
|
||||
uint32_t len = size;
|
||||
uint8_t data[(size * (16 * 64)) / 1024];
|
||||
|
||||
emlGetMem(data, 0, (size * 64) / 1024);
|
||||
emlGetMem_xt(data, 0, (size * 64) / 1024, MIFARE_BLOCK_SIZE);
|
||||
|
||||
char dest[SPIFFS_OBJ_NAME_LEN];
|
||||
uint8_t buid[4];
|
||||
@@ -646,7 +646,7 @@ failtag:
|
||||
emlClearMem();
|
||||
uint8_t mblock[16];
|
||||
for (uint8_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
|
||||
emlGetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
|
||||
emlGetMem_xt(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1, MIFARE_BLOCK_SIZE);
|
||||
for (uint8_t t = 0; t < 2; t++) {
|
||||
memcpy(mblock + t * 10, foundKey[t][sectorNo], 6);
|
||||
}
|
||||
@@ -807,7 +807,7 @@ int e_MifareECardLoad(uint32_t numofsectors, uint8_t keytype) {
|
||||
emlSetMem_xt(dataoutbuf, FirstBlockOfSector(s) + blockNo, 1, 16);
|
||||
} else {
|
||||
// sector trailer, keep the keys, set only the AC
|
||||
emlGetMem(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1);
|
||||
emlGetMem_xt(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1, MIFARE_BLOCK_SIZE);
|
||||
memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);
|
||||
emlSetMem_xt(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1, 16);
|
||||
}
|
||||
@@ -878,7 +878,7 @@ void saMifareMakeTag(void) {
|
||||
int flags = 0;
|
||||
for (int blockNum = 0; blockNum < 16 * 4; blockNum++) {
|
||||
uint8_t mblock[16];
|
||||
emlGetMem(mblock, blockNum, 1);
|
||||
emlGetMem_xt(mblock, blockNum, 1, MIFARE_BLOCK_SIZE);
|
||||
// switch on field and send magic sequence
|
||||
if (blockNum == 0)
|
||||
flags = 0x08 + 0x02;
|
||||
|
||||
@@ -500,7 +500,7 @@ void RunMod(void) {
|
||||
uint8_t mblock[MIFARE_BLOCK_SIZE];
|
||||
for (uint8_t sectorNo = 0; sectorNo < sectorsCnt; ++sectorNo) {
|
||||
if (validKey[0][sectorNo] || validKey[1][sectorNo]) {
|
||||
emlGetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
|
||||
emlGetMem_xt(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1, MIFARE_BLOCK_SIZE);
|
||||
for (uint8_t keyType = 0; keyType < 2; ++keyType) {
|
||||
if (validKey[keyType][sectorNo]) {
|
||||
memcpy(mblock + keyType * 10, foundKey[keyType][sectorNo], 6);
|
||||
|
||||
@@ -445,7 +445,7 @@ void RunMod(void) {
|
||||
// received a RATS request
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) {
|
||||
prevCmd = 0;
|
||||
p_response = &responses[RESP_INDEX_RATS];
|
||||
p_response = &responses[RESP_INDEX_ATS];
|
||||
|
||||
} else {
|
||||
if (g_dbglevel == DBG_DEBUG) {
|
||||
|
||||
@@ -338,7 +338,7 @@ void RunMod() {
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1)
|
||||
p_response = &responses[RESP_INDEX_SAKC1];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
|
||||
p_response = &responses[RESP_INDEX_RATS];
|
||||
p_response = &responses[RESP_INDEX_ATS];
|
||||
resp = 1;
|
||||
} else if (receivedCmd[0] == 0xf2 && len == 4) { // ACKed - Time extension
|
||||
DbpString(_YELLOW_("!!") " Reader accepted time extension!");
|
||||
|
||||
@@ -247,7 +247,7 @@ void RunMod(void) {
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2)
|
||||
p_response = &responses[RESP_INDEX_SAKC2];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
|
||||
p_response = &responses[RESP_INDEX_RATS];
|
||||
p_response = &responses[RESP_INDEX_ATS];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_PPS) {
|
||||
p_response = &responses[RESP_INDEX_PPS];
|
||||
} else {
|
||||
@@ -425,7 +425,7 @@ void RunMod(void) {
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2)
|
||||
p_response = &responses[RESP_INDEX_SAKC2];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
|
||||
p_response = &responses[RESP_INDEX_RATS];
|
||||
p_response = &responses[RESP_INDEX_ATS];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_PPS) {
|
||||
p_response = &responses[RESP_INDEX_PPS];
|
||||
} else {
|
||||
|
||||
@@ -257,7 +257,7 @@ void hid_corporate_1000_calculate_checksum_and_set(uint32_t *high, uint32_t *low
|
||||
|
||||
// Calculate new high and low base value from card number and facility code, without parity
|
||||
new_low = (fc << 21) | (cardnum << 1);
|
||||
new_high = 0x28 | ((fc >> 11) & 1); // 0x28 is 101000
|
||||
new_high = (fc >> 11) & 1;
|
||||
|
||||
int n_ones;
|
||||
uint32_t i;
|
||||
@@ -319,6 +319,7 @@ void hid_corporate_1000_calculate_checksum_and_set(uint32_t *high, uint32_t *low
|
||||
new_high = new_high | 0x4;
|
||||
|
||||
// Setting new calculated values
|
||||
add_HID_preamble(0, &new_high, &new_low, 35);
|
||||
*low = new_low;
|
||||
*high = new_high;
|
||||
}
|
||||
|
||||
@@ -176,8 +176,7 @@ void hid_calculate_checksum_and_set(uint32_t *high, uint32_t *low, uint32_t card
|
||||
newlow |= oddparity32((newlow >> 1) & 0xFFF);
|
||||
newlow |= (evenparity32((newlow >> 13) & 0xFFF)) << 25;
|
||||
|
||||
newhigh |= 0x20; // Bit 37; standard header
|
||||
newlow |= 1U << 26; // leading 1: start bit
|
||||
add_HID_preamble(NULL, &newhigh, &newlow, 26);
|
||||
|
||||
*low = newlow;
|
||||
*high = newhigh;
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// LF HID ProxII Brutforce v2 by lnv42 - based on Proxbrute by Brad antoniewicz
|
||||
//
|
||||
// Following code is a trivial brute forcer for when you know the facility
|
||||
// code and want to find valid(s) card number(s). It will try all card
|
||||
// Following code is a trivial brute forcer (H10301 26-bit) when you know the
|
||||
// facility code and want to find valid(s) card number(s). It will try all card
|
||||
// fnumbers rom CARDNUM_START to CARDNUM_END one by one (max. ~65k tries).
|
||||
// This brute force will be a lot faster than Proxbrute that will try all
|
||||
// possibles values for LF low, even those with bad checksum (~4g tries).
|
||||
@@ -46,8 +46,7 @@ void RunMod(void) {
|
||||
StandAloneMode();
|
||||
Dbprintf(">> LF HID proxII bruteforce v2 a.k.a Prox2Brute Started <<");
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
|
||||
const uint32_t high = 0x20; // LF high value is always 0x20 here
|
||||
uint32_t high = 0;
|
||||
|
||||
uint32_t fac = FACILITY_CODE, cardnum = 0;
|
||||
|
||||
@@ -82,6 +81,7 @@ void RunMod(void) {
|
||||
uint32_t low = (cardnum << 1) | (fac << 17);
|
||||
low |= oddparity32((low >> 1) & 0xFFF);
|
||||
low |= evenparity32((low >> 13) & 0xFFF) << 25;
|
||||
add_HID_preamble(NULL, &high, &low, 26);
|
||||
|
||||
Dbprintf("[=] trying Facility = %08x, Card = %08x, raw = %08x%08x",
|
||||
fac, cardnum, high, low);
|
||||
|
||||
+67
-22
@@ -1370,7 +1370,11 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
// involved in dealing with emulator memory. But if it is called later, it might
|
||||
// destroy the Emulator Memory.
|
||||
//-----------------------------------------------------------------------------
|
||||
EmlClearIso15693();
|
||||
// Resetting the bitstream also frees the BigBuf memory, so we do this here to prevent
|
||||
// an inconvenient reset in the future by Iso15693InitTag
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF_15);
|
||||
BigBuf_Clear_EM();
|
||||
reply_ng(CMD_HF_ISO15693_EML_CLEAR, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_EML_SETMEM: {
|
||||
@@ -1402,7 +1406,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *buf = BigBuf_malloc(payload->length);
|
||||
uint8_t *buf = BigBuf_calloc(payload->length);
|
||||
emlGet(buf, payload->offset, payload->length);
|
||||
LED_B_ON();
|
||||
reply_ng(CMD_HF_ISO15693_EML_GETMEM, PM3_SUCCESS, buf, payload->length);
|
||||
@@ -1463,6 +1467,17 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
WritePasswordSlixIso15693(payload->old_pwd, payload->new_pwd, payload->pwd_id);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_SLIX_PROTECT_PAGE: {
|
||||
struct p {
|
||||
uint8_t read_pwd[4];
|
||||
uint8_t write_pwd[4];
|
||||
uint8_t divide_ptr;
|
||||
uint8_t prot_status;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
ProtectPageSlixIso15693(payload->read_pwd, payload->write_pwd, payload->divide_ptr, payload->prot_status);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_SLIX_DISABLE_PRIVACY: {
|
||||
struct p {
|
||||
uint8_t pwd[4];
|
||||
@@ -1677,7 +1692,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
EMVsim(payload->flags, payload->exitAfter, payload->uid, payload->atqa, payload->sak);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
case CMD_HF_ISO14443A_SIMULATE: {
|
||||
struct p {
|
||||
uint8_t tagtype;
|
||||
@@ -1696,20 +1711,21 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
uint8_t tagtype;
|
||||
uint16_t flags;
|
||||
uint8_t uid[10];
|
||||
uint8_t rats[20];
|
||||
uint8_t ats[20];
|
||||
uint8_t aid[30];
|
||||
uint8_t response[100];
|
||||
uint8_t apdu[100];
|
||||
int aid_len;
|
||||
int respond_len;
|
||||
int apdu_len;
|
||||
bool enumerate;
|
||||
uint8_t selectaid_response[100];
|
||||
uint8_t getdata_response[100];
|
||||
uint32_t ats_len;
|
||||
uint32_t aid_len;
|
||||
uint32_t selectaid_response_len;
|
||||
uint32_t getdata_response_len;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
// ## Simulate iso14443a tag - pass tag type, UID, ATS, AID, responses
|
||||
SimulateIso14443aTagAID(payload->tagtype, payload->flags, payload->uid,
|
||||
payload->rats, sizeof(payload->rats), payload->aid, payload->response,
|
||||
payload->apdu, payload->aid_len, payload->respond_len,
|
||||
payload->apdu_len, payload->enumerate); // ## Simulate iso14443a tag - pass tag type, UID, rats, aid, resp, apdu
|
||||
payload->ats, payload->ats_len, payload->aid, payload->aid_len,
|
||||
payload->selectaid_response, payload->selectaid_response_len,
|
||||
payload->getdata_response, payload->getdata_response_len);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO14443A_ANTIFUZZ: {
|
||||
@@ -1889,36 +1905,65 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_EML_MEMCLR: {
|
||||
MifareEMemClr();
|
||||
reply_ng(CMD_HF_MIFARE_EML_MEMCLR, PM3_SUCCESS, NULL, 0);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Work with emulator memory
|
||||
//
|
||||
// Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_HF) here although FPGA is not
|
||||
// involved in dealing with emulator memory. But if it is called later, it might
|
||||
// destroy the Emulator Memory.
|
||||
//-----------------------------------------------------------------------------
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
// Not only clears the emulator memory,
|
||||
// also sets default MIFARE values for sector trailers.
|
||||
emlClearMem();
|
||||
reply_ng(CMD_HF_MIFARE_EML_MEMCLR, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_EML_MEMSET: {
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
struct p {
|
||||
uint8_t blockno;
|
||||
uint16_t blockno;
|
||||
uint8_t blockcnt;
|
||||
uint8_t blockwidth;
|
||||
uint8_t data[];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
// backwards compat... default bytewidth
|
||||
if (payload->blockwidth == 0)
|
||||
payload->blockwidth = 16;
|
||||
if (payload->blockwidth == 0) {
|
||||
payload->blockwidth = MIFARE_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
emlSetMem_xt(payload->data, payload->blockno, payload->blockcnt, payload->blockwidth);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_EML_MEMGET: {
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
struct p {
|
||||
uint8_t blockno;
|
||||
uint16_t blockno;
|
||||
uint8_t blockcnt;
|
||||
uint8_t blockwidth;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
MifareEMemGet(payload->blockno, payload->blockcnt);
|
||||
|
||||
//
|
||||
size_t size = payload->blockno * payload->blockwidth;
|
||||
if (size > PM3_CMD_DATA_SIZE) {
|
||||
reply_ng(CMD_HF_MIFARE_EML_MEMGET, PM3_EMALLOC, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *buf = BigBuf_calloc(size);
|
||||
|
||||
emlGetMem_xt(buf, payload->blockno, payload->blockcnt, payload->blockwidth); // data, block num, blocks count (max 4)
|
||||
|
||||
LED_B_ON();
|
||||
reply_ng(CMD_HF_MIFARE_EML_MEMGET, PM3_SUCCESS, buf, size);
|
||||
LED_B_OFF();
|
||||
BigBuf_free_keep_EM();
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_EML_LOAD: {
|
||||
|
||||
+107
-74
@@ -133,7 +133,9 @@ void tdes_nxp_send(const void *in, void *out, size_t length, const void *key, ui
|
||||
}
|
||||
|
||||
void aes128_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[16]) {
|
||||
if (length % 8) return;
|
||||
if (length % 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *tin = (uint8_t *) in;
|
||||
uint8_t *tout = (uint8_t *) out;
|
||||
@@ -143,7 +145,9 @@ void aes128_nxp_receive(const void *in, void *out, size_t length, const void *ke
|
||||
}
|
||||
|
||||
void aes128_nxp_send(const void *in, void *out, size_t length, const void *key, unsigned char iv[16]) {
|
||||
if (length % 8) return;
|
||||
if (length % 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *tin = (uint8_t *) in;
|
||||
uint8_t *tout = (uint8_t *) out;
|
||||
@@ -152,12 +156,15 @@ void aes128_nxp_send(const void *in, void *out, size_t length, const void *key,
|
||||
mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_ENCRYPT, length, iv, tin, tout);
|
||||
}
|
||||
|
||||
void Desfire_des_key_new(const uint8_t value[8], desfirekey_t key) {
|
||||
uint8_t data[8];
|
||||
memcpy(data, value, 8);
|
||||
for (int n = 0; n < 8; n++) {
|
||||
void Desfire_des_key_new(const uint8_t *value, desfirekey_t key) {
|
||||
|
||||
uint8_t data[8] = {0};
|
||||
memcpy(data, value, sizeof(data));
|
||||
|
||||
for (size_t n = 0; n < sizeof(data); n++) {
|
||||
data[n] &= 0xFE;
|
||||
}
|
||||
|
||||
Desfire_des_key_new_with_version(data, key);
|
||||
}
|
||||
|
||||
@@ -246,22 +253,24 @@ void Desfire_key_set_version(desfirekey_t key, uint8_t version) {
|
||||
|
||||
void Desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey, desfirekey_t key) {
|
||||
|
||||
uint8_t buffer[24];
|
||||
uint8_t buffer[24] = {0};
|
||||
|
||||
switch (authkey->type) {
|
||||
case T_DES:
|
||||
case T_DES: {
|
||||
memcpy(buffer, rnda, 4);
|
||||
memcpy(buffer + 4, rndb, 4);
|
||||
Desfire_des_key_new_with_version(buffer, key);
|
||||
break;
|
||||
case T_3DES:
|
||||
}
|
||||
case T_3DES: {
|
||||
memcpy(buffer, rnda, 4);
|
||||
memcpy(buffer + 4, rndb, 4);
|
||||
memcpy(buffer + 8, rnda + 4, 4);
|
||||
memcpy(buffer + 12, rndb + 4, 4);
|
||||
Desfire_3des_key_new_with_version(buffer, key);
|
||||
break;
|
||||
case T_3K3DES:
|
||||
}
|
||||
case T_3K3DES: {
|
||||
memcpy(buffer, rnda, 4);
|
||||
memcpy(buffer + 4, rndb, 4);
|
||||
memcpy(buffer + 8, rnda + 6, 4);
|
||||
@@ -270,22 +279,15 @@ void Desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], desfire
|
||||
memcpy(buffer + 20, rndb + 12, 4);
|
||||
Desfire_3k3des_key_new(buffer, key);
|
||||
break;
|
||||
case T_AES:
|
||||
}
|
||||
case T_AES: {
|
||||
memcpy(buffer, rnda, 4);
|
||||
memcpy(buffer + 4, rndb, 4);
|
||||
memcpy(buffer + 8, rnda + 12, 4);
|
||||
memcpy(buffer + 12, rndb + 12, 4);
|
||||
Desfire_aes_key_new(buffer, key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t key_macing_length(desfirekey_t key);
|
||||
|
||||
// iceman, see memxor inside string.c, dest/src swapped..
|
||||
static void xor(const uint8_t *ivect, uint8_t *data, const size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
data[i] ^= ivect[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +308,7 @@ void cmac_generate_subkeys(desfirekey_t key) {
|
||||
// Used to compute CMAC on complete blocks
|
||||
memcpy(key->cmac_sk1, l, kbs);
|
||||
|
||||
txor = l[0] & 0x80;
|
||||
txor = (l[0] & 0x80);
|
||||
|
||||
lsl(key->cmac_sk1, kbs);
|
||||
|
||||
@@ -317,7 +319,7 @@ void cmac_generate_subkeys(desfirekey_t key) {
|
||||
// Used to compute CMAC on the last block if non-complete
|
||||
memcpy(key->cmac_sk2, key->cmac_sk1, kbs);
|
||||
|
||||
txor = key->cmac_sk1[0] & 0x80;
|
||||
txor = (key->cmac_sk1[0] & 0x80);
|
||||
|
||||
lsl(key->cmac_sk2, kbs);
|
||||
|
||||
@@ -341,15 +343,14 @@ void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t le
|
||||
while (len % kbs) {
|
||||
buffer[len++] = 0x00;
|
||||
}
|
||||
xor(key->cmac_sk2, buffer + len - kbs, kbs);
|
||||
xor(buffer + len - kbs, key->cmac_sk2, kbs);
|
||||
} else {
|
||||
xor(key->cmac_sk1, buffer + len - kbs, kbs);
|
||||
xor(buffer + len - kbs, key->cmac_sk1, kbs);
|
||||
}
|
||||
|
||||
mifare_cypher_blocks_chained(NULL, key, ivect, buffer, len, MCD_SEND, MCO_ENCYPHER);
|
||||
|
||||
memcpy(cmac, ivect, kbs);
|
||||
//free(buffer);
|
||||
}
|
||||
|
||||
size_t key_block_size(const desfirekey_t key) {
|
||||
@@ -374,7 +375,7 @@ size_t key_block_size(const desfirekey_t key) {
|
||||
/*
|
||||
* Size of MACing produced with the key.
|
||||
*/
|
||||
static size_t key_macing_length(const desfirekey_t key) {
|
||||
size_t key_macing_length(const desfirekey_t key) {
|
||||
size_t mac_length = DESFIRE_MAC_LENGTH;
|
||||
switch (key->type) {
|
||||
case T_DES:
|
||||
@@ -393,10 +394,11 @@ static size_t key_macing_length(const desfirekey_t key) {
|
||||
* Size required to store nbytes of data in a buffer of size n*block_size.
|
||||
*/
|
||||
size_t padded_data_length(const size_t nbytes, const size_t block_size) {
|
||||
if ((!nbytes) || (nbytes % block_size))
|
||||
if ((!nbytes) || (nbytes % block_size)) {
|
||||
return ((nbytes / block_size) + 1) * block_size;
|
||||
else
|
||||
} else {
|
||||
return nbytes;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -412,12 +414,14 @@ size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int c
|
||||
size_t crc_length = 0;
|
||||
if (!(communication_settings & NO_CRC)) {
|
||||
switch (DESFIRE(tag)->authentication_scheme) {
|
||||
case AS_LEGACY:
|
||||
case AS_LEGACY: {
|
||||
crc_length = 2;
|
||||
break;
|
||||
case AS_NEW:
|
||||
}
|
||||
case AS_NEW: {
|
||||
crc_length = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,18 +432,20 @@ size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int c
|
||||
|
||||
void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes, size_t offset, int communication_settings) {
|
||||
uint8_t *res = data;
|
||||
uint8_t mac[4];
|
||||
uint8_t mac[4] = {0};
|
||||
size_t edl;
|
||||
bool append_mac = true;
|
||||
desfirekey_t key = DESFIRE(tag)->session_key;
|
||||
|
||||
if (!key)
|
||||
desfirekey_t key = DESFIRE(tag)->session_key;
|
||||
if (!key) {
|
||||
return data;
|
||||
}
|
||||
|
||||
switch (communication_settings & MDCM_MASK) {
|
||||
case MDCM_PLAIN:
|
||||
if (AS_LEGACY == DESFIRE(tag)->authentication_scheme)
|
||||
case MDCM_PLAIN: {
|
||||
if (AS_LEGACY == DESFIRE(tag)->authentication_scheme) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* When using new authentication methods, PLAIN data transmission from
|
||||
@@ -452,13 +458,16 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||
*/
|
||||
|
||||
append_mac = false;
|
||||
|
||||
}
|
||||
/* pass through */
|
||||
case MDCM_MACED:
|
||||
case MDCM_MACED: {
|
||||
switch (DESFIRE(tag)->authentication_scheme) {
|
||||
case AS_LEGACY:
|
||||
if (!(communication_settings & MAC_COMMAND))
|
||||
case AS_LEGACY: {
|
||||
|
||||
if (!(communication_settings & MAC_COMMAND)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* pass through */
|
||||
edl = padded_data_length(*nbytes - offset, key_block_size(DESFIRE(tag)->session_key)) + offset;
|
||||
@@ -475,8 +484,9 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||
// Copy again provided data (was overwritten by mifare_cypher_blocks_chained)
|
||||
memcpy(res, data, *nbytes);
|
||||
|
||||
if (!(communication_settings & MAC_COMMAND))
|
||||
if (!(communication_settings & MAC_COMMAND)) {
|
||||
break;
|
||||
}
|
||||
// Append MAC
|
||||
size_t bla = maced_data_length(DESFIRE(tag)->session_key, *nbytes - offset) + offset;
|
||||
(void)bla++;
|
||||
@@ -485,9 +495,12 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||
|
||||
*nbytes += 4;
|
||||
break;
|
||||
case AS_NEW:
|
||||
if (!(communication_settings & CMAC_COMMAND))
|
||||
}
|
||||
case AS_NEW: {
|
||||
if (!(communication_settings & CMAC_COMMAND)) {
|
||||
break;
|
||||
}
|
||||
|
||||
cmac(key, DESFIRE(tag)->ivect, res, *nbytes, DESFIRE(tag)->cmac);
|
||||
|
||||
if (append_mac) {
|
||||
@@ -498,10 +511,11 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||
*nbytes += DESFIRE_CMAC_LENGTH;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case MDCM_ENCIPHERED:
|
||||
}
|
||||
case MDCM_ENCIPHERED: {
|
||||
/* |<-------------- data -------------->|
|
||||
* |<--- offset -->| |
|
||||
* +---------------+--------------------+-----+---------+
|
||||
@@ -517,8 +531,10 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||
* encypher()/decypher()
|
||||
*/
|
||||
|
||||
if (!(communication_settings & ENC_COMMAND))
|
||||
if (!(communication_settings & ENC_COMMAND)) {
|
||||
break;
|
||||
}
|
||||
|
||||
edl = enciphered_data_length(tag, *nbytes - offset, communication_settings) + offset;
|
||||
|
||||
// Fill in the crypto buffer with data ...
|
||||
@@ -526,14 +542,16 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||
if (!(communication_settings & NO_CRC)) {
|
||||
// ... CRC ...
|
||||
switch (DESFIRE(tag)->authentication_scheme) {
|
||||
case AS_LEGACY:
|
||||
case AS_LEGACY: {
|
||||
AddCrc14A(res + offset, *nbytes - offset);
|
||||
*nbytes += 2;
|
||||
break;
|
||||
case AS_NEW:
|
||||
}
|
||||
case AS_NEW: {
|
||||
crc32_append(res, *nbytes);
|
||||
*nbytes += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ... and padding
|
||||
@@ -543,32 +561,34 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||
|
||||
mifare_cypher_blocks_chained(tag, NULL, NULL, res + offset, *nbytes - offset, MCD_SEND, (AS_NEW == DESFIRE(tag)->authentication_scheme) ? MCO_ENCYPHER : MCO_DECYPHER);
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
default: {
|
||||
*nbytes = -1;
|
||||
res = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes, int communication_settings) {
|
||||
|
||||
void *res = data;
|
||||
uint8_t first_cmac_byte = 0x00;
|
||||
|
||||
desfirekey_t key = DESFIRE(tag)->session_key;
|
||||
|
||||
if (!key) {
|
||||
return data;
|
||||
}
|
||||
|
||||
// Return directly if we just have a status code.
|
||||
if (1 == *nbytes) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
desfirekey_t key = DESFIRE(tag)->session_key;
|
||||
if (!key) {
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t first_cmac_byte = 0x00;
|
||||
|
||||
switch (communication_settings & MDCM_MASK) {
|
||||
case MDCM_PLAIN: {
|
||||
|
||||
@@ -659,11 +679,12 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
break;
|
||||
}
|
||||
case MDCM_ENCIPHERED: {
|
||||
|
||||
(*nbytes)--;
|
||||
|
||||
bool verified = false;
|
||||
int crc_pos = 0x00;
|
||||
int end_crc_pos = 0x00;
|
||||
uint8_t x;
|
||||
|
||||
/*
|
||||
* AS_LEGACY:
|
||||
@@ -742,8 +763,9 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
verified = true;
|
||||
for (int n = end_crc_pos; n < *nbytes - 1; n++) {
|
||||
uint8_t byte = ((uint8_t *)res)[n];
|
||||
if (!((0x00 == byte) || ((0x80 == byte) && (n == end_crc_pos))))
|
||||
if (!((0x00 == byte) || ((0x80 == byte) && (n == end_crc_pos)))) {
|
||||
verified = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -768,7 +790,7 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
break;
|
||||
}
|
||||
case AS_NEW: {
|
||||
x = ((uint8_t *)res)[crc_pos - 1];
|
||||
uint8_t x = ((uint8_t *)res)[crc_pos - 1];
|
||||
((uint8_t *)res)[crc_pos - 1] = ((uint8_t *)res)[crc_pos];
|
||||
((uint8_t *)res)[crc_pos] = x;
|
||||
break;
|
||||
@@ -802,9 +824,10 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
|
||||
|
||||
void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size) {
|
||||
|
||||
uint8_t ovect[DESFIRE_MAX_CRYPTO_BLOCK_SIZE];
|
||||
if (direction == MCD_SEND) {
|
||||
xor(ivect, data, block_size);
|
||||
xor(data, ivect, block_size);
|
||||
} else {
|
||||
memcpy(ovect, data, block_size);
|
||||
}
|
||||
@@ -812,70 +835,80 @@ void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect,
|
||||
uint8_t edata[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||
|
||||
switch (key->type) {
|
||||
case T_DES:
|
||||
case T_DES: {
|
||||
switch (operation) {
|
||||
case MCO_ENCYPHER:
|
||||
case MCO_ENCYPHER: {
|
||||
//DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
|
||||
des_encrypt(edata, data, key->data);
|
||||
break;
|
||||
case MCO_DECYPHER:
|
||||
}
|
||||
case MCO_DECYPHER: {
|
||||
//DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
||||
des_decrypt(edata, data, key->data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case T_3DES:
|
||||
}
|
||||
case T_3DES: {
|
||||
switch (operation) {
|
||||
case MCO_ENCYPHER:
|
||||
case MCO_ENCYPHER: {
|
||||
mbedtls_des3_set2key_enc(&ctx3, key->data);
|
||||
mbedtls_des3_crypt_ecb(&ctx3, data, edata);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
|
||||
break;
|
||||
case MCO_DECYPHER:
|
||||
}
|
||||
case MCO_DECYPHER: {
|
||||
mbedtls_des3_set2key_dec(&ctx3, key->data);
|
||||
mbedtls_des3_crypt_ecb(&ctx3, data, edata);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case T_3K3DES:
|
||||
}
|
||||
case T_3K3DES: {
|
||||
switch (operation) {
|
||||
case MCO_ENCYPHER:
|
||||
case MCO_ENCYPHER: {
|
||||
mbedtls_des3_set3key_enc(&ctx3, key->data);
|
||||
mbedtls_des3_crypt_ecb(&ctx3, data, edata);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_ENCRYPT);
|
||||
break;
|
||||
case MCO_DECYPHER:
|
||||
}
|
||||
case MCO_DECYPHER: {
|
||||
mbedtls_des3_set3key_dec(&ctx3, key->data);
|
||||
mbedtls_des3_crypt_ecb(&ctx3, data, edata);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_DECRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case T_AES:
|
||||
}
|
||||
case T_AES: {
|
||||
switch (operation) {
|
||||
case MCO_ENCYPHER: {
|
||||
mbedtls_aes_init(&actx);
|
||||
mbedtls_aes_setkey_enc(&actx, key->data, 128);
|
||||
mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_ENCRYPT, sizeof(edata), ivect, data, edata);
|
||||
mbedtls_aes_crypt_ecb(&actx, MBEDTLS_AES_ENCRYPT, data, edata);
|
||||
break;
|
||||
}
|
||||
case MCO_DECYPHER: {
|
||||
mbedtls_aes_init(&actx);
|
||||
mbedtls_aes_setkey_dec(&actx, key->data, 128);
|
||||
mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_DECRYPT, sizeof(edata), ivect, edata, data);
|
||||
mbedtls_aes_crypt_ecb(&actx, MBEDTLS_AES_DECRYPT, data, edata);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(data, edata, block_size);
|
||||
@@ -883,7 +916,7 @@ void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect,
|
||||
if (direction == MCD_SEND) {
|
||||
memcpy(ivect, data, block_size);
|
||||
} else {
|
||||
xor(ivect, data, block_size);
|
||||
xor(data, ivect, block_size);
|
||||
memcpy(ivect, ovect, block_size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ void tdes_nxp_send(const void *in, void *out, size_t length, const void *key, ui
|
||||
void aes128_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[16]);
|
||||
void aes128_nxp_send(const void *in, void *out, size_t length, const void *key, unsigned char iv[16]);
|
||||
|
||||
void Desfire_des_key_new(const uint8_t value[8], desfirekey_t key);
|
||||
void Desfire_des_key_new(const uint8_t *value, desfirekey_t key);
|
||||
void Desfire_3des_key_new(const uint8_t value[16], desfirekey_t key);
|
||||
void Desfire_des_key_new_with_version(const uint8_t value[8], desfirekey_t key);
|
||||
void Desfire_3des_key_new_with_version(const uint8_t value[16], desfirekey_t key);
|
||||
@@ -207,4 +207,6 @@ size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int c
|
||||
void cmac_generate_subkeys(desfirekey_t key);
|
||||
void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac);
|
||||
|
||||
size_t key_macing_length(desfirekey_t key);
|
||||
|
||||
#endif
|
||||
|
||||
+4
-3
@@ -125,7 +125,7 @@ void ExecuteEMVSim(uint8_t *receivedCmd, uint16_t receivedCmd_len, uint8_t *rece
|
||||
Dbprintf("");
|
||||
|
||||
// use annotate to give some hints about the command
|
||||
annotate(&receivedCmd[1], receivedCmd_len-1);
|
||||
annotate(&receivedCmd[1], receivedCmd_len - 1);
|
||||
|
||||
// This is a common request from the reader which we can just immediately respond to since we know we can't
|
||||
// handle it.
|
||||
@@ -141,7 +141,7 @@ void ExecuteEMVSim(uint8_t *receivedCmd, uint16_t receivedCmd_len, uint8_t *rece
|
||||
|
||||
currentState = GENERATE_AC;
|
||||
|
||||
memcpy(receivedCmd, (unsigned char[]){ 0x03, 0x80, 0xae, 0x80, 0x00, 0x1d }, 6);
|
||||
memcpy(receivedCmd, (unsigned char[]) { 0x03, 0x80, 0xae, 0x80, 0x00, 0x1d }, 6);
|
||||
|
||||
for (int i = 0; i < 29; i++) {
|
||||
receivedCmd[6 + i] = receivedCmd[12 + i];
|
||||
@@ -240,7 +240,8 @@ void ExecuteEMVSim(uint8_t *receivedCmd, uint16_t receivedCmd_len, uint8_t *rece
|
||||
0x20, 0x00, 0x9f, 0x26, 0x08, 0x56, 0xcb, 0x4e, 0xe1, 0xa4,
|
||||
0xef, 0xac, 0x74, 0x9f, 0x27, 0x01, 0x80, 0x9f, 0x36, 0x02,
|
||||
0x00, 0x07, 0x9f, 0x6c, 0x02, 0x3e, 0x00, 0x9f, 0x6e, 0x04,
|
||||
0x20, 0x70, 0x00, 0x00, 0x90, 0x00, 0xff, 0xff};
|
||||
0x20, 0x70, 0x00, 0x00, 0x90, 0x00, 0xff, 0xff
|
||||
};
|
||||
|
||||
// do the replacement
|
||||
template[0] = responseToReader[0]; // class bit 0
|
||||
|
||||
+9
-4
@@ -821,12 +821,17 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *
|
||||
// stage 1, got UID
|
||||
if (bCrypto == false) {
|
||||
|
||||
uint64_t ui64key = key[0] |
|
||||
((uint64_t)key[1]) << 8 |
|
||||
((uint64_t)key[2]) << 16 |
|
||||
((uint64_t)key[3]) << 24 |
|
||||
((uint64_t)key[4]) << 32 |
|
||||
((uint64_t)key[5]) << 40;
|
||||
|
||||
uint32_t ui32uid = MemLeToUint4byte(rx);
|
||||
|
||||
DBG Dbprintf("hitag2_crypto: key array ");
|
||||
DBG Dbhexdump(6, key, false);
|
||||
|
||||
uint64_t ui64key = key[0] | ((uint64_t)key[1]) << 8 | ((uint64_t)key[2]) << 16 | ((uint64_t)key[3]) << 24 | ((uint64_t)key[4]) << 32 | ((uint64_t)key[5]) << 40;
|
||||
|
||||
uint32_t ui32uid = rx[0] | ((uint32_t)rx[1]) << 8 | ((uint32_t)rx[2]) << 16 | ((uint32_t)rx[3]) << 24;
|
||||
DBG Dbprintf("hitag2_crypto: key=0x%x%x uid=0x%x"
|
||||
, (uint32_t)((REV64(ui64key)) >> 32)
|
||||
, (uint32_t)((REV64(ui64key)) & 0xffffffff)
|
||||
|
||||
+16
-13
@@ -74,7 +74,7 @@ static uint8_t pwdh0, pwdl0, pwdl1; // password bytes
|
||||
static uint8_t rnd[] = {0x85, 0x44, 0x12, 0x74}; // random number
|
||||
static uint16_t timestamp_high = 0; // Timer Counter 2 overflow count, ~47min
|
||||
|
||||
#define TIMESTAMP (AT91C_BASE_TC2->TC_SR &AT91C_TC_COVFS ? timestamp_high += 1 : 0, ((timestamp_high << 16) + AT91C_BASE_TC2->TC_CV) / T0)
|
||||
#define TIMESTAMP ( (AT91C_BASE_TC2->TC_SR & AT91C_TC_COVFS) ? timestamp_high += 1 : 0, ((timestamp_high << 16) + AT91C_BASE_TC2->TC_CV) / T0)
|
||||
|
||||
//#define SENDBIT_TEST
|
||||
|
||||
@@ -538,7 +538,8 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
||||
rotate_uid++;
|
||||
*txlen = 32;
|
||||
// init crypt engine
|
||||
state = ht2_hitag2_init(REV64(tag.data.s.key), REV32(tag.data.s.uid_le), REV32(*(uint32_t *)rx));
|
||||
uint32_t le_rx = MemLeToUint4byte(rx);
|
||||
state = ht2_hitag2_init(REV64(tag.data.s.key), REV32(tag.data.s.uid_le), REV32(le_rx));
|
||||
DBG Dbhexdump(8, tx, false);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@@ -776,7 +777,9 @@ void hts_simulate(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol) {
|
||||
|
||||
if (ledcontrol) LED_B_ON();
|
||||
// Capture reader cmd start timestamp
|
||||
if (start_time == 0) start_time = TIMESTAMP - HITAG_T_LOW;
|
||||
if (start_time == 0) {
|
||||
start_time = TIMESTAMP - HITAG_T_LOW;
|
||||
}
|
||||
|
||||
// Capture reader frame
|
||||
if (rb >= HITAG_T_STOP) {
|
||||
@@ -864,9 +867,6 @@ static void hts_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint3
|
||||
uint32_t rb_i = 0, h2 = 0, h3 = 0, h4 = 0;
|
||||
uint8_t edges[160] = {0};
|
||||
|
||||
// Dbprintf("TC0_CV:%i TC1_CV:%i TC1_RB:%i TIMESTAMP:%u", AT91C_BASE_TC0->TC_CV, AT91C_BASE_TC1->TC_CV,
|
||||
// AT91C_BASE_TC1->TC_RB, TIMESTAMP);
|
||||
|
||||
// Receive tag frame, watch for at most T0*HITAG_T_PROG_MAX periods
|
||||
while (AT91C_BASE_TC0->TC_CV < (T0 * HITAG_T_PROG_MAX)) {
|
||||
|
||||
@@ -1034,8 +1034,9 @@ static int hts_send_receive(const uint8_t *tx, size_t txlen, uint8_t *rx, size_t
|
||||
DbpString("htS: response_bit:");
|
||||
Dbhexdump(*rxlen, response_bit, false);
|
||||
Dbprintf("htS: skipping %d bit SOF", sof_bits);
|
||||
|
||||
if ((rx[0] >> (8 - sof_bits)) != ((1 << sof_bits) - 1)) {
|
||||
DbpString("htS: Warning, not all bits of SOF are 1");
|
||||
DBG DbpString("htS: Warning, not all bits of SOF are 1");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1128,12 +1129,10 @@ static int hts_select_tag(const lf_hitag_data_t *packet, uint8_t *tx, size_t siz
|
||||
// if the tag is in authentication mode try the key or challenge
|
||||
if (packet->cmd == HTSF_KEY) {
|
||||
|
||||
DBG DbpString("Authenticating using key:");
|
||||
DBG Dbhexdump(6, packet->key, false);
|
||||
key_le = MemLeToUint6byte(packet->key);
|
||||
|
||||
key_le = *(uint64_t *)packet->key;
|
||||
|
||||
uint64_t state = ht2_hitag2_init(REV64(key_le), REV32(tag.data.s.uid_le), REV32(*(uint32_t *)rnd));
|
||||
uint32_t le_val = MemLeToUint4byte(rnd);
|
||||
uint64_t state = ht2_hitag2_init(REV64(key_le), REV32(tag.data.s.uid_le), REV32(le_val));
|
||||
|
||||
uint8_t auth_ks[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@@ -1144,6 +1143,8 @@ static int hts_select_tag(const lf_hitag_data_t *packet, uint8_t *tx, size_t siz
|
||||
txlen = concatbits(tx, txlen, rnd, 0, 32);
|
||||
txlen = concatbits(tx, txlen, auth_ks, 0, 32);
|
||||
|
||||
DBG DbpString("Authenticating using key:");
|
||||
DBG Dbhexdump(6, packet->key, false);
|
||||
DBG Dbprintf("%02X %02X %02X %02X %02X %02X %02X %02X", tx[0], tx[1], tx[2], tx[3], tx[4], tx[5], tx[6], tx[7]);
|
||||
|
||||
} else if (packet->cmd == HTSF_CHALLENGE) {
|
||||
@@ -1225,7 +1226,9 @@ static int hts_select_tag(const lf_hitag_data_t *packet, uint8_t *tx, size_t siz
|
||||
pwdl1 = 0;
|
||||
if (packet->cmd == HTSF_KEY) {
|
||||
|
||||
uint64_t state = ht2_hitag2_init(REV64(key_le), REV32(tag.data.s.uid_le), REV32(*(uint32_t *)rnd));
|
||||
uint32_t le_val = MemLeToUint4byte(rnd);
|
||||
uint64_t state = ht2_hitag2_init(REV64(key_le), REV32(tag.data.s.uid_le), REV32(le_val));
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ht2_hitag2_byte(&state);
|
||||
}
|
||||
|
||||
+117
-91
@@ -690,8 +690,6 @@ static RAMFUNC int ManchesterDecoding_Thinfilm(uint8_t bit) {
|
||||
if (Demod.bitCount) { // there are some remaining data bits
|
||||
Demod.shiftReg <<= (8 - Demod.bitCount); // left align the decoded bits
|
||||
Demod.output[Demod.len++] = Demod.shiftReg & 0xFF; // and add them to the output
|
||||
|
||||
// Dbprintf("A | len... %u - %u == 0x%02x", Demod.len, Demod.bitCount, Demod.output[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1077,6 +1075,7 @@ bool prepare_tag_modulation(tag_response_info_t *response_info, size_t max_buffe
|
||||
if (ts->max > max_buffer_size) {
|
||||
Dbprintf("ToSend buffer, Out-of-bound, when modulating bits for tag answer:");
|
||||
Dbhexdump(response_info->response_n, response_info->response, false);
|
||||
Dbprintf("Need %i, got %i", ts->max, max_buffer_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1108,7 +1107,7 @@ bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_
|
||||
}
|
||||
|
||||
bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
uint8_t *iRATs, size_t irats_len, tag_response_info_t **responses,
|
||||
uint8_t *ats, size_t ats_len, tag_response_info_t **responses,
|
||||
uint32_t *cuid, uint32_t counters[3], uint8_t tearings[3], uint8_t *pages) {
|
||||
uint8_t sak = 0;
|
||||
// The first response contains the ATQA (note: bytes are transmitted in reverse order).
|
||||
@@ -1130,9 +1129,9 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
// TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1
|
||||
// TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us)
|
||||
// TC(1) = 0x02: CID supported, NAD not supported
|
||||
// static uint8_t rRATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 };
|
||||
static uint8_t rRATS[40] = { 0x05, 0x75, 0x80, 0x60, 0x02, 0x00, 0x00, 0x00 };
|
||||
uint8_t rRATS_len = 8;
|
||||
// static uint8_t rATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 };
|
||||
static uint8_t rATS[40] = { 0x06, 0x75, 0x80, 0x60, 0x02, 0x00, 0x00, 0x00 };
|
||||
uint8_t rATS_len = 8;
|
||||
|
||||
// GET_VERSION response for EV1/NTAG
|
||||
static uint8_t rVERSION[10] = { 0x00 };
|
||||
@@ -1184,8 +1183,8 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
rATQA[0] = 0x44;
|
||||
rATQA[1] = 0x03;
|
||||
sak = 0x20;
|
||||
memcpy(rRATS, "\x06\x75\x77\x81\x02\x80\x00\x00", 8);
|
||||
rRATS_len = 8;
|
||||
memcpy(rATS, "\x06\x75\x77\x81\x02\x80\x00\x00", 8);
|
||||
rATS_len = 8; // including CRC
|
||||
break;
|
||||
}
|
||||
case 4: { // ISO/IEC 14443-4 - javacard (JCOP)
|
||||
@@ -1254,8 +1253,8 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
}
|
||||
case 11: { // ISO/IEC 14443-4 - javacard (JCOP) / EMV
|
||||
|
||||
memcpy(rRATS, "\x13\x78\x80\x72\x02\x80\x31\x80\x66\xb1\x84\x0c\x01\x6e\x01\x83\x00\x90\x00", 19);
|
||||
rRATS_len = 19;
|
||||
memcpy(rATS, "\x13\x78\x80\x72\x02\x80\x31\x80\x66\xb1\x84\x0c\x01\x6e\x01\x83\x00\x90\x00\x00\x00", 21);
|
||||
rATS_len = 21; // including CRC
|
||||
rATQA[0] = 0x04;
|
||||
sak = 0x20;
|
||||
break;
|
||||
@@ -1271,19 +1270,21 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
}
|
||||
}
|
||||
|
||||
// copy the iRATs if supplied.
|
||||
// iRATs is a pointer to 20 byte array
|
||||
// rRATS is a 40 byte array
|
||||
if ((flags & FLAG_RATS_IN_DATA) == FLAG_RATS_IN_DATA) {
|
||||
memcpy(rRATS, iRATs, irats_len);
|
||||
// rats len is dictated by the first char of the string, add 2 crc bytes
|
||||
rRATS_len = (iRATs[0] + 2);
|
||||
// Since its Varible length we can send value > 40 and overflow our array.
|
||||
// Even if RATS protocol defined as max 40 bytes doesn't mean people try stuff
|
||||
if (rRATS_len > sizeof(rRATS)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("[-] ERROR: iRATS overflow. Max %zu, got %zu", sizeof(rRATS), rRATS_len);
|
||||
// copy the ats if supplied.
|
||||
// ats is a pointer to 20 byte array
|
||||
// rATS is a 40 byte array
|
||||
if ((flags & FLAG_ATS_IN_DATA) == FLAG_ATS_IN_DATA) {
|
||||
// Even if RATS protocol defined as max 40 bytes doesn't mean people try stuff. Check for overflow before copy
|
||||
if (ats_len + 2 > sizeof(rATS)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("[-] ERROR: ATS overflow. Max %zu, got %zu", sizeof(rATS) - 2, ats_len);
|
||||
return false;
|
||||
}
|
||||
memcpy(rATS, ats, ats_len);
|
||||
rATS_len = ats_len + 2;
|
||||
// ATS length (without CRC) is supposed to match its first byte TL
|
||||
if (ats_len != ats[0]) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("[-] WARNING: actual ATS length (%zu) differs from its TL value (%u).", ats_len, ats[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// if uid not supplied then get from emulator memory
|
||||
@@ -1379,7 +1380,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
return false;
|
||||
}
|
||||
|
||||
AddCrc14A(rRATS, rRATS_len - 2);
|
||||
AddCrc14A(rATS, rATS_len - 2);
|
||||
|
||||
AddCrc14A(rPPS, sizeof(rPPS) - 2);
|
||||
|
||||
@@ -1407,7 +1408,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
{ .response = rSAKc1, .response_n = sizeof(rSAKc1) }, // Acknowledge select - cascade 1
|
||||
{ .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2
|
||||
{ .response = rSAKc3, .response_n = sizeof(rSAKc3) }, // Acknowledge select - cascade 3
|
||||
{ .response = rRATS, .response_n = sizeof(rRATS) }, // dummy ATS (pseudo-ATR), answer to RATS
|
||||
{ .response = rATS, .response_n = sizeof(rATS) }, // dummy ATS (pseudo-ATR), answer to RATS
|
||||
{ .response = rVERSION, .response_n = sizeof(rVERSION) }, // EV1/NTAG GET_VERSION response
|
||||
{ .response = rSIGN, .response_n = sizeof(rSIGN) }, // EV1/NTAG READ_SIG response
|
||||
{ .response = rPPS, .response_n = sizeof(rPPS) }, // PPS response
|
||||
@@ -1415,7 +1416,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
};
|
||||
|
||||
// since rats len is variable now.
|
||||
responses_init[RESP_INDEX_RATS].response_n = rRATS_len;
|
||||
responses_init[RESP_INDEX_ATS].response_n = rATS_len;
|
||||
|
||||
// "precompiled" responses.
|
||||
// These exist for speed reasons. There are no time in the anti collision phase to calculate responses.
|
||||
@@ -1428,7 +1429,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
// 85 bytes normally (rats = 8 bytes)
|
||||
// 77 bytes + ratslen,
|
||||
|
||||
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE ( ((77 + rRATS_len) * 8) + 77 + rRATS_len + 12 + 12 + 12)
|
||||
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE ( ((77 + rATS_len) * 8) + 77 + rATS_len + 12 + 12 + 12)
|
||||
|
||||
uint8_t *free_buffer = BigBuf_calloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE);
|
||||
// modulation buffer pointer and current buffer free space size
|
||||
@@ -1454,8 +1455,8 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
// response to send, and send it.
|
||||
// 'hf 14a sim'
|
||||
//-----------------------------------------------------------------------------
|
||||
void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_t exitAfterNReads,
|
||||
uint8_t *iRATs, size_t irats_len) {
|
||||
void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uint8_t exitAfterNReads,
|
||||
uint8_t *ats, size_t ats_len) {
|
||||
|
||||
#define ATTACK_KEY_COUNT 16
|
||||
|
||||
@@ -1489,7 +1490,17 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
|
||||
#define DYNAMIC_MODULATION_BUFFER_SIZE 512
|
||||
|
||||
uint8_t *dynamic_response_buffer = BigBuf_calloc(DYNAMIC_RESPONSE_BUFFER_SIZE);
|
||||
if (dynamic_response_buffer == NULL) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EMALLOC, NULL, 0);
|
||||
return;
|
||||
}
|
||||
uint8_t *dynamic_modulation_buffer = BigBuf_calloc(DYNAMIC_MODULATION_BUFFER_SIZE);
|
||||
if (dynamic_modulation_buffer == NULL) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EMALLOC, NULL, 0);
|
||||
return;
|
||||
}
|
||||
tag_response_info_t dynamic_response_info = {
|
||||
.response = dynamic_response_buffer,
|
||||
.response_n = 0,
|
||||
@@ -1497,7 +1508,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
|
||||
.modulation_n = 0
|
||||
};
|
||||
|
||||
if (SimulateIso14443aInit(tagType, flags, data, iRATs, irats_len, &responses, &cuid, counters, tearings, &pages) == false) {
|
||||
if (SimulateIso14443aInit(tagType, flags, useruid, ats, ats_len, &responses, &cuid, counters, tearings, &pages) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
return;
|
||||
@@ -1671,10 +1682,10 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
|
||||
EmSend4bit(CARD_NACK_IV);
|
||||
} else {
|
||||
// first blocks of emu are header
|
||||
uint16_t start = block * 4 + MFU_DUMP_PREFIX_LENGTH;
|
||||
uint8_t emdata[MAX_MIFARE_FRAME_SIZE];
|
||||
emlGet(emdata, start, 16);
|
||||
AddCrc14A(emdata, 16);
|
||||
uint16_t start = (block * 4) + MFU_DUMP_PREFIX_LENGTH;
|
||||
uint8_t emdata[MAX_MIFARE_FRAME_SIZE] = {0};
|
||||
emlGet(emdata, start, MIFARE_BLOCK_SIZE);
|
||||
AddCrc14A(emdata, MIFARE_BLOCK_SIZE);
|
||||
EmSendCmd(emdata, sizeof(emdata));
|
||||
numReads++; // Increment number of times reader requested a block
|
||||
|
||||
@@ -1692,8 +1703,8 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
|
||||
p_response = &responses[RESP_INDEX_UIDC1];
|
||||
} else { // all other tags (16 byte block tags)
|
||||
uint8_t emdata[MAX_MIFARE_FRAME_SIZE] = {0};
|
||||
emlGet(emdata, block, 16);
|
||||
AddCrc14A(emdata, 16);
|
||||
emlGet(emdata, block, MIFARE_BLOCK_SIZE);
|
||||
AddCrc14A(emdata, MIFARE_BLOCK_SIZE);
|
||||
EmSendCmd(emdata, sizeof(emdata));
|
||||
// We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
|
||||
p_response = NULL;
|
||||
@@ -1717,13 +1728,14 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_WRITE && len == 8 && (tagType == 2 || tagType == 7)) { // Received a WRITE
|
||||
// cmd + block + 4 bytes data + 2 bytes crc
|
||||
if (CheckCrc14A(receivedCmd, len)) {
|
||||
|
||||
uint8_t block = receivedCmd[1];
|
||||
if (block > pages) {
|
||||
// send NACK 0x0 == invalid argument
|
||||
EmSend4bit(CARD_NACK_IV);
|
||||
} else {
|
||||
// first blocks of emu are header
|
||||
emlSetMem_xt(&receivedCmd[2], block + MFU_DUMP_PREFIX_LENGTH / 4, 1, 4);
|
||||
emlSetMem_xt(&receivedCmd[2], block + (MFU_DUMP_PREFIX_LENGTH / 4), 1, 4);
|
||||
// send ACK
|
||||
EmSend4bit(CARD_ACK);
|
||||
}
|
||||
@@ -1820,7 +1832,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
|
||||
EmSend4bit(CARD_NACK_NA);
|
||||
p_response = NULL;
|
||||
} else {
|
||||
p_response = &responses[RESP_INDEX_RATS];
|
||||
p_response = &responses[RESP_INDEX_ATS];
|
||||
}
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_AUTH_1) { // ULC authentication, or Desfire Authentication
|
||||
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
|
||||
@@ -1836,7 +1848,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
|
||||
}
|
||||
|
||||
if (memcmp(pwd, "\x00\x00\x00\x00", 4) == 0) {
|
||||
Uint4byteToMemLe(pwd, ul_ev1_pwdgenB(data));
|
||||
Uint4byteToMemLe(pwd, ul_ev1_pwdgenB(useruid));
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Calc pwd... %02X %02X %02X %02X", pwd[0], pwd[1], pwd[2], pwd[3]);
|
||||
}
|
||||
|
||||
@@ -3941,9 +3953,10 @@ It can also continue after the AID has been selected, and respond to other reque
|
||||
This was forked from the original function to allow for more flexibility in the future, and to increase the processing speed of the original function.
|
||||
/// */
|
||||
|
||||
void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
uint8_t *iRATs, size_t irats_len, uint8_t *aid, uint8_t *resp,
|
||||
uint8_t *apdu, int aidLen, int respondLen, int apduLen, bool enumerate) {
|
||||
void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *uid,
|
||||
uint8_t *ats, size_t ats_len, uint8_t *aid, size_t aid_len,
|
||||
uint8_t *selectaid_response, size_t selectaid_response_len,
|
||||
uint8_t *getdata_response, size_t getdata_response_len) {
|
||||
tag_response_info_t *responses;
|
||||
uint32_t cuid = 0;
|
||||
uint32_t counters[3] = { 0x00, 0x00, 0x00 };
|
||||
@@ -3954,6 +3967,12 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
uint8_t receivedCmd[MAX_FRAME_SIZE] = { 0x00 };
|
||||
uint8_t receivedCmdPar[MAX_PARITY_SIZE] = { 0x00 };
|
||||
|
||||
// Buffers must be provided by the caller, even if lengths are 0
|
||||
// Copy the AID, AID Response, and the GetData APDU response into our variables
|
||||
if ((aid == NULL) || (selectaid_response == NULL) || (getdata_response == NULL)) {
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINVARG, NULL, 0);
|
||||
}
|
||||
|
||||
// free eventually allocated BigBuf memory but keep Emulator Memory
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
@@ -3962,7 +3981,17 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
#define DYNAMIC_MODULATION_BUFFER2_SIZE 1536
|
||||
|
||||
uint8_t *dynamic_response_buffer2 = BigBuf_calloc(DYNAMIC_RESPONSE_BUFFER2_SIZE);
|
||||
if (dynamic_response_buffer2 == NULL) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EMALLOC, NULL, 0);
|
||||
return;
|
||||
}
|
||||
uint8_t *dynamic_modulation_buffer2 = BigBuf_calloc(DYNAMIC_MODULATION_BUFFER2_SIZE);
|
||||
if (dynamic_modulation_buffer2 == NULL) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EMALLOC, NULL, 0);
|
||||
return;
|
||||
}
|
||||
tag_response_info_t dynamic_response_info = {
|
||||
.response = dynamic_response_buffer2,
|
||||
.response_n = 0,
|
||||
@@ -3970,7 +3999,7 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
.modulation_n = 0
|
||||
};
|
||||
|
||||
if (SimulateIso14443aInit(tagType, flags, data, iRATs, irats_len, &responses, &cuid, counters, tearings, &pages) == false) {
|
||||
if (SimulateIso14443aInit(tagType, flags, uid, ats, ats_len, &responses, &cuid, counters, tearings, &pages) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
return;
|
||||
@@ -3990,25 +4019,9 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
set_tracing(true);
|
||||
LED_A_ON();
|
||||
|
||||
// Filters for when this comes through
|
||||
static uint8_t aidFilter[30] = { 0x00 }; // Default AID Value
|
||||
static uint8_t aidResponse[100] = { 0x00 }; // Default AID Response
|
||||
static uint8_t apduCommand [100] = { 0x00 }; // Default APDU GetData Response
|
||||
|
||||
// Copy the AID, AID Response, and the GetData APDU response into our variables
|
||||
if (aid != 0) {
|
||||
memcpy(aidFilter, aid, aidLen);
|
||||
}
|
||||
if (resp != 0) {
|
||||
memcpy(aidResponse, resp, respondLen);
|
||||
}
|
||||
if (apdu != 0) {
|
||||
memcpy(apduCommand, apdu, apduLen);
|
||||
}
|
||||
|
||||
|
||||
// main loop
|
||||
bool finished = false;
|
||||
bool got_rats = false;
|
||||
while (finished == false) {
|
||||
// BUTTON_PRESS check done in GetIso14443aCommandFromReader
|
||||
WDT_HIT();
|
||||
@@ -4046,24 +4059,32 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { // Received a HALT
|
||||
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
|
||||
p_response = NULL;
|
||||
finished = true;
|
||||
if (got_rats) {
|
||||
finished = true;
|
||||
}
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
|
||||
p_response = &responses[RESP_INDEX_RATS];
|
||||
p_response = &responses[RESP_INDEX_ATS];
|
||||
got_rats = true;
|
||||
} else {
|
||||
// clear old dynamic responses
|
||||
dynamic_response_info.response_n = 0;
|
||||
dynamic_response_info.modulation_n = 0;
|
||||
|
||||
// Check for ISO 14443A-4 compliant commands, look at left nibble
|
||||
// Check for ISO 14443A-4 compliant commands, look at left byte (PCB)
|
||||
uint8_t offset = 0;
|
||||
switch (receivedCmd[0]) {
|
||||
case 0x0B:
|
||||
case 0x0A: { // IBlock (command CID)
|
||||
case 0x0B: // IBlock with CID
|
||||
case 0x0A:
|
||||
offset = 1;
|
||||
case 0x02: // IBlock without CID
|
||||
case 0x03: {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x00;
|
||||
|
||||
switch (receivedCmd[3]) { // APDU Class Byte
|
||||
// receivedCmd in this case is expecting to structured with a CID, then the APDU command for SelectFile
|
||||
// | IBlock (CID) | CID | APDU Command | CRC |
|
||||
switch (receivedCmd[2 + offset]) { // APDU Class Byte
|
||||
// receivedCmd in this case is expecting to structured with possibly a CID, then the APDU command for SelectFile
|
||||
// | IBlock (CID) | CID | APDU Command | CRC |
|
||||
// or | IBlock (noCID) | APDU Command | CRC |
|
||||
|
||||
case 0xA4: { // SELECT FILE
|
||||
// Select File AID uses the following format for GlobalPlatform
|
||||
@@ -4072,40 +4093,40 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
// xx in this case is len of the AID value in hex
|
||||
|
||||
// aid len is found as a hex value in receivedCmd[6] (Index Starts at 0)
|
||||
int aid_len = receivedCmd[6];
|
||||
uint8_t *received_aid = &receivedCmd[7];
|
||||
int received_aid_len = receivedCmd[5 + offset];
|
||||
uint8_t *received_aid = &receivedCmd[6 + offset];
|
||||
|
||||
// aid enumeration flag
|
||||
if (enumerate == true) {
|
||||
Dbprintf("Received AID (%d):", aid_len);
|
||||
Dbhexdump(aid_len, received_aid, false);
|
||||
if ((flags & FLAG_ENUMERATE_AID) == FLAG_ENUMERATE_AID) {
|
||||
Dbprintf("Received AID (%d):", received_aid_len);
|
||||
Dbhexdump(received_aid_len, received_aid, false);
|
||||
}
|
||||
|
||||
if (memcmp(aidFilter, received_aid, aid_len) == 0) { // Evaluate the AID sent by the Reader to the AID supplied
|
||||
if ((received_aid_len == aid_len) && (memcmp(aid, received_aid, aid_len) == 0)) { // Evaluate the AID sent by the Reader to the AID supplied
|
||||
// AID Response will be parsed here
|
||||
memcpy(dynamic_response_info.response + 2, aidResponse, respondLen + 2);
|
||||
dynamic_response_info.response_n = respondLen + 2;
|
||||
memcpy(dynamic_response_info.response + 1 + offset, selectaid_response, selectaid_response_len + 1 + offset);
|
||||
dynamic_response_info.response_n = selectaid_response_len + 2;
|
||||
} else { // Any other SELECT FILE command will return with a Not Found
|
||||
dynamic_response_info.response[2] = 0x6A;
|
||||
dynamic_response_info.response[3] = 0x82;
|
||||
dynamic_response_info.response_n = 4;
|
||||
dynamic_response_info.response[1 + offset] = 0x6A;
|
||||
dynamic_response_info.response[2 + offset] = 0x82;
|
||||
dynamic_response_info.response_n = 3 + offset;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xDA: { // PUT DATA
|
||||
// Just send them a 90 00 response
|
||||
dynamic_response_info.response[2] = 0x90;
|
||||
dynamic_response_info.response[3] = 0x00;
|
||||
dynamic_response_info.response_n = 4;
|
||||
dynamic_response_info.response[1 + offset] = 0x90;
|
||||
dynamic_response_info.response[2 + offset] = 0x00;
|
||||
dynamic_response_info.response_n = 3 + offset;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xCA: { // GET DATA
|
||||
if (sentCount == 0) {
|
||||
// APDU Command will just be parsed here
|
||||
memcpy(dynamic_response_info.response + 2, apduCommand, apduLen + 2);
|
||||
dynamic_response_info.response_n = respondLen + 2;
|
||||
memcpy(dynamic_response_info.response + 1 + offset, getdata_response, getdata_response_len + 2);
|
||||
dynamic_response_info.response_n = selectaid_response_len + 1 + offset;
|
||||
} else {
|
||||
finished = true;
|
||||
break;
|
||||
@@ -4116,18 +4137,18 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
default : {
|
||||
// Any other non-listed command
|
||||
// Respond Not Found
|
||||
dynamic_response_info.response[2] = 0x6A;
|
||||
dynamic_response_info.response[3] = 0x82;
|
||||
dynamic_response_info.response_n = 4;
|
||||
dynamic_response_info.response[1 + offset] = 0x6A;
|
||||
dynamic_response_info.response[2 + offset] = 0x82;
|
||||
dynamic_response_info.response_n = 3 + offset;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xCA:
|
||||
case 0xC2: { // Readers sends deselect command
|
||||
dynamic_response_info.response[0] = 0xCA;
|
||||
case 0xCA: // S-Block Deselect with CID
|
||||
case 0xC2: { // S-Block Deselect without CID
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x00;
|
||||
dynamic_response_info.response_n = 2;
|
||||
finished = true;
|
||||
@@ -4135,12 +4156,15 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
break;
|
||||
|
||||
default: {
|
||||
// Never seen this command before
|
||||
// Never seen this PCB before
|
||||
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("Received unknown command (len=%d):", len);
|
||||
Dbhexdump(len, receivedCmd, false);
|
||||
}
|
||||
if ((receivedCmd[0] & 0x10) == 0x10) {
|
||||
Dbprintf("Warning, reader sent a chained command but we lack support for it. Ignoring command.");
|
||||
}
|
||||
// Do not respond
|
||||
dynamic_response_info.response_n = 0;
|
||||
}
|
||||
@@ -4149,13 +4173,15 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
if (dynamic_response_info.response_n > 0) {
|
||||
|
||||
// Copy the CID from the reader query
|
||||
dynamic_response_info.response[1] = receivedCmd[1];
|
||||
if (offset > 0) {
|
||||
dynamic_response_info.response[1] = receivedCmd[1];
|
||||
}
|
||||
|
||||
// Add CRC bytes, always used in ISO 14443A-4 compliant cards
|
||||
AddCrc14A(dynamic_response_info.response, dynamic_response_info.response_n);
|
||||
dynamic_response_info.response_n += 2;
|
||||
|
||||
if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE) == false) {
|
||||
if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER2_SIZE) == false) {
|
||||
if (g_dbglevel >= DBG_DEBUG) DbpString("Error preparing tag response");
|
||||
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
|
||||
break;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user