mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 13:00:42 -07:00
Merge branch 'master' into master
Signed-off-by: Jarek Barwinski <116510448+jareckib@users.noreply.github.com>
This commit is contained in:
commit
06ff7934f3
124 changed files with 3736 additions and 2282 deletions
7
.github/workflows/codeql-analysis.yml
vendored
7
.github/workflows/codeql-analysis.yml
vendored
|
|
@ -45,6 +45,13 @@ jobs:
|
||||||
- name: Install dependencies
|
- 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
|
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
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|
|
||||||
17
CHANGELOG.md
17
CHANGELOG.md
|
|
@ -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...
|
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]
|
||||||
|
- 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 mf cload` - now accepts MFC Ev1 sized dumps (@iceman1001)
|
||||||
- Changed `hf mfu info` - now properly identify ULEv1 AES 50pF (@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)
|
- Changed `hf mf info` - now differentiates between full USCUID and cut down ZUID chips (@nvx)
|
||||||
|
|
|
||||||
6
Makefile
6
Makefile
|
|
@ -204,6 +204,7 @@ help:
|
||||||
@echo "+ fpga_compress - Make tools/fpga_compress"
|
@echo "+ fpga_compress - Make tools/fpga_compress"
|
||||||
@echo
|
@echo
|
||||||
@echo "+ style - Apply some automated source code formatting rules"
|
@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. Set CHECKARGS to pass arguments to the test script"
|
||||||
@echo "+ .../check - Run offline tests against specific target. See above."
|
@echo "+ .../check - Run offline tests against specific target. See above."
|
||||||
@echo "+ miscchecks - Detect various encoding issues in source code"
|
@echo "+ miscchecks - Detect various encoding issues in source code"
|
||||||
|
|
@ -303,7 +304,7 @@ endif
|
||||||
# easy printing of MAKE VARIABLES
|
# easy printing of MAKE VARIABLES
|
||||||
print-%: ; @echo $* = $($*)
|
print-%: ; @echo $* = $($*)
|
||||||
|
|
||||||
style:
|
style: commands
|
||||||
# Make sure astyle is installed
|
# Make sure astyle is installed
|
||||||
@command -v astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 )
|
@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
|
# 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 \
|
--keep-one-line-blocks --max-continuation-indent=60 \
|
||||||
--style=google --pad-oper --unpad-paren --pad-header \
|
--style=google --pad-oper --unpad-paren --pad-header \
|
||||||
--align-pointer=name {} \;
|
--align-pointer=name {} \;
|
||||||
|
|
||||||
|
commands:
|
||||||
# Update commands.md
|
# Update commands.md
|
||||||
[ -x client/proxmark3 ] && client/proxmark3 -m | tr -d '\r' > doc/commands.md
|
[ -x client/proxmark3 ] && client/proxmark3 -m | tr -d '\r' > doc/commands.md
|
||||||
# Make sure python3 is installed
|
# Make sure python3 is installed
|
||||||
@command -v python3 >/dev/null || ( echo "Please install 'python3' package first" ; exit 1 )
|
@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
|
# 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
|
[ -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
|
# 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
|
[ -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
|
# 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.
|
# 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
|
PLATFORM=PM3RDV4
|
||||||
|
|
||||||
|
# For PM3 Easy:
|
||||||
|
# uncomment the line below
|
||||||
#PLATFORM=PM3GENERIC
|
#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:
|
# If you want more than one PLATFORM_EXTRAS option, separate them by spaces:
|
||||||
#PLATFORM_EXTRAS=BTADDON
|
#PLATFORM_EXTRAS=BTADDON
|
||||||
#PLATFORM_EXTRAS=FLASH
|
#PLATFORM_EXTRAS=FLASH
|
||||||
|
|
@ -10,6 +22,7 @@ PLATFORM=PM3RDV4
|
||||||
#PLATFORM_EXTRAS=BTADDON FLASH
|
#PLATFORM_EXTRAS=BTADDON FLASH
|
||||||
#STANDALONE=LF_SAMYRUN
|
#STANDALONE=LF_SAMYRUN
|
||||||
|
|
||||||
|
|
||||||
# Uncomment the line below to set the correct LED order on board Proxmark3 Easy
|
# Uncomment the line below to set the correct LED order on board Proxmark3 Easy
|
||||||
# Only available with PLATFORM=PM3GENERIC
|
# Only available with PLATFORM=PM3GENERIC
|
||||||
#LED_ORDER=PM3EASY
|
#LED_ORDER=PM3EASY
|
||||||
|
|
|
||||||
|
|
@ -321,9 +321,10 @@ bool RAMFUNC LogTraceBits(const uint8_t *btBytes, uint16_t bitLen, uint32_t time
|
||||||
// Emulator memory
|
// Emulator memory
|
||||||
int emlSet(const uint8_t *data, uint32_t offset, uint32_t length) {
|
int emlSet(const uint8_t *data, uint32_t offset, uint32_t length) {
|
||||||
uint8_t *mem = BigBuf_get_EM_addr();
|
uint8_t *mem = BigBuf_get_EM_addr();
|
||||||
if (!mem) {
|
if (mem == NULL) {
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset + length <= CARD_MEMORY_SIZE) {
|
if (offset + length <= CARD_MEMORY_SIZE) {
|
||||||
memcpy(mem + offset, data, length);
|
memcpy(mem + offset, data, length);
|
||||||
return PM3_SUCCESS;
|
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) {
|
int emlGet(uint8_t *out, uint32_t offset, uint32_t length) {
|
||||||
uint8_t *mem = BigBuf_get_EM_addr();
|
uint8_t *mem = BigBuf_get_EM_addr();
|
||||||
if (!mem) {
|
if (mem == NULL) {
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset + length <= CARD_MEMORY_SIZE) {
|
if (offset + length <= CARD_MEMORY_SIZE) {
|
||||||
memcpy(out, mem + offset, length);
|
memcpy(out, mem + offset, length);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
|
|
||||||
|
|
@ -311,7 +311,7 @@ void WriteTagToFlash(uint32_t uid, size_t size) {
|
||||||
uint32_t len = size;
|
uint32_t len = size;
|
||||||
uint8_t data[(size * (16 * 64)) / 1024];
|
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];
|
char dest[SPIFFS_OBJ_NAME_LEN];
|
||||||
uint8_t buid[4];
|
uint8_t buid[4];
|
||||||
|
|
@ -646,7 +646,7 @@ failtag:
|
||||||
emlClearMem();
|
emlClearMem();
|
||||||
uint8_t mblock[16];
|
uint8_t mblock[16];
|
||||||
for (uint8_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
|
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++) {
|
for (uint8_t t = 0; t < 2; t++) {
|
||||||
memcpy(mblock + t * 10, foundKey[t][sectorNo], 6);
|
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);
|
emlSetMem_xt(dataoutbuf, FirstBlockOfSector(s) + blockNo, 1, 16);
|
||||||
} else {
|
} else {
|
||||||
// sector trailer, keep the keys, set only the AC
|
// 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);
|
memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);
|
||||||
emlSetMem_xt(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1, 16);
|
emlSetMem_xt(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1, 16);
|
||||||
}
|
}
|
||||||
|
|
@ -878,7 +878,7 @@ void saMifareMakeTag(void) {
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
for (int blockNum = 0; blockNum < 16 * 4; blockNum++) {
|
for (int blockNum = 0; blockNum < 16 * 4; blockNum++) {
|
||||||
uint8_t mblock[16];
|
uint8_t mblock[16];
|
||||||
emlGetMem(mblock, blockNum, 1);
|
emlGetMem_xt(mblock, blockNum, 1, MIFARE_BLOCK_SIZE);
|
||||||
// switch on field and send magic sequence
|
// switch on field and send magic sequence
|
||||||
if (blockNum == 0)
|
if (blockNum == 0)
|
||||||
flags = 0x08 + 0x02;
|
flags = 0x08 + 0x02;
|
||||||
|
|
|
||||||
|
|
@ -500,7 +500,7 @@ void RunMod(void) {
|
||||||
uint8_t mblock[MIFARE_BLOCK_SIZE];
|
uint8_t mblock[MIFARE_BLOCK_SIZE];
|
||||||
for (uint8_t sectorNo = 0; sectorNo < sectorsCnt; ++sectorNo) {
|
for (uint8_t sectorNo = 0; sectorNo < sectorsCnt; ++sectorNo) {
|
||||||
if (validKey[0][sectorNo] || validKey[1][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) {
|
for (uint8_t keyType = 0; keyType < 2; ++keyType) {
|
||||||
if (validKey[keyType][sectorNo]) {
|
if (validKey[keyType][sectorNo]) {
|
||||||
memcpy(mblock + keyType * 10, foundKey[keyType][sectorNo], 6);
|
memcpy(mblock + keyType * 10, foundKey[keyType][sectorNo], 6);
|
||||||
|
|
|
||||||
|
|
@ -445,7 +445,7 @@ void RunMod(void) {
|
||||||
// received a RATS request
|
// received a RATS request
|
||||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) {
|
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) {
|
||||||
prevCmd = 0;
|
prevCmd = 0;
|
||||||
p_response = &responses[RESP_INDEX_RATS];
|
p_response = &responses[RESP_INDEX_ATS];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (g_dbglevel == DBG_DEBUG) {
|
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)
|
} 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];
|
p_response = &responses[RESP_INDEX_SAKC1];
|
||||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
|
} 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;
|
resp = 1;
|
||||||
} else if (receivedCmd[0] == 0xf2 && len == 4) { // ACKed - Time extension
|
} else if (receivedCmd[0] == 0xf2 && len == 4) { // ACKed - Time extension
|
||||||
DbpString(_YELLOW_("!!") " Reader accepted 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)
|
} 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];
|
p_response = &responses[RESP_INDEX_SAKC2];
|
||||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
|
} 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) {
|
} else if (receivedCmd[0] == ISO14443A_CMD_PPS) {
|
||||||
p_response = &responses[RESP_INDEX_PPS];
|
p_response = &responses[RESP_INDEX_PPS];
|
||||||
} else {
|
} 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)
|
} 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];
|
p_response = &responses[RESP_INDEX_SAKC2];
|
||||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
|
} 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) {
|
} else if (receivedCmd[0] == ISO14443A_CMD_PPS) {
|
||||||
p_response = &responses[RESP_INDEX_PPS];
|
p_response = &responses[RESP_INDEX_PPS];
|
||||||
} else {
|
} 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
|
// Calculate new high and low base value from card number and facility code, without parity
|
||||||
new_low = (fc << 21) | (cardnum << 1);
|
new_low = (fc << 21) | (cardnum << 1);
|
||||||
new_high = 0x28 | ((fc >> 11) & 1); // 0x28 is 101000
|
new_high = (fc >> 11) & 1;
|
||||||
|
|
||||||
int n_ones;
|
int n_ones;
|
||||||
uint32_t i;
|
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;
|
new_high = new_high | 0x4;
|
||||||
|
|
||||||
// Setting new calculated values
|
// Setting new calculated values
|
||||||
|
add_HID_preamble(0, &new_high, &new_low, 35);
|
||||||
*low = new_low;
|
*low = new_low;
|
||||||
*high = new_high;
|
*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 |= oddparity32((newlow >> 1) & 0xFFF);
|
||||||
newlow |= (evenparity32((newlow >> 13) & 0xFFF)) << 25;
|
newlow |= (evenparity32((newlow >> 13) & 0xFFF)) << 25;
|
||||||
|
|
||||||
newhigh |= 0x20; // Bit 37; standard header
|
add_HID_preamble(NULL, &newhigh, &newlow, 26);
|
||||||
newlow |= 1U << 26; // leading 1: start bit
|
|
||||||
|
|
||||||
*low = newlow;
|
*low = newlow;
|
||||||
*high = newhigh;
|
*high = newhigh;
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// LF HID ProxII Brutforce v2 by lnv42 - based on Proxbrute by Brad antoniewicz
|
// 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
|
// Following code is a trivial brute forcer (H10301 26-bit) when you know the
|
||||||
// code and want to find valid(s) card number(s). It will try all card
|
// 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).
|
// 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
|
// 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).
|
// possibles values for LF low, even those with bad checksum (~4g tries).
|
||||||
|
|
@ -46,8 +46,7 @@ void RunMod(void) {
|
||||||
StandAloneMode();
|
StandAloneMode();
|
||||||
Dbprintf(">> LF HID proxII bruteforce v2 a.k.a Prox2Brute Started <<");
|
Dbprintf(">> LF HID proxII bruteforce v2 a.k.a Prox2Brute Started <<");
|
||||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||||
|
uint32_t high = 0;
|
||||||
const uint32_t high = 0x20; // LF high value is always 0x20 here
|
|
||||||
|
|
||||||
uint32_t fac = FACILITY_CODE, cardnum = 0;
|
uint32_t fac = FACILITY_CODE, cardnum = 0;
|
||||||
|
|
||||||
|
|
@ -82,6 +81,7 @@ void RunMod(void) {
|
||||||
uint32_t low = (cardnum << 1) | (fac << 17);
|
uint32_t low = (cardnum << 1) | (fac << 17);
|
||||||
low |= oddparity32((low >> 1) & 0xFFF);
|
low |= oddparity32((low >> 1) & 0xFFF);
|
||||||
low |= evenparity32((low >> 13) & 0xFFF) << 25;
|
low |= evenparity32((low >> 13) & 0xFFF) << 25;
|
||||||
|
add_HID_preamble(NULL, &high, &low, 26);
|
||||||
|
|
||||||
Dbprintf("[=] trying Facility = %08x, Card = %08x, raw = %08x%08x",
|
Dbprintf("[=] trying Facility = %08x, Card = %08x, raw = %08x%08x",
|
||||||
fac, cardnum, high, low);
|
fac, cardnum, high, low);
|
||||||
|
|
|
||||||
|
|
@ -1370,7 +1370,11 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
// involved in dealing with emulator memory. But if it is called later, it might
|
// involved in dealing with emulator memory. But if it is called later, it might
|
||||||
// destroy the Emulator Memory.
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_HF_ISO15693_EML_SETMEM: {
|
case CMD_HF_ISO15693_EML_SETMEM: {
|
||||||
|
|
@ -1402,7 +1406,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *buf = BigBuf_malloc(payload->length);
|
uint8_t *buf = BigBuf_calloc(payload->length);
|
||||||
emlGet(buf, payload->offset, payload->length);
|
emlGet(buf, payload->offset, payload->length);
|
||||||
LED_B_ON();
|
LED_B_ON();
|
||||||
reply_ng(CMD_HF_ISO15693_EML_GETMEM, PM3_SUCCESS, buf, payload->length);
|
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);
|
WritePasswordSlixIso15693(payload->old_pwd, payload->new_pwd, payload->pwd_id);
|
||||||
break;
|
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: {
|
case CMD_HF_ISO15693_SLIX_DISABLE_PRIVACY: {
|
||||||
struct p {
|
struct p {
|
||||||
uint8_t pwd[4];
|
uint8_t pwd[4];
|
||||||
|
|
@ -1696,20 +1711,21 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
uint8_t tagtype;
|
uint8_t tagtype;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
uint8_t uid[10];
|
uint8_t uid[10];
|
||||||
uint8_t rats[20];
|
uint8_t ats[20];
|
||||||
uint8_t aid[30];
|
uint8_t aid[30];
|
||||||
uint8_t response[100];
|
uint8_t selectaid_response[100];
|
||||||
uint8_t apdu[100];
|
uint8_t getdata_response[100];
|
||||||
int aid_len;
|
uint32_t ats_len;
|
||||||
int respond_len;
|
uint32_t aid_len;
|
||||||
int apdu_len;
|
uint32_t selectaid_response_len;
|
||||||
bool enumerate;
|
uint32_t getdata_response_len;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
struct p *payload = (struct p *) packet->data.asBytes;
|
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,
|
SimulateIso14443aTagAID(payload->tagtype, payload->flags, payload->uid,
|
||||||
payload->rats, sizeof(payload->rats), payload->aid, payload->response,
|
payload->ats, payload->ats_len, payload->aid, payload->aid_len,
|
||||||
payload->apdu, payload->aid_len, payload->respond_len,
|
payload->selectaid_response, payload->selectaid_response_len,
|
||||||
payload->apdu_len, payload->enumerate); // ## Simulate iso14443a tag - pass tag type, UID, rats, aid, resp, apdu
|
payload->getdata_response, payload->getdata_response_len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_HF_ISO14443A_ANTIFUZZ: {
|
case CMD_HF_ISO14443A_ANTIFUZZ: {
|
||||||
|
|
@ -1889,36 +1905,65 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_HF_MIFARE_EML_MEMCLR: {
|
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);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_HF_MIFARE_EML_MEMSET: {
|
case CMD_HF_MIFARE_EML_MEMSET: {
|
||||||
|
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||||
struct p {
|
struct p {
|
||||||
uint8_t blockno;
|
uint16_t blockno;
|
||||||
uint8_t blockcnt;
|
uint8_t blockcnt;
|
||||||
uint8_t blockwidth;
|
uint8_t blockwidth;
|
||||||
uint8_t data[];
|
uint8_t data[];
|
||||||
} PACKED;
|
} PACKED;
|
||||||
struct p *payload = (struct p *) packet->data.asBytes;
|
struct p *payload = (struct p *) packet->data.asBytes;
|
||||||
|
|
||||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
|
||||||
|
|
||||||
// backwards compat... default bytewidth
|
// backwards compat... default bytewidth
|
||||||
if (payload->blockwidth == 0)
|
if (payload->blockwidth == 0) {
|
||||||
payload->blockwidth = 16;
|
payload->blockwidth = MIFARE_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
emlSetMem_xt(payload->data, payload->blockno, payload->blockcnt, payload->blockwidth);
|
emlSetMem_xt(payload->data, payload->blockno, payload->blockcnt, payload->blockwidth);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_HF_MIFARE_EML_MEMGET: {
|
case CMD_HF_MIFARE_EML_MEMGET: {
|
||||||
|
|
||||||
|
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||||
struct p {
|
struct p {
|
||||||
uint8_t blockno;
|
uint16_t blockno;
|
||||||
uint8_t blockcnt;
|
uint8_t blockcnt;
|
||||||
|
uint8_t blockwidth;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
struct p *payload = (struct p *) packet->data.asBytes;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_HF_MIFARE_EML_LOAD: {
|
case CMD_HF_MIFARE_EML_LOAD: {
|
||||||
|
|
|
||||||
|
|
@ -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]) {
|
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 *tin = (uint8_t *) in;
|
||||||
uint8_t *tout = (uint8_t *) out;
|
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]) {
|
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 *tin = (uint8_t *) in;
|
||||||
uint8_t *tout = (uint8_t *) out;
|
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);
|
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) {
|
void Desfire_des_key_new(const uint8_t *value, desfirekey_t key) {
|
||||||
uint8_t data[8];
|
|
||||||
memcpy(data, value, 8);
|
uint8_t data[8] = {0};
|
||||||
for (int n = 0; n < 8; n++) {
|
memcpy(data, value, sizeof(data));
|
||||||
|
|
||||||
|
for (size_t n = 0; n < sizeof(data); n++) {
|
||||||
data[n] &= 0xFE;
|
data[n] &= 0xFE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Desfire_des_key_new_with_version(data, key);
|
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) {
|
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) {
|
switch (authkey->type) {
|
||||||
case T_DES:
|
case T_DES: {
|
||||||
memcpy(buffer, rnda, 4);
|
memcpy(buffer, rnda, 4);
|
||||||
memcpy(buffer + 4, rndb, 4);
|
memcpy(buffer + 4, rndb, 4);
|
||||||
Desfire_des_key_new_with_version(buffer, key);
|
Desfire_des_key_new_with_version(buffer, key);
|
||||||
break;
|
break;
|
||||||
case T_3DES:
|
}
|
||||||
|
case T_3DES: {
|
||||||
memcpy(buffer, rnda, 4);
|
memcpy(buffer, rnda, 4);
|
||||||
memcpy(buffer + 4, rndb, 4);
|
memcpy(buffer + 4, rndb, 4);
|
||||||
memcpy(buffer + 8, rnda + 4, 4);
|
memcpy(buffer + 8, rnda + 4, 4);
|
||||||
memcpy(buffer + 12, rndb + 4, 4);
|
memcpy(buffer + 12, rndb + 4, 4);
|
||||||
Desfire_3des_key_new_with_version(buffer, key);
|
Desfire_3des_key_new_with_version(buffer, key);
|
||||||
break;
|
break;
|
||||||
case T_3K3DES:
|
}
|
||||||
|
case T_3K3DES: {
|
||||||
memcpy(buffer, rnda, 4);
|
memcpy(buffer, rnda, 4);
|
||||||
memcpy(buffer + 4, rndb, 4);
|
memcpy(buffer + 4, rndb, 4);
|
||||||
memcpy(buffer + 8, rnda + 6, 4);
|
memcpy(buffer + 8, rnda + 6, 4);
|
||||||
|
|
@ -270,7 +279,8 @@ void Desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], desfire
|
||||||
memcpy(buffer + 20, rndb + 12, 4);
|
memcpy(buffer + 20, rndb + 12, 4);
|
||||||
Desfire_3k3des_key_new(buffer, key);
|
Desfire_3k3des_key_new(buffer, key);
|
||||||
break;
|
break;
|
||||||
case T_AES:
|
}
|
||||||
|
case T_AES: {
|
||||||
memcpy(buffer, rnda, 4);
|
memcpy(buffer, rnda, 4);
|
||||||
memcpy(buffer + 4, rndb, 4);
|
memcpy(buffer + 4, rndb, 4);
|
||||||
memcpy(buffer + 8, rnda + 12, 4);
|
memcpy(buffer + 8, rnda + 12, 4);
|
||||||
|
|
@ -278,14 +288,6 @@ void Desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], desfire
|
||||||
Desfire_aes_key_new(buffer, key);
|
Desfire_aes_key_new(buffer, key);
|
||||||
break;
|
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
|
// Used to compute CMAC on complete blocks
|
||||||
memcpy(key->cmac_sk1, l, kbs);
|
memcpy(key->cmac_sk1, l, kbs);
|
||||||
|
|
||||||
txor = l[0] & 0x80;
|
txor = (l[0] & 0x80);
|
||||||
|
|
||||||
lsl(key->cmac_sk1, kbs);
|
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
|
// Used to compute CMAC on the last block if non-complete
|
||||||
memcpy(key->cmac_sk2, key->cmac_sk1, kbs);
|
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);
|
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) {
|
while (len % kbs) {
|
||||||
buffer[len++] = 0x00;
|
buffer[len++] = 0x00;
|
||||||
}
|
}
|
||||||
xor(key->cmac_sk2, buffer + len - kbs, kbs);
|
xor(buffer + len - kbs, key->cmac_sk2, kbs);
|
||||||
} else {
|
} 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);
|
mifare_cypher_blocks_chained(NULL, key, ivect, buffer, len, MCD_SEND, MCO_ENCYPHER);
|
||||||
|
|
||||||
memcpy(cmac, ivect, kbs);
|
memcpy(cmac, ivect, kbs);
|
||||||
//free(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t key_block_size(const desfirekey_t key) {
|
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.
|
* 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;
|
size_t mac_length = DESFIRE_MAC_LENGTH;
|
||||||
switch (key->type) {
|
switch (key->type) {
|
||||||
case T_DES:
|
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 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) {
|
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;
|
return ((nbytes / block_size) + 1) * block_size;
|
||||||
else
|
} else {
|
||||||
return nbytes;
|
return nbytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -412,14 +414,16 @@ size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int c
|
||||||
size_t crc_length = 0;
|
size_t crc_length = 0;
|
||||||
if (!(communication_settings & NO_CRC)) {
|
if (!(communication_settings & NO_CRC)) {
|
||||||
switch (DESFIRE(tag)->authentication_scheme) {
|
switch (DESFIRE(tag)->authentication_scheme) {
|
||||||
case AS_LEGACY:
|
case AS_LEGACY: {
|
||||||
crc_length = 2;
|
crc_length = 2;
|
||||||
break;
|
break;
|
||||||
case AS_NEW:
|
}
|
||||||
|
case AS_NEW: {
|
||||||
crc_length = 4;
|
crc_length = 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t block_size = DESFIRE(tag)->session_key ? key_block_size(DESFIRE(tag)->session_key) : 1;
|
size_t block_size = DESFIRE(tag)->session_key ? key_block_size(DESFIRE(tag)->session_key) : 1;
|
||||||
|
|
||||||
|
|
@ -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) {
|
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 *res = data;
|
||||||
uint8_t mac[4];
|
uint8_t mac[4] = {0};
|
||||||
size_t edl;
|
size_t edl;
|
||||||
bool append_mac = true;
|
bool append_mac = true;
|
||||||
desfirekey_t key = DESFIRE(tag)->session_key;
|
|
||||||
|
|
||||||
if (!key)
|
desfirekey_t key = DESFIRE(tag)->session_key;
|
||||||
|
if (!key) {
|
||||||
return data;
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
switch (communication_settings & MDCM_MASK) {
|
switch (communication_settings & MDCM_MASK) {
|
||||||
case MDCM_PLAIN:
|
case MDCM_PLAIN: {
|
||||||
if (AS_LEGACY == DESFIRE(tag)->authentication_scheme)
|
if (AS_LEGACY == DESFIRE(tag)->authentication_scheme) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When using new authentication methods, PLAIN data transmission from
|
* 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;
|
append_mac = false;
|
||||||
|
}
|
||||||
/* pass through */
|
/* pass through */
|
||||||
case MDCM_MACED:
|
case MDCM_MACED: {
|
||||||
switch (DESFIRE(tag)->authentication_scheme) {
|
switch (DESFIRE(tag)->authentication_scheme) {
|
||||||
case AS_LEGACY:
|
case AS_LEGACY: {
|
||||||
if (!(communication_settings & MAC_COMMAND))
|
|
||||||
|
if (!(communication_settings & MAC_COMMAND)) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* pass through */
|
/* pass through */
|
||||||
edl = padded_data_length(*nbytes - offset, key_block_size(DESFIRE(tag)->session_key)) + offset;
|
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)
|
// Copy again provided data (was overwritten by mifare_cypher_blocks_chained)
|
||||||
memcpy(res, data, *nbytes);
|
memcpy(res, data, *nbytes);
|
||||||
|
|
||||||
if (!(communication_settings & MAC_COMMAND))
|
if (!(communication_settings & MAC_COMMAND)) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
// Append MAC
|
// Append MAC
|
||||||
size_t bla = maced_data_length(DESFIRE(tag)->session_key, *nbytes - offset) + offset;
|
size_t bla = maced_data_length(DESFIRE(tag)->session_key, *nbytes - offset) + offset;
|
||||||
(void)bla++;
|
(void)bla++;
|
||||||
|
|
@ -485,9 +495,12 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||||
|
|
||||||
*nbytes += 4;
|
*nbytes += 4;
|
||||||
break;
|
break;
|
||||||
case AS_NEW:
|
}
|
||||||
if (!(communication_settings & CMAC_COMMAND))
|
case AS_NEW: {
|
||||||
|
if (!(communication_settings & CMAC_COMMAND)) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
cmac(key, DESFIRE(tag)->ivect, res, *nbytes, DESFIRE(tag)->cmac);
|
cmac(key, DESFIRE(tag)->ivect, res, *nbytes, DESFIRE(tag)->cmac);
|
||||||
|
|
||||||
if (append_mac) {
|
if (append_mac) {
|
||||||
|
|
@ -499,9 +512,10 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case MDCM_ENCIPHERED:
|
}
|
||||||
|
case MDCM_ENCIPHERED: {
|
||||||
/* |<-------------- data -------------->|
|
/* |<-------------- data -------------->|
|
||||||
* |<--- offset -->| |
|
* |<--- offset -->| |
|
||||||
* +---------------+--------------------+-----+---------+
|
* +---------------+--------------------+-----+---------+
|
||||||
|
|
@ -517,8 +531,10 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||||
* encypher()/decypher()
|
* encypher()/decypher()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!(communication_settings & ENC_COMMAND))
|
if (!(communication_settings & ENC_COMMAND)) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
edl = enciphered_data_length(tag, *nbytes - offset, communication_settings) + offset;
|
edl = enciphered_data_length(tag, *nbytes - offset, communication_settings) + offset;
|
||||||
|
|
||||||
// Fill in the crypto buffer with data ...
|
// Fill in the crypto buffer with data ...
|
||||||
|
|
@ -526,16 +542,18 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||||
if (!(communication_settings & NO_CRC)) {
|
if (!(communication_settings & NO_CRC)) {
|
||||||
// ... CRC ...
|
// ... CRC ...
|
||||||
switch (DESFIRE(tag)->authentication_scheme) {
|
switch (DESFIRE(tag)->authentication_scheme) {
|
||||||
case AS_LEGACY:
|
case AS_LEGACY: {
|
||||||
AddCrc14A(res + offset, *nbytes - offset);
|
AddCrc14A(res + offset, *nbytes - offset);
|
||||||
*nbytes += 2;
|
*nbytes += 2;
|
||||||
break;
|
break;
|
||||||
case AS_NEW:
|
}
|
||||||
|
case AS_NEW: {
|
||||||
crc32_append(res, *nbytes);
|
crc32_append(res, *nbytes);
|
||||||
*nbytes += 4;
|
*nbytes += 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// ... and padding
|
// ... and padding
|
||||||
memset(res + *nbytes, 0, edl - *nbytes);
|
memset(res + *nbytes, 0, edl - *nbytes);
|
||||||
|
|
||||||
|
|
@ -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);
|
mifare_cypher_blocks_chained(tag, NULL, NULL, res + offset, *nbytes - offset, MCD_SEND, (AS_NEW == DESFIRE(tag)->authentication_scheme) ? MCO_ENCYPHER : MCO_DECYPHER);
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
*nbytes = -1;
|
*nbytes = -1;
|
||||||
res = NULL;
|
res = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes, int communication_settings) {
|
void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes, int communication_settings) {
|
||||||
|
|
||||||
void *res = data;
|
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.
|
// Return directly if we just have a status code.
|
||||||
if (1 == *nbytes) {
|
if (1 == *nbytes) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
desfirekey_t key = DESFIRE(tag)->session_key;
|
||||||
|
if (!key) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t first_cmac_byte = 0x00;
|
||||||
|
|
||||||
switch (communication_settings & MDCM_MASK) {
|
switch (communication_settings & MDCM_MASK) {
|
||||||
case MDCM_PLAIN: {
|
case MDCM_PLAIN: {
|
||||||
|
|
||||||
|
|
@ -659,11 +679,12 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MDCM_ENCIPHERED: {
|
case MDCM_ENCIPHERED: {
|
||||||
|
|
||||||
(*nbytes)--;
|
(*nbytes)--;
|
||||||
|
|
||||||
bool verified = false;
|
bool verified = false;
|
||||||
int crc_pos = 0x00;
|
int crc_pos = 0x00;
|
||||||
int end_crc_pos = 0x00;
|
int end_crc_pos = 0x00;
|
||||||
uint8_t x;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AS_LEGACY:
|
* AS_LEGACY:
|
||||||
|
|
@ -742,10 +763,11 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||||
verified = true;
|
verified = true;
|
||||||
for (int n = end_crc_pos; n < *nbytes - 1; n++) {
|
for (int n = end_crc_pos; n < *nbytes - 1; n++) {
|
||||||
uint8_t byte = ((uint8_t *)res)[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;
|
verified = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (verified) {
|
if (verified) {
|
||||||
|
|
||||||
|
|
@ -768,7 +790,7 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AS_NEW: {
|
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 - 1] = ((uint8_t *)res)[crc_pos];
|
||||||
((uint8_t *)res)[crc_pos] = x;
|
((uint8_t *)res)[crc_pos] = x;
|
||||||
break;
|
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) {
|
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];
|
uint8_t ovect[DESFIRE_MAX_CRYPTO_BLOCK_SIZE];
|
||||||
if (direction == MCD_SEND) {
|
if (direction == MCD_SEND) {
|
||||||
xor(ivect, data, block_size);
|
xor(data, ivect, block_size);
|
||||||
} else {
|
} else {
|
||||||
memcpy(ovect, data, block_size);
|
memcpy(ovect, data, block_size);
|
||||||
}
|
}
|
||||||
|
|
@ -812,28 +835,32 @@ void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect,
|
||||||
uint8_t edata[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
uint8_t edata[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||||
|
|
||||||
switch (key->type) {
|
switch (key->type) {
|
||||||
case T_DES:
|
case T_DES: {
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case MCO_ENCYPHER:
|
case MCO_ENCYPHER: {
|
||||||
//DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
|
//DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
|
||||||
des_encrypt(edata, data, key->data);
|
des_encrypt(edata, data, key->data);
|
||||||
break;
|
break;
|
||||||
case MCO_DECYPHER:
|
}
|
||||||
|
case MCO_DECYPHER: {
|
||||||
//DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
//DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
||||||
des_decrypt(edata, data, key->data);
|
des_decrypt(edata, data, key->data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case T_3DES:
|
}
|
||||||
|
case T_3DES: {
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case MCO_ENCYPHER:
|
case MCO_ENCYPHER: {
|
||||||
mbedtls_des3_set2key_enc(&ctx3, key->data);
|
mbedtls_des3_set2key_enc(&ctx3, key->data);
|
||||||
mbedtls_des3_crypt_ecb(&ctx3, data, edata);
|
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 *) 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 *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT);
|
||||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
|
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
|
||||||
break;
|
break;
|
||||||
case MCO_DECYPHER:
|
}
|
||||||
|
case MCO_DECYPHER: {
|
||||||
mbedtls_des3_set2key_dec(&ctx3, key->data);
|
mbedtls_des3_set2key_dec(&ctx3, key->data);
|
||||||
mbedtls_des3_crypt_ecb(&ctx3, data, edata);
|
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 *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
||||||
|
|
@ -841,17 +868,20 @@ void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect,
|
||||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case T_3K3DES:
|
}
|
||||||
|
case T_3K3DES: {
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case MCO_ENCYPHER:
|
case MCO_ENCYPHER: {
|
||||||
mbedtls_des3_set3key_enc(&ctx3, key->data);
|
mbedtls_des3_set3key_enc(&ctx3, key->data);
|
||||||
mbedtls_des3_crypt_ecb(&ctx3, data, edata);
|
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 *) 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 *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT);
|
||||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_ENCRYPT);
|
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_ENCRYPT);
|
||||||
break;
|
break;
|
||||||
case MCO_DECYPHER:
|
}
|
||||||
|
case MCO_DECYPHER: {
|
||||||
mbedtls_des3_set3key_dec(&ctx3, key->data);
|
mbedtls_des3_set3key_dec(&ctx3, key->data);
|
||||||
mbedtls_des3_crypt_ecb(&ctx3, data, edata);
|
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 *) data, (DES_cblock *) edata, &(key->ks3), DES_DECRYPT);
|
||||||
|
|
@ -859,31 +889,34 @@ void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect,
|
||||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case T_AES:
|
}
|
||||||
|
case T_AES: {
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case MCO_ENCYPHER: {
|
case MCO_ENCYPHER: {
|
||||||
mbedtls_aes_init(&actx);
|
mbedtls_aes_init(&actx);
|
||||||
mbedtls_aes_setkey_enc(&actx, key->data, 128);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case MCO_DECYPHER: {
|
case MCO_DECYPHER: {
|
||||||
mbedtls_aes_init(&actx);
|
mbedtls_aes_init(&actx);
|
||||||
mbedtls_aes_setkey_dec(&actx, key->data, 128);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(data, edata, block_size);
|
memcpy(data, edata, block_size);
|
||||||
|
|
||||||
if (direction == MCD_SEND) {
|
if (direction == MCD_SEND) {
|
||||||
memcpy(ivect, data, block_size);
|
memcpy(ivect, data, block_size);
|
||||||
} else {
|
} else {
|
||||||
xor(ivect, data, block_size);
|
xor(data, ivect, block_size);
|
||||||
memcpy(ivect, ovect, 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_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 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_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_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);
|
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_generate_subkeys(desfirekey_t key);
|
||||||
void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac);
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ void ExecuteEMVSim(uint8_t *receivedCmd, uint16_t receivedCmd_len, uint8_t *rece
|
||||||
Dbprintf("");
|
Dbprintf("");
|
||||||
|
|
||||||
// use annotate to give some hints about the command
|
// 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
|
// This is a common request from the reader which we can just immediately respond to since we know we can't
|
||||||
// handle it.
|
// handle it.
|
||||||
|
|
@ -141,7 +141,7 @@ void ExecuteEMVSim(uint8_t *receivedCmd, uint16_t receivedCmd_len, uint8_t *rece
|
||||||
|
|
||||||
currentState = GENERATE_AC;
|
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++) {
|
for (int i = 0; i < 29; i++) {
|
||||||
receivedCmd[6 + i] = receivedCmd[12 + 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,
|
0x20, 0x00, 0x9f, 0x26, 0x08, 0x56, 0xcb, 0x4e, 0xe1, 0xa4,
|
||||||
0xef, 0xac, 0x74, 0x9f, 0x27, 0x01, 0x80, 0x9f, 0x36, 0x02,
|
0xef, 0xac, 0x74, 0x9f, 0x27, 0x01, 0x80, 0x9f, 0x36, 0x02,
|
||||||
0x00, 0x07, 0x9f, 0x6c, 0x02, 0x3e, 0x00, 0x9f, 0x6e, 0x04,
|
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
|
// do the replacement
|
||||||
template[0] = responseToReader[0]; // class bit 0
|
template[0] = responseToReader[0]; // class bit 0
|
||||||
|
|
|
||||||
|
|
@ -821,12 +821,17 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *
|
||||||
// stage 1, got UID
|
// stage 1, got UID
|
||||||
if (bCrypto == false) {
|
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 Dbprintf("hitag2_crypto: key array ");
|
||||||
DBG Dbhexdump(6, key, false);
|
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"
|
DBG Dbprintf("hitag2_crypto: key=0x%x%x uid=0x%x"
|
||||||
, (uint32_t)((REV64(ui64key)) >> 32)
|
, (uint32_t)((REV64(ui64key)) >> 32)
|
||||||
, (uint32_t)((REV64(ui64key)) & 0xffffffff)
|
, (uint32_t)((REV64(ui64key)) & 0xffffffff)
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ static uint8_t pwdh0, pwdl0, pwdl1; // password bytes
|
||||||
static uint8_t rnd[] = {0x85, 0x44, 0x12, 0x74}; // random number
|
static uint8_t rnd[] = {0x85, 0x44, 0x12, 0x74}; // random number
|
||||||
static uint16_t timestamp_high = 0; // Timer Counter 2 overflow count, ~47min
|
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
|
//#define SENDBIT_TEST
|
||||||
|
|
||||||
|
|
@ -538,7 +538,8 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
||||||
rotate_uid++;
|
rotate_uid++;
|
||||||
*txlen = 32;
|
*txlen = 32;
|
||||||
// init crypt engine
|
// 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);
|
DBG Dbhexdump(8, tx, false);
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
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();
|
if (ledcontrol) LED_B_ON();
|
||||||
// Capture reader cmd start timestamp
|
// 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
|
// Capture reader frame
|
||||||
if (rb >= HITAG_T_STOP) {
|
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;
|
uint32_t rb_i = 0, h2 = 0, h3 = 0, h4 = 0;
|
||||||
uint8_t edges[160] = {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
|
// Receive tag frame, watch for at most T0*HITAG_T_PROG_MAX periods
|
||||||
while (AT91C_BASE_TC0->TC_CV < (T0 * HITAG_T_PROG_MAX)) {
|
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:");
|
DbpString("htS: response_bit:");
|
||||||
Dbhexdump(*rxlen, response_bit, false);
|
Dbhexdump(*rxlen, response_bit, false);
|
||||||
Dbprintf("htS: skipping %d bit SOF", sof_bits);
|
Dbprintf("htS: skipping %d bit SOF", sof_bits);
|
||||||
|
|
||||||
if ((rx[0] >> (8 - sof_bits)) != ((1 << sof_bits) - 1)) {
|
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 the tag is in authentication mode try the key or challenge
|
||||||
if (packet->cmd == HTSF_KEY) {
|
if (packet->cmd == HTSF_KEY) {
|
||||||
|
|
||||||
DBG DbpString("Authenticating using key:");
|
key_le = MemLeToUint6byte(packet->key);
|
||||||
DBG Dbhexdump(6, packet->key, false);
|
|
||||||
|
|
||||||
key_le = *(uint64_t *)packet->key;
|
uint32_t le_val = MemLeToUint4byte(rnd);
|
||||||
|
uint64_t state = ht2_hitag2_init(REV64(key_le), REV32(tag.data.s.uid_le), REV32(le_val));
|
||||||
uint64_t state = ht2_hitag2_init(REV64(key_le), REV32(tag.data.s.uid_le), REV32(*(uint32_t *)rnd));
|
|
||||||
|
|
||||||
uint8_t auth_ks[4];
|
uint8_t auth_ks[4];
|
||||||
for (int i = 0; i < 4; i++) {
|
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, rnd, 0, 32);
|
||||||
txlen = concatbits(tx, txlen, auth_ks, 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]);
|
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) {
|
} 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;
|
pwdl1 = 0;
|
||||||
if (packet->cmd == HTSF_KEY) {
|
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++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
ht2_hitag2_byte(&state);
|
ht2_hitag2_byte(&state);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -690,8 +690,6 @@ static RAMFUNC int ManchesterDecoding_Thinfilm(uint8_t bit) {
|
||||||
if (Demod.bitCount) { // there are some remaining data bits
|
if (Demod.bitCount) { // there are some remaining data bits
|
||||||
Demod.shiftReg <<= (8 - Demod.bitCount); // left align the decoded bits
|
Demod.shiftReg <<= (8 - Demod.bitCount); // left align the decoded bits
|
||||||
Demod.output[Demod.len++] = Demod.shiftReg & 0xFF; // and add them to the output
|
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;
|
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) {
|
if (ts->max > max_buffer_size) {
|
||||||
Dbprintf("ToSend buffer, Out-of-bound, when modulating bits for tag answer:");
|
Dbprintf("ToSend buffer, Out-of-bound, when modulating bits for tag answer:");
|
||||||
Dbhexdump(response_info->response_n, response_info->response, false);
|
Dbhexdump(response_info->response_n, response_info->response, false);
|
||||||
|
Dbprintf("Need %i, got %i", ts->max, max_buffer_size);
|
||||||
return false;
|
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,
|
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) {
|
uint32_t *cuid, uint32_t counters[3], uint8_t tearings[3], uint8_t *pages) {
|
||||||
uint8_t sak = 0;
|
uint8_t sak = 0;
|
||||||
// The first response contains the ATQA (note: bytes are transmitted in reverse order).
|
// 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
|
// 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)
|
// 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
|
// TC(1) = 0x02: CID supported, NAD not supported
|
||||||
// static uint8_t rRATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 };
|
// static uint8_t rATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 };
|
||||||
static uint8_t rRATS[40] = { 0x05, 0x75, 0x80, 0x60, 0x02, 0x00, 0x00, 0x00 };
|
static uint8_t rATS[40] = { 0x06, 0x75, 0x80, 0x60, 0x02, 0x00, 0x00, 0x00 };
|
||||||
uint8_t rRATS_len = 8;
|
uint8_t rATS_len = 8;
|
||||||
|
|
||||||
// GET_VERSION response for EV1/NTAG
|
// GET_VERSION response for EV1/NTAG
|
||||||
static uint8_t rVERSION[10] = { 0x00 };
|
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[0] = 0x44;
|
||||||
rATQA[1] = 0x03;
|
rATQA[1] = 0x03;
|
||||||
sak = 0x20;
|
sak = 0x20;
|
||||||
memcpy(rRATS, "\x06\x75\x77\x81\x02\x80\x00\x00", 8);
|
memcpy(rATS, "\x06\x75\x77\x81\x02\x80\x00\x00", 8);
|
||||||
rRATS_len = 8;
|
rATS_len = 8; // including CRC
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4: { // ISO/IEC 14443-4 - javacard (JCOP)
|
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
|
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);
|
memcpy(rATS, "\x13\x78\x80\x72\x02\x80\x31\x80\x66\xb1\x84\x0c\x01\x6e\x01\x83\x00\x90\x00\x00\x00", 21);
|
||||||
rRATS_len = 19;
|
rATS_len = 21; // including CRC
|
||||||
rATQA[0] = 0x04;
|
rATQA[0] = 0x04;
|
||||||
sak = 0x20;
|
sak = 0x20;
|
||||||
break;
|
break;
|
||||||
|
|
@ -1271,19 +1270,21 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy the iRATs if supplied.
|
// copy the ats if supplied.
|
||||||
// iRATs is a pointer to 20 byte array
|
// ats is a pointer to 20 byte array
|
||||||
// rRATS is a 40 byte array
|
// rATS is a 40 byte array
|
||||||
if ((flags & FLAG_RATS_IN_DATA) == FLAG_RATS_IN_DATA) {
|
if ((flags & FLAG_ATS_IN_DATA) == FLAG_ATS_IN_DATA) {
|
||||||
memcpy(rRATS, iRATs, irats_len);
|
// Even if RATS protocol defined as max 40 bytes doesn't mean people try stuff. Check for overflow before copy
|
||||||
// rats len is dictated by the first char of the string, add 2 crc bytes
|
if (ats_len + 2 > sizeof(rATS)) {
|
||||||
rRATS_len = (iRATs[0] + 2);
|
if (g_dbglevel >= DBG_ERROR) Dbprintf("[-] ERROR: ATS overflow. Max %zu, got %zu", sizeof(rATS) - 2, ats_len);
|
||||||
// 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);
|
|
||||||
return false;
|
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
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddCrc14A(rRATS, rRATS_len - 2);
|
AddCrc14A(rATS, rATS_len - 2);
|
||||||
|
|
||||||
AddCrc14A(rPPS, sizeof(rPPS) - 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 = rSAKc1, .response_n = sizeof(rSAKc1) }, // Acknowledge select - cascade 1
|
||||||
{ .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2
|
{ .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2
|
||||||
{ .response = rSAKc3, .response_n = sizeof(rSAKc3) }, // Acknowledge select - cascade 3
|
{ .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 = rVERSION, .response_n = sizeof(rVERSION) }, // EV1/NTAG GET_VERSION response
|
||||||
{ .response = rSIGN, .response_n = sizeof(rSIGN) }, // EV1/NTAG READ_SIG response
|
{ .response = rSIGN, .response_n = sizeof(rSIGN) }, // EV1/NTAG READ_SIG response
|
||||||
{ .response = rPPS, .response_n = sizeof(rPPS) }, // PPS 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.
|
// 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.
|
// "precompiled" responses.
|
||||||
// These exist for speed reasons. There are no time in the anti collision phase to calculate 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)
|
// 85 bytes normally (rats = 8 bytes)
|
||||||
// 77 bytes + ratslen,
|
// 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);
|
uint8_t *free_buffer = BigBuf_calloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE);
|
||||||
// modulation buffer pointer and current buffer free space 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.
|
// response to send, and send it.
|
||||||
// 'hf 14a sim'
|
// 'hf 14a sim'
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_t exitAfterNReads,
|
void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uint8_t exitAfterNReads,
|
||||||
uint8_t *iRATs, size_t irats_len) {
|
uint8_t *ats, size_t ats_len) {
|
||||||
|
|
||||||
#define ATTACK_KEY_COUNT 16
|
#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
|
#define DYNAMIC_MODULATION_BUFFER_SIZE 512
|
||||||
|
|
||||||
uint8_t *dynamic_response_buffer = BigBuf_calloc(DYNAMIC_RESPONSE_BUFFER_SIZE);
|
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);
|
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 = {
|
tag_response_info_t dynamic_response_info = {
|
||||||
.response = dynamic_response_buffer,
|
.response = dynamic_response_buffer,
|
||||||
.response_n = 0,
|
.response_n = 0,
|
||||||
|
|
@ -1497,7 +1508,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
|
||||||
.modulation_n = 0
|
.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();
|
BigBuf_free_keep_EM();
|
||||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||||
return;
|
return;
|
||||||
|
|
@ -1671,10 +1682,10 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
|
||||||
EmSend4bit(CARD_NACK_IV);
|
EmSend4bit(CARD_NACK_IV);
|
||||||
} else {
|
} else {
|
||||||
// first blocks of emu are header
|
// first blocks of emu are header
|
||||||
uint16_t start = block * 4 + MFU_DUMP_PREFIX_LENGTH;
|
uint16_t start = (block * 4) + MFU_DUMP_PREFIX_LENGTH;
|
||||||
uint8_t emdata[MAX_MIFARE_FRAME_SIZE];
|
uint8_t emdata[MAX_MIFARE_FRAME_SIZE] = {0};
|
||||||
emlGet(emdata, start, 16);
|
emlGet(emdata, start, MIFARE_BLOCK_SIZE);
|
||||||
AddCrc14A(emdata, 16);
|
AddCrc14A(emdata, MIFARE_BLOCK_SIZE);
|
||||||
EmSendCmd(emdata, sizeof(emdata));
|
EmSendCmd(emdata, sizeof(emdata));
|
||||||
numReads++; // Increment number of times reader requested a block
|
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];
|
p_response = &responses[RESP_INDEX_UIDC1];
|
||||||
} else { // all other tags (16 byte block tags)
|
} else { // all other tags (16 byte block tags)
|
||||||
uint8_t emdata[MAX_MIFARE_FRAME_SIZE] = {0};
|
uint8_t emdata[MAX_MIFARE_FRAME_SIZE] = {0};
|
||||||
emlGet(emdata, block, 16);
|
emlGet(emdata, block, MIFARE_BLOCK_SIZE);
|
||||||
AddCrc14A(emdata, 16);
|
AddCrc14A(emdata, MIFARE_BLOCK_SIZE);
|
||||||
EmSendCmd(emdata, sizeof(emdata));
|
EmSendCmd(emdata, sizeof(emdata));
|
||||||
// We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
|
// We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
|
||||||
p_response = NULL;
|
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
|
} else if (receivedCmd[0] == MIFARE_ULC_WRITE && len == 8 && (tagType == 2 || tagType == 7)) { // Received a WRITE
|
||||||
// cmd + block + 4 bytes data + 2 bytes crc
|
// cmd + block + 4 bytes data + 2 bytes crc
|
||||||
if (CheckCrc14A(receivedCmd, len)) {
|
if (CheckCrc14A(receivedCmd, len)) {
|
||||||
|
|
||||||
uint8_t block = receivedCmd[1];
|
uint8_t block = receivedCmd[1];
|
||||||
if (block > pages) {
|
if (block > pages) {
|
||||||
// send NACK 0x0 == invalid argument
|
// send NACK 0x0 == invalid argument
|
||||||
EmSend4bit(CARD_NACK_IV);
|
EmSend4bit(CARD_NACK_IV);
|
||||||
} else {
|
} else {
|
||||||
// first blocks of emu are header
|
// 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
|
// send ACK
|
||||||
EmSend4bit(CARD_ACK);
|
EmSend4bit(CARD_ACK);
|
||||||
}
|
}
|
||||||
|
|
@ -1820,7 +1832,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
|
||||||
EmSend4bit(CARD_NACK_NA);
|
EmSend4bit(CARD_NACK_NA);
|
||||||
p_response = NULL;
|
p_response = NULL;
|
||||||
} else {
|
} 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
|
} 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);
|
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) {
|
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]);
|
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.
|
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,
|
void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *uid,
|
||||||
uint8_t *iRATs, size_t irats_len, uint8_t *aid, uint8_t *resp,
|
uint8_t *ats, size_t ats_len, uint8_t *aid, size_t aid_len,
|
||||||
uint8_t *apdu, int aidLen, int respondLen, int apduLen, bool enumerate) {
|
uint8_t *selectaid_response, size_t selectaid_response_len,
|
||||||
|
uint8_t *getdata_response, size_t getdata_response_len) {
|
||||||
tag_response_info_t *responses;
|
tag_response_info_t *responses;
|
||||||
uint32_t cuid = 0;
|
uint32_t cuid = 0;
|
||||||
uint32_t counters[3] = { 0x00, 0x00, 0x00 };
|
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 receivedCmd[MAX_FRAME_SIZE] = { 0x00 };
|
||||||
uint8_t receivedCmdPar[MAX_PARITY_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
|
// free eventually allocated BigBuf memory but keep Emulator Memory
|
||||||
BigBuf_free_keep_EM();
|
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
|
#define DYNAMIC_MODULATION_BUFFER2_SIZE 1536
|
||||||
|
|
||||||
uint8_t *dynamic_response_buffer2 = BigBuf_calloc(DYNAMIC_RESPONSE_BUFFER2_SIZE);
|
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);
|
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 = {
|
tag_response_info_t dynamic_response_info = {
|
||||||
.response = dynamic_response_buffer2,
|
.response = dynamic_response_buffer2,
|
||||||
.response_n = 0,
|
.response_n = 0,
|
||||||
|
|
@ -3970,7 +3999,7 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||||
.modulation_n = 0
|
.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();
|
BigBuf_free_keep_EM();
|
||||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||||
return;
|
return;
|
||||||
|
|
@ -3990,25 +4019,9 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||||
set_tracing(true);
|
set_tracing(true);
|
||||||
LED_A_ON();
|
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
|
// main loop
|
||||||
bool finished = false;
|
bool finished = false;
|
||||||
|
bool got_rats = false;
|
||||||
while (finished == false) {
|
while (finished == false) {
|
||||||
// BUTTON_PRESS check done in GetIso14443aCommandFromReader
|
// BUTTON_PRESS check done in GetIso14443aCommandFromReader
|
||||||
WDT_HIT();
|
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
|
} 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);
|
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
|
||||||
p_response = NULL;
|
p_response = NULL;
|
||||||
|
if (got_rats) {
|
||||||
finished = true;
|
finished = true;
|
||||||
|
}
|
||||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
|
} 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 {
|
} else {
|
||||||
// clear old dynamic responses
|
// clear old dynamic responses
|
||||||
dynamic_response_info.response_n = 0;
|
dynamic_response_info.response_n = 0;
|
||||||
dynamic_response_info.modulation_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]) {
|
switch (receivedCmd[0]) {
|
||||||
case 0x0B:
|
case 0x0B: // IBlock with CID
|
||||||
case 0x0A: { // IBlock (command CID)
|
case 0x0A:
|
||||||
|
offset = 1;
|
||||||
|
case 0x02: // IBlock without CID
|
||||||
|
case 0x03: {
|
||||||
dynamic_response_info.response[0] = receivedCmd[0];
|
dynamic_response_info.response[0] = receivedCmd[0];
|
||||||
dynamic_response_info.response[1] = 0x00;
|
dynamic_response_info.response[1] = 0x00;
|
||||||
|
|
||||||
switch (receivedCmd[3]) { // APDU Class Byte
|
switch (receivedCmd[2 + offset]) { // APDU Class Byte
|
||||||
// receivedCmd in this case is expecting to structured with a CID, then the APDU command for SelectFile
|
// receivedCmd in this case is expecting to structured with possibly a CID, then the APDU command for SelectFile
|
||||||
// | IBlock (CID) | CID | APDU Command | CRC |
|
// | IBlock (CID) | CID | APDU Command | CRC |
|
||||||
|
// or | IBlock (noCID) | APDU Command | CRC |
|
||||||
|
|
||||||
case 0xA4: { // SELECT FILE
|
case 0xA4: { // SELECT FILE
|
||||||
// Select File AID uses the following format for GlobalPlatform
|
// 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
|
// 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)
|
// aid len is found as a hex value in receivedCmd[6] (Index Starts at 0)
|
||||||
int aid_len = receivedCmd[6];
|
int received_aid_len = receivedCmd[5 + offset];
|
||||||
uint8_t *received_aid = &receivedCmd[7];
|
uint8_t *received_aid = &receivedCmd[6 + offset];
|
||||||
|
|
||||||
// aid enumeration flag
|
// aid enumeration flag
|
||||||
if (enumerate == true) {
|
if ((flags & FLAG_ENUMERATE_AID) == FLAG_ENUMERATE_AID) {
|
||||||
Dbprintf("Received AID (%d):", aid_len);
|
Dbprintf("Received AID (%d):", received_aid_len);
|
||||||
Dbhexdump(aid_len, received_aid, false);
|
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
|
// AID Response will be parsed here
|
||||||
memcpy(dynamic_response_info.response + 2, aidResponse, respondLen + 2);
|
memcpy(dynamic_response_info.response + 1 + offset, selectaid_response, selectaid_response_len + 1 + offset);
|
||||||
dynamic_response_info.response_n = respondLen + 2;
|
dynamic_response_info.response_n = selectaid_response_len + 2;
|
||||||
} else { // Any other SELECT FILE command will return with a Not Found
|
} else { // Any other SELECT FILE command will return with a Not Found
|
||||||
dynamic_response_info.response[2] = 0x6A;
|
dynamic_response_info.response[1 + offset] = 0x6A;
|
||||||
dynamic_response_info.response[3] = 0x82;
|
dynamic_response_info.response[2 + offset] = 0x82;
|
||||||
dynamic_response_info.response_n = 4;
|
dynamic_response_info.response_n = 3 + offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xDA: { // PUT DATA
|
case 0xDA: { // PUT DATA
|
||||||
// Just send them a 90 00 response
|
// Just send them a 90 00 response
|
||||||
dynamic_response_info.response[2] = 0x90;
|
dynamic_response_info.response[1 + offset] = 0x90;
|
||||||
dynamic_response_info.response[3] = 0x00;
|
dynamic_response_info.response[2 + offset] = 0x00;
|
||||||
dynamic_response_info.response_n = 4;
|
dynamic_response_info.response_n = 3 + offset;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xCA: { // GET DATA
|
case 0xCA: { // GET DATA
|
||||||
if (sentCount == 0) {
|
if (sentCount == 0) {
|
||||||
// APDU Command will just be parsed here
|
// APDU Command will just be parsed here
|
||||||
memcpy(dynamic_response_info.response + 2, apduCommand, apduLen + 2);
|
memcpy(dynamic_response_info.response + 1 + offset, getdata_response, getdata_response_len + 2);
|
||||||
dynamic_response_info.response_n = respondLen + 2;
|
dynamic_response_info.response_n = selectaid_response_len + 1 + offset;
|
||||||
} else {
|
} else {
|
||||||
finished = true;
|
finished = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -4116,18 +4137,18 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||||
default : {
|
default : {
|
||||||
// Any other non-listed command
|
// Any other non-listed command
|
||||||
// Respond Not Found
|
// Respond Not Found
|
||||||
dynamic_response_info.response[2] = 0x6A;
|
dynamic_response_info.response[1 + offset] = 0x6A;
|
||||||
dynamic_response_info.response[3] = 0x82;
|
dynamic_response_info.response[2 + offset] = 0x82;
|
||||||
dynamic_response_info.response_n = 4;
|
dynamic_response_info.response_n = 3 + offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xCA:
|
case 0xCA: // S-Block Deselect with CID
|
||||||
case 0xC2: { // Readers sends deselect command
|
case 0xC2: { // S-Block Deselect without CID
|
||||||
dynamic_response_info.response[0] = 0xCA;
|
dynamic_response_info.response[0] = receivedCmd[0];
|
||||||
dynamic_response_info.response[1] = 0x00;
|
dynamic_response_info.response[1] = 0x00;
|
||||||
dynamic_response_info.response_n = 2;
|
dynamic_response_info.response_n = 2;
|
||||||
finished = true;
|
finished = true;
|
||||||
|
|
@ -4135,12 +4156,15 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: {
|
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);
|
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) {
|
if (g_dbglevel >= DBG_DEBUG) {
|
||||||
Dbprintf("Received unknown command (len=%d):", len);
|
Dbprintf("Received unknown command (len=%d):", len);
|
||||||
Dbhexdump(len, receivedCmd, false);
|
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
|
// Do not respond
|
||||||
dynamic_response_info.response_n = 0;
|
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) {
|
if (dynamic_response_info.response_n > 0) {
|
||||||
|
|
||||||
// Copy the CID from the reader query
|
// Copy the CID from the reader query
|
||||||
|
if (offset > 0) {
|
||||||
dynamic_response_info.response[1] = receivedCmd[1];
|
dynamic_response_info.response[1] = receivedCmd[1];
|
||||||
|
}
|
||||||
|
|
||||||
// Add CRC bytes, always used in ISO 14443A-4 compliant cards
|
// Add CRC bytes, always used in ISO 14443A-4 compliant cards
|
||||||
AddCrc14A(dynamic_response_info.response, dynamic_response_info.response_n);
|
AddCrc14A(dynamic_response_info.response, dynamic_response_info.response_n);
|
||||||
dynamic_response_info.response_n += 2;
|
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");
|
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);
|
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ typedef enum {
|
||||||
RESP_INDEX_SAKC1,
|
RESP_INDEX_SAKC1,
|
||||||
RESP_INDEX_SAKC2,
|
RESP_INDEX_SAKC2,
|
||||||
RESP_INDEX_SAKC3,
|
RESP_INDEX_SAKC3,
|
||||||
RESP_INDEX_RATS,
|
RESP_INDEX_ATS,
|
||||||
RESP_INDEX_VERSION,
|
RESP_INDEX_VERSION,
|
||||||
RESP_INDEX_SIGNATURE,
|
RESP_INDEX_SIGNATURE,
|
||||||
RESP_INDEX_PPS,
|
RESP_INDEX_PPS,
|
||||||
|
|
@ -142,12 +142,13 @@ RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time);
|
||||||
RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time);
|
RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time);
|
||||||
|
|
||||||
void RAMFUNC SniffIso14443a(uint8_t param);
|
void RAMFUNC SniffIso14443a(uint8_t param);
|
||||||
void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_t exitAfterNReads,
|
void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uint8_t exitAfterNReads,
|
||||||
uint8_t *iRATs, size_t irats_len);
|
uint8_t *iRATs, size_t irats_len);
|
||||||
|
|
||||||
void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *data,
|
void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *uid,
|
||||||
uint8_t *iRATs, size_t irats_len, uint8_t *aid, uint8_t *resp,
|
uint8_t *ats, size_t ats_len, uint8_t *aid, size_t aid_len,
|
||||||
uint8_t *apdu, int aid_len, int respond_len, int apdu_len, bool enumerate);
|
uint8_t *selectaid_response, size_t selectaid_response_len,
|
||||||
|
uint8_t *getdata_response, size_t getdata_response_len);
|
||||||
|
|
||||||
bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
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 *iRATs, size_t irats_len, tag_response_info_t **responses,
|
||||||
|
|
|
||||||
|
|
@ -2117,14 +2117,6 @@ void Iso15693InitTag(void) {
|
||||||
StartCountSspClk();
|
StartCountSspClk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmlClearIso15693(void) {
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands
|
// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands
|
||||||
// all demodulation performed in arm rather than host. - greg
|
// all demodulation performed in arm rather than host. - greg
|
||||||
void SimTagIso15693(const uint8_t *uid, uint8_t block_size) {
|
void SimTagIso15693(const uint8_t *uid, uint8_t block_size) {
|
||||||
|
|
@ -2775,10 +2767,10 @@ void LockPassSlixIso15693(uint32_t pass_id, uint32_t password) {
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
|
|
||||||
uint8_t cmd_inventory[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1, 0x01, 0x00, 0x00, 0x00 };
|
uint8_t cmd_inventory[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1, 0x01, 0x00, 0x00, 0x00 };
|
||||||
uint8_t cmd_get_rnd[] = {ISO15693_REQ_DATARATE_HIGH, 0xB2, 0x04, 0x00, 0x00 };
|
uint8_t cmd_get_rnd[] = {ISO15693_REQ_DATARATE_HIGH, ISO15693_GET_RANDOM_NUMBER, 0x04, 0x00, 0x00 };
|
||||||
uint8_t cmd_set_pass[] = {ISO15693_REQ_DATARATE_HIGH, 0xB3, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
uint8_t cmd_set_pass[] = {ISO15693_REQ_DATARATE_HIGH, ISO15693_SET_PASSWORD, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
//uint8_t cmd_write_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
//uint8_t cmd_write_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, ISO15693_WRITE_PASSWORD, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
uint8_t cmd_lock_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00 };
|
uint8_t cmd_lock_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, ISO15693_LOCK_PASSWORD, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00 };
|
||||||
uint16_t crc;
|
uint16_t crc;
|
||||||
uint16_t recvlen = 0;
|
uint16_t recvlen = 0;
|
||||||
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
|
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
|
||||||
|
|
@ -3028,14 +3020,7 @@ static uint32_t disable_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_ti
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t set_pass_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, const uint8_t *password, const uint8_t *uid) {
|
static uint32_t set_pass_15693_SlixRnd(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, const uint8_t *password, const uint8_t *uid, uint8_t *rnd) {
|
||||||
|
|
||||||
|
|
||||||
uint8_t rnd[2];
|
|
||||||
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
|
|
||||||
return PM3_ETIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x04, == NXP from manufacture id list.
|
// 0x04, == NXP from manufacture id list.
|
||||||
uint8_t c[] = { (ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS), ISO15693_SET_PASSWORD, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, pass_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
uint8_t c[] = { (ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS), ISO15693_SET_PASSWORD, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, pass_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
|
@ -3055,6 +3040,18 @@ static uint32_t set_pass_15693_Slix(uint32_t start_time, uint32_t *eof_time, uin
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t set_pass_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, const uint8_t *password, const uint8_t *uid) {
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t rnd[2];
|
||||||
|
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return set_pass_15693_SlixRnd(start_time, eof_time, pass_id, password, uid, rnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint32_t set_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time, const uint8_t *password) {
|
static uint32_t set_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time, const uint8_t *password) {
|
||||||
uint8_t rnd[2];
|
uint8_t rnd[2];
|
||||||
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
|
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
|
||||||
|
|
@ -3062,7 +3059,7 @@ static uint32_t set_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x04, == NXP from manufacture id list.
|
// 0x04, == NXP from manufacture id list.
|
||||||
uint8_t c[] = { ISO15_REQ_DATARATE_HIGH, 0xBA, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t c[] = { ISO15_REQ_DATARATE_HIGH, ISO15693_ENABLE_PRIVACY, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
init_password_15693_Slix(&c[3], password, rnd);
|
init_password_15693_Slix(&c[3], password, rnd);
|
||||||
AddCrc15(c, 7);
|
AddCrc15(c, 7);
|
||||||
|
|
||||||
|
|
@ -3096,7 +3093,7 @@ static uint32_t disable_eas_15693_Slix(uint32_t start_time, uint32_t *eof_time,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x04, == NXP from manufacture id list.
|
// 0x04, == NXP from manufacture id list.
|
||||||
uint8_t c[] = { ISO15_REQ_DATARATE_HIGH, 0xA3, 0x04, 0x00, 0x00};
|
uint8_t c[] = { ISO15_REQ_DATARATE_HIGH, ISO15693_RESET_EAS, 0x04, 0x00, 0x00};
|
||||||
AddCrc15(c, 3);
|
AddCrc15(c, 3);
|
||||||
|
|
||||||
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
||||||
|
|
@ -3127,7 +3124,7 @@ static uint32_t enable_eas_15693_Slix(uint32_t start_time, uint32_t *eof_time, c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 0x04, == NXP from manufacture id list.
|
// 0x04, == NXP from manufacture id list.
|
||||||
uint8_t c[] = { ISO15_REQ_DATARATE_HIGH, 0xA2, 0x04, 0x00, 0x00};
|
uint8_t c[] = { ISO15_REQ_DATARATE_HIGH, ISO15693_SET_EAS, 0x04, 0x00, 0x00};
|
||||||
//init_password_15693_Slix(&c[3], password, rnd);
|
//init_password_15693_Slix(&c[3], password, rnd);
|
||||||
AddCrc15(c, 3);
|
AddCrc15(c, 3);
|
||||||
|
|
||||||
|
|
@ -3162,6 +3159,26 @@ static uint32_t write_password_15693_Slix(uint32_t start_time, uint32_t *eof_tim
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t protect_page_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t divide_ptr, uint8_t prot_status, const uint8_t *uid) {
|
||||||
|
|
||||||
|
uint8_t protect_cmd[] = { (ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS), ISO15693_PROTECT_PAGE, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, divide_ptr, prot_status, 0x00, 0x00};
|
||||||
|
|
||||||
|
memcpy(&protect_cmd[3], uid, 8);
|
||||||
|
|
||||||
|
AddCrc15(protect_cmd, 13);
|
||||||
|
|
||||||
|
start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
||||||
|
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
|
||||||
|
uint16_t recvlen = 0;
|
||||||
|
|
||||||
|
int res_wrp = SendDataTag(protect_cmd, sizeof(protect_cmd), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time, &recvlen);
|
||||||
|
if (res_wrp != PM3_SUCCESS && recvlen != 3) {
|
||||||
|
return PM3_EWRONGANSWER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t pass_protect_EASAFI_15693_Slix(uint32_t start_time, uint32_t *eof_time, bool set_option_flag, const uint8_t *password) {
|
static uint32_t pass_protect_EASAFI_15693_Slix(uint32_t start_time, uint32_t *eof_time, bool set_option_flag, const uint8_t *password) {
|
||||||
|
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
|
|
@ -3262,6 +3279,37 @@ void WritePasswordSlixIso15693(const uint8_t *old_password, const uint8_t *new_p
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtectPageSlixIso15693(const uint8_t *read_password, const uint8_t *write_password, uint8_t divide_ptr, uint8_t prot_status) {
|
||||||
|
LED_D_ON();
|
||||||
|
Iso15693InitReader();
|
||||||
|
StartCountSspClk();
|
||||||
|
uint32_t start_time = 0, eof_time = 0;
|
||||||
|
int res = PM3_SUCCESS;
|
||||||
|
|
||||||
|
uint8_t uid[8], rnd[2];
|
||||||
|
get_uid_slix(start_time, &eof_time, uid);
|
||||||
|
|
||||||
|
if (get_rnd_15693_Slix(start_time, &eof_time, rnd) == false) {
|
||||||
|
reply_ng(CMD_HF_ISO15693_SLIX_PROTECT_PAGE, PM3_ETIMEOUT, NULL, 0);
|
||||||
|
switch_off();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_password)
|
||||||
|
res = set_pass_15693_SlixRnd(start_time, &eof_time, 0x01, read_password, uid, rnd);
|
||||||
|
|
||||||
|
if (res == PM3_SUCCESS && write_password)
|
||||||
|
res = set_pass_15693_SlixRnd(start_time, &eof_time, 0x02, write_password, uid, rnd);
|
||||||
|
|
||||||
|
if (res == PM3_SUCCESS)
|
||||||
|
res = protect_page_15693_Slix(start_time, &eof_time, divide_ptr, prot_status, uid);
|
||||||
|
|
||||||
|
reply_ng(CMD_HF_ISO15693_SLIX_PROTECT_PAGE, res, NULL, 0);
|
||||||
|
|
||||||
|
switch_off();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void DisablePrivacySlixIso15693(const uint8_t *password) {
|
void DisablePrivacySlixIso15693(const uint8_t *password) {
|
||||||
LED_D_ON();
|
LED_D_ON();
|
||||||
Iso15693InitReader();
|
Iso15693InitReader();
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo
|
||||||
//void RecordRawAdcSamplesIso15693(void);
|
//void RecordRawAdcSamplesIso15693(void);
|
||||||
void AcquireRawAdcSamplesIso15693(void);
|
void AcquireRawAdcSamplesIso15693(void);
|
||||||
void ReaderIso15693(iso15_card_select_t *p_card); // ISO15693 reader
|
void ReaderIso15693(iso15_card_select_t *p_card); // ISO15693 reader
|
||||||
void EmlClearIso15693(void);
|
|
||||||
void SimTagIso15693(const uint8_t *uid, uint8_t block_size); // simulate an ISO15693 tag
|
void SimTagIso15693(const uint8_t *uid, uint8_t block_size); // simulate an ISO15693 tag
|
||||||
void BruteforceIso15693Afi(uint32_t flags); // find an AFI of a tag
|
void BruteforceIso15693Afi(uint32_t flags); // find an AFI of a tag
|
||||||
void SendRawCommand15693(iso15_raw_cmd_t *packet); // send arbitrary commands from CLI
|
void SendRawCommand15693(iso15_raw_cmd_t *packet); // send arbitrary commands from CLI
|
||||||
|
|
@ -69,4 +68,5 @@ void EnableEAS_AFISlixIso15693(const uint8_t *password, bool usepwd);
|
||||||
void PassProtextEASSlixIso15693(const uint8_t *password);
|
void PassProtextEASSlixIso15693(const uint8_t *password);
|
||||||
void PassProtectAFISlixIso15693(const uint8_t *password);
|
void PassProtectAFISlixIso15693(const uint8_t *password);
|
||||||
void WriteAFIIso15693(const uint8_t *password, bool use_pwd, uint8_t *uid, bool use_uid, uint8_t afi);
|
void WriteAFIIso15693(const uint8_t *password, bool use_pwd, uint8_t *uid, bool use_uid, uint8_t afi);
|
||||||
|
void ProtectPageSlixIso15693(const uint8_t *read_password, const uint8_t *write_password, uint8_t divide_ptr, uint8_t prot_status);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -944,6 +944,33 @@ static void fcAll(uint8_t fc, int *n, uint8_t clock, int16_t *remainder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool add_HID_preamble(uint32_t *hi2, uint32_t *hi, uint32_t *lo, uint8_t length) {
|
||||||
|
// Invalid value
|
||||||
|
if (length > 84 || length == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (length == 48) {
|
||||||
|
*hi |= 1U << (length - 32); // Example leading 1: start bit
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (length >= 64) {
|
||||||
|
*hi2 |= 0x09e00000; // Extended-length header
|
||||||
|
*hi2 |= 1U << (length - 64); // leading 1: start bit
|
||||||
|
} else if (length > 37) {
|
||||||
|
*hi2 |= 0x09e00000; // Extended-length header
|
||||||
|
*hi |= 1U << (length - 32); // leading 1: start bit
|
||||||
|
} else if (length == 37) {
|
||||||
|
// No header bits added to 37-bit cards
|
||||||
|
} else if (length >= 32) {
|
||||||
|
*hi |= 0x20; // Bit 37; standard header
|
||||||
|
*hi |= 1U << (length - 32); // leading 1: start bit
|
||||||
|
} else {
|
||||||
|
*hi |= 0x20; // Bit 37; standard header
|
||||||
|
*lo |= 1U << length; // leading 1: start bit
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// prepare a waveform pattern in the buffer based on the ID given then
|
// prepare a waveform pattern in the buffer based on the ID given then
|
||||||
// simulate a HID tag until the button is pressed
|
// simulate a HID tag until the button is pressed
|
||||||
void CmdHIDsimTAGEx(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, bool ledcontrol, int numcycles) {
|
void CmdHIDsimTAGEx(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, bool ledcontrol, int numcycles) {
|
||||||
|
|
@ -968,13 +995,7 @@ void CmdHIDsimTAGEx(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, boo
|
||||||
uint16_t n = 8;
|
uint16_t n = 8;
|
||||||
|
|
||||||
if (longFMT) {
|
if (longFMT) {
|
||||||
// Ensure no more than 84 bits supplied
|
|
||||||
if (hi2 > 0xFFFFF) {
|
|
||||||
DbpString("Tags can only have 84 bits.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bitlen = 8 + 8 * 2 + 84 * 2;
|
bitlen = 8 + 8 * 2 + 84 * 2;
|
||||||
hi2 |= 0x9E00000; // 9E: long format identifier
|
|
||||||
manchesterEncodeUint32(hi2, 16 + 12, bits, &n);
|
manchesterEncodeUint32(hi2, 16 + 12, bits, &n);
|
||||||
manchesterEncodeUint32(hi, 32, bits, &n);
|
manchesterEncodeUint32(hi, 32, bits, &n);
|
||||||
manchesterEncodeUint32(lo, 32, bits, &n);
|
manchesterEncodeUint32(lo, 32, bits, &n);
|
||||||
|
|
@ -1316,10 +1337,6 @@ int lf_hid_watch(int findone, uint32_t *high, uint32_t *low, bool ledcontrol) {
|
||||||
cardnum = (lo >> 1) & 0xFFFF;
|
cardnum = (lo >> 1) & 0xFFFF;
|
||||||
fac = (lo >> 17) & 0xFF;
|
fac = (lo >> 17) & 0xFF;
|
||||||
}
|
}
|
||||||
if (bitlen == 37) {
|
|
||||||
cardnum = (lo >> 1) & 0x7FFFF;
|
|
||||||
fac = ((hi & 0xF) << 12) | (lo >> 20);
|
|
||||||
}
|
|
||||||
if (bitlen == 34) {
|
if (bitlen == 34) {
|
||||||
cardnum = (lo >> 1) & 0xFFFF;
|
cardnum = (lo >> 1) & 0xFFFF;
|
||||||
fac = ((hi & 1) << 15) | (lo >> 17);
|
fac = ((hi & 1) << 15) | (lo >> 17);
|
||||||
|
|
@ -2274,15 +2291,10 @@ void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, boo
|
||||||
uint8_t last_block = 0;
|
uint8_t last_block = 0;
|
||||||
|
|
||||||
if (longFMT) {
|
if (longFMT) {
|
||||||
// Ensure no more than 84 bits supplied
|
|
||||||
if (hi2 > 0xFFFFF) {
|
|
||||||
DbpString("Tags can only have 84 bits");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Build the 6 data blocks for supplied 84bit ID
|
// Build the 6 data blocks for supplied 84bit ID
|
||||||
last_block = 6;
|
last_block = 6;
|
||||||
// load preamble (1D) & long format identifier (9E manchester encoded)
|
// load preamble (1D)
|
||||||
data[1] = 0x1D96A900 | (manchesterEncode2Bytes((hi2 >> 16) & 0xF) & 0xFF);
|
data[1] = 0x1D000000 | (manchesterEncode2Bytes((hi2 >> 16) & 0xFFFF) & 0xFFFFFF);
|
||||||
// load raw id from hi2, hi, lo to data blocks (manchester encoded)
|
// load raw id from hi2, hi, lo to data blocks (manchester encoded)
|
||||||
data[2] = manchesterEncode2Bytes(hi2 & 0xFFFF);
|
data[2] = manchesterEncode2Bytes(hi2 & 0xFFFF);
|
||||||
data[3] = manchesterEncode2Bytes(hi >> 16);
|
data[3] = manchesterEncode2Bytes(hi >> 16);
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ void SimulateTagLowFrequencyEx(int period, int gap, bool ledcontrol, int numcycl
|
||||||
void SimulateTagLowFrequency(int period, int gap, bool ledcontrol);
|
void SimulateTagLowFrequency(int period, int gap, bool ledcontrol);
|
||||||
void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen);
|
void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen);
|
||||||
|
|
||||||
|
bool add_HID_preamble(uint32_t *hi2, uint32_t *hi, uint32_t *lo, uint8_t length);
|
||||||
void CmdHIDsimTAGEx(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, bool ledcontrol, int numcycles);
|
void CmdHIDsimTAGEx(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, bool ledcontrol, int numcycles);
|
||||||
void CmdHIDsimTAG(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, bool ledcontrol);
|
void CmdHIDsimTAG(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, bool ledcontrol);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2223,7 +2223,7 @@ OUT:
|
||||||
blockno = (32 * 4 + (i - 32) * 16) ^ 0xF;
|
blockno = (32 * 4 + (i - 32) * 16) ^ 0xF;
|
||||||
}
|
}
|
||||||
// get ST
|
// get ST
|
||||||
emlGetMem(block, blockno, 1);
|
emlGetMem_xt(block, blockno, 1, MIFARE_BLOCK_SIZE);
|
||||||
|
|
||||||
memcpy(block, k_sector[i].keyA, 6);
|
memcpy(block, k_sector[i].keyA, 6);
|
||||||
memcpy(block + 10, k_sector[i].keyB, 6);
|
memcpy(block + 10, k_sector[i].keyB, 6);
|
||||||
|
|
@ -2376,8 +2376,8 @@ void MifareChkKeys_file(uint8_t *fn) {
|
||||||
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key) {
|
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key) {
|
||||||
|
|
||||||
uint16_t isOK = PM3_EUNDEF;
|
uint16_t isOK = PM3_EUNDEF;
|
||||||
uint8_t uid[10];
|
uint8_t uid[10] = { 0 };
|
||||||
uint32_t cuid;
|
uint32_t cuid = 0;
|
||||||
struct Crypto1State mpcs = {0, 0};
|
struct Crypto1State mpcs = {0, 0};
|
||||||
struct Crypto1State *pcs;
|
struct Crypto1State *pcs;
|
||||||
pcs = &mpcs;
|
pcs = &mpcs;
|
||||||
|
|
@ -2388,8 +2388,12 @@ void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key) {
|
||||||
|
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
|
|
||||||
|
uint8_t rec_answer[MAX_MIFARE_FRAME_SIZE] = {0};
|
||||||
|
uint8_t rec_answer_par[MAX_MIFARE_PARITY_SIZE] = {0};
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
|
||||||
|
if (iso14443a_select_card(uid, NULL, &cuid, true, 0, true) == false) {
|
||||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card");
|
if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -2400,11 +2404,9 @@ void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
|
int len = mifare_sendcmd_short(pcs, true, MIFARE_EV1_PERSONAL_UID, perso_option, rec_answer, sizeof(rec_answer), rec_answer_par, NULL);
|
||||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
if (len != 1 || rec_answer[0] != CARD_ACK) {
|
||||||
int len = mifare_sendcmd_short(pcs, true, MIFARE_EV1_PERSONAL_UID, perso_option, receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar, NULL);
|
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", rec_answer[0]);
|
||||||
if (len != 1 || receivedAnswer[0] != CARD_ACK) {
|
|
||||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2427,39 +2429,6 @@ void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// 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.
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void MifareEMemClr(void) {
|
|
||||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
|
||||||
emlClearMem();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MifareEMemGet(uint8_t blockno, uint8_t blockcnt) {
|
|
||||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
|
||||||
|
|
||||||
//
|
|
||||||
size_t size = blockcnt * 16;
|
|
||||||
if (size > PM3_CMD_DATA_SIZE) {
|
|
||||||
reply_ng(CMD_HF_MIFARE_EML_MEMGET, PM3_EMALLOC, NULL, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *buf = BigBuf_malloc(size);
|
|
||||||
|
|
||||||
emlGetMem(buf, blockno, blockcnt); // 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Load a card into the emulator memory
|
// Load a card into the emulator memory
|
||||||
//
|
//
|
||||||
|
|
@ -2471,12 +2440,15 @@ int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype, uint8_t *key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype, uint8_t *key) {
|
int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype, uint8_t *key) {
|
||||||
|
|
||||||
if ((keytype > MF_KEY_B) && (key == NULL)) {
|
if ((keytype > MF_KEY_B) && (key == NULL)) {
|
||||||
|
|
||||||
if (g_dbglevel >= DBG_ERROR) {
|
if (g_dbglevel >= DBG_ERROR) {
|
||||||
Dbprintf("Error, missing key");
|
Dbprintf("Error, missing key");
|
||||||
}
|
}
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||||
|
|
||||||
|
|
@ -2510,10 +2482,10 @@ int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype, uint8_t *key) {
|
||||||
// MFC 1K EV1, skip sector 16 since its lockdown
|
// MFC 1K EV1, skip sector 16 since its lockdown
|
||||||
if (s == 16) {
|
if (s == 16) {
|
||||||
// unknown sector trailer, keep the keys, set only the AC
|
// unknown sector trailer, keep the keys, set only the AC
|
||||||
uint8_t st[16] = {0x00};
|
uint8_t st[MIFARE_BLOCK_SIZE] = {0x00};
|
||||||
emlGetMem(st, FirstBlockOfSector(s) + 3, 1);
|
emlGetMem_xt(st, FirstBlockOfSector(s) + 3, 1, MIFARE_BLOCK_SIZE);
|
||||||
memcpy(st + 6, "\x70\xF0\xF8\x69", 4);
|
memcpy(st + 6, "\x70\xF0\xF8\x69", 4);
|
||||||
emlSetMem_xt(st, FirstBlockOfSector(s) + 3, 1, 16);
|
emlSetMem_xt(st, FirstBlockOfSector(s) + 3, 1, MIFARE_BLOCK_SIZE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2556,7 +2528,8 @@ int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype, uint8_t *key) {
|
||||||
}
|
}
|
||||||
have_uid = true;
|
have_uid = true;
|
||||||
} else { // no need for anticollision. We can directly select the card
|
} else { // no need for anticollision. We can directly select the card
|
||||||
if (!bd_authenticated) { // no need to select if bd_authenticated with backdoor
|
|
||||||
|
if (bd_authenticated == false) { // no need to select if bd_authenticated with backdoor
|
||||||
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
|
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -2565,7 +2538,7 @@ int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype, uint8_t *key) {
|
||||||
|
|
||||||
// Auth
|
// Auth
|
||||||
if (keytype > MF_KEY_B) {
|
if (keytype > MF_KEY_B) {
|
||||||
if (! bd_authenticated) {
|
if (bd_authenticated == false) {
|
||||||
ui64Key = bytes_to_num(key, 6);
|
ui64Key = bytes_to_num(key, 6);
|
||||||
if (mifare_classic_auth(pcs, cuid, 0, keytype, ui64Key, AUTH_FIRST)) {
|
if (mifare_classic_auth(pcs, cuid, 0, keytype, ui64Key, AUTH_FIRST)) {
|
||||||
retval = PM3_EFAILED;
|
retval = PM3_EFAILED;
|
||||||
|
|
@ -2592,7 +2565,7 @@ int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype, uint8_t *key) {
|
||||||
|
|
||||||
#define MAX_RETRIES 2
|
#define MAX_RETRIES 2
|
||||||
|
|
||||||
uint8_t data[16] = {0x00};
|
uint8_t data[MIFARE_BLOCK_SIZE] = {0x00};
|
||||||
for (uint8_t b = 0; b < NumBlocksPerSector(s); b++) {
|
for (uint8_t b = 0; b < NumBlocksPerSector(s); b++) {
|
||||||
|
|
||||||
memset(data, 0x00, sizeof(data));
|
memset(data, 0x00, sizeof(data));
|
||||||
|
|
@ -2614,18 +2587,18 @@ int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype, uint8_t *key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// No need to copy empty
|
// No need to copy empty
|
||||||
if (memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) {
|
if (memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", sizeof(data)) == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsSectorTrailer(b)) {
|
if (IsSectorTrailer(b)) {
|
||||||
// sector trailer, keep the keys, set only the AC
|
// sector trailer, keep the keys, set only the AC
|
||||||
uint8_t st[16] = {0x00};
|
uint8_t st[MIFARE_BLOCK_SIZE] = {0x00};
|
||||||
emlGetMem(st, tb, 1);
|
emlGetMem_xt(st, tb, 1, MIFARE_BLOCK_SIZE);
|
||||||
memcpy(st + 6, data + 6, 4);
|
memcpy(st + 6, data + 6, 4);
|
||||||
emlSetMem_xt(st, tb, 1, 16);
|
emlSetMem_xt(st, tb, 1, MIFARE_BLOCK_SIZE);
|
||||||
} else {
|
} else {
|
||||||
emlSetMem_xt(data, tb, 1, 16);
|
emlSetMem_xt(data, tb, 1, MIFARE_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -2927,7 +2900,6 @@ void MifareCIdent(bool is_mfc, uint8_t keytype, uint8_t *key) {
|
||||||
// variables
|
// variables
|
||||||
uint8_t rec[1] = {0x00};
|
uint8_t rec[1] = {0x00};
|
||||||
uint8_t recpar[1] = {0x00};
|
uint8_t recpar[1] = {0x00};
|
||||||
uint8_t rats[4] = {ISO14443A_CMD_RATS, 0x80, 0x31, 0x73};
|
|
||||||
uint8_t rdblf0[4] = {ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f};
|
uint8_t rdblf0[4] = {ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f};
|
||||||
uint8_t rdbl00[4] = {ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa8};
|
uint8_t rdbl00[4] = {ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa8};
|
||||||
uint8_t gen4gdmAuth[4] = {MIFARE_MAGIC_GDM_AUTH_KEY, 0x00, 0x6C, 0x92};
|
uint8_t gen4gdmAuth[4] = {MIFARE_MAGIC_GDM_AUTH_KEY, 0x00, 0x6C, 0x92};
|
||||||
|
|
@ -2940,6 +2912,8 @@ void MifareCIdent(bool is_mfc, uint8_t keytype, uint8_t *key) {
|
||||||
uint8_t *par = BigBuf_calloc(MAX_PARITY_SIZE);
|
uint8_t *par = BigBuf_calloc(MAX_PARITY_SIZE);
|
||||||
uint8_t *buf = BigBuf_calloc(PM3_CMD_DATA_SIZE);
|
uint8_t *buf = BigBuf_calloc(PM3_CMD_DATA_SIZE);
|
||||||
uint8_t *uid = BigBuf_calloc(10);
|
uint8_t *uid = BigBuf_calloc(10);
|
||||||
|
iso14a_card_select_t *card = (iso14a_card_select_t *) BigBuf_calloc(sizeof(iso14a_card_select_t));
|
||||||
|
|
||||||
uint16_t flag = MAGIC_FLAG_NONE;
|
uint16_t flag = MAGIC_FLAG_NONE;
|
||||||
uint32_t cuid = 0;
|
uint32_t cuid = 0;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
@ -2991,41 +2965,37 @@ void MifareCIdent(bool is_mfc, uint8_t keytype, uint8_t *key) {
|
||||||
// reset card
|
// reset card
|
||||||
mf_reset_card();
|
mf_reset_card();
|
||||||
|
|
||||||
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, false);
|
res = iso14443a_select_card(uid, card, &cuid, true, 0, false);
|
||||||
if (res) {
|
if (res) {
|
||||||
if (cuid == 0xAA55C396) {
|
if (cuid == 0xAA55C396) {
|
||||||
flag |= MAGIC_FLAG_GEN_UNFUSED;
|
flag |= MAGIC_FLAG_GEN_UNFUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReaderTransmit(rats, sizeof(rats), NULL);
|
if (memcmp(card->ats, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10", 9) == 0) {
|
||||||
res = ReaderReceive(buf, PM3_CMD_DATA_SIZE, par);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10", 9) == 0) {
|
|
||||||
// test for some MFC gen2
|
// test for some MFC gen2
|
||||||
isGen2 = true;
|
isGen2 = true;
|
||||||
flag |= MAGIC_FLAG_GEN_2;
|
flag |= MAGIC_FLAG_GEN_2;
|
||||||
} else if (memcmp(buf, "\x0D\x78\x00\x71\x02\x88\x49\xA1\x30\x20\x15\x06\x08\x56\x3D", 15) == 0) {
|
} else if (memcmp(card->ats, "\x0D\x78\x00\x71\x02\x88\x49\xA1\x30\x20\x15\x06\x08\x56\x3D", 15) == 0) {
|
||||||
// test for some MFC 7b gen2
|
// test for some MFC 7b gen2
|
||||||
isGen2 = true;
|
isGen2 = true;
|
||||||
flag |= MAGIC_FLAG_GEN_2;
|
flag |= MAGIC_FLAG_GEN_2;
|
||||||
} else if (memcmp(buf, "\x0A\x78\x00\x81\x02\xDB\xA0\xC1\x19\x40\x2A\xB5", 12) == 0) {
|
} else if (memcmp(card->ats, "\x0A\x78\x00\x81\x02\xDB\xA0\xC1\x19\x40\x2A\xB5", 12) == 0) {
|
||||||
// test for Ultralight magic gen2
|
// test for Ultralight magic gen2
|
||||||
isGen2 = true;
|
isGen2 = true;
|
||||||
flag |= MAGIC_FLAG_GEN_2;
|
flag |= MAGIC_FLAG_GEN_2;
|
||||||
} else if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x41\xDF", 18) == 0) {
|
} else if (memcmp(card->ats, "\x85\x00\x00\xA0\x00\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x41\xDF", 18) == 0) {
|
||||||
// test for Ultralight EV1 magic gen2
|
// test for Ultralight EV1 magic gen2
|
||||||
isGen2 = true;
|
isGen2 = true;
|
||||||
flag |= MAGIC_FLAG_GEN_2;
|
flag |= MAGIC_FLAG_GEN_2;
|
||||||
} else if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x16\xD7", 18) == 0) {
|
} else if (memcmp(card->ats, "\x85\x00\x00\xA0\x0A\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x16\xD7", 18) == 0) {
|
||||||
// test for some other Ultralight EV1 magic gen2
|
// test for some other Ultralight EV1 magic gen2
|
||||||
isGen2 = true;
|
isGen2 = true;
|
||||||
flag |= MAGIC_FLAG_GEN_2;
|
flag |= MAGIC_FLAG_GEN_2;
|
||||||
} else if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xB0\x00\x00\x00\x00\x00\x00\x00\x00\x18\x4D", 18) == 0) {
|
} else if (memcmp(card->ats, "\x85\x00\x00\xA0\x0A\x00\x0A\xB0\x00\x00\x00\x00\x00\x00\x00\x00\x18\x4D", 18) == 0) {
|
||||||
// test for some other Ultralight magic gen2
|
// test for some other Ultralight magic gen2
|
||||||
isGen2 = true;
|
isGen2 = true;
|
||||||
flag |= MAGIC_FLAG_GEN_2;
|
flag |= MAGIC_FLAG_GEN_2;
|
||||||
} else if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xA5\x00\x04\x04\x02\x01\x00\x0F\x03\x79\x0C", 18) == 0) {
|
} else if (memcmp(card->ats, "\x85\x00\x00\xA0\x00\x00\x0A\xA5\x00\x04\x04\x02\x01\x00\x0F\x03\x79\x0C", 18) == 0) {
|
||||||
// test for NTAG213 magic gen2
|
// test for NTAG213 magic gen2
|
||||||
isGen2 = true;
|
isGen2 = true;
|
||||||
flag |= MAGIC_FLAG_GEN_2;
|
flag |= MAGIC_FLAG_GEN_2;
|
||||||
|
|
@ -3064,6 +3034,7 @@ void MifareCIdent(bool is_mfc, uint8_t keytype, uint8_t *key) {
|
||||||
flag |= MAGIC_FLAG_NTAG21X;
|
flag |= MAGIC_FLAG_NTAG21X;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
struct Crypto1State mpcs = {0, 0};
|
struct Crypto1State mpcs = {0, 0};
|
||||||
|
|
@ -3122,13 +3093,13 @@ void MifareCIdent(bool is_mfc, uint8_t keytype, uint8_t *key) {
|
||||||
|
|
||||||
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
|
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
|
||||||
if (res) {
|
if (res) {
|
||||||
|
|
||||||
if (mifare_classic_authex(pcs, cuid, 68, MF_KEY_B, 0x707B11FC1481, AUTH_FIRST, NULL, NULL) == 0) {
|
if (mifare_classic_authex(pcs, cuid, 68, MF_KEY_B, 0x707B11FC1481, AUTH_FIRST, NULL, NULL) == 0) {
|
||||||
flag |= MAGIC_FLAG_QL88;
|
flag |= MAGIC_FLAG_QL88;
|
||||||
}
|
}
|
||||||
crypto1_deinit(pcs);
|
crypto1_deinit(pcs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// GDM alt magic wakeup (20)
|
// GDM alt magic wakeup (20)
|
||||||
ReaderTransmitBitsPar(wupGDM1, 7, NULL, NULL);
|
ReaderTransmitBitsPar(wupGDM1, 7, NULL, NULL);
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,6 @@ void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem);
|
||||||
void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||||
void MifareChkKeys_file(uint8_t *fn);
|
void MifareChkKeys_file(uint8_t *fn);
|
||||||
|
|
||||||
void MifareEMemClr(void);
|
|
||||||
void MifareEMemGet(uint8_t blockno, uint8_t blockcnt);
|
|
||||||
int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype, uint8_t *key);
|
int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype, uint8_t *key);
|
||||||
int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype, uint8_t *key);
|
int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype, uint8_t *key);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,8 @@
|
||||||
#include "parity.h"
|
#include "parity.h"
|
||||||
|
|
||||||
static bool IsKeyBReadable(uint8_t blockNo) {
|
static bool IsKeyBReadable(uint8_t blockNo) {
|
||||||
uint8_t sector_trailer[16];
|
uint8_t sector_trailer[MIFARE_BLOCK_SIZE] = {0};
|
||||||
emlGetMem(sector_trailer, SectorTrailer(blockNo), 1);
|
emlGetMem_xt(sector_trailer, SectorTrailer(blockNo), 1, MIFARE_BLOCK_SIZE);
|
||||||
uint8_t AC = ((sector_trailer[7] >> 5) & 0x04)
|
uint8_t AC = ((sector_trailer[7] >> 5) & 0x04)
|
||||||
| ((sector_trailer[8] >> 2) & 0x02)
|
| ((sector_trailer[8] >> 2) & 0x02)
|
||||||
| ((sector_trailer[8] >> 7) & 0x01);
|
| ((sector_trailer[8] >> 7) & 0x01);
|
||||||
|
|
@ -57,55 +57,64 @@ static bool IsKeyBReadable(uint8_t blockNo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
|
static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
|
||||||
uint8_t sector_trailer[16];
|
uint8_t sector_trailer[MIFARE_BLOCK_SIZE] = {0};
|
||||||
emlGetMem(sector_trailer, blockNo, 1);
|
emlGetMem_xt(sector_trailer, blockNo, 1, MIFARE_BLOCK_SIZE);
|
||||||
|
|
||||||
uint8_t AC = ((sector_trailer[7] >> 5) & 0x04)
|
uint8_t AC = ((sector_trailer[7] >> 5) & 0x04)
|
||||||
| ((sector_trailer[8] >> 2) & 0x02)
|
| ((sector_trailer[8] >> 2) & 0x02)
|
||||||
| ((sector_trailer[8] >> 7) & 0x01);
|
| ((sector_trailer[8] >> 7) & 0x01);
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case AC_KEYA_READ: {
|
case AC_KEYA_READ: {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsTrailerAccessAllowed: AC_KEYA_READ");
|
Dbprintf("IsTrailerAccessAllowed: AC_KEYA_READ");
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case AC_KEYA_WRITE: {
|
case AC_KEYA_WRITE: {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsTrailerAccessAllowed: AC_KEYA_WRITE");
|
Dbprintf("IsTrailerAccessAllowed: AC_KEYA_WRITE");
|
||||||
|
}
|
||||||
return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01))
|
return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01))
|
||||||
|| (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03)));
|
|| (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03)));
|
||||||
}
|
}
|
||||||
case AC_KEYB_READ: {
|
case AC_KEYB_READ: {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsTrailerAccessAllowed: AC_KEYB_READ");
|
Dbprintf("IsTrailerAccessAllowed: AC_KEYB_READ");
|
||||||
|
}
|
||||||
return (keytype == AUTHKEYA && (AC == 0x00 || AC == 0x02 || AC == 0x01));
|
return (keytype == AUTHKEYA && (AC == 0x00 || AC == 0x02 || AC == 0x01));
|
||||||
}
|
}
|
||||||
case AC_KEYB_WRITE: {
|
case AC_KEYB_WRITE: {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsTrailerAccessAllowed: AC_KEYB_WRITE");
|
Dbprintf("IsTrailerAccessAllowed: AC_KEYB_WRITE");
|
||||||
|
}
|
||||||
return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01))
|
return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01))
|
||||||
|| (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03)));
|
|| (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03)));
|
||||||
}
|
}
|
||||||
case AC_AC_READ: {
|
case AC_AC_READ: {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsTrailerAccessAllowed: AC_AC_READ");
|
Dbprintf("IsTrailerAccessAllowed: AC_AC_READ");
|
||||||
|
}
|
||||||
return ((keytype == AUTHKEYA)
|
return ((keytype == AUTHKEYA)
|
||||||
|| (keytype == AUTHKEYB && !(AC == 0x00 || AC == 0x02 || AC == 0x01)));
|
|| (keytype == AUTHKEYB && !(AC == 0x00 || AC == 0x02 || AC == 0x01)));
|
||||||
}
|
}
|
||||||
case AC_AC_WRITE: {
|
case AC_AC_WRITE: {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsTrailerAccessAllowed: AC_AC_WRITE");
|
Dbprintf("IsTrailerAccessAllowed: AC_AC_WRITE");
|
||||||
|
}
|
||||||
return ((keytype == AUTHKEYA && (AC == 0x01))
|
return ((keytype == AUTHKEYA && (AC == 0x01))
|
||||||
|| (keytype == AUTHKEYB && (AC == 0x03 || AC == 0x05)));
|
|| (keytype == AUTHKEYB && (AC == 0x03 || AC == 0x05)));
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsDataAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
|
static bool IsDataAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
|
||||||
|
|
||||||
uint8_t sector_trailer[16];
|
uint8_t sector_trailer[MIFARE_BLOCK_SIZE] = {0};
|
||||||
emlGetMem(sector_trailer, SectorTrailer(blockNo), 1);
|
emlGetMem_xt(sector_trailer, SectorTrailer(blockNo), 1, MIFARE_BLOCK_SIZE);
|
||||||
|
|
||||||
uint8_t sector_block;
|
uint8_t sector_block;
|
||||||
if (blockNo <= MIFARE_2K_MAXBLOCK) {
|
if (blockNo <= MIFARE_2K_MAXBLOCK) {
|
||||||
|
|
@ -120,54 +129,62 @@ static bool IsDataAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action
|
||||||
AC = ((sector_trailer[7] >> 2) & 0x04)
|
AC = ((sector_trailer[7] >> 2) & 0x04)
|
||||||
| ((sector_trailer[8] << 1) & 0x02)
|
| ((sector_trailer[8] << 1) & 0x02)
|
||||||
| ((sector_trailer[8] >> 4) & 0x01);
|
| ((sector_trailer[8] >> 4) & 0x01);
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsDataAccessAllowed: case 0x00 - %02x", AC);
|
Dbprintf("IsDataAccessAllowed: case 0x00 - %02x", AC);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x01: {
|
case 0x01: {
|
||||||
AC = ((sector_trailer[7] >> 3) & 0x04)
|
AC = ((sector_trailer[7] >> 3) & 0x04)
|
||||||
| ((sector_trailer[8] >> 0) & 0x02)
|
| ((sector_trailer[8] >> 0) & 0x02)
|
||||||
| ((sector_trailer[8] >> 5) & 0x01);
|
| ((sector_trailer[8] >> 5) & 0x01);
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsDataAccessAllowed: case 0x01 - %02x", AC);
|
Dbprintf("IsDataAccessAllowed: case 0x01 - %02x", AC);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x02: {
|
case 0x02: {
|
||||||
AC = ((sector_trailer[7] >> 4) & 0x04)
|
AC = ((sector_trailer[7] >> 4) & 0x04)
|
||||||
| ((sector_trailer[8] >> 1) & 0x02)
|
| ((sector_trailer[8] >> 1) & 0x02)
|
||||||
| ((sector_trailer[8] >> 6) & 0x01);
|
| ((sector_trailer[8] >> 6) & 0x01);
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsDataAccessAllowed: case 0x02 - %02x", AC);
|
Dbprintf("IsDataAccessAllowed: case 0x02 - %02x", AC);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsDataAccessAllowed: Error");
|
Dbprintf("IsDataAccessAllowed: Error");
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case AC_DATA_READ: {
|
case AC_DATA_READ: {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsDataAccessAllowed - AC_DATA_READ: OK");
|
Dbprintf("IsDataAccessAllowed - AC_DATA_READ: OK");
|
||||||
|
}
|
||||||
return ((keytype == AUTHKEYA && !(AC == 0x03 || AC == 0x05 || AC == 0x07))
|
return ((keytype == AUTHKEYA && !(AC == 0x03 || AC == 0x05 || AC == 0x07))
|
||||||
|| (keytype == AUTHKEYB && !(AC == 0x07)));
|
|| (keytype == AUTHKEYB && !(AC == 0x07)));
|
||||||
}
|
}
|
||||||
case AC_DATA_WRITE: {
|
case AC_DATA_WRITE: {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsDataAccessAllowed - AC_DATA_WRITE: OK");
|
Dbprintf("IsDataAccessAllowed - AC_DATA_WRITE: OK");
|
||||||
|
}
|
||||||
return ((keytype == AUTHKEYA && (AC == 0x00))
|
return ((keytype == AUTHKEYA && (AC == 0x00))
|
||||||
|| (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03)));
|
|| (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03)));
|
||||||
}
|
}
|
||||||
case AC_DATA_INC: {
|
case AC_DATA_INC: {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("IsDataAccessAllowed - AC_DATA_INC: OK");
|
Dbprintf("IsDataAccessAllowed - AC_DATA_INC: OK");
|
||||||
|
}
|
||||||
return ((keytype == AUTHKEYA && (AC == 0x00))
|
return ((keytype == AUTHKEYA && (AC == 0x00))
|
||||||
|| (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06)));
|
|| (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06)));
|
||||||
}
|
}
|
||||||
case AC_DATA_DEC_TRANS_REST: {
|
case AC_DATA_DEC_TRANS_REST: {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("AC_DATA_DEC_TRANS_REST: OK");
|
Dbprintf("AC_DATA_DEC_TRANS_REST: OK");
|
||||||
|
}
|
||||||
return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x06 || AC == 0x01))
|
return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x06 || AC == 0x01))
|
||||||
|| (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06 || AC == 0x01)));
|
|| (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06 || AC == 0x01)));
|
||||||
}
|
}
|
||||||
|
|
@ -252,29 +269,33 @@ bool MifareSimInit(uint16_t flags, uint8_t *uid, uint16_t atqa, uint8_t sak, tag
|
||||||
// Length: 4,7,or 10 bytes
|
// Length: 4,7,or 10 bytes
|
||||||
|
|
||||||
if (IS_FLAG_UID_IN_EMUL(flags)) {
|
if (IS_FLAG_UID_IN_EMUL(flags)) {
|
||||||
|
|
||||||
if (uid == NULL) {
|
if (uid == NULL) {
|
||||||
uid = uid_tmp;
|
uid = uid_tmp;
|
||||||
}
|
}
|
||||||
// Get UID, SAK, ATQA from EMUL
|
// Get UID, SAK, ATQA from EMUL
|
||||||
uint8_t block0[16];
|
uint8_t block0[MIFARE_BLOCK_SIZE];
|
||||||
emlGet(block0, 0, 16);
|
emlGet(block0, 0, MIFARE_BLOCK_SIZE);
|
||||||
|
|
||||||
// Check for 4 bytes uid: bcc corrected and single size uid bits in ATQA
|
// Check for 4 bytes uid: bcc corrected and single size uid bits in ATQA
|
||||||
if ((block0[0] ^ block0[1] ^ block0[2] ^ block0[3]) == block0[4] && (block0[6] & 0xc0) == 0) {
|
if ((block0[0] ^ block0[1] ^ block0[2] ^ block0[3]) == block0[4] && (block0[6] & 0xc0) == 0) {
|
||||||
FLAG_SET_UID_IN_DATA(flags, 4);
|
FLAG_SET_UID_IN_DATA(flags, 4);
|
||||||
memcpy(uid, block0, 4);
|
memcpy(uid, block0, 4);
|
||||||
rSAK[0] = block0[5];
|
rSAK[0] = block0[5];
|
||||||
memcpy(rATQA, &block0[6], sizeof(rATQA));
|
memcpy(rATQA, &block0[6], sizeof(rATQA));
|
||||||
}
|
|
||||||
|
} else if ((block0[8] & 0xc0) == 0x40) {
|
||||||
// Check for 7 bytes UID: double size uid bits in ATQA
|
// Check for 7 bytes UID: double size uid bits in ATQA
|
||||||
else if ((block0[8] & 0xc0) == 0x40) {
|
|
||||||
FLAG_SET_UID_IN_DATA(flags, 7);
|
FLAG_SET_UID_IN_DATA(flags, 7);
|
||||||
memcpy(uid, block0, 7);
|
memcpy(uid, block0, 7);
|
||||||
rSAK[0] = block0[7];
|
rSAK[0] = block0[7];
|
||||||
memcpy(rATQA, &block0[8], sizeof(rATQA));
|
memcpy(rATQA, &block0[8], sizeof(rATQA));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Dbprintf("ERROR: " _RED_("Invalid dump. UID/SAK/ATQA not found"));
|
Dbprintf("ERROR: " _RED_("Invalid dump. UID/SAK/ATQA not found"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (uid == NULL) {
|
if (uid == NULL) {
|
||||||
Dbprintf("ERROR: " _RED_("Missing UID"));
|
Dbprintf("ERROR: " _RED_("Missing UID"));
|
||||||
|
|
@ -288,16 +309,19 @@ bool MifareSimInit(uint16_t flags, uint8_t *uid, uint16_t atqa, uint8_t sak, tag
|
||||||
memcpy(rATQA, rATQA_Mini, sizeof(rATQA));
|
memcpy(rATQA, rATQA_Mini, sizeof(rATQA));
|
||||||
rSAK[0] = rSAK_Mini;
|
rSAK[0] = rSAK_Mini;
|
||||||
if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare Mini ATQA/SAK");
|
if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare Mini ATQA/SAK");
|
||||||
|
|
||||||
} else if (IS_FLAG_MF_SIZE(flags, MIFARE_1K_MAX_BYTES)) {
|
} else if (IS_FLAG_MF_SIZE(flags, MIFARE_1K_MAX_BYTES)) {
|
||||||
memcpy(rATQA, rATQA_1k, sizeof(rATQA));
|
memcpy(rATQA, rATQA_1k, sizeof(rATQA));
|
||||||
rSAK[0] = rSAK_1k;
|
rSAK[0] = rSAK_1k;
|
||||||
if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare 1K ATQA/SAK");
|
if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare 1K ATQA/SAK");
|
||||||
|
|
||||||
} else if (IS_FLAG_MF_SIZE(flags, MIFARE_2K_MAX_BYTES)) {
|
} else if (IS_FLAG_MF_SIZE(flags, MIFARE_2K_MAX_BYTES)) {
|
||||||
memcpy(rATQA, rATQA_2k, sizeof(rATQA));
|
memcpy(rATQA, rATQA_2k, sizeof(rATQA));
|
||||||
rSAK[0] = rSAK_2k;
|
rSAK[0] = rSAK_2k;
|
||||||
*rats = rRATS;
|
*rats = rRATS;
|
||||||
*rats_len = sizeof(rRATS);
|
*rats_len = sizeof(rRATS);
|
||||||
if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare 2K ATQA/SAK with RATS support");
|
if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare 2K ATQA/SAK with RATS support");
|
||||||
|
|
||||||
} else if (IS_FLAG_MF_SIZE(flags, MIFARE_4K_MAX_BYTES)) {
|
} else if (IS_FLAG_MF_SIZE(flags, MIFARE_4K_MAX_BYTES)) {
|
||||||
memcpy(rATQA, rATQA_4k, sizeof(rATQA));
|
memcpy(rATQA, rATQA_4k, sizeof(rATQA));
|
||||||
rSAK[0] = rSAK_4k;
|
rSAK[0] = rSAK_4k;
|
||||||
|
|
@ -825,8 +849,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t
|
||||||
// if key not known and FLAG_NESTED_AUTH_ATTACK and we have nt/nt_enc/parity, send recorded nt_enc and parity
|
// if key not known and FLAG_NESTED_AUTH_ATTACK and we have nt/nt_enc/parity, send recorded nt_enc and parity
|
||||||
if ((flags & FLAG_NESTED_AUTH_ATTACK) == FLAG_NESTED_AUTH_ATTACK) {
|
if ((flags & FLAG_NESTED_AUTH_ATTACK) == FLAG_NESTED_AUTH_ATTACK) {
|
||||||
if (emlGetKey(cardAUTHSC, cardAUTHKEY) == 0) {
|
if (emlGetKey(cardAUTHSC, cardAUTHKEY) == 0) {
|
||||||
uint8_t buf[16] = {0};
|
uint8_t buf[MIFARE_BLOCK_SIZE] = {0};
|
||||||
emlGetMem(buf, (CARD_MEMORY_RF08S_OFFSET / MIFARE_BLOCK_SIZE) + cardAUTHSC, 1);
|
emlGetMem_xt(buf, (CARD_MEMORY_RF08S_OFFSET / MIFARE_BLOCK_SIZE) + cardAUTHSC, 1, MIFARE_BLOCK_SIZE);
|
||||||
if (buf[(cardAUTHKEY * 8) + 3] == 0xAA) { // extra check to tell we have nt/nt_enc/par_err
|
if (buf[(cardAUTHKEY * 8) + 3] == 0xAA) { // extra check to tell we have nt/nt_enc/par_err
|
||||||
running_nested_auth_attack = true;
|
running_nested_auth_attack = true;
|
||||||
// nt
|
// nt
|
||||||
|
|
@ -955,7 +979,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t
|
||||||
// first block
|
// first block
|
||||||
if (blockNo == 4) {
|
if (blockNo == 4) {
|
||||||
|
|
||||||
p_em += blockNo * 16;
|
p_em += (blockNo * MIFARE_BLOCK_SIZE);
|
||||||
// TLV in NDEF, flip length between
|
// TLV in NDEF, flip length between
|
||||||
// 4 | 03 21 D1 02 1C 53 70 91 01 09 54 02 65 6E 4C 69
|
// 4 | 03 21 D1 02 1C 53 70 91 01 09 54 02 65 6E 4C 69
|
||||||
// 0xFF means long length
|
// 0xFF means long length
|
||||||
|
|
@ -970,7 +994,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emlGetMem(response, blockNo, 1);
|
emlGetMem_xt(response, blockNo, 1, MIFARE_BLOCK_SIZE);
|
||||||
|
|
||||||
if (g_dbglevel >= DBG_EXTENDED) {
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("[MFEMUL_WORK - ISO14443A_CMD_READBLOCK] Data Block[%d]: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", blockNo,
|
Dbprintf("[MFEMUL_WORK - ISO14443A_CMD_READBLOCK] Data Block[%d]: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", blockNo,
|
||||||
|
|
@ -1010,11 +1034,11 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (IsAccessAllowed(blockNo, cardAUTHKEY, AC_DATA_READ) == false) {
|
if (IsAccessAllowed(blockNo, cardAUTHKEY, AC_DATA_READ) == false) {
|
||||||
memset(response, 0x00, 16); // datablock cannot be read
|
memset(response, 0x00, MIFARE_BLOCK_SIZE); // datablock cannot be read
|
||||||
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsAccessAllowed] Data block %d (0x%02x) cannot be read", blockNo, blockNo);
|
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsAccessAllowed] Data block %d (0x%02x) cannot be read", blockNo, blockNo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AddCrc14A(response, 16);
|
AddCrc14A(response, MIFARE_BLOCK_SIZE);
|
||||||
mf_crypto1_encrypt(pcs, response, MAX_MIFARE_FRAME_SIZE, response_par);
|
mf_crypto1_encrypt(pcs, response, MAX_MIFARE_FRAME_SIZE, response_par);
|
||||||
EmSendCmdPar(response, MAX_MIFARE_FRAME_SIZE, response_par);
|
EmSendCmdPar(response, MAX_MIFARE_FRAME_SIZE, response_par);
|
||||||
FpgaDisableTracing();
|
FpgaDisableTracing();
|
||||||
|
|
@ -1109,7 +1133,9 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t
|
||||||
|
|
||||||
// case MFEMUL_WORK => CMD RATS
|
// case MFEMUL_WORK => CMD RATS
|
||||||
if (receivedCmd_len == 4 && receivedCmd_dec[0] == ISO14443A_CMD_RATS && (receivedCmd_dec[1] & 0xF0) <= 0x80 && (receivedCmd_dec[1] & 0x0F) <= 0x0e) {
|
if (receivedCmd_len == 4 && receivedCmd_dec[0] == ISO14443A_CMD_RATS && (receivedCmd_dec[1] & 0xF0) <= 0x80 && (receivedCmd_dec[1] & 0x0F) <= 0x0e) {
|
||||||
|
|
||||||
if (rats && rats_len) {
|
if (rats && rats_len) {
|
||||||
|
|
||||||
if (encrypted_data) {
|
if (encrypted_data) {
|
||||||
memcpy(response, rats, rats_len);
|
memcpy(response, rats, rats_len);
|
||||||
mf_crypto1_encrypt(pcs, response, rats_len, response_par);
|
mf_crypto1_encrypt(pcs, response, rats_len, response_par);
|
||||||
|
|
@ -1117,46 +1143,58 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t
|
||||||
} else {
|
} else {
|
||||||
EmSendCmd(rats, rats_len);
|
EmSendCmd(rats, rats_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
FpgaDisableTracing();
|
FpgaDisableTracing();
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
|
||||||
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("[MFEMUL_WORK] RCV RATS => ACK");
|
Dbprintf("[MFEMUL_WORK] RCV RATS => ACK");
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
|
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
|
||||||
FpgaDisableTracing();
|
FpgaDisableTracing();
|
||||||
cardSTATE_TO_IDLE();
|
cardSTATE_TO_IDLE();
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("[MFEMUL_WORK] RCV RATS => NACK");
|
Dbprintf("[MFEMUL_WORK] RCV RATS => NACK");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// case MFEMUL_WORK => ISO14443A_CMD_NXP_DESELECT
|
// case MFEMUL_WORK => ISO14443A_CMD_NXP_DESELECT
|
||||||
if (receivedCmd_len == 3 && receivedCmd_dec[0] == ISO14443A_CMD_NXP_DESELECT) {
|
if (receivedCmd_len == 3 && receivedCmd_dec[0] == ISO14443A_CMD_NXP_DESELECT) {
|
||||||
|
|
||||||
if (rats && rats_len) {
|
if (rats && rats_len) {
|
||||||
|
|
||||||
// response back NXP_DESELECT
|
// response back NXP_DESELECT
|
||||||
if (encrypted_data) {
|
if (encrypted_data) {
|
||||||
memcpy(response, receivedCmd_dec, receivedCmd_len);
|
memcpy(response, receivedCmd_dec, receivedCmd_len);
|
||||||
mf_crypto1_encrypt(pcs, response, receivedCmd_len, response_par);
|
mf_crypto1_encrypt(pcs, response, receivedCmd_len, response_par);
|
||||||
EmSendCmdPar(response, receivedCmd_len, response_par);
|
EmSendCmdPar(response, receivedCmd_len, response_par);
|
||||||
} else
|
} else {
|
||||||
EmSendCmd(receivedCmd_dec, receivedCmd_len);
|
EmSendCmd(receivedCmd_dec, receivedCmd_len);
|
||||||
|
}
|
||||||
|
|
||||||
FpgaDisableTracing();
|
FpgaDisableTracing();
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => ACK");
|
Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => ACK");
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
|
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
|
||||||
FpgaDisableTracing();
|
FpgaDisableTracing();
|
||||||
cardSTATE_TO_IDLE();
|
cardSTATE_TO_IDLE();
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => NACK");
|
Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => NACK");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// case MFEMUL_WORK => command not allowed
|
// case MFEMUL_WORK => command not allowed
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("Received command not allowed, nacking");
|
Dbprintf("Received command not allowed, nacking");
|
||||||
|
}
|
||||||
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
|
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
|
||||||
FpgaDisableTracing();
|
FpgaDisableTracing();
|
||||||
break;
|
break;
|
||||||
|
|
@ -1164,14 +1202,16 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t
|
||||||
|
|
||||||
// AUTH1
|
// AUTH1
|
||||||
case MFEMUL_AUTH1: {
|
case MFEMUL_AUTH1: {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("[MFEMUL_AUTH1] Enter case");
|
Dbprintf("[MFEMUL_AUTH1] Enter case");
|
||||||
|
}
|
||||||
|
|
||||||
if (receivedCmd_len != 8) {
|
if (receivedCmd_len != 8) {
|
||||||
cardSTATE_TO_IDLE();
|
cardSTATE_TO_IDLE();
|
||||||
LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true);
|
LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true);
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED) {
|
||||||
Dbprintf("MFEMUL_AUTH1: receivedCmd_len != 8 (%d) => cardSTATE_TO_IDLE())", receivedCmd_len);
|
Dbprintf("MFEMUL_AUTH1: receivedCmd_len != 8 (%d) => cardSTATE_TO_IDLE())", receivedCmd_len);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1191,6 +1231,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t
|
||||||
ar_nr_resp[0].state = NESTED;
|
ar_nr_resp[0].state = NESTED;
|
||||||
finished = true;
|
finished = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) {
|
if ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) {
|
||||||
|
|
||||||
for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) {
|
for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) {
|
||||||
|
|
@ -1267,22 +1308,29 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t
|
||||||
|
|
||||||
// WRITE BL2
|
// WRITE BL2
|
||||||
case MFEMUL_WRITEBL2: {
|
case MFEMUL_WRITEBL2: {
|
||||||
|
|
||||||
if (receivedCmd_len == MAX_MIFARE_FRAME_SIZE) {
|
if (receivedCmd_len == MAX_MIFARE_FRAME_SIZE) {
|
||||||
|
|
||||||
mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, receivedCmd_dec);
|
mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, receivedCmd_dec);
|
||||||
|
|
||||||
if (CheckCrc14A(receivedCmd_dec, receivedCmd_len)) {
|
if (CheckCrc14A(receivedCmd_dec, receivedCmd_len)) {
|
||||||
|
|
||||||
if (IsSectorTrailer(cardWRBL)) {
|
if (IsSectorTrailer(cardWRBL)) {
|
||||||
emlGetMem(response, cardWRBL, 1);
|
|
||||||
if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_KEYA_WRITE)) {
|
emlGetMem_xt(response, cardWRBL, 1, MIFARE_BLOCK_SIZE);
|
||||||
|
|
||||||
|
if (IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_KEYA_WRITE) == false) {
|
||||||
memcpy(receivedCmd_dec, response, 6); // don't change KeyA
|
memcpy(receivedCmd_dec, response, 6); // don't change KeyA
|
||||||
}
|
}
|
||||||
if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_KEYB_WRITE)) {
|
if (IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_KEYB_WRITE) == false) {
|
||||||
memcpy(receivedCmd_dec + 10, response + 10, 6); // don't change KeyA
|
memcpy(receivedCmd_dec + 10, response + 10, 6); // don't change KeyA
|
||||||
}
|
}
|
||||||
if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_AC_WRITE)) {
|
if (IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_AC_WRITE) == false) {
|
||||||
memcpy(receivedCmd_dec + 6, response + 6, 4); // don't change AC bits
|
memcpy(receivedCmd_dec + 6, response + 6, 4); // don't change AC bits
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_DATA_WRITE)) {
|
if (IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_DATA_WRITE) == false) {
|
||||||
memcpy(receivedCmd_dec, response, 16); // don't change anything
|
memcpy(receivedCmd_dec, response, 16); // don't change anything
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -756,14 +756,16 @@ uint8_t FirstBlockOfSector(uint8_t sectorNo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// work with emulator memory
|
// work with emulator memory
|
||||||
void emlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int block_width) {
|
void emlSetMem_xt(uint8_t *data, uint16_t blockNum, uint8_t blocksCount, uint8_t block_width) {
|
||||||
uint32_t offset = blockNum * block_width;
|
uint32_t offset = blockNum * block_width;
|
||||||
uint32_t len = blocksCount * block_width;
|
uint32_t len = blocksCount * block_width;
|
||||||
emlSet(data, offset, len);
|
emlSet(data, offset, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void emlGetMem(uint8_t *data, int blockNum, int blocksCount) {
|
void emlGetMem_xt(uint8_t *data, uint16_t blockNum, uint8_t blocksCount, uint8_t block_width) {
|
||||||
emlGet(data, (blockNum * 16), (blocksCount * 16));
|
uint32_t offset = blockNum * block_width;
|
||||||
|
uint32_t len = blocksCount * block_width;
|
||||||
|
emlGet(data, offset, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emlCheckValBl(int blockNum) {
|
bool emlCheckValBl(int blockNum) {
|
||||||
|
|
@ -817,10 +819,11 @@ uint64_t emlGetKey(int sectorNum, int keyType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void emlClearMem(void) {
|
void emlClearMem(void) {
|
||||||
|
|
||||||
|
BigBuf_Clear_EM();
|
||||||
|
|
||||||
const uint8_t trailer[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x80, 0x69, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
const uint8_t trailer[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x80, 0x69, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||||
const uint8_t uid[] = {0xe6, 0x84, 0x87, 0xf3, 0x16, 0x88, 0x04, 0x00, 0x46, 0x8e, 0x45, 0x55, 0x4d, 0x70, 0x41, 0x04};
|
const uint8_t uid[] = {0xe6, 0x84, 0x87, 0xf3, 0x16, 0x88, 0x04, 0x00, 0x46, 0x8e, 0x45, 0x55, 0x4d, 0x70, 0x41, 0x04};
|
||||||
uint8_t *mem = BigBuf_get_EM_addr();
|
|
||||||
memset(mem, 0, CARD_MEMORY_SIZE);
|
|
||||||
|
|
||||||
// fill sectors trailer data
|
// fill sectors trailer data
|
||||||
for (uint16_t b = 3; b < MIFARE_4K_MAXBLOCK; ((b < MIFARE_2K_MAXBLOCK - 4) ? (b += 4) : (b += 16))) {
|
for (uint16_t b = 3; b < MIFARE_4K_MAXBLOCK; ((b < MIFARE_2K_MAXBLOCK - 4) ? (b += 4) : (b += 16))) {
|
||||||
|
|
|
||||||
|
|
@ -131,8 +131,9 @@ uint8_t SectorTrailer(uint8_t blockNo);
|
||||||
|
|
||||||
// emulator functions
|
// emulator functions
|
||||||
void emlClearMem(void);
|
void emlClearMem(void);
|
||||||
void emlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int block_width);
|
void emlSetMem_xt(uint8_t *data, uint16_t blockNum, uint8_t blocksCount, uint8_t block_width);
|
||||||
void emlGetMem(uint8_t *data, int blockNum, int blocksCount);
|
void emlGetMem_xt(uint8_t *data, uint16_t blockNum, uint8_t blocksCount, uint8_t block_width);
|
||||||
|
|
||||||
uint64_t emlGetKey(int sectorNum, int keyType);
|
uint64_t emlGetKey(int sectorNum, int keyType);
|
||||||
int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum);
|
int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum);
|
||||||
void emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum);
|
void emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum);
|
||||||
|
|
|
||||||
561
armsrc/pcf7931.c
561
armsrc/pcf7931.c
|
|
@ -28,105 +28,151 @@
|
||||||
#define T0_PCF 8 //period for the pcf7931 in us
|
#define T0_PCF 8 //period for the pcf7931 in us
|
||||||
#define ALLOC 16
|
#define ALLOC 16
|
||||||
|
|
||||||
size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
|
// IIR filter consts
|
||||||
|
#define IIR_CONST1 0.1f
|
||||||
|
#define IIR_CONST2 0.9f
|
||||||
|
|
||||||
// 2021 iceman, memor
|
// used to decimate samples. this allows DoAcquisition to sample for a longer duration.
|
||||||
|
// Decimation of 4 makes sure that all blocks can be sampled at once!
|
||||||
|
#define DECIMATION 4
|
||||||
|
|
||||||
|
#define CLOCK (64/DECIMATION) // this actually is 64, but since samples are decimated by 2, CLOCK is also /2
|
||||||
|
#define TOLERANCE (CLOCK / 8)
|
||||||
|
#define _16T0 (CLOCK/4)
|
||||||
|
#define _32T0 (CLOCK/2)
|
||||||
|
#define _64T0 (CLOCK)
|
||||||
|
|
||||||
|
// calculating the two possible pmc lengths, based on the clock. -4 at the end is to make sure not to increment too far
|
||||||
|
#define PMC_16T0_LEN ((128 + 127 + 16 + 32 + 33 + 16) * CLOCK/64);
|
||||||
|
#define PMC_32T0_LEN ((128 + 127 + 16 + 32 + 33 ) * CLOCK/64);
|
||||||
|
|
||||||
|
// theshold for recognition of positive/negative slope
|
||||||
|
#define THRESHOLD 80
|
||||||
|
|
||||||
|
size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
|
||||||
uint8_t bits[256] = {0x00};
|
uint8_t bits[256] = {0x00};
|
||||||
uint8_t blocks[8][16];
|
uint8_t blocks[8][16];
|
||||||
|
|
||||||
uint8_t *dest = BigBuf_get_addr();
|
uint8_t *dest = BigBuf_get_addr();
|
||||||
|
uint16_t g_GraphTraceLen = BigBuf_max_traceLen();
|
||||||
|
// limit g_GraphTraceLen to a little more than 2 data frames.
|
||||||
|
// To make sure a complete dataframe is in the dataset.
|
||||||
|
// 1 Frame is 16 Byte -> 128byte. at a T0 of 64 -> 8129 Samples per frame.
|
||||||
|
// + PMC -> 384T0 --> 8576 samples required for one block
|
||||||
|
// to make sure that one complete block is definitely being sampled, we need 2 times that
|
||||||
|
// which is ~17.xxx samples. round up. and clamp to this value.
|
||||||
|
|
||||||
int g_GraphTraceLen = BigBuf_max_traceLen();
|
// TODO: Doublecheck why this is being limited? - seems not to be needed.
|
||||||
if (g_GraphTraceLen > 18000) {
|
// g_GraphTraceLen = (g_GraphTraceLen > 18000) ? 18000 : g_GraphTraceLen;
|
||||||
g_GraphTraceLen = 18000;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 2, j, lastval, bitidx, half_switch;
|
|
||||||
int clock = 64;
|
|
||||||
int tolerance = clock / 8;
|
|
||||||
int pmc, block_done;
|
|
||||||
int lc, warnings = 0;
|
|
||||||
size_t num_blocks = 0;
|
|
||||||
int lmin = 64, lmax = 192;
|
|
||||||
uint8_t dir;
|
|
||||||
|
|
||||||
BigBuf_Clear_keep_EM();
|
BigBuf_Clear_keep_EM();
|
||||||
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
||||||
DoAcquisition_default(0, true, ledcontrol);
|
DoAcquisition(DECIMATION, 8, 0, 0, false, 0, 0, 0, ledcontrol);
|
||||||
|
|
||||||
/* Find first local max/min */
|
uint8_t j;
|
||||||
if (dest[1] > dest[0]) {
|
uint8_t half_switch;
|
||||||
while (i < g_GraphTraceLen) {
|
uint8_t bitPos;
|
||||||
if (!(dest[i] > dest[i - 1]) && dest[i] > lmax) {
|
|
||||||
break;
|
uint32_t sample; // to keep track of the current sample that is being analyzed
|
||||||
}
|
uint32_t samplePosLastEdge;
|
||||||
i++;
|
uint32_t samplePosCurrentEdge;
|
||||||
}
|
uint8_t lastClockDuration; // used to store the duration of the last "clock", for decoding. clock may not be the correct term, maybe bit is better. The duration between two edges is meant
|
||||||
dir = 0;
|
uint8_t beforeLastClockDuration; // store the clock duration of the cycle before the last Clock duration. Basically clockduration -2
|
||||||
} else {
|
|
||||||
while (i < g_GraphTraceLen) {
|
|
||||||
if (!(dest[i] < dest[i - 1]) && dest[i] < lmin) {
|
uint8_t block_done;
|
||||||
break;
|
size_t num_blocks = 0;
|
||||||
}
|
EdgeType expectedNextEdge = FALLING; // direction in which the next edge is expected should go.
|
||||||
i++;
|
|
||||||
}
|
|
||||||
dir = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastval = i++;
|
|
||||||
half_switch = 0;
|
half_switch = 0;
|
||||||
pmc = 0;
|
samplePosLastEdge = 0;
|
||||||
block_done = 0;
|
block_done = 0;
|
||||||
|
bitPos = 0;
|
||||||
|
lastClockDuration=0;
|
||||||
|
|
||||||
for (bitidx = 0; i < g_GraphTraceLen; i++) {
|
for (sample = 1 ; sample < g_GraphTraceLen-4; sample++) {
|
||||||
|
// condition is searching for the next edge, in the expected diretion.
|
||||||
|
//todo: without flouz
|
||||||
|
dest[sample] = (uint8_t)(dest[sample-1] * IIR_CONST1 + dest[sample] * IIR_CONST2); // apply IIR filter
|
||||||
|
|
||||||
if ((dest[i - 1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i - 1] < dest[i] && dir == 0 && dest[i] < lmin)) {
|
if ( ((dest[sample] + THRESHOLD) < dest[sample-1] && expectedNextEdge == FALLING ) ||
|
||||||
lc = i - lastval;
|
((dest[sample] - THRESHOLD) > dest[sample-1] && expectedNextEdge == RISING )) {
|
||||||
lastval = i;
|
//okay, next falling/rising edge found
|
||||||
|
|
||||||
// Switch depending on lc length:
|
expectedNextEdge = (expectedNextEdge == FALLING) ? RISING : FALLING; //toggle the next expected edge
|
||||||
// Tolerance is 1/8 of clock rate (arbitrary)
|
samplePosCurrentEdge = sample;
|
||||||
if (ABS(lc - clock / 4) < tolerance) {
|
beforeLastClockDuration = lastClockDuration; // save the previous clock duration for PMC recognition
|
||||||
|
lastClockDuration = samplePosCurrentEdge - samplePosLastEdge;
|
||||||
|
samplePosLastEdge = sample;
|
||||||
|
|
||||||
|
// Dbprintf("%d, %d, edge found, len: %d, nextEdge: %d", sample, dest[sample], lastClockDuration*DECIMATION, expectedNextEdge);
|
||||||
|
|
||||||
|
// Switch depending on lastClockDuration length:
|
||||||
// 16T0
|
// 16T0
|
||||||
if ((i - pmc) == lc) { // 16T0 was previous one
|
if (ABS(lastClockDuration - _16T0) < TOLERANCE) {
|
||||||
|
|
||||||
|
// if the clock before also was 16T0, it is a PMC!
|
||||||
|
if (ABS(beforeLastClockDuration - _16T0) < TOLERANCE) {
|
||||||
// It's a PMC
|
// It's a PMC
|
||||||
i += (128 + 127 + 16 + 32 + 33 + 16) - 1;
|
Dbprintf(_GREEN_("PMC 16T0 FOUND:") " bitPos: %d, sample: %d", bitPos, sample);
|
||||||
lastval = i;
|
sample += PMC_16T0_LEN; // move to the sample after PMC
|
||||||
pmc = 0;
|
|
||||||
|
expectedNextEdge = FALLING;
|
||||||
|
samplePosLastEdge = sample;
|
||||||
block_done = 1;
|
block_done = 1;
|
||||||
} else {
|
|
||||||
pmc = i;
|
|
||||||
}
|
}
|
||||||
} else if (ABS(lc - clock / 2) < tolerance) {
|
|
||||||
// 32TO
|
// 32TO
|
||||||
if ((i - pmc) == lc) { // 16T0 was previous one
|
} else if (ABS(lastClockDuration - _32T0) < TOLERANCE) {
|
||||||
|
// if the clock before also was 16T0, it is a PMC!
|
||||||
|
if (ABS(beforeLastClockDuration - _16T0) < TOLERANCE) {
|
||||||
// It's a PMC !
|
// It's a PMC !
|
||||||
i += (128 + 127 + 16 + 32 + 33) - 1;
|
Dbprintf(_GREEN_("PMC 32T0 FOUND:") " bitPos: %d, sample: %d", bitPos, sample);
|
||||||
lastval = i;
|
|
||||||
pmc = 0;
|
sample += PMC_32T0_LEN; // move to the sample after PMC
|
||||||
|
|
||||||
|
expectedNextEdge = FALLING;
|
||||||
|
samplePosLastEdge = sample;
|
||||||
block_done = 1;
|
block_done = 1;
|
||||||
|
|
||||||
|
// if no pmc, then its a normal bit.
|
||||||
|
// Check if its the second time, the edge changed if yes, then the bit is 0
|
||||||
} else if (half_switch == 1) {
|
} else if (half_switch == 1) {
|
||||||
bits[bitidx++] = 0;
|
bits[bitPos] = 0;
|
||||||
|
// reset the edge counter to 0
|
||||||
half_switch = 0;
|
half_switch = 0;
|
||||||
|
bitPos++;
|
||||||
|
|
||||||
|
// if it is the first time the edge changed. No bit value will be set here, bit if the
|
||||||
|
// edge changes again, it will be. see case above.
|
||||||
} else
|
} else
|
||||||
half_switch++;
|
half_switch++;
|
||||||
} else if (ABS(lc - clock) < tolerance) {
|
|
||||||
// 64TO
|
// 64T0
|
||||||
bits[bitidx++] = 1;
|
} else if (ABS(lastClockDuration - _64T0) < TOLERANCE) {
|
||||||
} else {
|
// this means, bit here is 1
|
||||||
|
bits[bitPos] = 1;
|
||||||
|
bitPos++;
|
||||||
|
|
||||||
// Error
|
// Error
|
||||||
if (++warnings > 10) {
|
} else {
|
||||||
|
// some Error. maybe check tolerances.
|
||||||
|
// likeley to happen in the first block.
|
||||||
|
|
||||||
if (g_dbglevel >= DBG_EXTENDED) {
|
// In an Ideal world, this can be enabled. However, if only bad antenna field, this print will flood the output
|
||||||
Dbprintf("Error: too many detection errors, aborting");
|
// and one might miss some "good" frames.
|
||||||
}
|
//Dbprintf(_RED_("ERROR in demodulation") " Length last clock: %d - check threshold/tolerance/signal. Toss block", lastClockDuration*DECIMATION);
|
||||||
|
|
||||||
return 0;
|
// Toss this block.
|
||||||
}
|
block_done = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block_done == 1) {
|
if (block_done == 1) {
|
||||||
if (bitidx == 128) {
|
// Dbprintf(_YELLOW_("Block Done") " bitPos: %d, sample: %d", bitPos, sample);
|
||||||
|
|
||||||
|
// check if it is a complete block. If bitpos <128, it means that we did not receive
|
||||||
|
// a complete block. E.g. at the first start of a transmission.
|
||||||
|
// only save if a complete block is being received.
|
||||||
|
if (bitPos == 128) {
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
blocks[num_blocks][j] =
|
blocks[num_blocks][j] =
|
||||||
128 * bits[j * 8 + 7] +
|
128 * bits[j * 8 + 7] +
|
||||||
|
|
@ -141,24 +187,25 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
|
||||||
}
|
}
|
||||||
num_blocks++;
|
num_blocks++;
|
||||||
}
|
}
|
||||||
bitidx = 0;
|
// now start over for the next block / first complete block.
|
||||||
|
bitPos = 0;
|
||||||
block_done = 0;
|
block_done = 0;
|
||||||
half_switch = 0;
|
half_switch = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < g_GraphTraceLen) {
|
}else {
|
||||||
dir = (dest[i - 1] > dest[i]) ? 0 : 1;
|
// Dbprintf("%d, %d", sample, dest[sample]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bitidx == 255) {
|
// one block only holds 16byte (=128 bit) and then comes the PMC. so if more bit are found than 129, there must be an issue and PMC has not been identfied...
|
||||||
bitidx = 0;
|
// TODO: not sure what to do in such case...
|
||||||
|
if (bitPos >= 129) {
|
||||||
|
Dbprintf(_RED_("PMC should have been found...") " bitPos: %d, sample: %d", bitPos, sample);
|
||||||
|
bitPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_blocks == 4) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(outBlocks, blocks, 16 * num_blocks);
|
memcpy(outBlocks, blocks, 16 * num_blocks);
|
||||||
return num_blocks;
|
return num_blocks;
|
||||||
}
|
}
|
||||||
|
|
@ -204,25 +251,32 @@ bool IsBlock1PCF7931(const uint8_t *block) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadPCF7931(bool ledcontrol) {
|
void ReadPCF7931(bool ledcontrol) {
|
||||||
|
|
||||||
|
uint8_t maxBlocks = 8; // readable blocks
|
||||||
int found_blocks = 0; // successfully read blocks
|
int found_blocks = 0; // successfully read blocks
|
||||||
int max_blocks = 8; // readable blocks
|
|
||||||
uint8_t memory_blocks[8][17]; // PCF content
|
// TODO: Why 17 byte len? 16 should be good.
|
||||||
uint8_t single_blocks[8][17]; // PFC blocks with unknown position
|
uint8_t memory_blocks[maxBlocks][17]; // PCF content
|
||||||
|
uint8_t single_blocks[maxBlocks][17]; // PFC blocks with unknown position
|
||||||
|
uint8_t tmp_blocks[4][16]; // temporary read buffer
|
||||||
|
|
||||||
int single_blocks_cnt = 0;
|
int single_blocks_cnt = 0;
|
||||||
|
|
||||||
size_t n; // transmitted blocks
|
size_t n; // transmitted blocks
|
||||||
uint8_t tmp_blocks[4][16]; // temporary read buffer
|
|
||||||
|
|
||||||
uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found
|
//uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found
|
||||||
int errors = 0; // error counter
|
int errors = 0; // error counter
|
||||||
int tries = 0; // tries counter
|
int tries = 0; // tries counter
|
||||||
|
|
||||||
|
// reuse lenghts and consts to properly clear
|
||||||
memset(memory_blocks, 0, 8 * 17 * sizeof(uint8_t));
|
memset(memory_blocks, 0, 8 * 17 * sizeof(uint8_t));
|
||||||
memset(single_blocks, 0, 8 * 17 * sizeof(uint8_t));
|
memset(single_blocks, 0, 8 * 17 * sizeof(uint8_t));
|
||||||
|
|
||||||
int i = 0, j = 0;
|
int i = 0;
|
||||||
|
//j = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
Dbprintf("ReadPCF7931() -- Reading Loop ==========");
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
memset(tmp_blocks, 0, 4 * 16 * sizeof(uint8_t));
|
memset(tmp_blocks, 0, 4 * 16 * sizeof(uint8_t));
|
||||||
|
|
@ -232,15 +286,13 @@ void ReadPCF7931(bool ledcontrol) {
|
||||||
|
|
||||||
// exit if no block is received
|
// exit if no block is received
|
||||||
if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) {
|
if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) {
|
||||||
|
|
||||||
if (g_dbglevel >= DBG_INFO)
|
|
||||||
Dbprintf("[!!] Error, no tag or bad tag");
|
Dbprintf("[!!] Error, no tag or bad tag");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// exit if too many errors during reading
|
// exit if too many tries without finding the first block
|
||||||
if (tries > 50 && (2 * errors > tries)) {
|
if (tries > 10) {
|
||||||
|
|
||||||
|
Dbprintf("End after 10 tries");
|
||||||
if (g_dbglevel >= DBG_INFO) {
|
if (g_dbglevel >= DBG_INFO) {
|
||||||
Dbprintf("[!!] Error reading the tag, only partial content");
|
Dbprintf("[!!] Error reading the tag, only partial content");
|
||||||
}
|
}
|
||||||
|
|
@ -248,93 +300,98 @@ void ReadPCF7931(bool ledcontrol) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// our logic breaks if we don't get at least two blocks
|
// This part was not working properly.
|
||||||
if (n < 2) {
|
// So currently the blocks are not being sorted, but at least printed.
|
||||||
// skip if all 0s block or no blocks
|
|
||||||
if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// add block to single blocks list
|
// // our logic breaks if we don't get at least two blocks
|
||||||
if (single_blocks_cnt < max_blocks) {
|
// if (n < 2) {
|
||||||
for (i = 0; i < single_blocks_cnt; ++i) {
|
// // skip if all 0s block or no blocks
|
||||||
if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) {
|
// if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
|
||||||
j = 1;
|
// continue;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (j != 1) {
|
|
||||||
memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16);
|
|
||||||
print_result("got single block", single_blocks[single_blocks_cnt], 16);
|
|
||||||
single_blocks_cnt++;
|
|
||||||
}
|
|
||||||
j = 0;
|
|
||||||
}
|
|
||||||
++tries;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
// // add block to single blocks list
|
||||||
Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors);
|
// if (single_blocks_cnt < maxBlocks) {
|
||||||
|
// for (i = 0; i < single_blocks_cnt; ++i) {
|
||||||
|
// if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) {
|
||||||
|
// j = 1;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (j != 1) {
|
||||||
|
// memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16);
|
||||||
|
// print_result("got single block", single_blocks[single_blocks_cnt], 16);
|
||||||
|
// single_blocks_cnt++;
|
||||||
|
// }
|
||||||
|
// j = 0;
|
||||||
|
// }
|
||||||
|
// ++tries;
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (maxBlocks == 0 ? found_blocks : maxBlocks), tries, errors);
|
||||||
|
// if (g_dbglevel >= DBG_EXTENDED)
|
||||||
|
// Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (maxBlocks == 0 ? found_blocks : maxBlocks), tries, errors);
|
||||||
|
|
||||||
|
// print blocks that have been found
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
print_result("got consecutive blocks", tmp_blocks[i], 16);
|
print_result("Block found: ", tmp_blocks[i], 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
i = 0;
|
// i = 0;
|
||||||
if (!found_0_1) {
|
// if (!found_0_1) {
|
||||||
while (i < n - 1) {
|
// while (i < n - 1) {
|
||||||
if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i + 1])) {
|
// if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i + 1])) {
|
||||||
found_0_1 = 1;
|
// found_0_1 = 1;
|
||||||
memcpy(memory_blocks[0], tmp_blocks[i], 16);
|
// memcpy(memory_blocks[0], tmp_blocks[i], 16);
|
||||||
memcpy(memory_blocks[1], tmp_blocks[i + 1], 16);
|
// memcpy(memory_blocks[1], tmp_blocks[i + 1], 16);
|
||||||
memory_blocks[0][ALLOC] = memory_blocks[1][ALLOC] = 1;
|
// memory_blocks[0][ALLOC] = memory_blocks[1][ALLOC] = 1;
|
||||||
// block 1 tells how many blocks are going to be sent
|
// // block 1 tells how many blocks are going to be sent
|
||||||
max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1;
|
// maxBlocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1;
|
||||||
found_blocks = 2;
|
// found_blocks = 2;
|
||||||
|
|
||||||
Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks);
|
// Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", maxBlocks);
|
||||||
|
|
||||||
// handle the following blocks
|
// // handle the following blocks
|
||||||
for (j = i + 2; j < n; ++j) {
|
// for (j = i + 2; j < n; ++j) {
|
||||||
memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16);
|
// memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16);
|
||||||
memory_blocks[found_blocks][ALLOC] = 1;
|
// memory_blocks[found_blocks][ALLOC] = 1;
|
||||||
++found_blocks;
|
// ++found_blocks;
|
||||||
}
|
// }
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
++i;
|
// ++i;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
// Trying to re-order blocks
|
// // Trying to re-order blocks
|
||||||
// Look for identical block in memory blocks
|
// // Look for identical block in memory blocks
|
||||||
while (i < n - 1) {
|
// while (i < n - 1) {
|
||||||
// skip all zeroes blocks
|
// // skip all zeroes blocks
|
||||||
if (memcmp(tmp_blocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) {
|
// if (memcmp(tmp_blocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) {
|
||||||
for (j = 1; j < max_blocks - 1; ++j) {
|
// for (j = 1; j < maxBlocks - 1; ++j) {
|
||||||
if (!memcmp(tmp_blocks[i], memory_blocks[j], 16) && !memory_blocks[j + 1][ALLOC]) {
|
// if (!memcmp(tmp_blocks[i], memory_blocks[j], 16) && !memory_blocks[j + 1][ALLOC]) {
|
||||||
memcpy(memory_blocks[j + 1], tmp_blocks[i + 1], 16);
|
// memcpy(memory_blocks[j + 1], tmp_blocks[i + 1], 16);
|
||||||
memory_blocks[j + 1][ALLOC] = 1;
|
// memory_blocks[j + 1][ALLOC] = 1;
|
||||||
if (++found_blocks >= max_blocks) goto end;
|
// if (++found_blocks >= maxBlocks) goto end;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if (memcmp(tmp_blocks[i + 1], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) {
|
// if (memcmp(tmp_blocks[i + 1], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) {
|
||||||
for (j = 0; j < max_blocks; ++j) {
|
// for (j = 0; j < maxBlocks; ++j) {
|
||||||
if (!memcmp(tmp_blocks[i + 1], memory_blocks[j], 16) && !memory_blocks[(j == 0 ? max_blocks : j) - 1][ALLOC]) {
|
// if (!memcmp(tmp_blocks[i + 1], memory_blocks[j], 16) && !memory_blocks[(j == 0 ? maxBlocks : j) - 1][ALLOC]) {
|
||||||
if (j == 0) {
|
// if (j == 0) {
|
||||||
memcpy(memory_blocks[max_blocks - 1], tmp_blocks[i], 16);
|
// memcpy(memory_blocks[maxBlocks - 1], tmp_blocks[i], 16);
|
||||||
memory_blocks[max_blocks - 1][ALLOC] = 1;
|
// memory_blocks[maxBlocks - 1][ALLOC] = 1;
|
||||||
} else {
|
// } else {
|
||||||
memcpy(memory_blocks[j - 1], tmp_blocks[i], 16);
|
// memcpy(memory_blocks[j - 1], tmp_blocks[i], 16);
|
||||||
memory_blocks[j - 1][ALLOC] = 1;
|
// memory_blocks[j - 1][ALLOC] = 1;
|
||||||
}
|
// }
|
||||||
if (++found_blocks >= max_blocks) goto end;
|
// if (++found_blocks >= maxBlocks) goto end;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
++i;
|
// ++i;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
++tries;
|
++tries;
|
||||||
if (BUTTON_PRESS()) {
|
if (BUTTON_PRESS()) {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED)
|
||||||
|
|
@ -342,13 +399,15 @@ void ReadPCF7931(bool ledcontrol) {
|
||||||
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
} while (found_blocks < max_blocks);
|
} while (found_blocks < maxBlocks);
|
||||||
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
/*
|
||||||
Dbprintf("-----------------------------------------");
|
Dbprintf("-----------------------------------------");
|
||||||
Dbprintf("Memory content:");
|
Dbprintf("Memory content:");
|
||||||
Dbprintf("-----------------------------------------");
|
Dbprintf("-----------------------------------------");
|
||||||
for (i = 0; i < max_blocks; ++i) {
|
for (i = 0; i < maxBlocks; ++i) {
|
||||||
if (memory_blocks[i][ALLOC])
|
if (memory_blocks[i][ALLOC])
|
||||||
print_result("Block", memory_blocks[i], 16);
|
print_result("Block", memory_blocks[i], 16);
|
||||||
else
|
else
|
||||||
|
|
@ -356,7 +415,7 @@ end:
|
||||||
}
|
}
|
||||||
Dbprintf("-----------------------------------------");
|
Dbprintf("-----------------------------------------");
|
||||||
|
|
||||||
if (found_blocks < max_blocks) {
|
if (found_blocks < maxBlocks) {
|
||||||
Dbprintf("-----------------------------------------");
|
Dbprintf("-----------------------------------------");
|
||||||
Dbprintf("Blocks with unknown position:");
|
Dbprintf("Blocks with unknown position:");
|
||||||
Dbprintf("-----------------------------------------");
|
Dbprintf("-----------------------------------------");
|
||||||
|
|
@ -365,39 +424,54 @@ end:
|
||||||
|
|
||||||
Dbprintf("-----------------------------------------");
|
Dbprintf("-----------------------------------------");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
|
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data, bool ledcontrol) {
|
static void RealWritePCF7931(
|
||||||
|
uint8_t *pass,
|
||||||
|
uint16_t init_delay,
|
||||||
|
int8_t offsetPulseWidth, int8_t offsetPulsePosition,
|
||||||
|
uint8_t address, uint8_t byte, uint8_t data,
|
||||||
|
bool ledcontrol){
|
||||||
|
|
||||||
uint32_t tab[1024] = {0}; // data times frame
|
uint32_t tab[1024] = {0}; // data times frame
|
||||||
uint32_t u = 0;
|
uint32_t u = 0;
|
||||||
uint8_t parity = 0;
|
uint8_t parity = 0;
|
||||||
bool comp = 0;
|
|
||||||
|
|
||||||
//BUILD OF THE DATA FRAME
|
//BUILD OF THE DATA FRAME
|
||||||
//alimentation of the tag (time for initializing)
|
//alimentation of the tag (time for initializing)
|
||||||
|
// ToDo: This could be optimized/automated. e.g. Read one cycle, find PMC and calculate time.
|
||||||
|
// I dont understand, why 8192/2
|
||||||
AddPatternPCF7931(init_delay, 0, 8192 / 2 * T0_PCF, tab);
|
AddPatternPCF7931(init_delay, 0, 8192 / 2 * T0_PCF, tab);
|
||||||
|
|
||||||
|
// why "... + 70"? Why not "... + x * T0"?
|
||||||
|
// I think he just added 70 to be somewhere in The PMC window, which is 32T0 (=32*8 = 256)
|
||||||
|
// 3*T0 = PMC width
|
||||||
|
// 29*T0 = rest of PMC window (total 32T0 = 3+29)
|
||||||
|
// after the PMC, it directly goes to the password indication bit.
|
||||||
AddPatternPCF7931(8192 / 2 * T0_PCF + 319 * T0_PCF + 70, 3 * T0_PCF, 29 * T0_PCF, tab);
|
AddPatternPCF7931(8192 / 2 * T0_PCF + 319 * T0_PCF + 70, 3 * T0_PCF, 29 * T0_PCF, tab);
|
||||||
//password indication bit
|
//password indication bit
|
||||||
AddBitPCF7931(1, tab, l, p);
|
AddBitPCF7931(1, tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
//password (on 56 bits)
|
//password (on 56 bits)
|
||||||
AddBytePCF7931(pass[0], tab, l, p);
|
AddBytePCF7931(pass[0], tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
AddBytePCF7931(pass[1], tab, l, p);
|
AddBytePCF7931(pass[1], tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
AddBytePCF7931(pass[2], tab, l, p);
|
AddBytePCF7931(pass[2], tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
AddBytePCF7931(pass[3], tab, l, p);
|
AddBytePCF7931(pass[3], tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
AddBytePCF7931(pass[4], tab, l, p);
|
AddBytePCF7931(pass[4], tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
AddBytePCF7931(pass[5], tab, l, p);
|
AddBytePCF7931(pass[5], tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
AddBytePCF7931(pass[6], tab, l, p);
|
AddBytePCF7931(pass[6], tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
//programming mode (0 or 1)
|
//programming mode (0 or 1) -> 0 = byte wise; 1 = block wise programming
|
||||||
AddBitPCF7931(0, tab, l, p);
|
AddBitPCF7931(0, tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
|
|
||||||
//block address on 6 bits
|
//block address on 6 bits
|
||||||
for (u = 0; u < 6; ++u) {
|
for (u = 0; u < 6; ++u) {
|
||||||
if (address & (1 << u)) { // bit 1
|
if (address & (1 << u)) { // bit 1
|
||||||
++parity;
|
++parity;
|
||||||
AddBitPCF7931(1, tab, l, p);
|
AddBitPCF7931(1, tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
} else { // bit 0
|
} else { // bit 0
|
||||||
AddBitPCF7931(0, tab, l, p);
|
AddBitPCF7931(0, tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -405,56 +479,48 @@ static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int3
|
||||||
for (u = 0; u < 4; ++u) {
|
for (u = 0; u < 4; ++u) {
|
||||||
if (byte & (1 << u)) { // bit 1
|
if (byte & (1 << u)) { // bit 1
|
||||||
parity++;
|
parity++;
|
||||||
AddBitPCF7931(1, tab, l, p);
|
AddBitPCF7931(1, tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
} else // bit 0
|
} else // bit 0
|
||||||
AddBitPCF7931(0, tab, l, p);
|
AddBitPCF7931(0, tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
//data on 8 bits
|
//data on 8 bits
|
||||||
for (u = 0; u < 8; u++) {
|
for (u = 0; u < 8; u++) {
|
||||||
if (data & (1 << u)) { // bit 1
|
if (data & (1 << u)) { // bit 1
|
||||||
parity++;
|
parity++;
|
||||||
AddBitPCF7931(1, tab, l, p);
|
AddBitPCF7931(1, tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
} else //bit 0
|
} else //bit 0
|
||||||
AddBitPCF7931(0, tab, l, p);
|
AddBitPCF7931(0, tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
//parity bit
|
//parity bit
|
||||||
if ((parity % 2) == 0)
|
if ((parity % 2) == 0)
|
||||||
AddBitPCF7931(0, tab, l, p); //even parity
|
AddBitPCF7931(0, tab, offsetPulseWidth, offsetPulsePosition); //even parity
|
||||||
else
|
else
|
||||||
AddBitPCF7931(1, tab, l, p);//odd parity
|
AddBitPCF7931(1, tab, offsetPulseWidth, offsetPulsePosition);//odd parity
|
||||||
|
|
||||||
//time access memory
|
// time access memory (640T0)
|
||||||
AddPatternPCF7931(5120 + 2680, 0, 0, tab);
|
// Not sure why 335*T0, but should not matter. Since programming should be finished at that point
|
||||||
|
AddPatternPCF7931((640 + 335)* T0_PCF, 0, 0, tab);
|
||||||
//conversion of the scale time
|
|
||||||
for (u = 0; u < 500; ++u)
|
|
||||||
tab[u] = (tab[u] * 3) / 2;
|
|
||||||
|
|
||||||
//compensation of the counter reload
|
|
||||||
while (!comp) {
|
|
||||||
comp = 1;
|
|
||||||
for (u = 0; tab[u] != 0; ++u)
|
|
||||||
if (tab[u] > 0xFFFF) {
|
|
||||||
tab[u] -= 0xFFFF;
|
|
||||||
comp = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SendCmdPCF7931(tab, ledcontrol);
|
SendCmdPCF7931(tab, ledcontrol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write on a byte of a PCF7931 tag
|
/* Write on a byte of a PCF7931 tag
|
||||||
* @param address : address of the block to write
|
* @param address : address of the block to write
|
||||||
@param byte : address of the byte to write
|
* @param byte : address of the byte to write
|
||||||
@param data : data to write
|
* @param data : data to write
|
||||||
*/
|
*/
|
||||||
void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data, bool ledcontrol) {
|
void WritePCF7931(
|
||||||
|
uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7,
|
||||||
|
uint16_t init_delay,
|
||||||
|
int8_t offsetPulseWidth, int8_t offsetPulsePosition,
|
||||||
|
uint8_t address, uint8_t byte, uint8_t data,
|
||||||
|
bool ledcontrol) {
|
||||||
|
|
||||||
if (g_dbglevel >= DBG_INFO) {
|
if (g_dbglevel >= DBG_INFO) {
|
||||||
Dbprintf("Initialization delay : %d us", init_delay);
|
Dbprintf("Initialization delay : %d us", init_delay);
|
||||||
Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p);
|
Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", offsetPulseWidth, offsetPulsePosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dbprintf("Password (LSB first on each byte): %02x %02x %02x %02x %02x %02x %02x", pass1, pass2, pass3, pass4, pass5, pass6, pass7);
|
Dbprintf("Password (LSB first on each byte): %02x %02x %02x %02x %02x %02x %02x", pass1, pass2, pass3, pass4, pass5, pass6, pass7);
|
||||||
|
|
@ -464,15 +530,15 @@ void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, ui
|
||||||
|
|
||||||
uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7};
|
uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7};
|
||||||
|
|
||||||
RealWritePCF7931(password, init_delay, l, p, address, byte, data, ledcontrol);
|
RealWritePCF7931(password, init_delay, offsetPulseWidth, offsetPulsePosition, address, byte, data, ledcontrol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Send a trame to a PCF7931 tags
|
/* Send a frame to a PCF7931 tags
|
||||||
* @param tab : array of the data frame
|
* @param tab : array of the data frame
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void SendCmdPCF7931(const uint32_t *tab, bool ledcontrol) {
|
void SendCmdPCF7931(uint32_t *tab, bool ledcontrol) {
|
||||||
uint16_t u = 0, tempo = 0;
|
uint16_t u = 0, tempo = 0;
|
||||||
|
|
||||||
if (g_dbglevel >= DBG_INFO) {
|
if (g_dbglevel >= DBG_INFO) {
|
||||||
|
|
@ -485,6 +551,20 @@ void SendCmdPCF7931(const uint32_t *tab, bool ledcontrol) {
|
||||||
|
|
||||||
if (ledcontrol) LED_A_ON();
|
if (ledcontrol) LED_A_ON();
|
||||||
|
|
||||||
|
// rescale the values to match the time of the timer below.
|
||||||
|
for (u = 0; u < 500; ++u) {
|
||||||
|
tab[u] = (tab[u] * 3) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compensation for the counter overflow
|
||||||
|
// only one overflow should be possible.
|
||||||
|
for (u = 0; tab[u] != 0; ++u)
|
||||||
|
if (tab[u] > 0xFFFF) {
|
||||||
|
tab[u] -= 0xFFFF;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// steal this pin from the SSP and use it to control the modulation
|
// steal this pin from the SSP and use it to control the modulation
|
||||||
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
|
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
|
||||||
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
|
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
|
||||||
|
|
@ -493,7 +573,7 @@ void SendCmdPCF7931(const uint32_t *tab, bool ledcontrol) {
|
||||||
AT91C_BASE_PMC->PMC_PCER |= (0x1 << AT91C_ID_TC0);
|
AT91C_BASE_PMC->PMC_PCER |= (0x1 << AT91C_ID_TC0);
|
||||||
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
|
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
|
||||||
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; // clock at 48/32 MHz
|
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; // clock at 48/32 MHz (48Mhz clock, 32 = prescaler (div3))
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
|
||||||
|
|
||||||
// Assert a sync signal. This sets all timers to 0 on next active clock edge
|
// Assert a sync signal. This sets all timers to 0 on next active clock edge
|
||||||
|
|
@ -503,19 +583,19 @@ void SendCmdPCF7931(const uint32_t *tab, bool ledcontrol) {
|
||||||
for (u = 0; tab[u] != 0; u += 3) {
|
for (u = 0; tab[u] != 0; u += 3) {
|
||||||
// modulate antenna
|
// modulate antenna
|
||||||
HIGH(GPIO_SSC_DOUT);
|
HIGH(GPIO_SSC_DOUT);
|
||||||
while (tempo != tab[u]) {
|
while ((uint32_t)tempo < tab[u]) {
|
||||||
tempo = AT91C_BASE_TC0->TC_CV;
|
tempo = AT91C_BASE_TC0->TC_CV;
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop modulating antenna
|
// stop modulating antenna
|
||||||
LOW(GPIO_SSC_DOUT);
|
LOW(GPIO_SSC_DOUT);
|
||||||
while (tempo != tab[u + 1]) {
|
while ((uint32_t)tempo < tab[u + 1]) {
|
||||||
tempo = AT91C_BASE_TC0->TC_CV;
|
tempo = AT91C_BASE_TC0->TC_CV;
|
||||||
}
|
}
|
||||||
|
|
||||||
// modulate antenna
|
// modulate antenna
|
||||||
HIGH(GPIO_SSC_DOUT);
|
HIGH(GPIO_SSC_DOUT);
|
||||||
while (tempo != tab[u + 2]) {
|
while ((uint32_t)tempo < tab[u + 2]) {
|
||||||
tempo = AT91C_BASE_TC0->TC_CV;
|
tempo = AT91C_BASE_TC0->TC_CV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -528,32 +608,36 @@ void SendCmdPCF7931(const uint32_t *tab, bool ledcontrol) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Add a byte for building the data frame of PCF7931 tags
|
/* Add a byte for building the data frame of PCF7931 tags.
|
||||||
|
* See Datasheet of PCF7931 diagramm on page 8. This explains pulse widht & positioning
|
||||||
|
* Normally, no offset should be required.
|
||||||
* @param b : byte to add
|
* @param b : byte to add
|
||||||
* @param tab : array of the data frame
|
* @param tab : array of the data frame
|
||||||
* @param l : offset on low pulse width
|
* @param offsetPulseWidth : offset on low pulse width in µs (default pulse widht is 6T0)
|
||||||
* @param p : offset on low pulse positioning
|
* @param offsetPulsePosition : offset on low pulse positioning in µs
|
||||||
*/
|
*/
|
||||||
bool AddBytePCF7931(uint8_t byte, uint32_t *tab, int32_t l, int32_t p) {
|
bool AddBytePCF7931(uint8_t byte, uint32_t *tab, int8_t offsetPulseWidth, int8_t offsetPulsePosition) {
|
||||||
uint32_t u;
|
uint32_t u;
|
||||||
for (u = 0; u < 8; ++u) {
|
for (u = 0; u < 8; ++u) {
|
||||||
if (byte & (1 << u)) { //bit is 1
|
if (byte & (1 << u)) { //bit is 1
|
||||||
if (AddBitPCF7931(1, tab, l, p) == 1) return true;
|
AddBitPCF7931(1, tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
} else { //bit is 0
|
} else { //bit is 0
|
||||||
if (AddBitPCF7931(0, tab, l, p) == 1) return true;
|
AddBitPCF7931(0, tab, offsetPulseWidth, offsetPulsePosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a bits for building the data frame of PCF7931 tags
|
/* Add a bits for building the data frame of PCF7931 tags.
|
||||||
|
* See Datasheet of PCF7931 diagramm on page 8. This explains pulse widht & positioning
|
||||||
|
* Normally, no offset should be required.
|
||||||
* @param b : bit to add
|
* @param b : bit to add
|
||||||
* @param tab : array of the data frame
|
* @param tab : array of the data frame
|
||||||
* @param l : offset on low pulse width
|
* @param offsetPulseWidth : offset on low pulse width in µs (default pulse widht is 6T0)
|
||||||
* @param p : offset on low pulse positioning
|
* @param offsetPulsePosition : offset on low pulse positioning in µs
|
||||||
*/
|
*/
|
||||||
bool AddBitPCF7931(bool b, uint32_t *tab, int32_t l, int32_t p) {
|
bool AddBitPCF7931(bool b, uint32_t *tab, int8_t offsetPulseWidth, int8_t offsetPulsePosition) {
|
||||||
uint8_t u = 0;
|
uint8_t u = 0;
|
||||||
|
|
||||||
//we put the cursor at the last value of the array
|
//we put the cursor at the last value of the array
|
||||||
|
|
@ -561,23 +645,22 @@ bool AddBitPCF7931(bool b, uint32_t *tab, int32_t l, int32_t p) {
|
||||||
|
|
||||||
if (b == 1) { //add a bit 1
|
if (b == 1) { //add a bit 1
|
||||||
if (u == 0)
|
if (u == 0)
|
||||||
tab[u] = 34 * T0_PCF + p;
|
tab[u] = 34 * T0_PCF + offsetPulsePosition;
|
||||||
else
|
else
|
||||||
tab[u] = 34 * T0_PCF + tab[u - 1] + p;
|
tab[u] = 34 * T0_PCF + tab[u - 1] + offsetPulsePosition;
|
||||||
|
|
||||||
|
tab[u + 1] = 6 * T0_PCF + tab[u] + offsetPulseWidth;
|
||||||
|
tab[u + 2] = 88 * T0_PCF + tab[u + 1] - offsetPulseWidth - offsetPulsePosition;
|
||||||
|
|
||||||
tab[u + 1] = 6 * T0_PCF + tab[u] + l;
|
|
||||||
tab[u + 2] = 88 * T0_PCF + tab[u + 1] - l - p;
|
|
||||||
return false;
|
|
||||||
} else { //add a bit 0
|
} else { //add a bit 0
|
||||||
|
|
||||||
if (u == 0)
|
if (u == 0)
|
||||||
tab[u] = 98 * T0_PCF + p;
|
tab[u] = 98 * T0_PCF + offsetPulsePosition;
|
||||||
else
|
else
|
||||||
tab[u] = 98 * T0_PCF + tab[u - 1] + p;
|
tab[u] = 98 * T0_PCF + tab[u - 1] + offsetPulsePosition;
|
||||||
|
|
||||||
|
tab[u + 1] = 6 * T0_PCF + tab[u] + offsetPulseWidth;
|
||||||
|
tab[u + 2] = 24 * T0_PCF + tab[u + 1] - offsetPulseWidth - offsetPulsePosition;
|
||||||
|
|
||||||
tab[u + 1] = 6 * T0_PCF + tab[u] + l;
|
|
||||||
tab[u + 2] = 24 * T0_PCF + tab[u + 1] - l - p;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -592,8 +675,8 @@ bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t *tab) {
|
||||||
uint32_t u = 0;
|
uint32_t u = 0;
|
||||||
for (u = 0; tab[u] != 0; u += 3) {} //we put the cursor at the last value of the array
|
for (u = 0; tab[u] != 0; u += 3) {} //we put the cursor at the last value of the array
|
||||||
|
|
||||||
tab[u] = (u == 0) ? a : a + tab[u - 1];
|
tab[u] = (u == 0) ? a : a + tab[u - 1]; // if it is the first value of the array, nothing needs to be added.
|
||||||
tab[u + 1] = b + tab[u];
|
tab[u + 1] = b + tab[u]; // otherwise always add up the values, because later on it is compared to a counter
|
||||||
tab[u + 2] = c + tab[u + 1];
|
tab[u + 2] = c + tab[u + 1];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,20 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
FALLING,
|
||||||
|
RISING
|
||||||
|
} EdgeType;
|
||||||
|
|
||||||
size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol);
|
size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol);
|
||||||
bool IsBlock0PCF7931(uint8_t *block);
|
bool IsBlock0PCF7931(uint8_t *block);
|
||||||
bool IsBlock1PCF7931(const uint8_t *block);
|
bool IsBlock1PCF7931(const uint8_t *block);
|
||||||
void ReadPCF7931(bool ledcontrol);
|
void ReadPCF7931(bool ledcontrol);
|
||||||
void SendCmdPCF7931(const uint32_t *tab, bool ledcontrol);
|
void SendCmdPCF7931(uint32_t *tab, bool ledcontrol);
|
||||||
bool AddBytePCF7931(uint8_t byte, uint32_t *tab, int32_t l, int32_t p);
|
bool AddBytePCF7931(uint8_t byte, uint32_t *tab, int8_t offsetPulseWidth, int8_t offsetPulsePosition);
|
||||||
bool AddBitPCF7931(bool b, uint32_t *tab, int32_t l, int32_t p);
|
bool AddBitPCF7931(bool b, uint32_t *tab, int8_t offsetPulseWidth, int8_t offsetPulsePosition);
|
||||||
bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t *tab);
|
bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t *tab);
|
||||||
void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data, bool ledcontrol);
|
void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int8_t offsetPulseWidth, int8_t offsetPulsePosition, uint8_t address, uint8_t byte, uint8_t data, bool ledcontrol);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,9 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re
|
||||||
if (g_dbglevel >= DBG_DEBUG)
|
if (g_dbglevel >= DBG_DEBUG)
|
||||||
DbpString("start sam_send_request_iso14a");
|
DbpString("start sam_send_request_iso14a");
|
||||||
|
|
||||||
uint8_t * buf1 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
uint8_t *buf1 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||||
uint8_t * buf2 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
uint8_t *buf2 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||||
if(buf1 == NULL || buf2 == NULL){
|
if (buf1 == NULL || buf2 == NULL) {
|
||||||
res = PM3_EMALLOC;
|
res = PM3_EMALLOC;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
@ -103,19 +103,19 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re
|
||||||
nfc_tx_len = sam_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf);
|
nfc_tx_len = sam_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf);
|
||||||
|
|
||||||
bool is_cmd_check = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_CHECK;
|
bool is_cmd_check = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_CHECK;
|
||||||
if(is_cmd_check && break_on_nr_mac){
|
if (is_cmd_check && break_on_nr_mac) {
|
||||||
memcpy(response, nfc_tx_buf, nfc_tx_len);
|
memcpy(response, nfc_tx_buf, nfc_tx_len);
|
||||||
*response_len = nfc_tx_len;
|
*response_len = nfc_tx_len;
|
||||||
if (g_dbglevel >= DBG_INFO) {
|
if (g_dbglevel >= DBG_INFO) {
|
||||||
DbpString("NR-MAC: ");
|
DbpString("NR-MAC: ");
|
||||||
Dbhexdump((*response_len)-1, response+1, false);
|
Dbhexdump((*response_len) - 1, response + 1, false);
|
||||||
}
|
}
|
||||||
res = PM3_SUCCESS;
|
res = PM3_SUCCESS;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_cmd_update = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_UPDATE;
|
bool is_cmd_update = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_UPDATE;
|
||||||
if(is_cmd_update && prevent_epurse_update && nfc_tx_buf[0] == 0x87 && nfc_tx_buf[1] == 0x02){
|
if (is_cmd_update && prevent_epurse_update && nfc_tx_buf[0] == 0x87 && nfc_tx_buf[1] == 0x02) {
|
||||||
// block update(2) command and fake the response to prevent update of epurse
|
// block update(2) command and fake the response to prevent update of epurse
|
||||||
|
|
||||||
// NFC TX BUFFERS PREPARED BY SAM LOOKS LIKE:
|
// NFC TX BUFFERS PREPARED BY SAM LOOKS LIKE:
|
||||||
|
|
@ -124,8 +124,8 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re
|
||||||
// NFC RX BUFFERS EXPECTED BY SAM WOULD LOOK LIKE:
|
// NFC RX BUFFERS EXPECTED BY SAM WOULD LOOK LIKE:
|
||||||
// #2(FF FF FF FF) #1(C9 FD FF FF) 3A 47
|
// #2(FF FF FF FF) #1(C9 FD FF FF) 3A 47
|
||||||
|
|
||||||
memcpy(nfc_rx_buf+0, nfc_tx_buf+6, 4);
|
memcpy(nfc_rx_buf + 0, nfc_tx_buf + 6, 4);
|
||||||
memcpy(nfc_rx_buf+4, nfc_tx_buf+0, 4);
|
memcpy(nfc_rx_buf + 4, nfc_tx_buf + 0, 4);
|
||||||
AddCrc(nfc_rx_buf, 8);
|
AddCrc(nfc_rx_buf, 8);
|
||||||
nfc_rx_len = 10;
|
nfc_rx_len = 10;
|
||||||
|
|
||||||
|
|
@ -155,7 +155,7 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (res != PM3_SUCCESS ) {
|
if (res != PM3_SUCCESS) {
|
||||||
res = PM3_ECARDEXCHANGE;
|
res = PM3_ECARDEXCHANGE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
@ -358,7 +358,7 @@ int sam_picopass_get_pacs(PacketCommandNG *c) {
|
||||||
|
|
||||||
// implicit StartSspClk() happens here
|
// implicit StartSspClk() happens here
|
||||||
Iso15693InitReader();
|
Iso15693InitReader();
|
||||||
if(!select_iclass_tag(&card_a_info, false, &eof_time, shallow_mod)){
|
if (!select_iclass_tag(&card_a_info, false, &eof_time, shallow_mod)) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -129,9 +129,9 @@ static int sam_send_request_iso14a(const uint8_t *const request, const uint8_t r
|
||||||
if (g_dbglevel >= DBG_DEBUG)
|
if (g_dbglevel >= DBG_DEBUG)
|
||||||
DbpString("start sam_send_request_iso14a");
|
DbpString("start sam_send_request_iso14a");
|
||||||
|
|
||||||
uint8_t * buf1 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
uint8_t *buf1 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||||
uint8_t * buf2 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
uint8_t *buf2 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||||
if(buf1 == NULL || buf2 == NULL){
|
if (buf1 == NULL || buf2 == NULL) {
|
||||||
res = PM3_EMALLOC;
|
res = PM3_EMALLOC;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -658,7 +658,7 @@ void rdv40_spiffs_safe_print_tree(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dbprintf("[%04x] " _YELLOW_("%5i") " B |-- %s%s", pe->obj_id, pe->size, pe->name, resolvedlink);
|
Dbprintf("[%04u] " _YELLOW_("%5i") " B |-- %s%s", pe->obj_id, pe->size, pe->name, resolvedlink);
|
||||||
printed = true;
|
printed = true;
|
||||||
}
|
}
|
||||||
if (printed == false) {
|
if (printed == false) {
|
||||||
|
|
|
||||||
|
|
@ -548,7 +548,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
||||||
SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_INTERNAL);
|
SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_INTERNAL);
|
||||||
}
|
}
|
||||||
// this checks for overflow of the multiplication of block_count+1 with SPIFFS_PAGES_PER_BLOCK(fs)
|
// this checks for overflow of the multiplication of block_count+1 with SPIFFS_PAGES_PER_BLOCK(fs)
|
||||||
if (((uint32_t)(-1)) / SPIFFS_PAGES_PER_BLOCK(fs) > (block_count+1)) {
|
if (((uint32_t)(-1)) / SPIFFS_PAGES_PER_BLOCK(fs) > (block_count + 1)) {
|
||||||
// checking with +1 block count to avoid overflow also in inner loop, which adds one page...
|
// checking with +1 block count to avoid overflow also in inner loop, which adds one page...
|
||||||
// would exceed value storable in uint32_t
|
// would exceed value storable in uint32_t
|
||||||
SPIFFS_DBG("Overflow: pages per block %04x with block count "_SPIPRIbl" results in overflow\n", SPIFFS_PAGES_PER_BLOCK(fs), block_count);
|
SPIFFS_DBG("Overflow: pages per block %04x with block count "_SPIPRIbl" results in overflow\n", SPIFFS_PAGES_PER_BLOCK(fs), block_count);
|
||||||
|
|
@ -556,13 +556,13 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
||||||
}
|
}
|
||||||
// because loop indices are using spiffs_page_ix type,
|
// because loop indices are using spiffs_page_ix type,
|
||||||
// that type can hold a large enough value
|
// that type can hold a large enough value
|
||||||
if (total_blocks > ((spiffs_page_ix)-1)) {
|
if (total_blocks > ((spiffs_page_ix) - 1)) {
|
||||||
SPIFFS_DBG("Avoiding infinite loop, total_blocks "_SPIPRIpg" too large for spiffs_page_ix type\n", total_blocks);
|
SPIFFS_DBG("Avoiding infinite loop, total_blocks "_SPIPRIpg" too large for spiffs_page_ix type\n", total_blocks);
|
||||||
SPIFFS_CHECK_RES(SPIFFS_ERR_INTERNAL);
|
SPIFFS_CHECK_RES(SPIFFS_ERR_INTERNAL);
|
||||||
}
|
}
|
||||||
// because loop indices are using spiffs_page_ix type,
|
// because loop indices are using spiffs_page_ix type,
|
||||||
// that type can hold a large enough value
|
// that type can hold a large enough value
|
||||||
if (total_blocks_plus_one_page > ((spiffs_page_ix)-1) || total_blocks_plus_one_page < total_blocks) {
|
if (total_blocks_plus_one_page > ((spiffs_page_ix) - 1) || total_blocks_plus_one_page < total_blocks) {
|
||||||
SPIFFS_DBG("Avoiding infinite loop, total_blocks_plus_one_page "_SPIPRIpg" too large for spiffs_page_ix type\n", total_blocks_plus_one_page);
|
SPIFFS_DBG("Avoiding infinite loop, total_blocks_plus_one_page "_SPIPRIpg" too large for spiffs_page_ix type\n", total_blocks_plus_one_page);
|
||||||
SPIFFS_CHECK_RES(SPIFFS_ERR_INTERNAL);
|
SPIFFS_CHECK_RES(SPIFFS_ERR_INTERNAL);
|
||||||
}
|
}
|
||||||
|
|
@ -586,7 +586,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
||||||
0);
|
0);
|
||||||
// traverse each page except for lookup pages
|
// traverse each page except for lookup pages
|
||||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
|
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
|
||||||
while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {
|
while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block + 1)) {
|
||||||
//if ((cur_pix & 0xff) == 0)
|
//if ((cur_pix & 0xff) == 0)
|
||||||
// SPIFFS_CHECK_DBG("PA: processing pix "_SPIPRIpg", block "_SPIPRIbl" of pix "_SPIPRIpg", block "_SPIPRIbl"\n",
|
// SPIFFS_CHECK_DBG("PA: processing pix "_SPIPRIpg", block "_SPIPRIbl" of pix "_SPIPRIpg", block "_SPIPRIbl"\n",
|
||||||
// cur_pix, cur_block, total_blocks, block_count);
|
// cur_pix, cur_block, total_blocks, block_count);
|
||||||
|
|
|
||||||
|
|
@ -887,7 +887,12 @@ ifneq (,$(INSTALLBIN))
|
||||||
endif
|
endif
|
||||||
ifneq (,$(INSTALLSHARE))
|
ifneq (,$(INSTALLSHARE))
|
||||||
$(Q)$(INSTALLSUDO) $(MKDIR) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)
|
$(Q)$(INSTALLSUDO) $(MKDIR) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)
|
||||||
|
# hack ahead: inject installation path into pm3_resources.py
|
||||||
|
$(Q)sed -i 's|^TOOLS_PATH \?= \?None|TOOLS_PATH="$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)"|' pyscripts/pm3_resources.py
|
||||||
|
$(Q)sed -i 's|^DICTS_PATH \?= \?None|DICTS_PATH="$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)/dictionaries"|' pyscripts/pm3_resources.py
|
||||||
$(Q)$(INSTALLSUDO) $(CP) $(INSTALLSHARE) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)
|
$(Q)$(INSTALLSUDO) $(CP) $(INSTALLSHARE) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)
|
||||||
|
$(Q)sed -i 's|^TOOLS_PATH \?=.*|TOOLS_PATH = None|' pyscripts/pm3_resources.py
|
||||||
|
$(Q)sed -i 's|^DICTS_PATH \?=.*|DICTS_PATH = None|' pyscripts/pm3_resources.py
|
||||||
endif
|
endif
|
||||||
@true
|
@true
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -180,8 +180,10 @@ int CLIParserParseStringEx(CLIParserContext *ctx, const char *str, void *vargtab
|
||||||
|
|
||||||
// parse params
|
// parse params
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case PS_FIRST: // first char
|
case PS_FIRST: { // first char
|
||||||
|
|
||||||
if (!clueData || str[i] == '-') { // first char before space is '-' - next element - option OR not "clueData" for not-option fields
|
if (!clueData || str[i] == '-') { // first char before space is '-' - next element - option OR not "clueData" for not-option fields
|
||||||
state = PS_OPTION;
|
state = PS_OPTION;
|
||||||
|
|
||||||
|
|
@ -193,24 +195,32 @@ int CLIParserParseStringEx(CLIParserContext *ctx, const char *str, void *vargtab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spaceptr = NULL;
|
spaceptr = NULL;
|
||||||
case PS_ARGUMENT:
|
}
|
||||||
if (state == PS_FIRST)
|
case PS_ARGUMENT: {
|
||||||
|
|
||||||
|
if (state == PS_FIRST) {
|
||||||
state = PS_ARGUMENT;
|
state = PS_ARGUMENT;
|
||||||
if (str[i] == '"') {
|
}
|
||||||
|
|
||||||
|
if (str[i] == '"' || str[i] == '\'') {
|
||||||
state = PS_QUOTE;
|
state = PS_QUOTE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSpace(str[i])) {
|
if (isSpace(str[i])) {
|
||||||
spaceptr = bufptr;
|
spaceptr = bufptr;
|
||||||
state = PS_FIRST;
|
state = PS_FIRST;
|
||||||
}
|
}
|
||||||
|
|
||||||
*bufptr = str[i];
|
*bufptr = str[i];
|
||||||
bufptr++;
|
bufptr++;
|
||||||
break;
|
break;
|
||||||
case PS_OPTION:
|
}
|
||||||
|
|
||||||
|
case PS_OPTION: {
|
||||||
|
|
||||||
if (isSpace(str[i])) {
|
if (isSpace(str[i])) {
|
||||||
state = PS_FIRST;
|
state = PS_FIRST;
|
||||||
|
|
||||||
*bufptr = 0x00;
|
*bufptr = 0x00;
|
||||||
bufptr++;
|
bufptr++;
|
||||||
argv[argc++] = bufptr;
|
argv[argc++] = bufptr;
|
||||||
|
|
@ -220,17 +230,22 @@ int CLIParserParseStringEx(CLIParserContext *ctx, const char *str, void *vargtab
|
||||||
*bufptr = str[i];
|
*bufptr = str[i];
|
||||||
bufptr++;
|
bufptr++;
|
||||||
break;
|
break;
|
||||||
case PS_QUOTE:
|
}
|
||||||
if (str[i] == '"') {
|
case PS_QUOTE: {
|
||||||
|
|
||||||
|
if (str[i] == '"' || str[i] == '\'') {
|
||||||
*bufptr++ = 0x00;
|
*bufptr++ = 0x00;
|
||||||
state = PS_FIRST;
|
state = PS_FIRST;
|
||||||
} else {
|
} else {
|
||||||
if (isSpace(str[i]) == false) {
|
|
||||||
|
// if (isSpace(str[i]) == false) {
|
||||||
*bufptr++ = str[i];
|
*bufptr++ = str[i];
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (bufptr > bufptrend) {
|
if (bufptr > bufptrend) {
|
||||||
PrintAndLogEx(ERR, "ERROR: Line too long\n");
|
PrintAndLogEx(ERR, "ERROR: Line too long\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
@ -296,8 +311,9 @@ int CLIParamBinToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
|
||||||
|
|
||||||
int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) {
|
int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) {
|
||||||
*datalen = 0;
|
*datalen = 0;
|
||||||
if (!argstr->count)
|
if (!argstr->count) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t tmpstr[MAX_INPUT_ARG_LENGTH + 1] = {0};
|
uint8_t tmpstr[MAX_INPUT_ARG_LENGTH + 1] = {0};
|
||||||
int ibuf = 0;
|
int ibuf = 0;
|
||||||
|
|
@ -319,8 +335,9 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
|
||||||
ibuf = MIN(ibuf, (sizeof(tmpstr) / 2));
|
ibuf = MIN(ibuf, (sizeof(tmpstr) / 2));
|
||||||
tmpstr[ibuf] = 0;
|
tmpstr[ibuf] = 0;
|
||||||
|
|
||||||
if (ibuf == 0)
|
if (ibuf == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (ibuf > maxdatalen) {
|
if (ibuf > maxdatalen) {
|
||||||
PrintAndLogEx(ERR, "Parameter error: string too long (%i chars), expected MAX %i chars\n", ibuf, maxdatalen);
|
PrintAndLogEx(ERR, "Parameter error: string too long (%i chars), expected MAX %i chars\n", ibuf, maxdatalen);
|
||||||
|
|
|
||||||
|
|
@ -2175,6 +2175,7 @@ D144BD193063
|
||||||
# Brazil transport Sec 8 / A
|
# Brazil transport Sec 8 / A
|
||||||
50d4c54fcdf5
|
50d4c54fcdf5
|
||||||
#
|
#
|
||||||
|
# TEKKEN 6 Namco Data Card
|
||||||
# Bandai Namco Passport [fka Banapassport] / Sega Aime Card
|
# Bandai Namco Passport [fka Banapassport] / Sega Aime Card
|
||||||
# Dumped on the Flipper Devices Discord Server
|
# Dumped on the Flipper Devices Discord Server
|
||||||
6090D00632F5
|
6090D00632F5
|
||||||
|
|
@ -2211,6 +2212,40 @@ C8382A233993
|
||||||
7B304F2A12A6
|
7B304F2A12A6
|
||||||
FC9418BF788B
|
FC9418BF788B
|
||||||
#
|
#
|
||||||
|
# Super Street Fighter 4 Capcom NESYS Card
|
||||||
|
4B6F74696174
|
||||||
|
6F746961744B
|
||||||
|
4176696E7520
|
||||||
|
76696E752041
|
||||||
|
576C61737265
|
||||||
|
6C6173726557
|
||||||
|
416962616320
|
||||||
|
696261632041
|
||||||
|
42622074656E
|
||||||
|
622074656E42
|
||||||
|
416174363030
|
||||||
|
617436303041
|
||||||
|
5475206F7469
|
||||||
|
75206F746954
|
||||||
|
41726576696E
|
||||||
|
726576696E41
|
||||||
|
4B63206C6173
|
||||||
|
63206C61734B
|
||||||
|
41656E696261
|
||||||
|
656E69626141
|
||||||
|
5A3030622074
|
||||||
|
30306220745A
|
||||||
|
557469617436
|
||||||
|
746961743655
|
||||||
|
48696E75206F
|
||||||
|
696E75206F48
|
||||||
|
496173726576
|
||||||
|
617372657649
|
||||||
|
52626163206C
|
||||||
|
626163206C52
|
||||||
|
4F2074656E69
|
||||||
|
2074656E694F
|
||||||
|
#
|
||||||
# Guest Cashless Prepaid Arcade Payment Cards
|
# Guest Cashless Prepaid Arcade Payment Cards
|
||||||
168168168168
|
168168168168
|
||||||
198407157610
|
198407157610
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ desc = [[
|
||||||
]]
|
]]
|
||||||
|
|
||||||
usage = [[
|
usage = [[
|
||||||
script run t55_chk [-s start_year] [-e end_year] [-d | -y]
|
script run lf_t55xx_chk [-s start_year] [-e end_year] [-d | -y]
|
||||||
]]
|
]]
|
||||||
options = [[
|
options = [[
|
||||||
-h this help
|
-h this help
|
||||||
|
|
@ -29,10 +29,10 @@ options = [[
|
||||||
-y search method: YYYYMMDD
|
-y search method: YYYYMMDD
|
||||||
]]
|
]]
|
||||||
examples = [[
|
examples = [[
|
||||||
script run t55_chk -s 1999 -d -> start 1999, end is current year, method 01011999
|
script run lf_t55xx_chk -s 1999 -d -> start 1999, end is current year, method 01011999
|
||||||
script run t55_chk -s 1999 -y -> start 1999, end is current year, method 19990101
|
script run lf_t55xx_chk -s 1999 -y -> start 1999, end is current year, method 19990101
|
||||||
script run t55_chk -s 1999 -e 2001 -y -> start 1999, end year 2001, method 19990101
|
script run lf_t55xx_chk -s 1999 -e 2001 -y -> start 1999, end year 2001, method 19990101
|
||||||
script run t55_chk -s 1999 -e 2001 -d -> start 1999, end year 2001, method 01011999
|
script run lf_t55xx_chk -s 1999 -e 2001 -d -> start 1999, end year 2001, method 01011999
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local function help()
|
local function help()
|
||||||
|
|
@ -14,10 +14,10 @@ desc = [[
|
||||||
useful if the password is, for example, a date of birth.
|
useful if the password is, for example, a date of birth.
|
||||||
]]
|
]]
|
||||||
usage = [[
|
usage = [[
|
||||||
script run t55_chk_date
|
script run lf_t55xx_chk_date
|
||||||
]]
|
]]
|
||||||
arguments = [[
|
arguments = [[
|
||||||
script run t55_chk_date -h : this help
|
script run lf_t55xx_chk_date -h : this help
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local DEBUG = true
|
local DEBUG = true
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
local getopt = require('getopt')
|
|
||||||
local utils = require('utils')
|
|
||||||
local ac = require('ansicolors')
|
|
||||||
local os = require('os')
|
|
||||||
local dash = string.rep('--', 32)
|
|
||||||
local dir = os.getenv('HOME') .. '/.proxmark3/logs/'
|
|
||||||
local logfile = (io.popen('dir /a-d /o-d /tw /b/s "' .. dir .. '" 2>nul:'):read("*a"):match("%C+"))
|
|
||||||
local command = core.console
|
|
||||||
|
|
||||||
author = ' Author: jareckib - 15.02.2025'
|
|
||||||
version = ' version v1.00'
|
|
||||||
desc = [[
|
|
||||||
This simple script first checks if a password has been set for the T5577.
|
|
||||||
It uses the dictionary t55xx_default_pwds.dic for this purpose. If a password
|
|
||||||
is found, it uses the wipe command to erase the T5577. Then the reanimation
|
|
||||||
procedure is applied. If the password is not found or doesn't exist the script
|
|
||||||
only performs the reanimation procedure. The script revives 99% of blocked tags.
|
|
||||||
]]
|
|
||||||
usage = [[
|
|
||||||
script run t55_fix
|
|
||||||
]]
|
|
||||||
arguments = [[
|
|
||||||
script run t55_fix -h : this help
|
|
||||||
]]
|
|
||||||
|
|
||||||
local function help()
|
|
||||||
print()
|
|
||||||
print(author)
|
|
||||||
print(version)
|
|
||||||
print(desc)
|
|
||||||
print(ac.cyan..' Usage'..ac.reset)
|
|
||||||
print(usage)
|
|
||||||
print(ac.cyan..' Arguments'..ac.reset)
|
|
||||||
print(arguments)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function read_log_file(logfile)
|
|
||||||
local file = io.open(logfile, "r")
|
|
||||||
if not file then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
local content = file:read("*all")
|
|
||||||
file:close()
|
|
||||||
return content
|
|
||||||
end
|
|
||||||
|
|
||||||
local function extract_password(log_content)
|
|
||||||
for line in log_content:gmatch("[^\r\n]+") do
|
|
||||||
local password = line:match('%[%+%] found valid password: %[ (%x%x%x%x%x%x%x%x) %]')
|
|
||||||
if password then
|
|
||||||
return password
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local function reanimate_t5577(password)
|
|
||||||
if password then
|
|
||||||
command('clear')
|
|
||||||
print(dash)
|
|
||||||
print(" Using found password to wipe: " .. password)
|
|
||||||
print(dash)
|
|
||||||
command('lf t55 wipe -p ' .. password)
|
|
||||||
else
|
|
||||||
command('clear')
|
|
||||||
print(dash)
|
|
||||||
print(ac.yellow.." No valid password found, proceeding with reanimation."..ac.reset)
|
|
||||||
print(dash)
|
|
||||||
end
|
|
||||||
command('lf t55 write -b 0 -d 000880E8 -p 00000000')
|
|
||||||
command('lf t55 write -b 0 -d 000880E0 --pg1 --r0 -t -p 00000000')
|
|
||||||
command('lf t55 write -b 0 -d 000880E0 --pg1 --r1 -t -p 00000000')
|
|
||||||
command('lf t55 write -b 0 -d 000880E0 --pg1 --r2 -t -p 00000000')
|
|
||||||
command('lf t55 write -b 0 -d 000880E0 --pg1 --r3 -t -p 00000000')
|
|
||||||
command('lf t55 write -b 0 -d 000880E0 --r0 -p 00000000')
|
|
||||||
command('lf t55 write -b 0 -d 000880E0 --r1 -p 00000000')
|
|
||||||
command('lf t55 write -b 0 -d 000880E0 --r2 -p 00000000')
|
|
||||||
command('lf t55 write -b 0 -d 000880E0 --r3 -p 00000000')
|
|
||||||
command('lf t55 write -b 0 -d 000880E0 --pg1 --r0 -p 00000000')
|
|
||||||
command('lf t55 write -b 0 -d 000880E0 --pg1 --r1 -p 00000000')
|
|
||||||
command('lf t55 write -b 0 -d 000880E0 --pg1 --r2 -p 00000000')
|
|
||||||
command('lf t55 write -b 0 -d 000880E0 --pg1 --r3 -p 00000000')
|
|
||||||
command('lf t55 detect')
|
|
||||||
local file = io.open(logfile, "w+")
|
|
||||||
file:write("")
|
|
||||||
file:close()
|
|
||||||
print(dash)
|
|
||||||
print('all done!')
|
|
||||||
end
|
|
||||||
|
|
||||||
local function main(args)
|
|
||||||
for o, a in getopt.getopt(args, 'h') do
|
|
||||||
if o == 'h' then return help() end
|
|
||||||
end
|
|
||||||
command('lf t55 chk')
|
|
||||||
local log_content = read_log_file(logfile)
|
|
||||||
local password = log_content and extract_password(log_content) or nil
|
|
||||||
reanimate_t5577(password)
|
|
||||||
end
|
|
||||||
|
|
||||||
main(args)
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
"""This script recovers Fudan FM11RF08S cards, including functionalities for Bambu tags decoding."""
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Imports
|
# Imports
|
||||||
|
|
@ -43,17 +44,18 @@ try:
|
||||||
from colors import color
|
from colors import color
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
def color(s, fg=None):
|
def color(s, fg=None):
|
||||||
|
"""Return the string as such, without color."""
|
||||||
_ = fg
|
_ = fg
|
||||||
return str(s)
|
return str(s)
|
||||||
|
|
||||||
|
|
||||||
def initlog():
|
def initlog():
|
||||||
"""Print and Log: init globals
|
"""Print and Log: init globals.
|
||||||
|
|
||||||
globals:
|
globals:
|
||||||
- logbuffer (W)
|
- logbuffer (W)
|
||||||
- logfile (W)
|
- logfile (W)
|
||||||
"""
|
"""
|
||||||
global logbuffer
|
global logbuffer
|
||||||
global logfile
|
global logfile
|
||||||
logbuffer = ''
|
logbuffer = ''
|
||||||
|
|
@ -61,12 +63,12 @@ globals:
|
||||||
|
|
||||||
|
|
||||||
def startlog(uid, dpath, append=False):
|
def startlog(uid, dpath, append=False):
|
||||||
"""Print and Log: set logfile and flush logbuffer
|
"""Print and Log: set logfile and flush logbuffer.
|
||||||
|
|
||||||
globals:
|
globals:
|
||||||
- logbuffer (RW)
|
- logbuffer (RW)
|
||||||
- logfile (RW)
|
- logfile (RW)
|
||||||
"""
|
"""
|
||||||
global logfile
|
global logfile
|
||||||
global logbuffer
|
global logbuffer
|
||||||
|
|
||||||
|
|
@ -81,13 +83,12 @@ globals:
|
||||||
|
|
||||||
|
|
||||||
def lprint(s='', end='\n', flush=False, prompt="[" + color("=", fg="yellow") + "] ", log=True):
|
def lprint(s='', end='\n', flush=False, prompt="[" + color("=", fg="yellow") + "] ", log=True):
|
||||||
"""Print and Log
|
"""Print and Log.
|
||||||
|
|
||||||
globals:
|
|
||||||
- logbuffer (RW)
|
|
||||||
- logfile (R)
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
globals:
|
||||||
|
- logbuffer (RW)
|
||||||
|
- logfile (R)
|
||||||
|
"""
|
||||||
s = f"{prompt}" + f"\n{prompt}".join(s.split('\n'))
|
s = f"{prompt}" + f"\n{prompt}".join(s.split('\n'))
|
||||||
print(s, end=end, flush=flush)
|
print(s, end=end, flush=flush)
|
||||||
|
|
||||||
|
|
@ -102,11 +103,11 @@ globals:
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""== MAIN ==
|
"""== MAIN ==.
|
||||||
|
|
||||||
globals:
|
globals:
|
||||||
- p (W)
|
- p (W)
|
||||||
"""
|
"""
|
||||||
global p
|
global p
|
||||||
p = pm3.pm3() # console interface
|
p = pm3.pm3() # console interface
|
||||||
initlog()
|
initlog()
|
||||||
|
|
@ -143,7 +144,7 @@ globals:
|
||||||
else:
|
else:
|
||||||
# FIXME: recovery() is only for RF08S. TODO for the other ones with a "darknested" attack
|
# FIXME: recovery() is only for RF08S. TODO for the other ones with a "darknested" attack
|
||||||
keyfile = recoverKeys(uid=uid, kdf=[["Bambu v1", kdfBambu1]])
|
keyfile = recoverKeys(uid=uid, kdf=[["Bambu v1", kdfBambu1]])
|
||||||
if keyfile == False:
|
if keyfile is False:
|
||||||
lprint("Script failed - aborting")
|
lprint("Script failed - aborting")
|
||||||
return
|
return
|
||||||
key = loadKeys(keyfile)
|
key = loadKeys(keyfile)
|
||||||
|
|
@ -181,11 +182,11 @@ globals:
|
||||||
|
|
||||||
|
|
||||||
def getPrefs():
|
def getPrefs():
|
||||||
"""Get PM3 preferences
|
"""Get PM3 preferences.
|
||||||
|
|
||||||
globals:
|
globals:
|
||||||
- p (R)
|
- p (R)
|
||||||
"""
|
"""
|
||||||
p.console("prefs show --json")
|
p.console("prefs show --json")
|
||||||
prefs = json.loads(p.grabbed_output)
|
prefs = json.loads(p.grabbed_output)
|
||||||
dpath = prefs['file.default.dumppath'] + os.path.sep
|
dpath = prefs['file.default.dumppath'] + os.path.sep
|
||||||
|
|
@ -193,7 +194,7 @@ globals:
|
||||||
|
|
||||||
|
|
||||||
def checkVer():
|
def checkVer():
|
||||||
"""Assert python version"""
|
"""Assert python version."""
|
||||||
required_version = (3, 8)
|
required_version = (3, 8)
|
||||||
if sys.version_info < required_version:
|
if sys.version_info < required_version:
|
||||||
print(f"Python version: {sys.version}")
|
print(f"Python version: {sys.version}")
|
||||||
|
|
@ -203,7 +204,7 @@ def checkVer():
|
||||||
|
|
||||||
|
|
||||||
def parseCli():
|
def parseCli():
|
||||||
"""Parse the CLi arguments"""
|
"""Parse the CLi arguments."""
|
||||||
parser = argparse.ArgumentParser(description='Full recovery of Fudan FM11RF08S cards.')
|
parser = argparse.ArgumentParser(description='Full recovery of Fudan FM11RF08S cards.')
|
||||||
|
|
||||||
parser.add_argument('-n', '--nokeys', action='store_true', help='extract data even if keys are missing')
|
parser.add_argument('-n', '--nokeys', action='store_true', help='extract data even if keys are missing')
|
||||||
|
|
@ -222,15 +223,15 @@ def parseCli():
|
||||||
|
|
||||||
|
|
||||||
def getBackdoorKey():
|
def getBackdoorKey():
|
||||||
"""Find backdoor key
|
r"""Find backdoor key.
|
||||||
[=] # | sector 00 / 0x00 | ascii
|
|
||||||
[=] ----+-------------------------------------------------+-----------------
|
|
||||||
[=] 0 | 5C B4 9C A6 D2 08 04 00 04 59 92 25 BF 5F 70 90 | \\........Y.%._p.
|
|
||||||
|
|
||||||
globals:
|
[=] # | sector 00 / 0x00 | ascii
|
||||||
- p (R)
|
[=] ----+-------------------------------------------------+-----------------
|
||||||
"""
|
[=] 0 | 5C B4 9C A6 D2 08 04 00 04 59 92 25 BF 5F 70 90 | \........Y.%._p.
|
||||||
|
|
||||||
|
globals:
|
||||||
|
- p (R)
|
||||||
|
"""
|
||||||
# FM11RF08S FM11RF08 FM11RF32
|
# FM11RF08S FM11RF08 FM11RF32
|
||||||
dklist = ["A396EFA4E24F", "A31667A8CEC1", "518b3354E760"]
|
dklist = ["A396EFA4E24F", "A31667A8CEC1", "518b3354E760"]
|
||||||
|
|
||||||
|
|
@ -259,14 +260,14 @@ globals:
|
||||||
|
|
||||||
|
|
||||||
def getUIDfromBlock0(blk0):
|
def getUIDfromBlock0(blk0):
|
||||||
"""Extract UID from block 0"""
|
"""Extract UID from block 0."""
|
||||||
uids = blk0[0:11] # UID string : "11 22 33 44"
|
uids = blk0[0:11] # UID string : "11 22 33 44"
|
||||||
uid = bytes.fromhex(uids.replace(' ', '')) # UID (bytes) : 11223344
|
uid = bytes.fromhex(uids.replace(' ', '')) # UID (bytes) : 11223344
|
||||||
return uid
|
return uid
|
||||||
|
|
||||||
|
|
||||||
def decodeBlock0(blk0):
|
def decodeBlock0(blk0):
|
||||||
"""Extract data from block 0"""
|
"""Extract data from block 0."""
|
||||||
lprint()
|
lprint()
|
||||||
lprint(" UID BCC ++---- RF08* ID -----++")
|
lprint(" UID BCC ++---- RF08* ID -----++")
|
||||||
lprint(" ! ! SAK !! !!")
|
lprint(" ! ! SAK !! !!")
|
||||||
|
|
@ -346,7 +347,7 @@ def decodeBlock0(blk0):
|
||||||
|
|
||||||
|
|
||||||
def fudanValidate(blk0, live=False):
|
def fudanValidate(blk0, live=False):
|
||||||
"""Fudan validation"""
|
"""Fudan validation."""
|
||||||
url = "https://rfid.fm-uivs.com/nfcTools/api/M1KeyRest"
|
url = "https://rfid.fm-uivs.com/nfcTools/api/M1KeyRest"
|
||||||
hdr = "Content-Type: application/text; charset=utf-8"
|
hdr = "Content-Type: application/text; charset=utf-8"
|
||||||
post = f"{blk0.replace(' ', '')}"
|
post = f"{blk0.replace(' ', '')}"
|
||||||
|
|
@ -387,10 +388,10 @@ def fudanValidate(blk0, live=False):
|
||||||
|
|
||||||
|
|
||||||
def loadKeys(keyfile):
|
def loadKeys(keyfile):
|
||||||
"""Load keys from file
|
"""Load keys from file.
|
||||||
|
|
||||||
If keys cannot be loaded AND --recover is specified, then run key recovery
|
If keys cannot be loaded AND --recover is specified, then run key recovery
|
||||||
"""
|
"""
|
||||||
key = [[b'' for _ in range(2)] for _ in range(17)] # create a fresh array
|
key = [[b'' for _ in range(2)] for _ in range(17)] # create a fresh array
|
||||||
|
|
||||||
lprint("\nLoad keys from file... " + color(f"{keyfile}", fg="yellow"))
|
lprint("\nLoad keys from file... " + color(f"{keyfile}", fg="yellow"))
|
||||||
|
|
@ -408,15 +409,15 @@ If keys cannot be loaded AND --recover is specified, then run key recovery
|
||||||
|
|
||||||
|
|
||||||
def recoverKeys(uid, kdf=[[]]):
|
def recoverKeys(uid, kdf=[[]]):
|
||||||
"""Run key recovery script"""
|
"""Run key recovery script."""
|
||||||
badrk = 0 # 'bad recovered key' count (ie. not recovered)
|
badrk = 0 # 'bad recovered key' count (ie. not recovered)
|
||||||
|
|
||||||
keys = False
|
keys = []
|
||||||
lprint(f"\nTrying KDFs:");
|
lprint("\nTrying KDFs:")
|
||||||
for fn in kdf:
|
for fn in kdf:
|
||||||
lprint(f" {fn[0]:s}", end='')
|
lprint(f" {fn[0]:s}", end='')
|
||||||
keys = fn[1](uid)
|
keys = fn[1](uid)
|
||||||
if keys != False:
|
if len(keys) > 0:
|
||||||
lprint(" .. Success", prompt='')
|
lprint(" .. Success", prompt='')
|
||||||
break
|
break
|
||||||
lprint(" .. Fail", prompt='')
|
lprint(" .. Fail", prompt='')
|
||||||
|
|
@ -427,7 +428,7 @@ def recoverKeys(uid, kdf=[[]]):
|
||||||
r = recovery(quiet=False, keyset=keys)
|
r = recovery(quiet=False, keyset=keys)
|
||||||
lprint('`-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
lprint('`-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
||||||
|
|
||||||
if r == False:
|
if r is False:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
keyfile = r['keyfile']
|
keyfile = r['keyfile']
|
||||||
|
|
@ -453,14 +454,28 @@ def recoverKeys(uid, kdf=[[]]):
|
||||||
lprint("", prompt='')
|
lprint("", prompt='')
|
||||||
return keyfile
|
return keyfile
|
||||||
|
|
||||||
|
|
||||||
def kdfBambu1(uid):
|
def kdfBambu1(uid):
|
||||||
|
"""Derive keys from a given UID using the Bambu HKDF algorithm and validates the card data.
|
||||||
|
|
||||||
|
This function generates two keys (keyA and keyB) using the Bambu HKDF algorithm with a predefined salt and context.
|
||||||
|
It then attempts to read block 13 from sector 3 of the card using keyA. If successful, it decodes the data
|
||||||
|
and checks if it matches a specific date format. If the data is valid, it returns a list of derived keys.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uid (bytes): The UID of the card.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: A list of derived keys if the card data is valid.
|
||||||
|
bool: False if any step in the process fails.
|
||||||
|
"""
|
||||||
from Cryptodome.Protocol.KDF import HKDF
|
from Cryptodome.Protocol.KDF import HKDF
|
||||||
from Cryptodome.Hash import SHA256
|
from Cryptodome.Hash import SHA256
|
||||||
|
|
||||||
# Generate all keys
|
# Generate all keys
|
||||||
try:
|
try:
|
||||||
# extracted from Bambu firmware
|
# extracted from Bambu firmware
|
||||||
salt = bytes([0x9a,0x75,0x9c,0xf2,0xc4,0xf7,0xca,0xff,0x22,0x2c,0xb9,0x76,0x9b,0x41,0xbc,0x96])
|
salt = bytes([0x9a, 0x75, 0x9c, 0xf2, 0xc4, 0xf7, 0xca, 0xff, 0x22, 0x2c, 0xb9, 0x76, 0x9b, 0x41, 0xbc, 0x96])
|
||||||
keyA = HKDF(uid, 6, salt, SHA256, 16, context=b"RFID-A\0")
|
keyA = HKDF(uid, 6, salt, SHA256, 16, context=b"RFID-A\0")
|
||||||
keyB = HKDF(uid, 6, salt, SHA256, 16, context=b"RFID-B\0")
|
keyB = HKDF(uid, 6, salt, SHA256, 16, context=b"RFID-B\0")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -469,7 +484,7 @@ def kdfBambu1(uid):
|
||||||
|
|
||||||
# --- Grab block 13 (in sector 3) ---
|
# --- Grab block 13 (in sector 3) ---
|
||||||
cmd = f"hf mf rdbl -c 0 --key {keyA[3].hex()} --blk 12"
|
cmd = f"hf mf rdbl -c 0 --key {keyA[3].hex()} --blk 12"
|
||||||
#lprint(f" `{cmd}`", flush=True, log=False, end='')
|
# lprint(f" `{cmd}`", flush=True, log=False, end='')
|
||||||
for retry in range(5):
|
for retry in range(5):
|
||||||
p.console(cmd)
|
p.console(cmd)
|
||||||
|
|
||||||
|
|
@ -502,13 +517,13 @@ def kdfBambu1(uid):
|
||||||
|
|
||||||
return keys
|
return keys
|
||||||
|
|
||||||
|
|
||||||
def verifyKeys(key):
|
def verifyKeys(key):
|
||||||
"""Verify keys
|
"""Verify keys.
|
||||||
|
|
||||||
globals:
|
|
||||||
- p (R)
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
globals:
|
||||||
|
- p (R)
|
||||||
|
"""
|
||||||
badk = 0
|
badk = 0
|
||||||
mad = False
|
mad = False
|
||||||
|
|
||||||
|
|
@ -563,16 +578,15 @@ globals:
|
||||||
|
|
||||||
|
|
||||||
def readBlocks(bdkey, fast=False):
|
def readBlocks(bdkey, fast=False):
|
||||||
|
r"""Read all block data - INCLUDING advanced verification blocks.
|
||||||
|
|
||||||
|
[=] # | sector 00 / 0x00 | ascii
|
||||||
|
[=] ----+-------------------------------------------------+-----------------
|
||||||
|
[=] 0 | 5C B4 9C A6 D2 08 04 00 04 59 92 25 BF 5F 70 90 | \........Y.%._p.
|
||||||
|
|
||||||
|
globals:
|
||||||
|
- p (R)
|
||||||
"""
|
"""
|
||||||
Read all block data - INCLUDING advanced verification blocks
|
|
||||||
|
|
||||||
[=] # | sector 00 / 0x00 | ascii
|
|
||||||
[=] ----+-------------------------------------------------+-----------------
|
|
||||||
[=] 0 | 5C B4 9C A6 D2 08 04 00 04 59 92 25 BF 5F 70 90 | \\........Y.%._p.
|
|
||||||
|
|
||||||
globals:
|
|
||||||
- p (R)
|
|
||||||
"""
|
|
||||||
data = []
|
data = []
|
||||||
blkn = list(range(0, 63 + 1)) + list(range(128, 135 + 1))
|
blkn = list(range(0, 63 + 1)) + list(range(128, 135 + 1))
|
||||||
|
|
||||||
|
|
@ -634,9 +648,10 @@ globals:
|
||||||
|
|
||||||
|
|
||||||
def patchKeys(data, key):
|
def patchKeys(data, key):
|
||||||
"""Patch keys in to data
|
"""Patch keys in to data.
|
||||||
|
|
||||||
3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
|
3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
|
||||||
"""
|
"""
|
||||||
lprint("\nPatching keys in to data")
|
lprint("\nPatching keys in to data")
|
||||||
|
|
||||||
for sec in range(0, 16 + 1):
|
for sec in range(0, 16 + 1):
|
||||||
|
|
@ -662,7 +677,7 @@ def patchKeys(data, key):
|
||||||
|
|
||||||
|
|
||||||
def dumpData(data, blkn):
|
def dumpData(data, blkn):
|
||||||
"""Dump data"""
|
"""Dump data."""
|
||||||
lprint()
|
lprint()
|
||||||
lprint("===========")
|
lprint("===========")
|
||||||
lprint(" Card Data")
|
lprint(" Card Data")
|
||||||
|
|
@ -708,14 +723,14 @@ def detectBambu(data):
|
||||||
|
|
||||||
|
|
||||||
def dumpBambu(data):
|
def dumpBambu(data):
|
||||||
"""Dump bambu details
|
"""Dump bambu details.
|
||||||
|
|
||||||
https://github.com/Bambu-Research-Group/RFID-Tag-Guide/blob/main/README.md
|
https://github.com/Bambu-Research-Group/RFID-Tag-Guide/blob/main/README.md
|
||||||
|
|
||||||
6 18 30 42 53
|
6 18 30 42 53
|
||||||
| | | | |
|
| | | | |
|
||||||
3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
|
3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
lprint()
|
lprint()
|
||||||
lprint("===========")
|
lprint("===========")
|
||||||
|
|
@ -833,14 +848,14 @@ https://github.com/Bambu-Research-Group/RFID-Tag-Guide/blob/main/README.md
|
||||||
|
|
||||||
# The Access bits on both (used) Sectors is the same: 78 77 88
|
# The Access bits on both (used) Sectors is the same: 78 77 88
|
||||||
|
|
||||||
# Let's reorganise that according to the official spec Fig 9.
|
# Let's reorganize that according to the official spec Fig 9.
|
||||||
# Access C1 C2 C3
|
# Access C1 C2 C3
|
||||||
# ========== ===========
|
# ========== ===========
|
||||||
# 78 77 88 --> 78 87 87
|
# 78 77 88 --> 78 87 87
|
||||||
# ab cd ef --> cb fa ed
|
# ab cd ef --> cb fa ed
|
||||||
|
|
||||||
# The second nybble of each byte is the inverse of the first nybble.
|
# The second nybble of each byte is the inverse of the first nybble.
|
||||||
# It is there to trap tranmission errors, so we can just ignore it/them.
|
# It is there to trap transmission errors, so we can just ignore it/them.
|
||||||
|
|
||||||
# So our Access Control value is : {c, f, e} == {7, 8, 8}
|
# So our Access Control value is : {c, f, e} == {7, 8, 8}
|
||||||
|
|
||||||
|
|
@ -903,13 +918,13 @@ https://github.com/Bambu-Research-Group/RFID-Tag-Guide/blob/main/README.md
|
||||||
# IF YOU PLAN TO CHANGE ACCESS BITS, RTFM, THERE IS MUCH TO CONSIDER !
|
# IF YOU PLAN TO CHANGE ACCESS BITS, RTFM, THERE IS MUCH TO CONSIDER !
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def dumpAcl(data):
|
def dumpAcl(data):
|
||||||
"""Dump ACL
|
"""Dump ACL.
|
||||||
|
|
||||||
6 18 24 27 30 33 42 53
|
6 18 24 27 30 33 42 53
|
||||||
| | | | | | | |
|
| | | | | | | |
|
||||||
3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
|
3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
|
||||||
ab cd ef
|
ab cd ef
|
||||||
"""
|
"""
|
||||||
aclkh = [] # key header
|
aclkh = [] # key header
|
||||||
aclk = [""] * 8 # key lookup
|
aclk = [""] * 8 # key lookup
|
||||||
aclkx = [] # key output
|
aclkx = [] # key output
|
||||||
|
|
@ -1010,10 +1025,10 @@ def dumpAcl(data):
|
||||||
|
|
||||||
|
|
||||||
def diskDump(data, uid, dpath):
|
def diskDump(data, uid, dpath):
|
||||||
"""Full Dump"""
|
"""Full Dump."""
|
||||||
dump18 = f'{dpath}hf-mf-{uid.hex().upper()}-dump18.bin'
|
dump18 = f'{dpath}hf-mf-{uid.hex().upper()}-dump18.bin'
|
||||||
|
|
||||||
lprint(f'\nDump card data to file... ' + color(dump18, fg='yellow'))
|
lprint('\nDump card data to file... ' + color(dump18, fg='yellow'))
|
||||||
|
|
||||||
bad = False
|
bad = False
|
||||||
try:
|
try:
|
||||||
|
|
@ -1037,12 +1052,11 @@ def diskDump(data, uid, dpath):
|
||||||
|
|
||||||
|
|
||||||
def dumpMad(dump18):
|
def dumpMad(dump18):
|
||||||
"""Dump MAD
|
"""Dump MAD.
|
||||||
|
|
||||||
globals:
|
|
||||||
- p (R)
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
globals:
|
||||||
|
- p (R)
|
||||||
|
"""
|
||||||
lprint()
|
lprint()
|
||||||
lprint("====================================")
|
lprint("====================================")
|
||||||
lprint(" MiFare Application Directory (MAD)")
|
lprint(" MiFare Application Directory (MAD)")
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Combine several attacks to recover all FM11RF08S keys.
|
||||||
|
|
||||||
# Combine several attacks to recover all FM11RF08S keys
|
Conditions:
|
||||||
#
|
* Presence of the backdoor with known key
|
||||||
# Conditions:
|
|
||||||
# * Presence of the backdoor with known key
|
Duration strongly depends on some key being reused and where.
|
||||||
#
|
Examples:
|
||||||
# Duration strongly depends on some key being reused and where.
|
* 32 random keys: ~20 min
|
||||||
# Examples:
|
* 16 random keys with keyA==keyB in each sector: ~30 min
|
||||||
# * 32 random keys: ~20 min
|
* 24 random keys, some reused across sectors: <1 min
|
||||||
# * 16 random keys with keyA==keyB in each sector: ~30 min
|
|
||||||
# * 24 random keys, some reused across sectors: <1 min
|
Doegox, 2024, cf https://eprint.iacr.org/2024/1275 for more info
|
||||||
#
|
"""
|
||||||
# Doegox, 2024, cf https://eprint.iacr.org/2024/1275 for more info
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -19,13 +20,17 @@ import time
|
||||||
import subprocess
|
import subprocess
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
import pm3
|
import pm3
|
||||||
|
from pm3_resources import find_tool, find_dict
|
||||||
|
|
||||||
# optional color support
|
# optional color support
|
||||||
try:
|
try:
|
||||||
# pip install ansicolors
|
# pip install ansicolors
|
||||||
from colors import color
|
from colors import color
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
def color(s, fg=None):
|
def color(s, fg=None):
|
||||||
|
"""Return the string as such, without color."""
|
||||||
_ = fg
|
_ = fg
|
||||||
return str(s)
|
return str(s)
|
||||||
|
|
||||||
|
|
@ -42,41 +47,52 @@ BACKDOOR_KEYS = ["A396EFA4E24F", "A31667A8CEC1", "518B3354E760"]
|
||||||
|
|
||||||
NUM_SECTORS = 16
|
NUM_SECTORS = 16
|
||||||
NUM_EXTRA_SECTORS = 1
|
NUM_EXTRA_SECTORS = 1
|
||||||
DICT_DEF = "mfc_default_keys.dic"
|
|
||||||
DEFAULT_KEYS = set()
|
DEFAULT_KEYS = set()
|
||||||
if __name__ == '__main__':
|
|
||||||
DIR_PATH = os.path.dirname(os.path.abspath(sys.argv[0]))
|
|
||||||
else:
|
|
||||||
DIR_PATH = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
|
|
||||||
if os.path.basename(os.path.dirname(DIR_PATH)) == 'client':
|
staticnested_1nt_path = find_tool("staticnested_1nt")
|
||||||
# dev setup
|
staticnested_2x1nt_path = find_tool("staticnested_2x1nt_rf08s")
|
||||||
TOOLS_PATH = os.path.normpath(os.path.join(DIR_PATH,
|
staticnested_2x1nt1key_path = find_tool("staticnested_2x1nt_rf08s_1key")
|
||||||
"..", "..", "tools", "mfc", "card_only"))
|
|
||||||
DICT_DEF_PATH = os.path.normpath(os.path.join(DIR_PATH,
|
|
||||||
"..", "dictionaries", DICT_DEF))
|
|
||||||
else:
|
|
||||||
# assuming installed
|
|
||||||
TOOLS_PATH = os.path.normpath(os.path.join(DIR_PATH,
|
|
||||||
"..", "tools"))
|
|
||||||
DICT_DEF_PATH = os.path.normpath(os.path.join(DIR_PATH,
|
|
||||||
"dictionaries", DICT_DEF))
|
|
||||||
|
|
||||||
tools = {
|
|
||||||
"staticnested_1nt": os.path.join(f"{TOOLS_PATH}", "staticnested_1nt"),
|
def match_key(line):
|
||||||
"staticnested_2x1nt": os.path.join(f"{TOOLS_PATH}", "staticnested_2x1nt_rf08s"),
|
"""
|
||||||
"staticnested_2x1nt1key": os.path.join(f"{TOOLS_PATH}", "staticnested_2x1nt_rf08s_1key"),
|
Extract a 12-character hexadecimal key from a given string.
|
||||||
}
|
|
||||||
for tool, bin in tools.items():
|
Args:
|
||||||
if not os.path.isfile(bin):
|
line (str): The input string to search for the hexadecimal key.
|
||||||
if os.path.isfile(bin + ".exe"):
|
|
||||||
tools[tool] = bin + ".exe"
|
Returns:
|
||||||
|
str or None: The 12-character hexadecimal key in uppercase if found, otherwise None.
|
||||||
|
"""
|
||||||
|
match = re.search(r'([0-9a-fA-F]{12})', line)
|
||||||
|
if match:
|
||||||
|
return match.group(1).upper()
|
||||||
else:
|
else:
|
||||||
print(f"Cannot find {bin}, abort!")
|
return None
|
||||||
exit()
|
|
||||||
|
|
||||||
|
|
||||||
def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debug=False, supply_chain=False, quiet=True, keyset=False):
|
def recovery(init_check=False, final_check=False, keep=False, no_oob=False,
|
||||||
|
debug=False, supply_chain=False, quiet=True, keyset=[]):
|
||||||
|
"""
|
||||||
|
Perform recovery operation for FM11RF08S cards.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
init_check (bool): If True, check for default keys initially.
|
||||||
|
final_check (bool): If True, perform a final check and dump keys.
|
||||||
|
keep (bool): If True, keep the generated dictionaries after processing.
|
||||||
|
no_oob (bool): If True, do not include out-of-bounds sectors.
|
||||||
|
debug (bool): If True, print debug information.
|
||||||
|
supply_chain (bool): If True, use supply-chain attack data.
|
||||||
|
quiet (bool): If True, suppress output messages.
|
||||||
|
keyset (list): A list of key pairs to use for the recovery process.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dictionary containing the following keys:
|
||||||
|
- 'keyfile': Path to the generated binary key file.
|
||||||
|
- 'found_keys': List of found keys for each sector.
|
||||||
|
- 'dump_file': Path to the generated dump file.
|
||||||
|
- 'data': List of data blocks for each sector.
|
||||||
|
"""
|
||||||
def show(s='', prompt="[" + color("=", fg="yellow") + "] ", **kwargs):
|
def show(s='', prompt="[" + color("=", fg="yellow") + "] ", **kwargs):
|
||||||
if not quiet:
|
if not quiet:
|
||||||
s = f"{prompt}" + f"\n{prompt}".join(s.split('\n'))
|
s = f"{prompt}" + f"\n{prompt}".join(s.split('\n'))
|
||||||
|
|
@ -107,10 +123,10 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
|
|
||||||
found_keys = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
found_keys = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
|
|
||||||
if keyset != False:
|
if len(keyset) > 0:
|
||||||
n = min(len(found_keys),len(keyset))
|
n = min(len(found_keys), len(keyset))
|
||||||
show(f"{n} Key pairs supplied: ")
|
show(f"{n} Key pairs supplied: ")
|
||||||
for i in range(0, n):
|
for i in range(n):
|
||||||
found_keys[i] = keyset[i]
|
found_keys[i] = keyset[i]
|
||||||
show(f" Sector {i:2d} : A = {found_keys[i][0]:12s} B = {found_keys[i][1]:12s}")
|
show(f" Sector {i:2d} : A = {found_keys[i][0]:12s} B = {found_keys[i][1]:12s}")
|
||||||
|
|
||||||
|
|
@ -136,8 +152,9 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
if "Wrong" in line or "error" in line:
|
if "Wrong" in line or "error" in line:
|
||||||
break
|
break
|
||||||
if "Saved" in line:
|
matched = "Saved to json file "
|
||||||
nonces_with_data = line[line.index("`"):].strip("`")
|
if matched in line:
|
||||||
|
nonces_with_data = line[line.index(matched)+len(matched):]
|
||||||
if nonces_with_data != "":
|
if nonces_with_data != "":
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
@ -171,8 +188,8 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
data[blk] = dict_nwd["blocks"][f"{blk}"]
|
data[blk] = dict_nwd["blocks"][f"{blk}"]
|
||||||
|
|
||||||
show("Generating first dump file")
|
show("Generating first dump file")
|
||||||
dumpfile = f"{save_path}hf-mf-{uid:08X}-dump.bin"
|
dump_file = f"{save_path}hf-mf-{uid:08X}-dump.bin"
|
||||||
with (open(dumpfile, "wb")) as f:
|
with (open(dump_file, "wb")) as f:
|
||||||
for sec in range(NUM_SECTORS):
|
for sec in range(NUM_SECTORS):
|
||||||
for b in range(4):
|
for b in range(4):
|
||||||
d = data[(sec * 4) + b]
|
d = data[(sec * 4) + b]
|
||||||
|
|
@ -185,7 +202,7 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
kb = "FFFFFFFFFFFF"
|
kb = "FFFFFFFFFFFF"
|
||||||
d = ka + d[12:20] + kb
|
d = ka + d[12:20] + kb
|
||||||
f.write(bytes.fromhex(d))
|
f.write(bytes.fromhex(d))
|
||||||
show(f"Data has been dumped to `{dumpfile}`")
|
show(f"Data has been dumped to `{dump_file}`")
|
||||||
|
|
||||||
elapsed_time1 = time.time() - start_time
|
elapsed_time1 = time.time() - start_time
|
||||||
minutes = int(elapsed_time1 // 60)
|
minutes = int(elapsed_time1 // 60)
|
||||||
|
|
@ -193,14 +210,18 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
show("----Step 1: " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
show("----Step 1: " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
||||||
color(f"{seconds:2}", fg="yellow") + " seconds -----------")
|
color(f"{seconds:2}", fg="yellow") + " seconds -----------")
|
||||||
|
|
||||||
if os.path.isfile(DICT_DEF_PATH):
|
dict_def = "mfc_default_keys.dic"
|
||||||
show(f"Loading {DICT_DEF}")
|
try:
|
||||||
with open(DICT_DEF_PATH, 'r', encoding='utf-8') as file:
|
dict_path = find_dict(dict_def)
|
||||||
|
with open(dict_path, 'r', encoding='utf-8') as file:
|
||||||
for line in file:
|
for line in file:
|
||||||
if line[0] != '#' and len(line) >= 12:
|
if line[0] != '#' and len(line) >= 12:
|
||||||
DEFAULT_KEYS.add(line[:12])
|
DEFAULT_KEYS.add(line[:12])
|
||||||
else:
|
show(f"Loaded {dict_def}")
|
||||||
show(f"Warning, {DICT_DEF} not found.")
|
except FileNotFoundError:
|
||||||
|
show(f"Warning, {dict_def} not found.")
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(f"Error loading {dict_def}: {e}")
|
||||||
|
|
||||||
dict_dnwd = None
|
dict_dnwd = None
|
||||||
def_nt = ["" for _ in range(NUM_SECTORS)]
|
def_nt = ["" for _ in range(NUM_SECTORS)]
|
||||||
|
|
@ -233,12 +254,12 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
continue
|
continue
|
||||||
if found_keys[sec][0] == "" and found_keys[sec][1] == "" and nt[sec][0] != nt[sec][1]:
|
if found_keys[sec][0] == "" and found_keys[sec][1] == "" and nt[sec][0] != nt[sec][1]:
|
||||||
for key_type in [0, 1]:
|
for key_type in [0, 1]:
|
||||||
cmd = [tools["staticnested_1nt"], f"{uid:08X}", f"{real_sec}",
|
cmd = [staticnested_1nt_path, f"{uid:08X}", f"{real_sec}",
|
||||||
nt[sec][key_type], nt_enc[sec][key_type], par_err[sec][key_type]]
|
nt[sec][key_type], nt_enc[sec][key_type], par_err[sec][key_type]]
|
||||||
if debug:
|
if debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
subprocess.run(cmd, capture_output=True)
|
subprocess.run(cmd, capture_output=True)
|
||||||
cmd = [tools["staticnested_2x1nt"],
|
cmd = [staticnested_2x1nt_path,
|
||||||
f"keys_{uid:08x}_{real_sec:02}_{nt[sec][0]}.dic", f"keys_{uid:08x}_{real_sec:02}_{nt[sec][1]}.dic"]
|
f"keys_{uid:08x}_{real_sec:02}_{nt[sec][0]}.dic", f"keys_{uid:08x}_{real_sec:02}_{nt[sec][1]}.dic"]
|
||||||
if debug:
|
if debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
|
|
@ -254,15 +275,16 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
all_keys.update(keys_set)
|
all_keys.update(keys_set)
|
||||||
if dict_dnwd is not None and sec < NUM_SECTORS:
|
if dict_dnwd is not None and sec < NUM_SECTORS:
|
||||||
# Prioritize keys from supply-chain attack
|
# Prioritize keys from supply-chain attack
|
||||||
cmd = [tools["staticnested_2x1nt1key"], def_nt[sec], "FFFFFFFFFFFF",
|
cmd = [staticnested_2x1nt1key_path, def_nt[sec], "FFFFFFFFFFFF",
|
||||||
f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_filtered.dic"]
|
f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_filtered.dic"]
|
||||||
if debug:
|
if debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
||||||
keys_def_set = set()
|
keys_def_set = set()
|
||||||
for line in result.split('\n'):
|
for line in result.split('\n'):
|
||||||
if "MATCH:" in line:
|
matched = match_key(line)
|
||||||
keys_def_set.add(line[12:])
|
if matched is not None:
|
||||||
|
keys_def_set.add(matched)
|
||||||
keys_set.difference_update(keys_def_set)
|
keys_set.difference_update(keys_def_set)
|
||||||
else:
|
else:
|
||||||
# Prioritize default keys
|
# Prioritize default keys
|
||||||
|
|
@ -285,7 +307,7 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
key_type = 0
|
key_type = 0
|
||||||
else:
|
else:
|
||||||
key_type = 1
|
key_type = 1
|
||||||
cmd = [tools["staticnested_1nt"], f"{uid:08X}", f"{real_sec}",
|
cmd = [staticnested_1nt_path, f"{uid:08X}", f"{real_sec}",
|
||||||
nt[sec][key_type], nt_enc[sec][key_type], par_err[sec][key_type]]
|
nt[sec][key_type], nt_enc[sec][key_type], par_err[sec][key_type]]
|
||||||
if debug:
|
if debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
|
|
@ -299,15 +321,16 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
all_keys.update(keys_set)
|
all_keys.update(keys_set)
|
||||||
if dict_dnwd is not None and sec < NUM_SECTORS:
|
if dict_dnwd is not None and sec < NUM_SECTORS:
|
||||||
# Prioritize keys from supply-chain attack
|
# Prioritize keys from supply-chain attack
|
||||||
cmd = [tools["staticnested_2x1nt1key"], def_nt[sec], "FFFFFFFFFFFF",
|
cmd = [staticnested_2x1nt1key_path, def_nt[sec], "FFFFFFFFFFFF",
|
||||||
f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}.dic"]
|
f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}.dic"]
|
||||||
if debug:
|
if debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
||||||
keys_def_set = set()
|
keys_def_set = set()
|
||||||
for line in result.split('\n'):
|
for line in result.split('\n'):
|
||||||
if "MATCH:" in line:
|
matched = match_key(line)
|
||||||
keys_def_set.add(line[12:])
|
if matched is not None:
|
||||||
|
keys_def_set.add(matched)
|
||||||
keys_set.difference_update(keys_def_set)
|
keys_set.difference_update(keys_def_set)
|
||||||
else:
|
else:
|
||||||
# Prioritize default keys
|
# Prioritize default keys
|
||||||
|
|
@ -440,8 +463,9 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
if "aborted via keyboard" in line:
|
if "aborted via keyboard" in line:
|
||||||
abort = True
|
abort = True
|
||||||
if "found:" in line:
|
matched = match_key(line)
|
||||||
found_keys[sec][key_type] = line[30:].strip()
|
if matched is not None:
|
||||||
|
found_keys[sec][key_type] = matched
|
||||||
show_key(real_sec, key_type, found_keys[sec][key_type])
|
show_key(real_sec, key_type, found_keys[sec][key_type])
|
||||||
if nt[sec][0] == nt[sec][1] and found_keys[sec][key_type ^ 1] == "":
|
if nt[sec][0] == nt[sec][1] and found_keys[sec][key_type ^ 1] == "":
|
||||||
found_keys[sec][key_type ^ 1] = found_keys[sec][key_type]
|
found_keys[sec][key_type ^ 1] = found_keys[sec][key_type]
|
||||||
|
|
@ -466,8 +490,9 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
if "aborted via keyboard" in line:
|
if "aborted via keyboard" in line:
|
||||||
abort = True
|
abort = True
|
||||||
if "found:" in line:
|
matched = match_key(line)
|
||||||
found_keys[sec][key_type] = line[30:].strip()
|
if matched is not None:
|
||||||
|
found_keys[sec][key_type] = matched
|
||||||
show_key(real_sec, key_type, found_keys[sec][key_type])
|
show_key(real_sec, key_type, found_keys[sec][key_type])
|
||||||
if abort:
|
if abort:
|
||||||
break
|
break
|
||||||
|
|
@ -487,11 +512,12 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
if "aborted via keyboard" in line:
|
if "aborted via keyboard" in line:
|
||||||
abort = True
|
abort = True
|
||||||
if "found:" in line:
|
matched = match_key(line)
|
||||||
found_keys[sec][0] = line[30:].strip()
|
if matched is not None:
|
||||||
found_keys[sec][1] = line[30:].strip()
|
found_keys[sec][0] = matched
|
||||||
show_key(real_sec, 0, found_keys[sec][key_type])
|
found_keys[sec][1] = matched
|
||||||
show_key(real_sec, 1, found_keys[sec][key_type])
|
show_key(real_sec, 0, found_keys[sec][0])
|
||||||
|
show_key(real_sec, 1, found_keys[sec][1])
|
||||||
if abort:
|
if abort:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
@ -509,14 +535,15 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type_target]}_filtered.dic"
|
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type_target]}_filtered.dic"
|
||||||
else:
|
else:
|
||||||
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type_target]}.dic"
|
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type_target]}.dic"
|
||||||
cmd = [tools["staticnested_2x1nt1key"], nt[sec][key_type_source], found_keys[sec][key_type_source], dic]
|
cmd = [staticnested_2x1nt1key_path, nt[sec][key_type_source], found_keys[sec][key_type_source], dic]
|
||||||
if debug:
|
if debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
||||||
keys = set()
|
keys = set()
|
||||||
for line in result.split('\n'):
|
for line in result.split('\n'):
|
||||||
if "MATCH:" in line:
|
matched = match_key(line)
|
||||||
keys.add(line[12:])
|
if matched is not None:
|
||||||
|
keys.add(matched)
|
||||||
if len(keys) > 1:
|
if len(keys) > 1:
|
||||||
kt = ['a', 'b'][key_type_target]
|
kt = ['a', 'b'][key_type_target]
|
||||||
cmd = f"hf mf fchk --blk {real_sec * 4} -{kt} --no-default"
|
cmd = f"hf mf fchk --blk {real_sec * 4} -{kt} --no-default"
|
||||||
|
|
@ -528,8 +555,9 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
if "aborted via keyboard" in line:
|
if "aborted via keyboard" in line:
|
||||||
abort = True
|
abort = True
|
||||||
if "found:" in line:
|
matched = match_key(line)
|
||||||
found_keys[sec][key_type_target] = line[30:].strip()
|
if matched is not None:
|
||||||
|
found_keys[sec][key_type_target] = matched
|
||||||
elif len(keys) == 1:
|
elif len(keys) == 1:
|
||||||
found_keys[sec][key_type_target] = keys.pop()
|
found_keys[sec][key_type_target] = keys.pop()
|
||||||
if found_keys[sec][key_type_target] != "":
|
if found_keys[sec][key_type_target] != "":
|
||||||
|
|
@ -551,7 +579,10 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
cmd = f"hf mf fchk -f keys_{uid:08x}.dic --no-default --dump"
|
cmd = f"hf mf fchk -f keys_{uid:08x}.dic --no-default --dump"
|
||||||
if debug:
|
if debug:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
p.console(cmd, capture=False, quiet=False)
|
p.console(cmd, capture=True, quiet=False)
|
||||||
|
for line in p.grabbed_output.split('\n'):
|
||||||
|
if "Found keys have been dumped to" in line:
|
||||||
|
keyfile = line[line.index("`"):].strip("`")
|
||||||
else:
|
else:
|
||||||
show()
|
show()
|
||||||
show(color("found keys:", fg="green"), prompt=plus)
|
show(color("found keys:", fg="green"), prompt=plus)
|
||||||
|
|
@ -591,8 +622,8 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
show(" --[ " + color("FFFFFFFFFFFF", fg="yellow") +
|
show(" --[ " + color("FFFFFFFFFFFF", fg="yellow") +
|
||||||
" ]-- has been inserted for unknown keys", prompt="[" + color("=", fg="yellow") + "]")
|
" ]-- has been inserted for unknown keys", prompt="[" + color("=", fg="yellow") + "]")
|
||||||
show("Generating final dump file", prompt=plus)
|
show("Generating final dump file", prompt=plus)
|
||||||
dumpfile = f"{save_path}hf-mf-{uid:08X}-dump.bin"
|
dump_file = f"{save_path}hf-mf-{uid:08X}-dump.bin"
|
||||||
with (open(dumpfile, "wb")) as f:
|
with (open(dump_file, "wb")) as f:
|
||||||
for sec in range(NUM_SECTORS):
|
for sec in range(NUM_SECTORS):
|
||||||
for b in range(4):
|
for b in range(4):
|
||||||
d = data[(sec * 4) + b]
|
d = data[(sec * 4) + b]
|
||||||
|
|
@ -605,7 +636,7 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
kb = "FFFFFFFFFFFF"
|
kb = "FFFFFFFFFFFF"
|
||||||
d = ka + d[12:20] + kb
|
d = ka + d[12:20] + kb
|
||||||
f.write(bytes.fromhex(d))
|
f.write(bytes.fromhex(d))
|
||||||
show("Data has been dumped to `" + color(dumpfile, fg="yellow")+"`", prompt=plus)
|
show("Data has been dumped to `" + color(dump_file, fg="yellow")+"`", prompt=plus)
|
||||||
|
|
||||||
# Remove generated dictionaries after processing
|
# Remove generated dictionaries after processing
|
||||||
if not keep:
|
if not keep:
|
||||||
|
|
@ -631,11 +662,27 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, debu
|
||||||
seconds = int(elapsed_time % 60)
|
seconds = int(elapsed_time % 60)
|
||||||
show("---- TOTAL: " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
show("---- TOTAL: " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
||||||
color(f"{seconds:2}", fg="yellow") + " seconds -----------")
|
color(f"{seconds:2}", fg="yellow") + " seconds -----------")
|
||||||
|
return {'keyfile': keyfile, 'found_keys': found_keys, 'dump_file': dump_file, 'data': data}
|
||||||
return {'keyfile': keyfile, 'found_keys': found_keys, 'dumpfile': dumpfile, 'data': data}
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
"""
|
||||||
|
Parse command-line arguments and initiate the recovery process.
|
||||||
|
|
||||||
|
Command-line arguments:
|
||||||
|
-x, --init-check: Run an initial fchk for default keys.
|
||||||
|
-y, --final-check: Run a final fchk with the found keys.
|
||||||
|
-n, --no-oob: Do not save out of bounds keys.
|
||||||
|
-k, --keep: Keep generated dictionaries after processing.
|
||||||
|
-d, --debug: Enable debug mode.
|
||||||
|
-s, --supply-chain: Enable supply-chain mode. Look for hf-mf-XXXXXXXX-default_nonces.json.
|
||||||
|
|
||||||
|
The supply-chain mode json can be produced from the json saved by
|
||||||
|
"hf mf isen --collect_fm11rf08s --key A396EFA4E24F" on a wiped card, then processed with
|
||||||
|
jq '{Created: .Created, FileType: "fm11rf08s_default_nonces", nt: .nt | del(.["32"]) | map_values(.a)}'.
|
||||||
|
|
||||||
|
This function calls the recovery function with the parsed arguments.
|
||||||
|
"""
|
||||||
parser = argparse.ArgumentParser(description='A script combining staticnested* tools '
|
parser = argparse.ArgumentParser(description='A script combining staticnested* tools '
|
||||||
'to recover all keys from a FM11RF08S card.')
|
'to recover all keys from a FM11RF08S card.')
|
||||||
parser.add_argument('-x', '--init-check', action='store_true', help='Run an initial fchk for default keys')
|
parser.add_argument('-x', '--init-check', action='store_true', help='Run an initial fchk for default keys')
|
||||||
|
|
|
||||||
198
client/pyscripts/hf_mfu_uscuid.py
Normal file
198
client/pyscripts/hf_mfu_uscuid.py
Normal file
|
|
@ -0,0 +1,198 @@
|
||||||
|
### Crappy helper script for USCUID-UL, v0.2.4.2
|
||||||
|
## Written and tested by Eltrick
|
||||||
|
# It is recommended that you are able to backdoor read main blocks
|
||||||
|
# in case changing from one type to another messes up keys/pwd
|
||||||
|
# unless you know what you're doing.
|
||||||
|
|
||||||
|
## For the uninitiated, the keys are stored in the following locations
|
||||||
|
## per the corresponding datasheets
|
||||||
|
# UL11 - PWD - page 18d
|
||||||
|
# UL21 - PWD - page 39d
|
||||||
|
# UL-C - KEY - pages 44d to 47d
|
||||||
|
# NTAG 213 - PWD - page 43d
|
||||||
|
# NTAG 215 - PWD - page 133d
|
||||||
|
# NTAG 216 - PWD - page 229d
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import pm3
|
||||||
|
|
||||||
|
try:
|
||||||
|
# pip install ansicolors
|
||||||
|
from colors import color
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
def color(s, fg=None):
|
||||||
|
_ = fg
|
||||||
|
return str(s)
|
||||||
|
|
||||||
|
HEX_DIGITS = "0123456789ABCDEF"
|
||||||
|
MEMORY_CONFIG = { "C3": "UL11", "3C": "UL21", "00": "UL-C", "A5": "NTAG 213", "5A": "NTAG 215", "AA": "NTAG 216", "55": "Unknown IC with 238 pages" }
|
||||||
|
KNOWN_CONFIGS = ["C30004030101000B03", "3C0004030101000E03", "000000000000000000", "A50004040201000F03", "5A0004040201001103", "AA0004040201001303"]
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='A script to help with raw USCUID-UL commands. Out of everything until -s, only one functionality can be used at a time, prioritised in order listed below.')
|
||||||
|
parser.add_argument('-r', '--read', action='store_true', help='Read and parse config from card')
|
||||||
|
parser.add_argument('-t', '--type', help='Type to change to: 1-UL11; 2-UL21; 3-UL-C; 4-NTAG213; 5-NTAG215; 6-NTAG216')
|
||||||
|
parser.add_argument('-c', '--cfg', help='Config to write')
|
||||||
|
parser.add_argument('-p', '--parse', help='Config to parse')
|
||||||
|
parser.add_argument('-b', '--bdr', help='Page num to read with backdoor')
|
||||||
|
parser.add_argument('-w', '--wbd', help='First page num to write with backdoor')
|
||||||
|
parser.add_argument('-u', '--uid', help='New UID to write')
|
||||||
|
parser.add_argument('-d', '--data', help='Page data to write if using -w, multiple of 4 bytes')
|
||||||
|
parser.add_argument('-s', '--sig', help='Signature to write with backdoor')
|
||||||
|
parser.add_argument('--gen1a', action='store_true', help='Use gen1a (40/43) magic wakeup')
|
||||||
|
parser.add_argument('--gdm', action='store_true', help='Use gdm alt (20/23) magic wakeup')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
card_config = args.read
|
||||||
|
ul_type = args.type
|
||||||
|
config = args.cfg
|
||||||
|
parse = args.parse
|
||||||
|
backdoor_block = args.bdr
|
||||||
|
write_backdoor = args.wbd
|
||||||
|
data = args.data
|
||||||
|
signature = args.sig
|
||||||
|
gen1a = args.gen1a
|
||||||
|
alt = args.gdm
|
||||||
|
uid = args.uid
|
||||||
|
|
||||||
|
field_on = False
|
||||||
|
p = pm3.pm3()
|
||||||
|
|
||||||
|
ERROR = "[" + color("-", "red") + "] "
|
||||||
|
SUCCESS = "[" + color("+", "green") + "] "
|
||||||
|
|
||||||
|
def verify_config(config: str) -> bool:
|
||||||
|
if len(config) != 32:
|
||||||
|
print(ERROR + "Configuration data must be 16 bytes.")
|
||||||
|
return False
|
||||||
|
if set(config) > set(HEX_DIGITS):
|
||||||
|
print(ERROR + "Configuration data must be in hex.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def parse_config(config: str):
|
||||||
|
print(SUCCESS + "" + config)
|
||||||
|
cfg_magic_wup = config[0:4]
|
||||||
|
cfg_wup_style = config[4:6]
|
||||||
|
cfg_regular_available = config[6:8]
|
||||||
|
cfg_auth_type = config[8:10]
|
||||||
|
cfg_cuid = config[12:14]
|
||||||
|
cfg_memory_config = config[14:16]
|
||||||
|
|
||||||
|
log_magic_wup = "Magic wakeup " + ("en" if cfg_magic_wup != "8500" else "dis") + "abled" + (" with config access" if cfg_magic_wup == "7AFF" else "")
|
||||||
|
log_wup_style = "Magic wakeup style " + ("Gen1a 40(7)/43" if cfg_wup_style == "00" else ("GDM 20(7)/23" if cfg_wup_style == "85" else "unknown"))
|
||||||
|
log_regular_available = "Config " + ("" if cfg_regular_available == "A0" else "un") + "available in regular mode"
|
||||||
|
log_auth_type = "Auth type " + ("1B - PWD" if cfg_auth_type == "00" else "1A - 3DES")
|
||||||
|
log_cuid = "CUID " + ("dis" if cfg_cuid == "A0" else "en") + "abled"
|
||||||
|
log_memory_config = "Maximum memory configuration: " + (MEMORY_CONFIG[cfg_memory_config] if cfg_memory_config in MEMORY_CONFIG.keys() else "unknown")
|
||||||
|
|
||||||
|
print(SUCCESS + "^^^^............................ " + log_magic_wup)
|
||||||
|
print(SUCCESS + "....^^.......................... " + log_wup_style)
|
||||||
|
print(SUCCESS + "......^^........................ " + log_regular_available)
|
||||||
|
print(SUCCESS + "........^^...................... " + log_auth_type)
|
||||||
|
print(SUCCESS + "..........^^.................... unknown")
|
||||||
|
print(SUCCESS + "............^^.................. " + log_cuid)
|
||||||
|
print(SUCCESS + "..............^^................ " + log_memory_config)
|
||||||
|
print(SUCCESS + "................^^^^^^^^^^^^^^^^ version info")
|
||||||
|
|
||||||
|
def try_auth_magic(enforced = False):
|
||||||
|
if enforced and not (gen1a | alt):
|
||||||
|
print(ERROR + "Magic wakeup required. Please select one.")
|
||||||
|
exit()
|
||||||
|
if gen1a ^ alt:
|
||||||
|
p.console("hf 14a raw -akb 7 " + ("40" if gen1a else "20"))
|
||||||
|
p.console("hf 14a raw -k " + ("43" if gen1a else "23"))
|
||||||
|
|
||||||
|
def write_config(config: str):
|
||||||
|
try_auth_magic()
|
||||||
|
for i in range(4):
|
||||||
|
p.console("hf 14a raw -" + ("s" if (i == 0 and not (gen1a or alt)) else "") + ("k" if i != 3 else "") + "c" + f" E2{i:02x}" + config[8*i:8*i+8], False, False)
|
||||||
|
|
||||||
|
def grab_config() -> str:
|
||||||
|
try_auth_magic()
|
||||||
|
p.console("hf 14a raw -c" + ("s" if not (gen1a or alt) else "") + " E050")
|
||||||
|
return p.grabbed_output.split("\n")[-2][4:-9].replace(" ", "")
|
||||||
|
|
||||||
|
if gen1a and alt:
|
||||||
|
print(ERROR + "Please only choose one magic wakeup type.")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
if card_config:
|
||||||
|
config_grab = grab_config()
|
||||||
|
if not verify_config(config_grab):
|
||||||
|
print(ERROR + "Failed to grab config data from card.")
|
||||||
|
exit()
|
||||||
|
parse_config(config_grab)
|
||||||
|
|
||||||
|
elif ul_type != None:
|
||||||
|
ul_type_num = int(ul_type) - 1
|
||||||
|
if ul_type_num < 0 or ul_type_num >= len(KNOWN_CONFIGS):
|
||||||
|
print(ERROR + "Type specified is non-existent.")
|
||||||
|
exit()
|
||||||
|
old_config = grab_config()
|
||||||
|
new_config = old_config[0:8] + ("0A" if ul_type_num == 2 else "00") + old_config[10:14] + KNOWN_CONFIGS[ul_type_num]
|
||||||
|
write_config(new_config)
|
||||||
|
|
||||||
|
elif config != None:
|
||||||
|
config = config.upper()
|
||||||
|
if not verify_config(config):
|
||||||
|
exit()
|
||||||
|
write_config(config)
|
||||||
|
|
||||||
|
elif parse != None:
|
||||||
|
parse = parse.upper()
|
||||||
|
if not verify_config(parse):
|
||||||
|
exit()
|
||||||
|
parse_config(parse)
|
||||||
|
|
||||||
|
elif backdoor_block != None:
|
||||||
|
block = int(backdoor_block)
|
||||||
|
try_auth_magic(True)
|
||||||
|
p.console(f"hf 14a raw -c 30{block:02x}")
|
||||||
|
print(p.grabbed_output.split("\n")[-2][4:-9].replace(" ", ""))
|
||||||
|
|
||||||
|
elif write_backdoor != None:
|
||||||
|
write_backdoor_num = int(write_backdoor)
|
||||||
|
if data == None:
|
||||||
|
print(ERROR + "Specify data to write to the block.")
|
||||||
|
exit()
|
||||||
|
if len(data) % 8 != 0:
|
||||||
|
print(ERROR + "Data must be a multiple of 4 bytes.")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
try_auth_magic(True)
|
||||||
|
for i in range(len(data) // 8):
|
||||||
|
p.console("hf 14a raw -" + ("k" if i != (len(data) // 8 - 1) else "") + f"c A2{(write_backdoor_num + i):02x}{data[8*i:8*i+8]}", False, False)
|
||||||
|
|
||||||
|
elif uid != None:
|
||||||
|
if len(uid) != 14:
|
||||||
|
print(ERROR + "UID must be 7 bytes.")
|
||||||
|
exit()
|
||||||
|
try_auth_magic()
|
||||||
|
p.console(f"hf 14a raw -kc" + ("s" if not (gen1a or alt) else "") + " 3002")
|
||||||
|
block_2 = p.grabbed_output.split("\n")[-2][4:-9].replace(" ", "")[:8]
|
||||||
|
uid_bytes = [int(uid[2*x:2*x+2], 16) for x in range(7)]
|
||||||
|
|
||||||
|
bcc_0 = 0x88 ^ uid_bytes[0] ^ uid_bytes[1] ^ uid_bytes[2]
|
||||||
|
new_block_0 = ""
|
||||||
|
for i in range(3):
|
||||||
|
new_block_0 += f"{uid_bytes[i]:02x}"
|
||||||
|
new_block_0 += f"{bcc_0:02x}"
|
||||||
|
|
||||||
|
bcc_1 = uid_bytes[3] ^ uid_bytes[4] ^ uid_bytes[5] ^ uid_bytes[6]
|
||||||
|
new_block_1 = uid[6:]
|
||||||
|
new_block_2 = f"{bcc_1:02x}" + block_2[2:]
|
||||||
|
p.console("hf 14a raw -kc A200" + new_block_0, False, False)
|
||||||
|
p.console("hf 14a raw -kc A201" + new_block_1, False, False)
|
||||||
|
p.console("hf 14a raw -c A202" + new_block_2, False, False)
|
||||||
|
|
||||||
|
elif signature != None:
|
||||||
|
if len(signature) != 64:
|
||||||
|
print(ERROR + "Signature must be 32 bytes.")
|
||||||
|
exit()
|
||||||
|
try_auth_magic(True)
|
||||||
|
signature_pages = [signature[8*x:8*x+8] for x in range(8)]
|
||||||
|
for i in range(8, 16):
|
||||||
|
p.console("hf 14a raw -c" + ("k" if i != 15 else "") + f" A2F{i:01x}{signature_pages[i - 8]}", False, False)
|
||||||
|
|
||||||
|
# Always try to HALT
|
||||||
|
p.console("hf 14a raw -c 5000")
|
||||||
|
|
@ -284,6 +284,7 @@ FRA_OrganizationalAuthority_Contract_Provider = {
|
||||||
},
|
},
|
||||||
0x091: {
|
0x091: {
|
||||||
1: InterticHelper('Strasbourg', 'CTS', Describe_Usage_4), # More dump needed, not only tram !
|
1: InterticHelper('Strasbourg', 'CTS', Describe_Usage_4), # More dump needed, not only tram !
|
||||||
|
5: InterticHelper('Strasbourg', 'CTS / new', Describe_Usage_4), # More dump needed, not only tram !
|
||||||
},
|
},
|
||||||
0x502: {
|
0x502: {
|
||||||
83: InterticHelper('Annecy', 'Sibra', Describe_Usage_2),
|
83: InterticHelper('Annecy', 'Sibra', Describe_Usage_2),
|
||||||
|
|
|
||||||
32
client/pyscripts/Paxton_convert.py → client/pyscripts/paxton_convert.py
Normal file → Executable file
32
client/pyscripts/Paxton_convert.py → client/pyscripts/paxton_convert.py
Normal file → Executable file
|
|
@ -1,3 +1,5 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# paxton_convert.py - Convert Paxton Net2 and Switch2 to EM4102
|
# paxton_convert.py - Convert Paxton Net2 and Switch2 to EM4102
|
||||||
# Author jareckib <jareckib@hotmail.com>
|
# Author jareckib <jareckib@hotmail.com>
|
||||||
# Based on Equipter's tutorial - Downgrade Paxton Net to EM410x
|
# Based on Equipter's tutorial - Downgrade Paxton Net to EM410x
|
||||||
|
|
@ -19,68 +21,95 @@
|
||||||
import sys
|
import sys
|
||||||
def hex_to_bin(hex_string):
|
def hex_to_bin(hex_string):
|
||||||
return ''.join(format(byte, '08b') for byte in bytearray.fromhex(hex_string))
|
return ''.join(format(byte, '08b') for byte in bytearray.fromhex(hex_string))
|
||||||
|
|
||||||
def remove_last_two_bits(binary_str):
|
def remove_last_two_bits(binary_str):
|
||||||
return binary_str[:-2]
|
return binary_str[:-2]
|
||||||
|
|
||||||
def split_into_5bit_chunks(binary_str):
|
def split_into_5bit_chunks(binary_str):
|
||||||
return [binary_str[i:i+5] for i in range(0, len(binary_str), 5)]
|
return [binary_str[i:i+5] for i in range(0, len(binary_str), 5)]
|
||||||
|
|
||||||
def remove_parity_bit(chunks):
|
def remove_parity_bit(chunks):
|
||||||
return [chunk[1:] for chunk in chunks if len(chunk) == 5]
|
return [chunk[1:] for chunk in chunks if len(chunk) == 5]
|
||||||
|
|
||||||
def convert_to_hex(chunks):
|
def convert_to_hex(chunks):
|
||||||
return [format(int(chunk, 2), 'X') for chunk in chunks]
|
return [format(int(chunk, 2), 'X') for chunk in chunks]
|
||||||
|
|
||||||
def convert_to_decimal(chunks):
|
def convert_to_decimal(chunks):
|
||||||
return [int(chunk, 2) for chunk in chunks]
|
return [int(chunk, 2) for chunk in chunks]
|
||||||
|
|
||||||
def find_until_before_f(hex_values):
|
def find_until_before_f(hex_values):
|
||||||
result = []
|
result = []
|
||||||
for value in hex_values:
|
for value in hex_values:
|
||||||
if value == 'F':
|
if value == 'F':
|
||||||
break
|
break
|
||||||
result.append(value)
|
result.append(value)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def process_block(block):
|
def process_block(block):
|
||||||
binary_str = hex_to_bin(block)
|
binary_str = hex_to_bin(block)
|
||||||
binary_str = remove_last_two_bits(binary_str)
|
binary_str = remove_last_two_bits(binary_str)
|
||||||
chunks = split_into_5bit_chunks(binary_str)
|
chunks = split_into_5bit_chunks(binary_str)
|
||||||
no_parity_chunks = remove_parity_bit(chunks)
|
no_parity_chunks = remove_parity_bit(chunks)
|
||||||
|
|
||||||
return no_parity_chunks
|
return no_parity_chunks
|
||||||
|
|
||||||
def calculate_id_net(blocks):
|
def calculate_id_net(blocks):
|
||||||
|
|
||||||
all_hex_values = []
|
all_hex_values = []
|
||||||
for block in blocks:
|
for block in blocks:
|
||||||
hex_values = convert_to_hex(process_block(block))
|
hex_values = convert_to_hex(process_block(block))
|
||||||
all_hex_values.extend(hex_values)
|
all_hex_values.extend(hex_values)
|
||||||
|
|
||||||
selected_hex_values = find_until_before_f(all_hex_values)
|
selected_hex_values = find_until_before_f(all_hex_values)
|
||||||
|
|
||||||
if not selected_hex_values:
|
if not selected_hex_values:
|
||||||
raise ValueError("Error: No valid data found in blocks 4 and 5.")
|
raise ValueError("Error: No valid data found in blocks 4 and 5.")
|
||||||
|
|
||||||
combined_hex = ''.join(selected_hex_values)
|
combined_hex = ''.join(selected_hex_values)
|
||||||
|
|
||||||
if not combined_hex.isdigit():
|
if not combined_hex.isdigit():
|
||||||
raise ValueError("Error: Invalid data in blocks 4 and 5.")
|
raise ValueError("Error: Invalid data in blocks 4 and 5.")
|
||||||
|
|
||||||
decimal_id = int(combined_hex)
|
decimal_id = int(combined_hex)
|
||||||
stripped_hex_id = format(decimal_id, 'X').upper()
|
stripped_hex_id = format(decimal_id, 'X').upper()
|
||||||
padded_hex_id = stripped_hex_id.zfill(10)
|
padded_hex_id = stripped_hex_id.zfill(10)
|
||||||
|
|
||||||
return decimal_id, padded_hex_id
|
return decimal_id, padded_hex_id
|
||||||
|
|
||||||
def calculate_id_switch(blocks):
|
def calculate_id_switch(blocks):
|
||||||
|
|
||||||
all_decimal_values = []
|
all_decimal_values = []
|
||||||
for block in blocks:
|
for block in blocks:
|
||||||
decimal_values = convert_to_decimal(process_block(block))
|
decimal_values = convert_to_decimal(process_block(block))
|
||||||
all_decimal_values.extend(decimal_values)
|
all_decimal_values.extend(decimal_values)
|
||||||
|
|
||||||
if len(all_decimal_values) < 15:
|
if len(all_decimal_values) < 15:
|
||||||
raise ValueError("Error: Not enough data after processing blocks 4, 5, 6, and 7.")
|
raise ValueError("Error: Not enough data after processing blocks 4, 5, 6, and 7.")
|
||||||
|
|
||||||
id_positions = [9, 11, 13, 15, 2, 4, 6, 8]
|
id_positions = [9, 11, 13, 15, 2, 4, 6, 8]
|
||||||
id_numbers = [all_decimal_values[pos-1] for pos in id_positions]
|
id_numbers = [all_decimal_values[pos-1] for pos in id_positions]
|
||||||
decimal_id = int(''.join(map(str, id_numbers)))
|
decimal_id = int(''.join(map(str, id_numbers)))
|
||||||
padded_hex_id = format(decimal_id, 'X').upper().zfill(10)
|
padded_hex_id = format(decimal_id, 'X').upper().zfill(10)
|
||||||
|
|
||||||
return decimal_id, padded_hex_id
|
return decimal_id, padded_hex_id
|
||||||
|
|
||||||
def input_block_data(block_number):
|
def input_block_data(block_number):
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
block_data = input("Enter data for block {} (4 bytes in hex): ".format(block_number)).strip()
|
block_data = input("Enter data for block {} (4 bytes in hex): ".format(block_number)).strip()
|
||||||
if len(block_data) != 8 or not all(c in '0123456789abcdefABCDEF' for c in block_data):
|
if len(block_data) != 8 or not all(c in '0123456789abcdefABCDEF' for c in block_data):
|
||||||
print("Error: Data must be 4 bytes (8 characters) in hex. Try again.")
|
print("Error: Data must be 4 bytes (8 characters) in hex. Try again.")
|
||||||
else:
|
else:
|
||||||
return block_data
|
return block_data
|
||||||
|
|
||||||
block_4 = input_block_data(4)
|
block_4 = input_block_data(4)
|
||||||
block_5 = input_block_data(5)
|
block_5 = input_block_data(5)
|
||||||
|
|
||||||
if block_5[3] == 'F' or block_5[3] == 'f':
|
if block_5[3] == 'F' or block_5[3] == 'f':
|
||||||
print("Identified Paxton Net2")
|
print("Identified Paxton Net2")
|
||||||
blocks = [block_4, block_5]
|
blocks = [block_4, block_5]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
decimal_id, padded_hex_id = calculate_id_net(blocks)
|
decimal_id, padded_hex_id = calculate_id_net(blocks)
|
||||||
print('Calculations for block 4 and block 5:')
|
print('Calculations for block 4 and block 5:')
|
||||||
|
|
@ -89,11 +118,13 @@ if block_5[3] == 'F' or block_5[3] == 'f':
|
||||||
print('Use the following command in Proxmark3: lf em 410x clone --id {}'.format(padded_hex_id))
|
print('Use the following command in Proxmark3: lf em 410x clone --id {}'.format(padded_hex_id))
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print("Identified Paxton Switch2")
|
print("Identified Paxton Switch2")
|
||||||
block_6 = input_block_data(6)
|
block_6 = input_block_data(6)
|
||||||
block_7 = input_block_data(7)
|
block_7 = input_block_data(7)
|
||||||
blocks = [block_4, block_5, block_6, block_7]
|
blocks = [block_4, block_5, block_6, block_7]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
decimal_id, padded_hex_id = calculate_id_switch(blocks)
|
decimal_id, padded_hex_id = calculate_id_switch(blocks)
|
||||||
print('Calculated data from blocks 4, 5, 6, 7:')
|
print('Calculated data from blocks 4, 5, 6, 7:')
|
||||||
|
|
@ -102,4 +133,5 @@ else:
|
||||||
print('Use the following command in Proxmark3: lf em 410x clone --id {}'.format(padded_hex_id))
|
print('Use the following command in Proxmark3: lf em 410x clone --id {}'.format(padded_hex_id))
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
print('If EM4102 does not work, this option is probably disabled. Sorry for the inconvenience.')
|
print('If EM4102 does not work, this option is probably disabled. Sorry for the inconvenience.')
|
||||||
19
client/pyscripts/PAXTON_NET.py → client/pyscripts/paxton_net.py
Normal file → Executable file
19
client/pyscripts/PAXTON_NET.py → client/pyscripts/paxton_net.py
Normal file → Executable file
|
|
@ -1,3 +1,5 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# paxton_net.py - Convert Paxton Net2 to EM4102
|
# paxton_net.py - Convert Paxton Net2 to EM4102
|
||||||
# Author jareckib <jareckib@hotmail.com>
|
# Author jareckib <jareckib@hotmail.com>
|
||||||
# Based on Equipter's tutorial - Downgrade Paxton Net to EM410x
|
# Based on Equipter's tutorial - Downgrade Paxton Net to EM410x
|
||||||
|
|
@ -17,16 +19,22 @@
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def hex_to_bin(hex_string):
|
def hex_to_bin(hex_string):
|
||||||
return ''.join(format(byte, '08b') for byte in bytearray.fromhex(hex_string))
|
return ''.join(format(byte, '08b') for byte in bytearray.fromhex(hex_string))
|
||||||
|
|
||||||
def remove_last_two_bits(binary_str):
|
def remove_last_two_bits(binary_str):
|
||||||
return binary_str[:-2]
|
return binary_str[:-2]
|
||||||
|
|
||||||
def split_into_5bit_chunks(binary_str):
|
def split_into_5bit_chunks(binary_str):
|
||||||
return [binary_str[i:i+5] for i in range(0, len(binary_str), 5)]
|
return [binary_str[i:i+5] for i in range(0, len(binary_str), 5)]
|
||||||
|
|
||||||
def remove_parity_bit(chunks):
|
def remove_parity_bit(chunks):
|
||||||
return [chunk[1:] for chunk in chunks if len(chunk) == 5]
|
return [chunk[1:] for chunk in chunks if len(chunk) == 5]
|
||||||
|
|
||||||
def convert_to_hex(chunks):
|
def convert_to_hex(chunks):
|
||||||
return [format(int(chunk, 2), 'X') for chunk in chunks]
|
return [format(int(chunk, 2), 'X') for chunk in chunks]
|
||||||
|
|
||||||
def find_until_before_f(hex_values):
|
def find_until_before_f(hex_values):
|
||||||
result = []
|
result = []
|
||||||
for value in hex_values:
|
for value in hex_values:
|
||||||
|
|
@ -34,6 +42,7 @@ def find_until_before_f(hex_values):
|
||||||
break
|
break
|
||||||
result.append(value)
|
result.append(value)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def process_block(block):
|
def process_block(block):
|
||||||
binary_str = hex_to_bin(block)
|
binary_str = hex_to_bin(block)
|
||||||
binary_str = remove_last_two_bits(binary_str)
|
binary_str = remove_last_two_bits(binary_str)
|
||||||
|
|
@ -41,21 +50,30 @@ def process_block(block):
|
||||||
no_parity_chunks = remove_parity_bit(chunks)
|
no_parity_chunks = remove_parity_bit(chunks)
|
||||||
hex_values = convert_to_hex(no_parity_chunks)
|
hex_values = convert_to_hex(no_parity_chunks)
|
||||||
return hex_values
|
return hex_values
|
||||||
|
|
||||||
def calculate_id(blocks):
|
def calculate_id(blocks):
|
||||||
|
|
||||||
all_hex_values = []
|
all_hex_values = []
|
||||||
|
|
||||||
for block in blocks:
|
for block in blocks:
|
||||||
hex_values = process_block(block)
|
hex_values = process_block(block)
|
||||||
all_hex_values.extend(hex_values)
|
all_hex_values.extend(hex_values)
|
||||||
|
|
||||||
selected_hex_values = find_until_before_f(all_hex_values)
|
selected_hex_values = find_until_before_f(all_hex_values)
|
||||||
|
|
||||||
if not selected_hex_values:
|
if not selected_hex_values:
|
||||||
raise ValueError("Error: No valid data found in blocks 4 and 5.")
|
raise ValueError("Error: No valid data found in blocks 4 and 5.")
|
||||||
|
|
||||||
combined_hex = ''.join(selected_hex_values)
|
combined_hex = ''.join(selected_hex_values)
|
||||||
|
|
||||||
if not combined_hex.isdigit():
|
if not combined_hex.isdigit():
|
||||||
raise ValueError("Error: Invalid data in blocks 4 and 5.")
|
raise ValueError("Error: Invalid data in blocks 4 and 5.")
|
||||||
|
|
||||||
decimal_id = int(combined_hex)
|
decimal_id = int(combined_hex)
|
||||||
stripped_hex_id = format(decimal_id, 'X').upper()
|
stripped_hex_id = format(decimal_id, 'X').upper()
|
||||||
padded_hex_id = stripped_hex_id.zfill(10)
|
padded_hex_id = stripped_hex_id.zfill(10)
|
||||||
return combined_hex, decimal_id, stripped_hex_id, padded_hex_id
|
return combined_hex, decimal_id, stripped_hex_id, padded_hex_id
|
||||||
|
|
||||||
def input_block_data(block_number):
|
def input_block_data(block_number):
|
||||||
while True:
|
while True:
|
||||||
block_data = input("Enter data for block {} (4 bytes in hex): ".format(block_number)).strip()
|
block_data = input("Enter data for block {} (4 bytes in hex): ".format(block_number)).strip()
|
||||||
|
|
@ -75,6 +93,7 @@ blocks = [
|
||||||
block_4,
|
block_4,
|
||||||
block_5,
|
block_5,
|
||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result_hex, result_decimal, stripped_hex_id, padded_hex_id = calculate_id(blocks)
|
result_hex, result_decimal, stripped_hex_id, padded_hex_id = calculate_id(blocks)
|
||||||
print('Calculations for block 4 and block 5:')
|
print('Calculations for block 4 and block 5:')
|
||||||
18
client/pyscripts/Paxton_switch.py → client/pyscripts/paxton_switch.py
Normal file → Executable file
18
client/pyscripts/Paxton_switch.py → client/pyscripts/paxton_switch.py
Normal file → Executable file
|
|
@ -1,3 +1,5 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# paxton_switch.py - Convert Paxton Switch2 to EM4102
|
# paxton_switch.py - Convert Paxton Switch2 to EM4102
|
||||||
# Author jareckib <jareckib@hotmail.com>
|
# Author jareckib <jareckib@hotmail.com>
|
||||||
# Based on Equipter's tutorial - Downgrade Paxton Net to EM410x
|
# Based on Equipter's tutorial - Downgrade Paxton Net to EM410x
|
||||||
|
|
@ -16,35 +18,48 @@
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def hex_to_bin(hex_string):
|
def hex_to_bin(hex_string):
|
||||||
return ''.join(format(byte, '08b') for byte in bytearray.fromhex(hex_string))
|
return ''.join(format(byte, '08b') for byte in bytearray.fromhex(hex_string))
|
||||||
|
|
||||||
def remove_last_two_bits(binary_str):
|
def remove_last_two_bits(binary_str):
|
||||||
return binary_str[:-2]
|
return binary_str[:-2]
|
||||||
|
|
||||||
def split_into_5bit_chunks(binary_str):
|
def split_into_5bit_chunks(binary_str):
|
||||||
return [binary_str[i:i+5] for i in range(0, len(binary_str), 5)]
|
return [binary_str[i:i+5] for i in range(0, len(binary_str), 5)]
|
||||||
|
|
||||||
def remove_parity_bit(chunks):
|
def remove_parity_bit(chunks):
|
||||||
return [chunk[1:] for chunk in chunks if len(chunk) == 5]
|
return [chunk[1:] for chunk in chunks if len(chunk) == 5]
|
||||||
|
|
||||||
def convert_to_decimal(chunks):
|
def convert_to_decimal(chunks):
|
||||||
return [int(chunk, 2) for chunk in chunks]
|
return [int(chunk, 2) for chunk in chunks]
|
||||||
|
|
||||||
def process_block(block):
|
def process_block(block):
|
||||||
binary_str = hex_to_bin(block)
|
binary_str = hex_to_bin(block)
|
||||||
binary_str = remove_last_two_bits(binary_str)
|
binary_str = remove_last_two_bits(binary_str)
|
||||||
chunks = split_into_5bit_chunks(binary_str)
|
chunks = split_into_5bit_chunks(binary_str)
|
||||||
no_parity_chunks = remove_parity_bit(chunks)
|
no_parity_chunks = remove_parity_bit(chunks)
|
||||||
decimal_values = convert_to_decimal(no_parity_chunks)
|
decimal_values = convert_to_decimal(no_parity_chunks)
|
||||||
|
|
||||||
return decimal_values
|
return decimal_values
|
||||||
|
|
||||||
def calculate_id(blocks):
|
def calculate_id(blocks):
|
||||||
|
|
||||||
all_decimal_values = []
|
all_decimal_values = []
|
||||||
for block in blocks:
|
for block in blocks:
|
||||||
decimal_values = process_block(block)
|
decimal_values = process_block(block)
|
||||||
all_decimal_values.extend(decimal_values)
|
all_decimal_values.extend(decimal_values)
|
||||||
|
|
||||||
if len(all_decimal_values) < 15:
|
if len(all_decimal_values) < 15:
|
||||||
raise ValueError("Error: Not enough data after processing blocks 4, 5, 6, and 7.")
|
raise ValueError("Error: Not enough data after processing blocks 4, 5, 6, and 7.")
|
||||||
|
|
||||||
id_positions = [9, 11, 13, 15, 2, 4, 6, 8]
|
id_positions = [9, 11, 13, 15, 2, 4, 6, 8]
|
||||||
id_numbers = [all_decimal_values[pos-1] for pos in id_positions]
|
id_numbers = [all_decimal_values[pos-1] for pos in id_positions]
|
||||||
decimal_id = int(''.join(map(str, id_numbers)))
|
decimal_id = int(''.join(map(str, id_numbers)))
|
||||||
padded_hex_id = format(decimal_id, 'X').upper().zfill(10)
|
padded_hex_id = format(decimal_id, 'X').upper().zfill(10)
|
||||||
|
|
||||||
return decimal_id, padded_hex_id
|
return decimal_id, padded_hex_id
|
||||||
|
|
||||||
def input_block_data(block_number):
|
def input_block_data(block_number):
|
||||||
while True:
|
while True:
|
||||||
block_data = input("Enter data for block {} (4 bytes in hex): ".format(block_number)).strip()
|
block_data = input("Enter data for block {} (4 bytes in hex): ".format(block_number)).strip()
|
||||||
|
|
@ -52,6 +67,8 @@ def input_block_data(block_number):
|
||||||
print("Error: Data must be 4 bytes (8 characters) in hex. Try again.")
|
print("Error: Data must be 4 bytes (8 characters) in hex. Try again.")
|
||||||
else:
|
else:
|
||||||
return block_data
|
return block_data
|
||||||
|
|
||||||
|
|
||||||
block_4 = input_block_data(4)
|
block_4 = input_block_data(4)
|
||||||
block_5 = input_block_data(5)
|
block_5 = input_block_data(5)
|
||||||
block_6 = input_block_data(6)
|
block_6 = input_block_data(6)
|
||||||
|
|
@ -62,6 +79,7 @@ blocks = [
|
||||||
block_6,
|
block_6,
|
||||||
block_7,
|
block_7,
|
||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
decimal_id, padded_hex_id = calculate_id(blocks)
|
decimal_id, padded_hex_id = calculate_id(blocks)
|
||||||
print('Calculated data from blocks 4, 5, 6, 7:')
|
print('Calculated data from blocks 4, 5, 6, 7:')
|
||||||
92
client/pyscripts/pm3_resources.py
Normal file
92
client/pyscripts/pm3_resources.py
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
"""
|
||||||
|
Helper library to locate resources for pm3 scripts.
|
||||||
|
|
||||||
|
This module provides functionality to locate tools and dictionaries required
|
||||||
|
for pm3 scripts. It determines the paths based on the directory structure
|
||||||
|
and whether the script is being run in a development setup or an installed setup.
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
find_tool(tool_name):
|
||||||
|
Finds the specified tool in the tools directory.
|
||||||
|
Args:
|
||||||
|
tool_name (str): The name of the tool to find.
|
||||||
|
Returns:
|
||||||
|
str: The full path to the tool if found, otherwise None.
|
||||||
|
|
||||||
|
find_dict(dict_name):
|
||||||
|
Find the specified dictionary in the dicts directory.
|
||||||
|
Args:
|
||||||
|
dict_name (str): The name of the dict to find.
|
||||||
|
Returns:
|
||||||
|
str: The full path to the dict if found, otherwise None.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Install script can hardcode paths in the following variables
|
||||||
|
TOOLS_PATH = None
|
||||||
|
DICTS_PATH = None
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("This is a library, don't use it as a script")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
DIR_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
if TOOLS_PATH is None:
|
||||||
|
if os.path.basename(os.path.dirname(DIR_PATH)) == 'client':
|
||||||
|
# dev setup
|
||||||
|
DEV_TOOLS_PATH = os.path.normpath(os.path.join(DIR_PATH, "..", "..", "tools", "mfc", "card_only"))
|
||||||
|
if os.path.isdir(DEV_TOOLS_PATH):
|
||||||
|
TOOLS_PATH = DEV_TOOLS_PATH
|
||||||
|
|
||||||
|
if TOOLS_PATH is None:
|
||||||
|
# assuming installed without having defined TOOLS_PATH
|
||||||
|
TEST_TOOLS_PATH = os.path.normpath(os.path.join(DIR_PATH, "..", "tools"))
|
||||||
|
if os.path.isdir(TEST_TOOLS_PATH):
|
||||||
|
TOOLS_PATH = TEST_TOOLS_PATH
|
||||||
|
|
||||||
|
|
||||||
|
if DICTS_PATH is None:
|
||||||
|
DEV_DICTS_PATH = os.path.normpath(os.path.join(DIR_PATH, "..", "dictionaries"))
|
||||||
|
if os.path.isdir(DEV_DICTS_PATH):
|
||||||
|
DICTS_PATH = DEV_DICTS_PATH
|
||||||
|
|
||||||
|
|
||||||
|
def find_tool(tool_name):
|
||||||
|
"""Find the specified tool in the tools directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tool_name (str): The name of the tool to find.
|
||||||
|
Returns:
|
||||||
|
str: The full path to the tool if found, otherwise None.
|
||||||
|
"""
|
||||||
|
if TOOLS_PATH is not None:
|
||||||
|
tool = os.path.join(TOOLS_PATH, tool_name)
|
||||||
|
if os.path.isfile(tool):
|
||||||
|
return tool
|
||||||
|
elif os.path.isfile(tool + ".exe"):
|
||||||
|
return tool + ".exe"
|
||||||
|
# if not found, search in the user PATH
|
||||||
|
for path in os.environ["PATH"].split(os.pathsep):
|
||||||
|
env_tool = os.path.join(path, tool_name)
|
||||||
|
if os.path.isfile(env_tool):
|
||||||
|
return env_tool
|
||||||
|
elif os.path.isfile(env_tool + ".exe"):
|
||||||
|
return env_tool + ".exe"
|
||||||
|
raise FileNotFoundError(f"Cannot find {tool_name}, abort!")
|
||||||
|
|
||||||
|
|
||||||
|
def find_dict(dict_name):
|
||||||
|
"""Find the specified dictionary in the dicts directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
dict_name (str): The name of the dict to find.
|
||||||
|
Returns:
|
||||||
|
str: The full path to the dict if found, otherwise None.
|
||||||
|
"""
|
||||||
|
if DICTS_PATH is not None:
|
||||||
|
dictionary = os.path.join(DICTS_PATH, dict_name)
|
||||||
|
if os.path.isfile(dictionary):
|
||||||
|
return dictionary
|
||||||
|
raise FileNotFoundError(f"Cannot find {dict_name}, abort!")
|
||||||
|
|
@ -335,6 +335,14 @@
|
||||||
"Description": "Card Application Directory (CAD)",
|
"Description": "Card Application Directory (CAD)",
|
||||||
"Type": "pacs"
|
"Type": "pacs"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"AID": "F484D1",
|
||||||
|
"Vendor": "HID",
|
||||||
|
"Country": "US",
|
||||||
|
"Name": "Unknown DESFire EV1",
|
||||||
|
"Description": "Access Control",
|
||||||
|
"Type": "pacs"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"AID": "F484E3",
|
"AID": "F484E3",
|
||||||
"Vendor": "HID",
|
"Vendor": "HID",
|
||||||
|
|
@ -511,6 +519,46 @@
|
||||||
"Description": "Multiservice Student Card",
|
"Description": "Multiservice Student Card",
|
||||||
"Type": "student"
|
"Type": "student"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"AID": "764970",
|
||||||
|
"Vendor": "Ubiquiti Inc",
|
||||||
|
"Country": "N/A",
|
||||||
|
"Name": "UniFi Access VID App",
|
||||||
|
"Description": "Contains issuer-signed static credential information used for KDF & other authentication operations",
|
||||||
|
"Type": "pacs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AID": "84D3FC",
|
||||||
|
"Vendor": "Ubiquiti Inc",
|
||||||
|
"Country": "N/A",
|
||||||
|
"Name": "UniFi Access FCD App",
|
||||||
|
"Description": "Contains static credential information used for KDF & other authentication operations",
|
||||||
|
"Type": "pacs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AID": "416343",
|
||||||
|
"Vendor": "Ubiquiti Inc",
|
||||||
|
"Country": "N/A",
|
||||||
|
"Name": "UniFi Access ACC App",
|
||||||
|
"Description": "Application created after enrollment into the system, containins unique authentication info",
|
||||||
|
"Type": "pacs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AID": "454955",
|
||||||
|
"Vendor": "Ubiquiti Inc",
|
||||||
|
"Country": "N/A",
|
||||||
|
"Name": "UniFi Access Touch Pass Apple Wallet Express",
|
||||||
|
"Description": "AID value is 'UIE' (UniFi Express) reversed. This app is selectable with or without auth",
|
||||||
|
"Type": "pacs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AID": "534955",
|
||||||
|
"Vendor": "Ubiquiti Inc",
|
||||||
|
"Country": "N/A",
|
||||||
|
"Name": "UniFi Access Touch Pass Apple Wallet Secure",
|
||||||
|
"Description": "AID value is 'UIS' (UniFi Secure) reversed. This app is selectable only after manual auth",
|
||||||
|
"Type": "pacs"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"AID": "535501",
|
"AID": "535501",
|
||||||
"Vendor": "TU Delft",
|
"Vendor": "TU Delft",
|
||||||
|
|
@ -1034,7 +1082,7 @@
|
||||||
{
|
{
|
||||||
"AID": "087522",
|
"AID": "087522",
|
||||||
"Vendor": "Umo Mobility via Cubic Transportation Systems",
|
"Vendor": "Umo Mobility via Cubic Transportation Systems",
|
||||||
"Country": "US",
|
"Country": "US / CA",
|
||||||
"Name": "Umo Mobility Card",
|
"Name": "Umo Mobility Card",
|
||||||
"Description": "Umo Mobility Card",
|
"Description": "Umo Mobility Card",
|
||||||
"Type": "transport"
|
"Type": "transport"
|
||||||
|
|
@ -1159,14 +1207,6 @@
|
||||||
"Description": "DEL Delhi Metro (App 5)",
|
"Description": "DEL Delhi Metro (App 5)",
|
||||||
"Type": "transport"
|
"Type": "transport"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"AID": "444D05",
|
|
||||||
"Vendor": "Delhi Metro Rail Corporation Limited",
|
|
||||||
"Country": "IN",
|
|
||||||
"Name": "Delhi Metro Travel Card (DEL)",
|
|
||||||
"Description": "DEL Delhi Metro (App 5)",
|
|
||||||
"Type": "transport"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"AID": "444D06",
|
"AID": "444D06",
|
||||||
"Vendor": "Delhi Metro Rail Corporation Limited",
|
"Vendor": "Delhi Metro Rail Corporation Limited",
|
||||||
|
|
@ -1219,7 +1259,7 @@
|
||||||
"AID": "578000",
|
"AID": "578000",
|
||||||
"Vendor": "Norwegian Public Roads Administration (NPRA)",
|
"Vendor": "Norwegian Public Roads Administration (NPRA)",
|
||||||
"Country": "NO",
|
"Country": "NO",
|
||||||
"Name": "NORTIC (Norway Public Transport Card)",
|
"Name": "NORTIC (Norway Public Transport Card) (Card Issuer App)",
|
||||||
"Description": "Norwegian Ticketing Interoperable Concept // FID 0C: Card Issuer Header",
|
"Description": "Norwegian Ticketing Interoperable Concept // FID 0C: Card Issuer Header",
|
||||||
"Type": "transport"
|
"Type": "transport"
|
||||||
},
|
},
|
||||||
|
|
@ -1227,7 +1267,7 @@
|
||||||
"AID": "578001",
|
"AID": "578001",
|
||||||
"Vendor": "Norwegian Public Roads Administration (NPRA)",
|
"Vendor": "Norwegian Public Roads Administration (NPRA)",
|
||||||
"Country": "NO",
|
"Country": "NO",
|
||||||
"Name": "NORTIC (Norway Public Transport Card)",
|
"Name": "NORTIC (Norway Public Transport Card) (Transport App)",
|
||||||
"Description": "FIDs 01: Product Retailer; 02: Service Provider; 03: Special Event; 04: Stored Value; 05: General Event Log; 06: SV Reload Log; 0A: Environment; 0C: Card Holder",
|
"Description": "FIDs 01: Product Retailer; 02: Service Provider; 03: Special Event; 04: Stored Value; 05: General Event Log; 06: SV Reload Log; 0A: Environment; 0C: Card Holder",
|
||||||
"Type": "transport"
|
"Type": "transport"
|
||||||
},
|
},
|
||||||
|
|
@ -1242,7 +1282,7 @@
|
||||||
{
|
{
|
||||||
"AID": "677F8E",
|
"AID": "677F8E",
|
||||||
"Vendor": "Umo Mobility via Cubic Transportation Systems",
|
"Vendor": "Umo Mobility via Cubic Transportation Systems",
|
||||||
"Country": "US",
|
"Country": "US / CA",
|
||||||
"Name": "Umo Mobility Card",
|
"Name": "Umo Mobility Card",
|
||||||
"Description": "Umo Mobility Card",
|
"Description": "Umo Mobility Card",
|
||||||
"Type": "transport"
|
"Type": "transport"
|
||||||
|
|
@ -1258,7 +1298,7 @@
|
||||||
{
|
{
|
||||||
"AID": "992CB5",
|
"AID": "992CB5",
|
||||||
"Vendor": "Umo Mobility via Cubic Transportation Systems",
|
"Vendor": "Umo Mobility via Cubic Transportation Systems",
|
||||||
"Country": "US",
|
"Country": "US / CA",
|
||||||
"Name": "Umo Mobility Card",
|
"Name": "Umo Mobility Card",
|
||||||
"Description": "Umo Mobility Card",
|
"Description": "Umo Mobility Card",
|
||||||
"Type": "transport"
|
"Type": "transport"
|
||||||
|
|
@ -1274,7 +1314,7 @@
|
||||||
{
|
{
|
||||||
"AID": "A4237D",
|
"AID": "A4237D",
|
||||||
"Vendor": "Umo Mobility via Cubic Transportation Systems",
|
"Vendor": "Umo Mobility via Cubic Transportation Systems",
|
||||||
"Country": "US",
|
"Country": "US / CA",
|
||||||
"Name": "Umo Mobility Card",
|
"Name": "Umo Mobility Card",
|
||||||
"Description": "Umo Mobility Card",
|
"Description": "Umo Mobility Card",
|
||||||
"Type": "transport"
|
"Type": "transport"
|
||||||
|
|
@ -1282,7 +1322,7 @@
|
||||||
{
|
{
|
||||||
"AID": "C65B80",
|
"AID": "C65B80",
|
||||||
"Vendor": "Umo Mobility via Cubic Transportation Systems",
|
"Vendor": "Umo Mobility via Cubic Transportation Systems",
|
||||||
"Country": "US",
|
"Country": "US / CA",
|
||||||
"Name": "Umo Mobility Card",
|
"Name": "Umo Mobility Card",
|
||||||
"Description": "Umo Mobility Card",
|
"Description": "Umo Mobility Card",
|
||||||
"Type": "transport"
|
"Type": "transport"
|
||||||
|
|
@ -1353,10 +1393,10 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"AID": "F21050",
|
"AID": "F21050",
|
||||||
"Vendor": "Metro Christchurch via INIT",
|
"Vendor": "Metro Christchurch via INIT / Arc",
|
||||||
"Country": "NZ",
|
"Country": "NZ / CA",
|
||||||
"Name": "Metrocard (CHC)",
|
"Name": "Metrocard (CHC) / Arc (YEG)",
|
||||||
"Description": "FIDs: 00: Backup Data; 01/02: Trip History; 03: Card Balance",
|
"Description": "CHC FIDs: 00: Backup Data; 01/02: Trip History; 03: Card Balance",
|
||||||
"Type": "transport"
|
"Type": "transport"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1400,11 +1440,19 @@
|
||||||
"Type": "transport"
|
"Type": "transport"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"AID": "F21201",
|
"AID": "F21191",
|
||||||
"Vendor": "Green Bay Metro Transit via Genfare",
|
"Vendor": "Metropolitan Transportation Commission via Cubic",
|
||||||
"Country": "US",
|
"Country": "US",
|
||||||
"Name": "Tap-N-Go Card (GRB)",
|
"Name": "Clipper Card (Mobile)",
|
||||||
"Description": "GRB Tap-N-Go Card",
|
"Description": "",
|
||||||
|
"Type": "transport"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AID": "F21201",
|
||||||
|
"Vendor": "Green Bay Metro Transit via Genfare / Winnipeg Transit",
|
||||||
|
"Country": "US / CA",
|
||||||
|
"Name": "Tap-N-Go Card (GRB) / peggo card (YWG)",
|
||||||
|
"Description": "GRB Tap-N-Go Card / YWG peggo card",
|
||||||
"Type": "transport"
|
"Type": "transport"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -82,20 +82,25 @@ int GetModels(char *Models[], int *count, uint8_t *width) {
|
||||||
SETBMP();
|
SETBMP();
|
||||||
|
|
||||||
if (width[0] == 0) { //reveng -D
|
if (width[0] == 0) { //reveng -D
|
||||||
|
|
||||||
*count = mcount();
|
*count = mcount();
|
||||||
if (!*count) {
|
if (!*count) {
|
||||||
PrintAndLogEx(WARNING, "no preset models available");
|
PrintAndLogEx(WARNING, "no preset models available");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int mode = 0; mode < *count; ++mode) {
|
for (int mode = 0; mode < *count; ++mode) {
|
||||||
|
|
||||||
mbynum(&model, mode);
|
mbynum(&model, mode);
|
||||||
mcanon(&model);
|
mcanon(&model);
|
||||||
size_t size = (model.name && *model.name) ? strlen(model.name) : 7;
|
size_t size = (model.name && *model.name) ? strlen(model.name) : 7;
|
||||||
|
|
||||||
char *tmp = calloc(size + 1, sizeof(char));
|
char *tmp = calloc(size + 1, sizeof(char));
|
||||||
if (tmp == NULL) {
|
if (tmp == NULL) {
|
||||||
PrintAndLogEx(WARNING, "out of memory?");
|
PrintAndLogEx(WARNING, "out of memory?");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.name != NULL) {
|
if (model.name != NULL) {
|
||||||
memcpy(tmp, model.name, size);
|
memcpy(tmp, model.name, size);
|
||||||
Models[mode] = tmp;
|
Models[mode] = tmp;
|
||||||
|
|
@ -113,18 +118,21 @@ int GetModels(char *Models[], int *count, uint8_t *width) {
|
||||||
PrintAndLogEx(WARNING, "cannot search for non-Williams compliant models");
|
PrintAndLogEx(WARNING, "cannot search for non-Williams compliant models");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
praloc(&model.spoly, (unsigned long)width[0]);
|
praloc(&model.spoly, (unsigned long)width[0]);
|
||||||
praloc(&model.init, (unsigned long)width[0]);
|
praloc(&model.init, (unsigned long)width[0]);
|
||||||
praloc(&model.xorout, (unsigned long)width[0]);
|
praloc(&model.xorout, (unsigned long)width[0]);
|
||||||
|
|
||||||
if (!plen(model.spoly))
|
if (!plen(model.spoly)) {
|
||||||
palloc(&model.spoly, (unsigned long)width[0]);
|
palloc(&model.spoly, (unsigned long)width[0]);
|
||||||
else
|
} else {
|
||||||
width[0] = (uint8_t)plen(model.spoly);
|
width[0] = (uint8_t)plen(model.spoly);
|
||||||
|
}
|
||||||
|
|
||||||
/* special case if qpoly is zero, search to end of range */
|
/* special case if qpoly is zero, search to end of range */
|
||||||
if (!ptst(qpoly))
|
if (!ptst(qpoly)) {
|
||||||
rflags &= ~R_HAVEQ;
|
rflags &= ~R_HAVEQ;
|
||||||
|
}
|
||||||
|
|
||||||
int pass;
|
int pass;
|
||||||
|
|
||||||
|
|
@ -135,31 +143,41 @@ int GetModels(char *Models[], int *count, uint8_t *width) {
|
||||||
*/
|
*/
|
||||||
/* scan against preset models */
|
/* scan against preset models */
|
||||||
if (~uflags & C_NOPCK) {
|
if (~uflags & C_NOPCK) {
|
||||||
|
|
||||||
pass = 0;
|
pass = 0;
|
||||||
int Cnt = 0;
|
int Cnt = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int psets = mcount();
|
int psets = mcount();
|
||||||
|
|
||||||
while (psets) {
|
while (psets) {
|
||||||
|
|
||||||
mbynum(&pset, --psets);
|
mbynum(&pset, --psets);
|
||||||
|
|
||||||
/* skip if different width, or refin or refout don't match */
|
/* skip if different width, or refin or refout don't match */
|
||||||
if (plen(pset.spoly) != width[0] || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT))
|
if (plen(pset.spoly) != width[0] || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* skip if the preset doesn't match specified parameters */
|
/* skip if the preset doesn't match specified parameters */
|
||||||
if (rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly))
|
if (rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly)) {
|
||||||
continue;
|
continue;
|
||||||
if (rflags & R_HAVEI && psncmp(&model.init, &pset.init))
|
}
|
||||||
|
|
||||||
|
if (rflags & R_HAVEI && psncmp(&model.init, &pset.init)) {
|
||||||
continue;
|
continue;
|
||||||
if (rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout))
|
}
|
||||||
|
|
||||||
|
if (rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
//for additional args (not used yet, maybe future?)
|
//for additional args (not used yet, maybe future?)
|
||||||
apoly = pclone(pset.xorout);
|
apoly = pclone(pset.xorout);
|
||||||
|
|
||||||
if (pset.flags & P_REFOUT)
|
if (pset.flags & P_REFOUT) {
|
||||||
prev(&apoly);
|
prev(&apoly);
|
||||||
|
}
|
||||||
|
|
||||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||||
crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0);
|
crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0);
|
||||||
|
|
@ -183,6 +201,7 @@ int GetModels(char *Models[], int *count, uint8_t *width) {
|
||||||
PrintAndLogEx(WARNING, "out of memory?");
|
PrintAndLogEx(WARNING, "out of memory?");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
width[Cnt] = width[0];
|
width[Cnt] = width[0];
|
||||||
memcpy(tmp, pset.name, size);
|
memcpy(tmp, pset.name, size);
|
||||||
Models[Cnt++] = tmp;
|
Models[Cnt++] = tmp;
|
||||||
|
|
@ -199,6 +218,7 @@ int GetModels(char *Models[], int *count, uint8_t *width) {
|
||||||
prevch(qptr, ibperhx);
|
prevch(qptr, ibperhx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (~rflags & R_HAVERI && ++pass < 2);
|
} while (~rflags & R_HAVERI && ++pass < 2);
|
||||||
}
|
}
|
||||||
//got everything now free the memory...
|
//got everything now free the memory...
|
||||||
|
|
@ -208,6 +228,7 @@ int GetModels(char *Models[], int *count, uint8_t *width) {
|
||||||
pfree(qptr);
|
pfree(qptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uflags & C_NOBFS && ~rflags & R_HAVEP) {
|
if (uflags & C_NOBFS && ~rflags & R_HAVEP) {
|
||||||
PrintAndLogEx(WARNING, "no models found");
|
PrintAndLogEx(WARNING, "no models found");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -217,24 +238,30 @@ int GetModels(char *Models[], int *count, uint8_t *width) {
|
||||||
PrintAndLogEx(WARNING, "cannot search for crossed-endian models");
|
PrintAndLogEx(WARNING, "cannot search for crossed-endian models");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pass = 0;
|
pass = 0;
|
||||||
int args = 0;
|
int args = 0;
|
||||||
do {
|
do {
|
||||||
|
|
||||||
model_t *candmods = reveng(&model, qpoly, rflags, args, apolys);
|
model_t *candmods = reveng(&model, qpoly, rflags, args, apolys);
|
||||||
model_t *mptr = candmods;
|
model_t *mptr = candmods;
|
||||||
if (mptr && plen(mptr->spoly)) {
|
if (mptr && plen(mptr->spoly)) {
|
||||||
uflags |= C_RESULT;
|
uflags |= C_RESULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (mptr && plen(mptr->spoly)) {
|
while (mptr && plen(mptr->spoly)) {
|
||||||
mfree(mptr++);
|
mfree(mptr++);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(candmods);
|
free(candmods);
|
||||||
|
|
||||||
if (~rflags & R_HAVERI) {
|
if (~rflags & R_HAVERI) {
|
||||||
model.flags ^= P_REFIN | P_REFOUT;
|
model.flags ^= P_REFIN | P_REFOUT;
|
||||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||||
prevch(qptr, ibperhx);
|
prevch(qptr, ibperhx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (~rflags & R_HAVERI && ++pass < 2);
|
} while (~rflags & R_HAVERI && ++pass < 2);
|
||||||
|
|
||||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||||
|
|
|
||||||
|
|
@ -1207,28 +1207,35 @@ static int CmdExchangeAPDU(bool chainingin, const uint8_t *datain, int datainlen
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t cmdc = 0;
|
uint16_t cmdc = 0;
|
||||||
if (chainingin)
|
if (chainingin) {
|
||||||
cmdc = ISO14A_SEND_CHAINING;
|
cmdc = ISO14A_SEND_CHAINING;
|
||||||
|
}
|
||||||
|
|
||||||
// "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes
|
// "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes
|
||||||
// https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size
|
// https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size
|
||||||
// here length PM3_CMD_DATA_SIZE=512
|
// here length PM3_CMD_DATA_SIZE=512
|
||||||
// timeout must be authomatically set by "get ATS"
|
// timeout must be authomatically set by "get ATS"
|
||||||
if (datain)
|
if (datain) {
|
||||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, (datainlen & 0x1FF), 0, datain, datainlen & 0x1FF);
|
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, (datainlen & 0x1FF), 0, datain, datainlen & 0x1FF);
|
||||||
else
|
} else {
|
||||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, 0, 0, NULL, 0);
|
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, 0, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
|
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, timeout)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, timeout) == false) {
|
||||||
|
PrintAndLogEx(DEBUG, "ERR: APDU: Reply timeout");
|
||||||
|
return PM3_EAPDU_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
const uint8_t *recv = resp.data.asBytes;
|
const uint8_t *recv = resp.data.asBytes;
|
||||||
int iLen = resp.oldarg[0];
|
int iLen = resp.oldarg[0];
|
||||||
uint8_t res = resp.oldarg[1];
|
uint8_t res = resp.oldarg[1];
|
||||||
|
|
||||||
int dlen = iLen - 2;
|
int dlen = iLen - 2;
|
||||||
if (dlen < 0)
|
if (dlen < 0) {
|
||||||
dlen = 0;
|
dlen = 0;
|
||||||
|
}
|
||||||
*dataoutlen += dlen;
|
*dataoutlen += dlen;
|
||||||
|
|
||||||
if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
|
if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
|
||||||
|
|
@ -1243,7 +1250,7 @@ static int CmdExchangeAPDU(bool chainingin, const uint8_t *datain, int datainlen
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iLen) {
|
if (iLen == 0) {
|
||||||
PrintAndLogEx(DEBUG, "ERR: APDU: No APDU response");
|
PrintAndLogEx(DEBUG, "ERR: APDU: No APDU response");
|
||||||
return PM3_EAPDU_FAIL;
|
return PM3_EAPDU_FAIL;
|
||||||
}
|
}
|
||||||
|
|
@ -1272,10 +1279,6 @@ static int CmdExchangeAPDU(bool chainingin, const uint8_t *datain, int datainlen
|
||||||
PrintAndLogEx(DEBUG, "ERR: APDU: ISO 14443A CRC error");
|
PrintAndLogEx(DEBUG, "ERR: APDU: ISO 14443A CRC error");
|
||||||
return PM3_EAPDU_FAIL;
|
return PM3_EAPDU_FAIL;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
PrintAndLogEx(DEBUG, "ERR: APDU: Reply timeout");
|
|
||||||
return PM3_EAPDU_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
@ -1300,18 +1303,18 @@ int ExchangeAPDU14a(const uint8_t *datain, int datainlen, bool activateField, bo
|
||||||
*dataoutlen = 0;
|
*dataoutlen = 0;
|
||||||
res = CmdExchangeAPDU(chainBlockNotLast, &datain[clen], vlen, vActivateField, dataout, maxdataoutlen, dataoutlen, &chaining);
|
res = CmdExchangeAPDU(chainBlockNotLast, &datain[clen], vlen, vActivateField, dataout, maxdataoutlen, dataoutlen, &chaining);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
if (leaveSignalON == false)
|
if (leaveSignalON == false) {
|
||||||
DropField();
|
DropField();
|
||||||
|
}
|
||||||
return 200;
|
return 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check R-block ACK
|
// check R-block ACK
|
||||||
// TODO check this one...
|
// TODO check this one...
|
||||||
if ((*dataoutlen == 0) && (chaining != chainBlockNotLast)) {
|
if ((*dataoutlen == 0) && (chaining != chainBlockNotLast)) {
|
||||||
if (leaveSignalON == false)
|
if (leaveSignalON == false) {
|
||||||
DropField();
|
DropField();
|
||||||
|
}
|
||||||
return 201;
|
return 201;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1323,6 +1326,7 @@ int ExchangeAPDU14a(const uint8_t *datain, int datainlen, bool activateField, bo
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (clen < datainlen);
|
} while (clen < datainlen);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2358,7 +2362,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
tc1 = (card.ats[1] & 0x40) == 0x40;
|
tc1 = (card.ats[1] & 0x40) == 0x40;
|
||||||
int16_t fsci = card.ats[1] & 0x0f;
|
int16_t fsci = card.ats[1] & 0x0f;
|
||||||
|
|
||||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ T0 TA1 is%s present, TB1 is%s present, "
|
PrintAndLogEx(INFO, " ..." _YELLOW_("%02X") "............ T0 TA1 is%s present, TB1 is%s present, "
|
||||||
"TC1 is%s present, FSCI is %d (FSC = %d)",
|
"TC1 is%s present, FSCI is %d (FSC = %d)",
|
||||||
card.ats[1],
|
card.ats[1],
|
||||||
(ta1 ? "" : _RED_(" NOT")),
|
(ta1 ? "" : _RED_(" NOT")),
|
||||||
|
|
@ -2380,7 +2384,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
if (card.ats[pos] & 0x04) strcat(dr, "8, ");
|
if (card.ats[pos] & 0x04) strcat(dr, "8, ");
|
||||||
if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0';
|
if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0';
|
||||||
if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0';
|
if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0';
|
||||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... TA1 different divisors are%s supported, "
|
PrintAndLogEx(INFO, " ......" _YELLOW_("%02X") "......... TA1 different divisors are%s supported, "
|
||||||
"DR: [%s], DS: [%s]",
|
"DR: [%s], DS: [%s]",
|
||||||
card.ats[pos],
|
card.ats[pos],
|
||||||
((card.ats[pos] & 0x80) ? _RED_(" NOT") : ""),
|
((card.ats[pos] & 0x80) ? _RED_(" NOT") : ""),
|
||||||
|
|
@ -2395,7 +2399,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
uint32_t sfgi = card.ats[pos] & 0x0F;
|
uint32_t sfgi = card.ats[pos] & 0x0F;
|
||||||
uint32_t fwi = card.ats[pos] >> 4;
|
uint32_t fwi = card.ats[pos] >> 4;
|
||||||
|
|
||||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... TB1 SFGI = %d (SFGT = %s%d/fc), FWI = " _YELLOW_("%d") " (FWT = %d/fc)",
|
PrintAndLogEx(INFO, " ........." _YELLOW_("%02X") "...... TB1 SFGI = %d (SFGT = %s%d/fc), FWI = " _YELLOW_("%d") " (FWT = %d/fc)",
|
||||||
card.ats[pos],
|
card.ats[pos],
|
||||||
(sfgi),
|
(sfgi),
|
||||||
sfgi ? "" : "(not needed) ",
|
sfgi ? "" : "(not needed) ",
|
||||||
|
|
@ -2407,7 +2411,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tc1 && (card.ats_len > pos + 2)) {
|
if (tc1 && (card.ats_len > pos + 2)) {
|
||||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... TC1 NAD is%s supported, CID is%s supported",
|
PrintAndLogEx(INFO, " ............" _YELLOW_("%02X") "... TC1 NAD is%s supported, CID is%s supported",
|
||||||
card.ats[pos],
|
card.ats[pos],
|
||||||
(card.ats[pos] & 0x01) ? "" : _RED_(" NOT"),
|
(card.ats[pos] & 0x01) ? "" : _RED_(" NOT"),
|
||||||
(card.ats[pos] & 0x02) ? "" : _RED_(" NOT")
|
(card.ats[pos] & 0x02) ? "" : _RED_(" NOT")
|
||||||
|
|
@ -2546,11 +2550,8 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
, sprint_ascii(card.ats + pos, calen)
|
, sprint_ascii(card.ats + pos, calen)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_aid_search) {
|
if (do_aid_search) {
|
||||||
|
|
@ -2781,7 +2782,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
if ((isMagic & MAGIC_FLAG_GEN_2) == MAGIC_FLAG_GEN_2) {
|
if ((isMagic & MAGIC_FLAG_GEN_2) == MAGIC_FLAG_GEN_2) {
|
||||||
PrintAndLogEx(HINT, "Hint: use `" _YELLOW_("hf mf") "` commands");
|
PrintAndLogEx(HINT, "Hint: use `" _YELLOW_("hf mf") "` commands");
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mf`") " commands");
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mf info`"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3718,55 +3719,58 @@ int CmdHF14AAIDSim(const char *Cmd) {
|
||||||
"hf 14a simaid -t 3 -> MIFARE Desfire\n"
|
"hf 14a simaid -t 3 -> MIFARE Desfire\n"
|
||||||
"hf 14a simaid -t 4 -> ISO/IEC 14443-4\n"
|
"hf 14a simaid -t 4 -> ISO/IEC 14443-4\n"
|
||||||
"hf 14a simaid -t 11 -> Javacard (JCOP)\n"
|
"hf 14a simaid -t 11 -> Javacard (JCOP)\n"
|
||||||
"hf 14a simaid -t 3 --aid a000000000000000000000 --response 9000 --apdu 9000 -> AID, Response and APDU\n"
|
"hf 14a simaid -t 3 --aid a000000000000000000000 --selectaid_response 9000 --getdata_response 9000 -> Custom AID and responses\n"
|
||||||
"hf 14a simaid -t 3 --rats 05788172220101 --response 01009000 --apdu 86009000 -> Custom RATS Added\n"
|
"hf 14a simaid -t 3 --ats 0578817222 --selectaid_response 01009000 --getdata_response 86009000 -> Custom ATS and responses\n"
|
||||||
"hf 14a simaid -t 3 --rats 05788172220101 -x -> Enumerate AID Values\n"
|
"hf 14a simaid -t 3 --ats 0578817222 -x -> Enumerate AID Values\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_int1("t", "type", "<1-12> ", "Simulation type to use"),
|
arg_int1("t", "type", "<1-12> ", "Simulation type to use"),
|
||||||
arg_str0("u", "uid", "<hex>", "<4|7|10> hex bytes UID"),
|
arg_str0("u", "uid", "<hex>", "<4|7|10> hex bytes UID"),
|
||||||
arg_str0("r", "rats", "<hex>", "<0-20> hex bytes RATS"),
|
arg_str0("r", "ats", "<hex>", "<0-20> hex bytes ATS"),
|
||||||
arg_str0("a", "aid", "<hex>", "<0-100> hex bytes for AID to respond to (Default: A000000000000000000000)"),
|
arg_str0("a", "aid", "<hex>", "<0-30> hex bytes for AID to respond to (Default: A000000000000000000000)"),
|
||||||
arg_str0("e", "response", "<hex>", "<0-100> hex bytes for APDU Response to AID Select (Default: 9000)"),
|
arg_str0("e", "selectaid_response", "<hex>", "<0-100> hex bytes for APDU Response to AID Select (Default: 9000)"),
|
||||||
arg_str0("p", "apdu", "<hex>", "<0-100> hex bytes for APDU Response to Get Data request after AID (Default: 9000)"),
|
arg_str0("p", "getdata_response", "<hex>", "<0-100> hex bytes for APDU Response to Get Data request after AID (Default: 9000)"),
|
||||||
arg_lit0("x", "enumerate", "Enumerate all AID values via returning Not Found and print them to console "),
|
arg_lit0("x", "enumerate", "Enumerate all AID values via returning Not Found and print them to console "),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
int tagtype = arg_get_int_def(ctx, 1, 1);
|
|
||||||
|
|
||||||
bool enumerate = arg_get_lit(ctx, 7);
|
|
||||||
|
|
||||||
int uid_len = 0;
|
int uid_len = 0;
|
||||||
int rats_len = 0;
|
int ats_len = 0;
|
||||||
int aid_len = 0;
|
int aid_len = 0;
|
||||||
int respond_len = 0;
|
int selectaid_response_len = 0;
|
||||||
int apdu_len = 0;
|
int getdata_response_len = 0;
|
||||||
|
|
||||||
uint8_t uid[10] = {0};
|
uint8_t uid[10] = {0};
|
||||||
uint8_t rats[20] = {0};
|
uint8_t ats[20] = {0};
|
||||||
uint8_t aid[30] = {0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t aid[30] = {0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t response[100] = {0x90, 0x00};
|
uint8_t default_aid_len = 11;
|
||||||
uint8_t apdu[100] = {0x90, 0x00};
|
uint8_t selectaid_response[100] = {0x90, 0x00};
|
||||||
|
uint8_t default_selectaid_response_len = 2;
|
||||||
|
uint8_t getdata_response[100] = {0x90, 0x00};
|
||||||
|
uint8_t default_getdata_response_len = 2;
|
||||||
|
|
||||||
|
int tagtype = arg_get_int_def(ctx, 1, 1);
|
||||||
CLIGetHexWithReturn(ctx, 2, uid, &uid_len);
|
CLIGetHexWithReturn(ctx, 2, uid, &uid_len);
|
||||||
CLIGetHexWithReturn(ctx, 3, rats, &rats_len);
|
CLIGetHexWithReturn(ctx, 3, ats, &ats_len);
|
||||||
CLIGetHexWithReturn(ctx, 4, aid, &aid_len);
|
CLIGetHexWithReturn(ctx, 4, aid, &aid_len);
|
||||||
CLIGetHexWithReturn(ctx, 5, response, &respond_len);
|
CLIGetHexWithReturn(ctx, 5, selectaid_response, &selectaid_response_len);
|
||||||
CLIGetHexWithReturn(ctx, 6, apdu, &apdu_len);
|
CLIGetHexWithReturn(ctx, 6, getdata_response, &getdata_response_len);
|
||||||
|
bool enumerate = arg_get_lit(ctx, 7);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
// default value fill for the AID, response, and apdu
|
// default value fill for the AID, selectaid_response, and getdata_response
|
||||||
if (aid_len == 0) {
|
if (aid_len == 0) {
|
||||||
aid_len = 11;
|
aid_len = default_aid_len;
|
||||||
}
|
}
|
||||||
if (respond_len == 0) {
|
|
||||||
respond_len = 2;
|
if (selectaid_response_len == 0) {
|
||||||
|
selectaid_response_len = default_selectaid_response_len;
|
||||||
}
|
}
|
||||||
if (apdu_len == 0) {
|
if (getdata_response_len == 0) {
|
||||||
apdu_len = 2;
|
getdata_response_len = default_getdata_response_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t flags = 0;
|
uint16_t flags = 0;
|
||||||
|
|
@ -3776,19 +3780,39 @@ int CmdHF14AAIDSim(const char *Cmd) {
|
||||||
FLAG_SET_UID_IN_DATA(flags, uid_len);
|
FLAG_SET_UID_IN_DATA(flags, uid_len);
|
||||||
if (IS_FLAG_UID_IN_EMUL(flags)) {
|
if (IS_FLAG_UID_IN_EMUL(flags)) {
|
||||||
PrintAndLogEx(ERR, "Please specify a 4, 7, or 10 byte UID");
|
PrintAndLogEx(ERR, "Please specify a 4, 7, or 10 byte UID");
|
||||||
CLIParserFree(ctx);
|
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(SUCCESS, "Emulating " _YELLOW_("ISO/IEC 14443 type A tag")" with " _GREEN_("%d byte UID (%s)"), uid_len, sprint_hex(uid, uid_len));
|
PrintAndLogEx(SUCCESS, "Emulating " _YELLOW_("ISO/IEC 14443 type A tag")" with " _GREEN_("%d byte UID (%s)"), uid_len, sprint_hex(uid, uid_len));
|
||||||
useUIDfromEML = false;
|
useUIDfromEML = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rats_len > 0) {
|
if (ats_len > sizeof(ats)) {
|
||||||
flags |= FLAG_RATS_IN_DATA;
|
PrintAndLogEx(ERR, "Provided ATS too long");
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aid_len > sizeof(aid)) {
|
||||||
|
PrintAndLogEx(ERR, "Provided AID too long");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
if (selectaid_response_len > sizeof(selectaid_response)) {
|
||||||
|
PrintAndLogEx(ERR, "Provided SelectAID response too long");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getdata_response_len > sizeof(getdata_response)) {
|
||||||
|
PrintAndLogEx(ERR, "Provided GetData response too long");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ats_len > 0) {
|
||||||
|
flags |= FLAG_ATS_IN_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enumerate) {
|
||||||
|
flags |= FLAG_ENUMERATE_AID;
|
||||||
|
}
|
||||||
|
|
||||||
if (tagtype > 12) {
|
if (tagtype > 12) {
|
||||||
PrintAndLogEx(ERR, "Undefined tag %d", tagtype);
|
PrintAndLogEx(ERR, "Undefined tag %d", tagtype);
|
||||||
|
|
@ -3803,31 +3827,31 @@ int CmdHF14AAIDSim(const char *Cmd) {
|
||||||
uint8_t tagtype;
|
uint8_t tagtype;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
uint8_t uid[10];
|
uint8_t uid[10];
|
||||||
uint8_t rats[20];
|
uint8_t ats[20];
|
||||||
uint8_t aid[30];
|
uint8_t aid[30];
|
||||||
uint8_t response[100];
|
uint8_t selectaid_response[100];
|
||||||
uint8_t apdu[100];
|
uint8_t getdata_response[100];
|
||||||
int aid_len;
|
uint32_t ats_len;
|
||||||
int respond_len;
|
uint32_t aid_len;
|
||||||
int apdu_len;
|
uint32_t selectaid_response_len;
|
||||||
bool enumerate;
|
uint32_t getdata_response_len;
|
||||||
} PACKED payload;
|
} PACKED payload;
|
||||||
|
|
||||||
payload.tagtype = tagtype;
|
payload.tagtype = tagtype;
|
||||||
payload.flags = flags;
|
payload.flags = flags;
|
||||||
payload.enumerate = enumerate;
|
|
||||||
|
|
||||||
// Copy data to payload
|
// Copy data to payload
|
||||||
memcpy(payload.uid, uid, uid_len);
|
memcpy(payload.uid, uid, uid_len);
|
||||||
memcpy(payload.rats, rats, rats_len);
|
memcpy(payload.ats, ats, ats_len);
|
||||||
memcpy(payload.aid, aid, aid_len);
|
memcpy(payload.aid, aid, aid_len);
|
||||||
memcpy(payload.response, response, respond_len);
|
memcpy(payload.selectaid_response, selectaid_response, selectaid_response_len);
|
||||||
memcpy(payload.apdu, apdu, apdu_len);
|
memcpy(payload.getdata_response, getdata_response, getdata_response_len);
|
||||||
|
|
||||||
// copy the lengths data to the payload
|
// copy the lengths data to the payload
|
||||||
memcpy(&payload.aid_len, &aid_len, sizeof(aid_len));
|
payload.ats_len = ats_len;
|
||||||
memcpy(&payload.respond_len, &respond_len, sizeof(respond_len));
|
payload.aid_len = aid_len;
|
||||||
memcpy(&payload.apdu_len, &apdu_len, sizeof(apdu_len));
|
payload.selectaid_response_len = selectaid_response_len;
|
||||||
|
payload.getdata_response_len = getdata_response_len;
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_ISO14443A_SIM_AID, (uint8_t *)&payload, sizeof(payload));
|
SendCommandNG(CMD_HF_ISO14443A_SIM_AID, (uint8_t *)&payload, sizeof(payload));
|
||||||
|
|
@ -3837,14 +3861,17 @@ int CmdHF14AAIDSim(const char *Cmd) {
|
||||||
bool keypress = kbd_enter_pressed();
|
bool keypress = kbd_enter_pressed();
|
||||||
while (keypress == false) {
|
while (keypress == false) {
|
||||||
|
|
||||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0)
|
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (resp.status != PM3_SUCCESS)
|
if (resp.status != PM3_SUCCESS) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK)
|
if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
keypress = kbd_enter_pressed();
|
keypress = kbd_enter_pressed();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -282,9 +282,9 @@ static const productName_t uidmapping[] = {
|
||||||
static int CmdHF15Help(const char *Cmd);
|
static int CmdHF15Help(const char *Cmd);
|
||||||
|
|
||||||
static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
|
static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
|
||||||
|
|
||||||
int reason = 0;
|
int reason = 0;
|
||||||
int index = -1;
|
int index = originality_check_verify(uid, 8, signature, 32, PK_MFC);
|
||||||
index = originality_check_verify(uid, 8, signature, 32, PK_MFC);
|
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
reason = 1;
|
reason = 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -306,11 +306,12 @@ static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
int ret = originality_check_print(signature, 32, index);
|
int ret = originality_check_print(signature, 32, index);
|
||||||
if (ret != PM3_SUCCESS) {
|
if (ret != PM3_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case 1:
|
case 1:
|
||||||
PrintAndLogEx(INFO, " Params used: UID and signature, plain");
|
PrintAndLogEx(INFO, " Params used: UID and signature, plain");
|
||||||
|
|
@ -825,6 +826,8 @@ static int NxpSysInfo(uint8_t *uid) {
|
||||||
PrintAndLogEx(INFO, "");
|
PrintAndLogEx(INFO, "");
|
||||||
PrintAndLogEx(INFO, _CYAN_(" Password protection configuration"));
|
PrintAndLogEx(INFO, _CYAN_(" Password protection configuration"));
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, " Page prot. ptr. " _YELLOW_("%d"), d[1]);
|
||||||
|
|
||||||
PrintAndLogEx(INFO, " Page L read.... %s"
|
PrintAndLogEx(INFO, " Page L read.... %s"
|
||||||
, (d[2] & 0x01) ? _RED_("password") : _GREEN_("no password")
|
, (d[2] & 0x01) ? _RED_("password") : _GREEN_("no password")
|
||||||
);
|
);
|
||||||
|
|
@ -3202,6 +3205,101 @@ static int CmdHF15SlixWritePassword(const char *Cmd) {
|
||||||
return resp.status;
|
return resp.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int CmdHF15SlixProtectPage(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf 15 slixprotectpage",
|
||||||
|
"Defines protection pointer address of user mem and access cond. for pages",
|
||||||
|
"hf 15 slixprotectpage -w deadbeef -p 3 -h 3");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0("r", "readpw", "<hex>", "read password, 4 hex bytes"),
|
||||||
|
arg_str0("w", "writepw", "<hex>", "write password, 4 hex bytes"),
|
||||||
|
arg_int0("p", "ptr", "<dec>", "protection pointer page (0-78), if 0 entire user mem"),
|
||||||
|
arg_int1("l", "lo", "<dec>", "page protection flags of lo page (0-None, 1-ReadPR, 2-WritePR)"),
|
||||||
|
arg_int1("i", "hi", "<dec>", "page protection flags of hi page (0-None, 1-ReadPR, 2-WritePR)"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
struct p {
|
||||||
|
uint8_t read_pwd[4];
|
||||||
|
uint8_t write_pwd[4];
|
||||||
|
uint8_t divide_ptr;
|
||||||
|
uint8_t prot_status;
|
||||||
|
} PACKED payload = {0};
|
||||||
|
int pwdlen = 0;
|
||||||
|
|
||||||
|
CLIGetHexWithReturn(ctx, 1, payload.read_pwd, &pwdlen);
|
||||||
|
|
||||||
|
if (pwdlen > 0 && pwdlen != 4) {
|
||||||
|
PrintAndLogEx(WARNING, "read password must be 4 hex bytes if provided");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIGetHexWithReturn(ctx, 2, payload.write_pwd, &pwdlen);
|
||||||
|
|
||||||
|
if (pwdlen > 0 && pwdlen != 4) {
|
||||||
|
PrintAndLogEx(WARNING, "write password must be 4 hex bytes if provided");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
payload.divide_ptr = (uint8_t)arg_get_int_def(ctx, 3, 0);
|
||||||
|
if (payload.divide_ptr > 78) {
|
||||||
|
PrintAndLogEx(WARNING, "protection pointer page is invalid (is %d but should be <=78).", payload.divide_ptr);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pwdlen = arg_get_int_def(ctx, 4, 0);
|
||||||
|
if (pwdlen > 3) {
|
||||||
|
PrintAndLogEx(WARNING, "page protection flags must be between 0 and 3");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
payload.prot_status = (uint8_t)pwdlen;
|
||||||
|
|
||||||
|
pwdlen = arg_get_int_def(ctx, 5, 0);
|
||||||
|
if (pwdlen > 3) {
|
||||||
|
PrintAndLogEx(WARNING, "page protection flags must be between 0 and 3");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
payload.prot_status |= (uint8_t)pwdlen << 4;
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Trying to set page protection pointer to " _YELLOW_("%d"), payload.divide_ptr);
|
||||||
|
PrintAndLogEx(INFO, _YELLOW_("LO") " page access %s%s", (payload.prot_status & 0x01) ? _RED_("R") : _GREEN_("r"), (payload.prot_status & 0x02) ? _RED_("W") : _GREEN_("w"));
|
||||||
|
PrintAndLogEx(INFO, _YELLOW_("HI") " page access %s%s", (payload.prot_status & 0x10) ? _RED_("R") : _GREEN_("r"), (payload.prot_status & 0x20) ? _RED_("W") : _GREEN_("w"));
|
||||||
|
|
||||||
|
PacketResponseNG resp;
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandNG(CMD_HF_ISO15693_SLIX_PROTECT_PAGE, (uint8_t *)&payload, sizeof(payload));
|
||||||
|
if (WaitForResponseTimeout(CMD_HF_ISO15693_SLIX_PROTECT_PAGE, &resp, 2000) == false) {
|
||||||
|
PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (resp.status) {
|
||||||
|
case PM3_ETIMEOUT: {
|
||||||
|
PrintAndLogEx(WARNING, "no tag found");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PM3_EWRONGANSWER: {
|
||||||
|
PrintAndLogEx(WARNING, "Protection flags were not accepted, locked? ( " _RED_("fail") " )");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PM3_SUCCESS: {
|
||||||
|
PrintAndLogEx(SUCCESS, "Page protection written ( " _GREEN_("ok") " ) ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp.status;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdHF15AFIPassProtect(const char *Cmd) {
|
static int CmdHF15AFIPassProtect(const char *Cmd) {
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
|
|
@ -3512,6 +3610,7 @@ static command_t CommandTable[] = {
|
||||||
{"slixeasenable", CmdHF15SlixEASEnable, IfPm3Iso15693, "Enable EAS mode on SLIX ISO-15693 tag"},
|
{"slixeasenable", CmdHF15SlixEASEnable, IfPm3Iso15693, "Enable EAS mode on SLIX ISO-15693 tag"},
|
||||||
{"slixprivacydisable", CmdHF15SlixDisable, IfPm3Iso15693, "Disable privacy mode on SLIX ISO-15693 tag"},
|
{"slixprivacydisable", CmdHF15SlixDisable, IfPm3Iso15693, "Disable privacy mode on SLIX ISO-15693 tag"},
|
||||||
{"slixprivacyenable", CmdHF15SlixEnable, IfPm3Iso15693, "Enable privacy mode on SLIX ISO-15693 tag"},
|
{"slixprivacyenable", CmdHF15SlixEnable, IfPm3Iso15693, "Enable privacy mode on SLIX ISO-15693 tag"},
|
||||||
|
{"slixprotectpage", CmdHF15SlixProtectPage, IfPm3Iso15693, "Protect pages on SLIX ISO-15693 tag"},
|
||||||
{"passprotectafi", CmdHF15AFIPassProtect, IfPm3Iso15693, "Password protect AFI - Cannot be undone"},
|
{"passprotectafi", CmdHF15AFIPassProtect, IfPm3Iso15693, "Password protect AFI - Cannot be undone"},
|
||||||
{"passprotecteas", CmdHF15EASPassProtect, IfPm3Iso15693, "Password protect EAS - Cannot be undone"},
|
{"passprotecteas", CmdHF15EASPassProtect, IfPm3Iso15693, "Password protect EAS - Cannot be undone"},
|
||||||
{"-----------", CmdHF15Help, IfPm3Iso15693, "-------------------------- " _CYAN_("afi") " ------------------------"},
|
{"-----------", CmdHF15Help, IfPm3Iso15693, "-------------------------- " _CYAN_("afi") " ------------------------"},
|
||||||
|
|
|
||||||
|
|
@ -767,23 +767,35 @@ static bool emrtd_select_and_read(uint8_t *dataout, size_t *dataoutlen, uint16_t
|
||||||
|
|
||||||
static const uint8_t jpeg_header[4] = { 0xFF, 0xD8, 0xFF, 0xE0 };
|
static const uint8_t jpeg_header[4] = { 0xFF, 0xD8, 0xFF, 0xE0 };
|
||||||
static const uint8_t jpeg2k_header[6] = { 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50 };
|
static const uint8_t jpeg2k_header[6] = { 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50 };
|
||||||
|
static const uint8_t jpeg2k_cs_header[4] = { 0xFF, 0x4F, 0xFF, 0x51 };
|
||||||
|
|
||||||
static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length, const char *path) {
|
static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length, const char *path) {
|
||||||
size_t offset;
|
size_t offset;
|
||||||
int datalen = 0;
|
int datalen = 0;
|
||||||
|
char suffix[5] = { '\0' };
|
||||||
|
|
||||||
// This is a hacky impl that just looks for the image header. I'll improve it eventually.
|
// This is a hacky impl that just looks for the image header. I'll improve it eventually.
|
||||||
// based on mrpkey.py
|
// based on mrpkey.py
|
||||||
// Note: Doing file_length - 6 to account for the longest data we're checking.
|
// Note: Doing file_length - 6 to account for the longest data we're checking.
|
||||||
// Checks first byte before the rest to reduce overhead
|
// Checks first byte before the rest to reduce overhead
|
||||||
for (offset = 0; offset < file_length - 6; offset++) {
|
for (offset = 0; offset < file_length - 6; offset++) {
|
||||||
if ((file_contents[offset] == 0xFF && memcmp(jpeg_header, file_contents + offset, 4) == 0) ||
|
if (file_contents[offset] == 0xFF) {
|
||||||
(file_contents[offset] == 0x00 && memcmp(jpeg2k_header, file_contents + offset, 6) == 0)) {
|
if (memcmp(jpeg_header, file_contents + offset, 4) == 0) {
|
||||||
|
datalen = file_length - offset;
|
||||||
|
strcpy(suffix, ".jpg");
|
||||||
|
break;
|
||||||
|
} else if (memcmp(jpeg2k_cs_header, file_contents + offset, 4) == 0) {
|
||||||
|
datalen = file_length - offset;
|
||||||
|
// no standardized extension for codestream data, using .jpc
|
||||||
|
strcpy(suffix, ".jpc");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (file_contents[offset] == 0x00 && memcmp(jpeg2k_header, file_contents + offset, 6) == 0) {
|
||||||
|
strcpy(suffix, ".jp2");
|
||||||
datalen = file_length - offset;
|
datalen = file_length - offset;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't get any data, return false.
|
// If we didn't get any data, return false.
|
||||||
if (datalen == 0) {
|
if (datalen == 0) {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
|
|
@ -797,7 +809,7 @@ static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length, const c
|
||||||
strncat(filepath, PATHSEP, 2);
|
strncat(filepath, PATHSEP, 2);
|
||||||
strcat(filepath, dg_table[EF_DG2].filename);
|
strcat(filepath, dg_table[EF_DG2].filename);
|
||||||
|
|
||||||
saveFile(filepath, file_contents[offset] == 0xFF ? ".jpg" : ".jp2", file_contents + offset, datalen);
|
saveFile(filepath, suffix, file_contents + offset, datalen);
|
||||||
|
|
||||||
free(filepath);
|
free(filepath);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
|
@ -1865,14 +1877,13 @@ static int emrtd_print_ef_sod_info(uint8_t *dg_hashes_calc, uint8_t *dg_hashes_s
|
||||||
PrintAndLogEx(INFO, "------------------------ " _CYAN_("EF_SOD") " ------------------------");
|
PrintAndLogEx(INFO, "------------------------ " _CYAN_("EF_SOD") " ------------------------");
|
||||||
PrintAndLogEx(INFO, "Document Security Object");
|
PrintAndLogEx(INFO, "Document Security Object");
|
||||||
PrintAndLogEx(INFO, "contains the digital signatures of the passport data");
|
PrintAndLogEx(INFO, "contains the digital signatures of the passport data");
|
||||||
|
PrintAndLogEx(INFO, "");
|
||||||
|
|
||||||
if (hash_algo == -1) {
|
if (hash_algo == -1) {
|
||||||
PrintAndLogEx(SUCCESS, "Hash algorithm... " _YELLOW_("Unknown"));
|
PrintAndLogEx(SUCCESS, "Hash algorithm... " _YELLOW_("Unknown"));
|
||||||
PrintAndLogEx(INFO, "");
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Hash algorithm... " _YELLOW_("%s"), hashalg_table[hash_algo].name);
|
PrintAndLogEx(SUCCESS, "Hash algorithm... " _YELLOW_("%s"), hashalg_table[hash_algo].name);
|
||||||
PrintAndLogEx(INFO, "");
|
|
||||||
|
|
||||||
uint8_t all_zeroes[64] = { 0x00 };
|
uint8_t all_zeroes[64] = { 0x00 };
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,6 @@ static uint8_t empty[PICOPASS_BLOCK_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
static uint8_t zeros[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
static uint8_t zeros[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
static void print_iclass_sio(uint8_t *iclass_dump, size_t dump_len);
|
|
||||||
|
|
||||||
static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][PICOPASS_BLOCK_SIZE] = {
|
static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][PICOPASS_BLOCK_SIZE] = {
|
||||||
{ 0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78 },
|
{ 0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78 },
|
||||||
|
|
@ -1346,10 +1345,7 @@ static int CmdHFiClassEView(const char *Cmd) {
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
printIclassDumpContents(dump, 1, blocks, bytes, dense_output);
|
printIclassDumpContents(dump, 1, blocks, bytes, dense_output);
|
||||||
|
print_iclass_sio(dump, bytes, verbose);
|
||||||
if (verbose) {
|
|
||||||
print_iclass_sio(dump, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(dump);
|
free(dump);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
|
@ -1400,7 +1396,7 @@ static int CmdHFiClassESetBlk(const char *Cmd) {
|
||||||
|
|
||||||
static bool iclass_detect_new_pacs(uint8_t *d) {
|
static bool iclass_detect_new_pacs(uint8_t *d) {
|
||||||
uint8_t n = 0;
|
uint8_t n = 0;
|
||||||
while (n++ < (PICOPASS_BLOCK_SIZE / 2)) {
|
while (n++ < (PICOPASS_BLOCK_SIZE >> 1)) {
|
||||||
if (d[n] && d[n + 1] == 0xA6) {
|
if (d[n] && d[n + 1] == 0xA6) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1418,7 +1414,7 @@ static int iclass_decode_credentials_new_pacs(uint8_t *d) {
|
||||||
|
|
||||||
uint8_t pad = d[offset];
|
uint8_t pad = d[offset];
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "%u , %u", offset, pad);
|
PrintAndLogEx(DEBUG, "%u , %u", offset, pad);
|
||||||
|
|
||||||
char *binstr = (char *)calloc((PICOPASS_BLOCK_SIZE * 8) + 1, sizeof(uint8_t));
|
char *binstr = (char *)calloc((PICOPASS_BLOCK_SIZE * 8) + 1, sizeof(uint8_t));
|
||||||
if (binstr == NULL) {
|
if (binstr == NULL) {
|
||||||
|
|
@ -1428,17 +1424,16 @@ static int iclass_decode_credentials_new_pacs(uint8_t *d) {
|
||||||
uint8_t n = PICOPASS_BLOCK_SIZE - offset - 2;
|
uint8_t n = PICOPASS_BLOCK_SIZE - offset - 2;
|
||||||
bytes_2_binstr(binstr, d + offset + 2, n);
|
bytes_2_binstr(binstr, d + offset + 2, n);
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(DEBUG, "PACS......... " _GREEN_("%s"), sprint_hex_inrow(d + offset + 2, n));
|
||||||
PrintAndLogEx(SUCCESS, "PACS......... " _GREEN_("%s"), sprint_hex_inrow(d + offset + 2, n));
|
PrintAndLogEx(DEBUG, "padded bin... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr));
|
||||||
PrintAndLogEx(SUCCESS, "padded bin... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr));
|
|
||||||
|
|
||||||
binstr[strlen(binstr) - pad] = '\0';
|
binstr[strlen(binstr) - pad] = '\0';
|
||||||
PrintAndLogEx(SUCCESS, "bin.......... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr));
|
PrintAndLogEx(DEBUG, "bin.......... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr));
|
||||||
|
|
||||||
size_t hexlen = 0;
|
size_t hexlen = 0;
|
||||||
uint8_t hex[16] = {0};
|
uint8_t hex[16] = {0};
|
||||||
binstr_2_bytes(hex, &hexlen, binstr);
|
binstr_2_bytes(hex, &hexlen, binstr);
|
||||||
PrintAndLogEx(SUCCESS, "hex.......... " _GREEN_("%s"), sprint_hex_inrow(hex, hexlen));
|
PrintAndLogEx(DEBUG, "hex.......... " _GREEN_("%s"), sprint_hex_inrow(hex, hexlen));
|
||||||
|
|
||||||
uint32_t top = 0, mid = 0, bot = 0;
|
uint32_t top = 0, mid = 0, bot = 0;
|
||||||
if (binstring_to_u96(&top, &mid, &bot, binstr) != strlen(binstr)) {
|
if (binstring_to_u96(&top, &mid, &bot, binstr) != strlen(binstr)) {
|
||||||
|
|
@ -1450,9 +1445,8 @@ static int iclass_decode_credentials_new_pacs(uint8_t *d) {
|
||||||
free(binstr);
|
free(binstr);
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "Wiegand decode");
|
PrintAndLogEx(INFO, "------------------------- " _CYAN_("SIO - Wiegand") " ----------------------------");
|
||||||
wiegand_message_t packed = initialize_message_object(top, mid, bot, 0);
|
decode_wiegand(top, mid, bot, 0);
|
||||||
HIDTryUnpack(&packed);
|
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
@ -1473,8 +1467,7 @@ static void iclass_decode_credentials(uint8_t *data) {
|
||||||
if (has_values && encryption == None) {
|
if (has_values && encryption == None) {
|
||||||
|
|
||||||
// todo: remove preamble/sentinel
|
// todo: remove preamble/sentinel
|
||||||
PrintAndLogEx(INFO, "Block 7 decoder");
|
PrintAndLogEx(INFO, "------------------------ " _CYAN_("Block 7 decoder") " --------------------------");
|
||||||
|
|
||||||
if (has_new_pacs) {
|
if (has_new_pacs) {
|
||||||
iclass_decode_credentials_new_pacs(b7);
|
iclass_decode_credentials_new_pacs(b7);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1489,11 +1482,8 @@ static void iclass_decode_credentials(uint8_t *data) {
|
||||||
char *pbin = binstr;
|
char *pbin = binstr;
|
||||||
while (strlen(pbin) && *(++pbin) == '0');
|
while (strlen(pbin) && *(++pbin) == '0');
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Binary..................... " _GREEN_("%s"), pbin);
|
PrintAndLogEx(SUCCESS, "Binary... %zu - " _GREEN_("%s"), strlen(pbin), pbin);
|
||||||
|
decode_wiegand(top, mid, bot, 0);
|
||||||
PrintAndLogEx(INFO, "Wiegand decode");
|
|
||||||
wiegand_message_t packed = initialize_message_object(top, mid, bot, 0);
|
|
||||||
HIDTryUnpack(&packed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1712,11 +1702,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen, dense_output);
|
printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen, dense_output);
|
||||||
|
print_iclass_sio(decrypted, decryptedlen, verbose);
|
||||||
if (verbose) {
|
|
||||||
print_iclass_sio(decrypted, decryptedlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
// decode block 6
|
// decode block 6
|
||||||
|
|
@ -1747,7 +1733,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "-----------------------------------------------------------------");
|
PrintAndLogEx(INFO, "-------------------------------------------------------------------");
|
||||||
free(decrypted);
|
free(decrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2865,8 +2851,9 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
bool use_sc = IsCardHelperPresent(verbose);
|
bool use_sc = IsCardHelperPresent(verbose);
|
||||||
if (use_sc == false)
|
if (use_sc == false) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
// crypto helper available.
|
// crypto helper available.
|
||||||
PrintAndLogEx(INFO, "----------------------------- " _CYAN_("Cardhelper") " -----------------------------");
|
PrintAndLogEx(INFO, "----------------------------- " _CYAN_("Cardhelper") " -----------------------------");
|
||||||
|
|
@ -2916,8 +2903,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
|
||||||
PrintAndLogEx(SUCCESS, " bin : %s", pbin);
|
PrintAndLogEx(SUCCESS, " bin : %s", pbin);
|
||||||
PrintAndLogEx(INFO, "");
|
PrintAndLogEx(INFO, "");
|
||||||
PrintAndLogEx(INFO, "------------------------------ " _CYAN_("Wiegand") " -------------------------------");
|
PrintAndLogEx(INFO, "------------------------------ " _CYAN_("Wiegand") " -------------------------------");
|
||||||
wiegand_message_t packed = initialize_message_object(top, mid, bot, 0);
|
decode_wiegand(top, mid, bot, 0);
|
||||||
HIDTryUnpack(&packed);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(INFO, "no credential found");
|
PrintAndLogEx(INFO, "no credential found");
|
||||||
|
|
@ -3187,7 +3173,7 @@ static void detect_credential(uint8_t *iclass_dump, size_t dump_len, bool *is_le
|
||||||
|
|
||||||
picopass_hdr_t *hdr = (picopass_hdr_t *)iclass_dump;
|
picopass_hdr_t *hdr = (picopass_hdr_t *)iclass_dump;
|
||||||
|
|
||||||
if (!memcmp(hdr->app_issuer_area, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", PICOPASS_BLOCK_SIZE)) {
|
if (memcmp(hdr->app_issuer_area, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", PICOPASS_BLOCK_SIZE) == 0) {
|
||||||
// Legacy AIA
|
// Legacy AIA
|
||||||
*is_legacy = true;
|
*is_legacy = true;
|
||||||
|
|
||||||
|
|
@ -3209,7 +3195,7 @@ static void detect_credential(uint8_t *iclass_dump, size_t dump_len, bool *is_le
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!memcmp(hdr->app_issuer_area, "\xFF\xFF\xFF\x00\x06\xFF\xFF\xFF", PICOPASS_BLOCK_SIZE)) {
|
} else if (memcmp(hdr->app_issuer_area, "\xFF\xFF\xFF\x00\x06\xFF\xFF\xFF", PICOPASS_BLOCK_SIZE) == 0) {
|
||||||
// SE AIA
|
// SE AIA
|
||||||
*is_se = true;
|
*is_se = true;
|
||||||
|
|
||||||
|
|
@ -3241,28 +3227,32 @@ static void detect_credential(uint8_t *iclass_dump, size_t dump_len, bool *is_le
|
||||||
}
|
}
|
||||||
|
|
||||||
// print ASN1 decoded array in TLV view
|
// print ASN1 decoded array in TLV view
|
||||||
static void print_iclass_sio(uint8_t *iclass_dump, size_t dump_len) {
|
void print_iclass_sio(uint8_t *iclass_dump, size_t dump_len, bool verbose) {
|
||||||
|
|
||||||
bool is_legacy, is_se, is_sr;
|
bool is_legacy, is_se, is_sr;
|
||||||
uint8_t *sio_start;
|
uint8_t *sio_start;
|
||||||
size_t sio_length;
|
size_t sio_length;
|
||||||
detect_credential(iclass_dump, dump_len, &is_legacy, &is_se, &is_sr, &sio_start, &sio_length);
|
detect_credential(iclass_dump, dump_len, &is_legacy, &is_se, &is_sr, &sio_start, &sio_length);
|
||||||
|
|
||||||
|
// sanity checks
|
||||||
if (sio_start == NULL) {
|
if (sio_start == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dump_len < sio_length + (sio_start - iclass_dump)) {
|
if (dump_len < sio_length + (sio_start - iclass_dump)) {
|
||||||
// SIO length exceeds the size of the dump we have, bail
|
// SIO length exceeds the size of the dump
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "---------------------------- " _CYAN_("SIO - RAW") " ----------------------------");
|
PrintAndLogEx(INFO, "--------------------------- " _CYAN_("SIO - RAW") " -----------------------------");
|
||||||
print_hex_noascii_break(sio_start, sio_length, 32);
|
print_hex_noascii_break(sio_start, sio_length, 32);
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "------------------------- " _CYAN_("SIO - ASN1 TLV") " --------------------------");
|
if (verbose) {
|
||||||
|
PrintAndLogEx(INFO, "----------------------- " _CYAN_("SIO - ASN1 TLV") " ---------------------------");
|
||||||
asn1_print(sio_start, sio_length, " ");
|
asn1_print(sio_start, sio_length, " ");
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize, bool dense_output) {
|
void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize, bool dense_output) {
|
||||||
|
|
@ -3460,8 +3450,9 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e
|
||||||
if (is_legacy)
|
if (is_legacy)
|
||||||
PrintAndLogEx(HINT, _YELLOW_("yellow") " = legacy credential");
|
PrintAndLogEx(HINT, _YELLOW_("yellow") " = legacy credential");
|
||||||
|
|
||||||
if (is_se)
|
if (is_se) {
|
||||||
PrintAndLogEx(HINT, _CYAN_("cyan") " = SIO / SE credential");
|
PrintAndLogEx(HINT, _CYAN_("cyan") " = SIO / SE credential");
|
||||||
|
}
|
||||||
|
|
||||||
if (is_sr)
|
if (is_sr)
|
||||||
PrintAndLogEx(HINT, _CYAN_("cyan") " = SIO / SR credential");
|
PrintAndLogEx(HINT, _CYAN_("cyan") " = SIO / SR credential");
|
||||||
|
|
@ -3519,10 +3510,7 @@ static int CmdHFiClassView(const char *Cmd) {
|
||||||
print_picopass_info((picopass_hdr_t *) dump);
|
print_picopass_info((picopass_hdr_t *) dump);
|
||||||
printIclassDumpContents(dump, startblock, endblock, bytes_read, dense_output);
|
printIclassDumpContents(dump, startblock, endblock, bytes_read, dense_output);
|
||||||
iclass_decode_credentials(dump);
|
iclass_decode_credentials(dump);
|
||||||
|
print_iclass_sio(dump, bytes_read, verbose);
|
||||||
if (verbose) {
|
|
||||||
print_iclass_sio(dump, bytes_read);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(dump);
|
free(dump);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
|
@ -3880,7 +3868,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
|
||||||
arg_lit0(NULL, "vb6kdf", "use the VB6 elite KDF instead of a file"),
|
arg_lit0(NULL, "vb6kdf", "use the VB6 elite KDF instead of a file"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
int fnlen = 0;
|
int fnlen = 0;
|
||||||
char filename[FILE_PATH_SIZE] = {0};
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
|
@ -4661,11 +4649,11 @@ static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
memcpy(CCNR + 8, macs, 4);
|
memcpy(CCNR + 8, macs, 4);
|
||||||
memcpy(MAC_TAG, macs + 4, 4);
|
memcpy(MAC_TAG, macs + 4, 4);
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(csn, sizeof(csn)));
|
PrintAndLogEx(SUCCESS, "CSN....... " _GREEN_("%s"), sprint_hex(csn, sizeof(csn)));
|
||||||
PrintAndLogEx(SUCCESS, " Epurse: %s", sprint_hex(epurse, sizeof(epurse)));
|
PrintAndLogEx(SUCCESS, "Epurse.... %s", sprint_hex(epurse, sizeof(epurse)));
|
||||||
PrintAndLogEx(SUCCESS, " MACS: %s", sprint_hex(macs, sizeof(macs)));
|
PrintAndLogEx(SUCCESS, "MACS...... %s", sprint_hex(macs, sizeof(macs)));
|
||||||
PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR)));
|
PrintAndLogEx(SUCCESS, "CCNR...... " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR)));
|
||||||
PrintAndLogEx(SUCCESS, "TAG MAC: %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG)));
|
PrintAndLogEx(SUCCESS, "TAG MAC... %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG)));
|
||||||
|
|
||||||
// Run time
|
// Run time
|
||||||
uint64_t t1 = msclock();
|
uint64_t t1 = msclock();
|
||||||
|
|
@ -4744,7 +4732,7 @@ typedef struct {
|
||||||
uint8_t use_raw;
|
uint8_t use_raw;
|
||||||
uint8_t use_elite;
|
uint8_t use_elite;
|
||||||
uint32_t keycnt;
|
uint32_t keycnt;
|
||||||
uint8_t csn[8];
|
uint8_t csn[PICOPASS_BLOCK_SIZE];
|
||||||
uint8_t cc_nr[12];
|
uint8_t cc_nr[12];
|
||||||
uint8_t *keys;
|
uint8_t *keys;
|
||||||
union {
|
union {
|
||||||
|
|
@ -4821,8 +4809,9 @@ void GenerateMacFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elite,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < iclass_tc; i++)
|
for (int i = 0; i < iclass_tc; i++) {
|
||||||
pthread_join(threads[i], NULL);
|
pthread_join(threads[i], NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *bf_generate_mackey(void *thread_arg) {
|
static void *bf_generate_mackey(void *thread_arg) {
|
||||||
|
|
@ -5436,7 +5425,7 @@ static int CmdHFiClassSAM(const char *Cmd) {
|
||||||
data[0] = flags;
|
data[0] = flags;
|
||||||
|
|
||||||
int cmdlen = 0;
|
int cmdlen = 0;
|
||||||
if (CLIParamHexToBuf(arg_get_str(ctx, 8), data+1, PM3_CMD_DATA_SIZE-1, &cmdlen) != PM3_SUCCESS){
|
if (CLIParamHexToBuf(arg_get_str(ctx, 8), data + 1, PM3_CMD_DATA_SIZE - 1, &cmdlen) != PM3_SUCCESS) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
@ -5448,7 +5437,7 @@ static int CmdHFiClassSAM(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_SAM_PICOPASS, data, cmdlen+1);
|
SendCommandNG(CMD_HF_SAM_PICOPASS, data, cmdlen + 1);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_HF_SAM_PICOPASS, &resp, 4000) == false) {
|
if (WaitForResponseTimeout(CMD_HF_SAM_PICOPASS, &resp, 4000) == false) {
|
||||||
PrintAndLogEx(WARNING, "SAM timeout");
|
PrintAndLogEx(WARNING, "SAM timeout");
|
||||||
|
|
@ -5506,11 +5495,11 @@ static int CmdHFiClassSAM(const char *Cmd) {
|
||||||
const uint8_t *mediaType = oid + 2 + oid_length;
|
const uint8_t *mediaType = oid + 2 + oid_length;
|
||||||
const uint8_t mediaType_data = mediaType[2];
|
const uint8_t mediaType_data = mediaType[2];
|
||||||
PrintAndLogEx(SUCCESS, "SIO Media Type: " _GREEN_("%s"), getSioMediaTypeInfo(mediaType_data));
|
PrintAndLogEx(SUCCESS, "SIO Media Type: " _GREEN_("%s"), getSioMediaTypeInfo(mediaType_data));
|
||||||
} else if(breakOnNrMac && d[0] == 0x05) {
|
} else if (breakOnNrMac && d[0] == 0x05) {
|
||||||
PrintAndLogEx(SUCCESS, "Nr-MAC: " _GREEN_("%s"), sprint_hex_inrow(d+1, 8));
|
PrintAndLogEx(SUCCESS, "Nr-MAC: " _GREEN_("%s"), sprint_hex_inrow(d + 1, 8));
|
||||||
if(verbose){
|
if (verbose) {
|
||||||
PrintAndLogEx(INFO, "Replay Nr-MAC to dump SIO:");
|
PrintAndLogEx(INFO, "Replay Nr-MAC to dump SIO:");
|
||||||
PrintAndLogEx(SUCCESS, " hf iclass dump -k \"%s\" --nr", sprint_hex_inrow(d+1, 8));
|
PrintAndLogEx(SUCCESS, " hf iclass dump -k \"%s\" --nr", sprint_hex_inrow(d + 1, 8));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print_hex(d, resp.length);
|
print_hex(d, resp.length);
|
||||||
|
|
|
||||||
|
|
@ -43,4 +43,5 @@ uint32_t picopass_elite_rng(void);
|
||||||
uint32_t picopass_elite_lcg(void);
|
uint32_t picopass_elite_lcg(void);
|
||||||
uint8_t picopass_elite_nextByte(void);
|
uint8_t picopass_elite_nextByte(void);
|
||||||
void generate_key_block_inverted(const uint8_t *startingKey, uint64_t index, uint8_t *keyBlock);
|
void generate_key_block_inverted(const uint8_t *startingKey, uint64_t index, uint8_t *keyBlock);
|
||||||
|
void print_iclass_sio(uint8_t *iclass_dump, size_t dump_len, bool verbose);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "cmdhficlass.h"
|
#include "cmdhficlass.h"
|
||||||
#include "mifare/mifaredefault.h" // mifare consts
|
#include "mifare/mifaredefault.h" // mifare consts
|
||||||
|
#include "cmdhfseos.h"
|
||||||
|
|
||||||
enum MifareAuthSeq {
|
enum MifareAuthSeq {
|
||||||
masNone,
|
masNone,
|
||||||
|
|
@ -70,8 +71,14 @@ static uint8_t *gs_mfuc_key = NULL;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint8_t iso14443A_CRC_check(bool isResponse, uint8_t *d, uint8_t n) {
|
uint8_t iso14443A_CRC_check(bool isResponse, uint8_t *d, uint8_t n) {
|
||||||
if (n < 3) return 2;
|
if (n < 3) {
|
||||||
if (isResponse && (n == 5)) return 2;
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isResponse && (n == 5)) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
if (d[1] == 0x50 &&
|
if (d[1] == 0x50 &&
|
||||||
d[0] >= ISO14443A_CMD_ANTICOLL_OR_SELECT &&
|
d[0] >= ISO14443A_CMD_ANTICOLL_OR_SELECT &&
|
||||||
d[0] <= ISO14443A_CMD_ANTICOLL_OR_SELECT_3) {
|
d[0] <= ISO14443A_CMD_ANTICOLL_OR_SELECT_3) {
|
||||||
|
|
@ -80,6 +87,25 @@ uint8_t iso14443A_CRC_check(bool isResponse, uint8_t *d, uint8_t n) {
|
||||||
return check_crc(CRC_14443_A, d, n);
|
return check_crc(CRC_14443_A, d, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t seos_CRC_check(bool isResponse, uint8_t *d, uint8_t n) {
|
||||||
|
if (n < 3) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5 bytes response Card busy 0xFA have crc, the rest is most likely 14a anticollision
|
||||||
|
if ((n == 5) && (d[0] != 0xFA)) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d[1] == 0x50 &&
|
||||||
|
d[0] >= ISO14443A_CMD_ANTICOLL_OR_SELECT &&
|
||||||
|
d[0] <= ISO14443A_CMD_ANTICOLL_OR_SELECT_3) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return check_crc(CRC_14443_A, d, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t mifare_CRC_check(bool isResponse, uint8_t *data, uint8_t len) {
|
uint8_t mifare_CRC_check(bool isResponse, uint8_t *data, uint8_t len) {
|
||||||
switch (MifareAuthState) {
|
switch (MifareAuthState) {
|
||||||
case masNone:
|
case masNone:
|
||||||
|
|
@ -273,9 +299,11 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i
|
||||||
snprintf(exp, size, "HALT");
|
snprintf(exp, size, "HALT");
|
||||||
MifareAuthState = masNone;
|
MifareAuthState = masNone;
|
||||||
break;
|
break;
|
||||||
case ISO14443A_CMD_RATS:
|
case ISO14443A_CMD_RATS: {
|
||||||
snprintf(exp, size, "RATS - FSDI=%x, CID=%x", (cmd[1] & 0xF0) >> 4, (cmd[1] & 0x0F));
|
uint16_t fsdi2fsd[] = {16, 24, 32, 40, 48, 64, 96, 128, 256, 512, 1024, 2048, 4096, 4096, 4096, 4096};
|
||||||
|
snprintf(exp, size, "RATS - FSDI=%x (FSD=%u), CID=%x", (cmd[1] & 0xF0) >> 4, fsdi2fsd[(cmd[1] & 0xF0) >> 4], (cmd[1] & 0x0F));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
/* Actually, PPSS is Dx
|
/* Actually, PPSS is Dx
|
||||||
case ISO14443A_CMD_PPS:
|
case ISO14443A_CMD_PPS:
|
||||||
snprintf(exp, size, "PPS");
|
snprintf(exp, size, "PPS");
|
||||||
|
|
@ -421,14 +449,14 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i
|
||||||
snprintf(exp, size, "?");
|
snprintf(exp, size, "?");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NTAG_I2C_FASTWRITE:
|
case NTAG_I2C_FASTWRITE: {
|
||||||
if (cmdsize == 69)
|
if (cmdsize == 69)
|
||||||
snprintf(exp, size, "FAST WRITE (" _MAGENTA_("%d-%d") ")", cmd[1], cmd[2]);
|
snprintf(exp, size, "FAST WRITE (" _MAGENTA_("%d-%d") ")", cmd[1], cmd[2]);
|
||||||
else
|
else
|
||||||
snprintf(exp, size, "?");
|
snprintf(exp, size, "?");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default: {
|
||||||
if ((cmd[0] & 0xF0) == 0xD0 && (cmdsize == 4 || cmdsize == 5)) {
|
if ((cmd[0] & 0xF0) == 0xD0 && (cmdsize == 4 || cmdsize == 5)) {
|
||||||
snprintf(exp, size, "PPS - CID=%x", cmd[0] & 0x0F) ;
|
snprintf(exp, size, "PPS - CID=%x", cmd[0] & 0x0F) ;
|
||||||
} else if ((cmd[0] & 0xF0) == 0x60 && (cmdsize == 4)) {
|
} else if ((cmd[0] & 0xF0) == 0x60 && (cmdsize == 4)) {
|
||||||
|
|
@ -438,7 +466,10 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (gs_mfuc_state == 1) {
|
if (gs_mfuc_state == 1) {
|
||||||
if ((cmd[0] == 0xAF) && (cmdsize == 11)) {
|
if ((cmd[0] == 0xAF) && (cmdsize == 11)) {
|
||||||
// register RndB
|
// register RndB
|
||||||
|
|
@ -448,6 +479,7 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i
|
||||||
gs_mfuc_state = 0;
|
gs_mfuc_state = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gs_mfuc_state == 3) {
|
if (gs_mfuc_state == 3) {
|
||||||
if ((cmd[0] == 0x00) && (cmdsize == 11)) {
|
if ((cmd[0] == 0x00) && (cmdsize == 11)) {
|
||||||
// register RndA'
|
// register RndA'
|
||||||
|
|
@ -1746,49 +1778,115 @@ void annotateCryptoRF(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void annotateSeos(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
void annotateSeos(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool isResponse) {
|
||||||
|
|
||||||
|
if (cmd[0] == 0xFA && cmdsize == 5) {
|
||||||
|
snprintf(exp, size, (isResponse) ? "BUSY" : "DONE?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// it's basically a ISO14443a tag, so try annotation from there
|
// it's basically a ISO14443a tag, so try annotation from there
|
||||||
if (applyIso14443a(exp, size, cmd, cmdsize, false) != PM3_SUCCESS) {
|
if (applyIso14443a(exp, size, cmd, cmdsize, false) != PM3_SUCCESS) {
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
switch (cmd[0]) {
|
switch (cmd[0]) {
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
pos = 2;
|
|
||||||
break;
|
|
||||||
case 0:
|
case 0:
|
||||||
|
case 2:
|
||||||
|
case 3: {
|
||||||
pos = 1;
|
pos = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
pos = 2;
|
pos = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (memcmp(cmd + pos, "\x00\xa4\x04\x00\x0a", 5) == 0) {
|
if (memcmp(cmd + pos, "\x00\xA4\x04\x00", 4) == 0) {
|
||||||
snprintf(exp, size, "SELECT AID");
|
uint8_t n = cmd[pos + 4];
|
||||||
|
snprintf(exp, size, "SELECT AID " _WHITE_("%s"), sprint_hex_inrow(cmd + pos + 4 + 1, n));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(cmd + pos, "\x80\xA5\x00\x00", 4) == 0) {
|
||||||
|
snprintf(exp, size, "SELECT GDF");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(cmd + pos, "\x80\xA5\x04\x00", 4) == 0) {
|
if (memcmp(cmd + pos, "\x80\xA5\x04\x00", 4) == 0) {
|
||||||
snprintf(exp, size, "SELECT ADF / OID");
|
uint8_t n = cmd[pos + 4 + 2];
|
||||||
|
snprintf(exp, size, "SELECT OID " _WHITE_("%s"), sprint_hex_inrow(cmd + pos + 4 + 2 + 1, n));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(cmd + pos, "\x00\x87\x00\x01\x04\x7c\x02\x81\x00", 9) == 0) {
|
if (memcmp(cmd + pos, "\x80\xA5\x07", 3) == 0) {
|
||||||
snprintf(exp, size, "GET CHALLENGE");
|
uint8_t ks = cmd[pos + 3];
|
||||||
|
snprintf(exp, size, "SELECT GDF " _WHITE_("(") " key " _MAGENTA_("%02X") " )", ks);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(cmd + pos, "\x00\x87\x00\x01\x2c", 5) == 0) {
|
if (memcmp(cmd + pos, "\x00\x87\x00", 3) == 0) {
|
||||||
snprintf(exp, size, "MUTUAL AUTHENTICATION");
|
uint8_t ks = cmd[pos + 3];
|
||||||
|
if (memcmp(cmd + pos + 3 + 1, "\x04\x7c\x02\x81\x00", 5) == 0) {
|
||||||
|
snprintf(exp, size, "GET CHALLENGE " _WHITE_("(") " key " _MAGENTA_("%02X") " )", ks);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(cmd + pos, "\x0c\xcb\x3f\xff", 4) == 0) {
|
if (memcmp(cmd + pos, "\x00\x87\x00", 3) == 0) {
|
||||||
|
uint8_t ks = cmd[pos + 3];
|
||||||
|
if (memcmp(cmd + pos + 3 + 1, "\x2C\x7C\x2A\x82\x28", 5) == 0) {
|
||||||
|
snprintf(exp, size, "MUTUAL AUTHENTICATION " _WHITE_("(") " key " _MAGENTA_("%02X") " )", ks);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(cmd + pos, "\x0C\xCB\x3F\xFF", 4) == 0) {
|
||||||
snprintf(exp, size, "GET DATA");
|
snprintf(exp, size, "GET DATA");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply ISO7816 annotations?
|
if (memcmp(cmd + pos, "\x0C\xDB\x3F\xFF", 4) == 0) {
|
||||||
// if (annotateIso7816(exp, size, cmd, cmdsize) == 0) {
|
snprintf(exp, size, "UPDATE DATA");
|
||||||
// }
|
return;
|
||||||
// apply SEOS annotations?
|
}
|
||||||
|
|
||||||
|
if (memcmp(cmd + pos, "\x0C\xED\x06\x00", 4) == 0) {
|
||||||
|
snprintf(exp, size, "DELETE DATA");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(cmd + pos, "\x0C\x41\x0C\x03", 4) == 0) {
|
||||||
|
snprintf(exp, size, "CREATE ADF");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isResponse) {
|
||||||
|
|
||||||
|
if (memcmp(cmd + pos, "\xCD\x02", 2) == 0) {
|
||||||
|
|
||||||
|
uint8_t ea = cmd[pos + 2];
|
||||||
|
uint8_t ha = cmd[pos + 3];
|
||||||
|
|
||||||
|
char eas[10] = {0};
|
||||||
|
if (ea == SEOS_ENCRYPTION_2K3DES) {
|
||||||
|
strcat(eas, "2K3DES");
|
||||||
|
} else if (ea == SEOS_ENCRYPTION_3K3DES) {
|
||||||
|
strcat(eas, "3K3DES");
|
||||||
|
} else if (ea == SEOS_ENCRYPTION_AES) {
|
||||||
|
strcat(eas, "AES");
|
||||||
|
}
|
||||||
|
|
||||||
|
char has[10] = {0};
|
||||||
|
if (ha == SEOS_HASHING_SHA1) {
|
||||||
|
strcat(has, "SHA1");
|
||||||
|
} else if (ha == SEOS_HASHING_SHA256) {
|
||||||
|
strcat(has, "SHA256");
|
||||||
|
}
|
||||||
|
snprintf(exp, size, "%s / %s", eas, has);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1828,11 +1926,13 @@ void annotateLegic(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||||
|
|
||||||
uint16_t address = (cmd[2] << 7) | cmd[1] >> 1;
|
uint16_t address = (cmd[2] << 7) | cmd[1] >> 1;
|
||||||
|
|
||||||
if (cmdBit == LEGIC_READ)
|
if (cmdBit == LEGIC_READ) {
|
||||||
snprintf(exp, size, "READ Byte(%d)", address);
|
snprintf(exp, size, "READ Byte(%d)", address);
|
||||||
|
}
|
||||||
|
|
||||||
if (cmdBit == LEGIC_WRITE)
|
if (cmdBit == LEGIC_WRITE) {
|
||||||
snprintf(exp, size, "WRITE Byte(%d)", address);
|
snprintf(exp, size, "WRITE Byte(%d)", address);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 21: {
|
case 21: {
|
||||||
|
|
@ -1852,9 +1952,10 @@ void annotateLegic(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 12:
|
case 12:
|
||||||
default:
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void annotateFelica(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
void annotateFelica(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ uint8_t felica_CRC_check(uint8_t *d, uint8_t n);
|
||||||
uint8_t mifare_CRC_check(bool isResponse, uint8_t *data, uint8_t len);
|
uint8_t mifare_CRC_check(bool isResponse, uint8_t *data, uint8_t len);
|
||||||
uint8_t iso15693_CRC_check(uint8_t *d, uint8_t n);
|
uint8_t iso15693_CRC_check(uint8_t *d, uint8_t n);
|
||||||
uint8_t iclass_CRC_check(bool isResponse, uint8_t *d, uint8_t n);
|
uint8_t iclass_CRC_check(bool isResponse, uint8_t *d, uint8_t n);
|
||||||
|
uint8_t seos_CRC_check(bool isResponse, uint8_t *d, uint8_t n);
|
||||||
|
|
||||||
int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response);
|
int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response);
|
||||||
|
|
||||||
|
|
@ -68,7 +69,7 @@ void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize,
|
||||||
void annotateLTO(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateLTO(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
void annotateCryptoRF(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateCryptoRF(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
|
|
||||||
void annotateSeos(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateSeos(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool isResponse);
|
||||||
|
|
||||||
bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen, const uint64_t *dicKeys, uint32_t dicKeysCount);
|
bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen, const uint64_t *dicKeys, uint32_t dicKeysCount);
|
||||||
bool NTParityChk(AuthData_t *ad, uint32_t ntx);
|
bool NTParityChk(AuthData_t *ad, uint32_t ntx);
|
||||||
|
|
|
||||||
|
|
@ -682,7 +682,7 @@ static int CmdHfLTOWriteBlock(const char *Cmd) {
|
||||||
|
|
||||||
int res = wrblLTO(blk, block_data, true);
|
int res = wrblLTO(blk, block_data, true);
|
||||||
if (res == PM3_SUCCESS)
|
if (res == PM3_SUCCESS)
|
||||||
PrintAndLogEx(HINT, "Try use 'hf lto rdbl' for verification");
|
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf lto rdbl") "` to verify");
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,6 @@ static int usage_hf14_keybrute(void) {
|
||||||
|
|
||||||
int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) {
|
int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) {
|
||||||
int index = originality_check_verify(uid, uidlen, signature, signature_len, PK_MFC);
|
int index = originality_check_verify(uid, uidlen, signature, signature_len, PK_MFC);
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return originality_check_print(signature, signature_len, index);
|
return originality_check_print(signature, signature_len, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,13 +121,6 @@ static char *GenerateFilename(const char *prefix, const char *suffix) {
|
||||||
// Each entry also stores whether the key was "found", defaults to false (0)
|
// Each entry also stores whether the key was "found", defaults to false (0)
|
||||||
static int initSectorTable(sector_t **src, size_t items) {
|
static int initSectorTable(sector_t **src, size_t items) {
|
||||||
|
|
||||||
|
|
||||||
// typedef struct {
|
|
||||||
// uint64_t Key[2];
|
|
||||||
// uint8_t foundKey[2];
|
|
||||||
// } sector_t;
|
|
||||||
|
|
||||||
// This allocates based on the size of a single item
|
|
||||||
(*src) = calloc(items, sizeof(sector_t));
|
(*src) = calloc(items, sizeof(sector_t));
|
||||||
if (*src == NULL) {
|
if (*src == NULL) {
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
|
|
@ -334,18 +326,18 @@ static void mf_print_block(uint8_t blockno, uint8_t *d, bool verbose) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
int32_t value = 0;
|
|
||||||
if (verbose && mfc_value(d, &value)) {
|
|
||||||
PrintAndLogEx(INFO, "%s| %3d | " _CYAN_("%s") " %"PRIi32, secstr, blockno, sprint_hex_ascii(d, MFBLOCK_SIZE), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blockno >= MIFARE_1K_MAXBLOCK) {
|
if (blockno >= MIFARE_1K_MAXBLOCK) {
|
||||||
// MFC Ev1 signature blocks.
|
// MFC Ev1 signature blocks.
|
||||||
PrintAndLogEx(INFO, _BACK_BLUE_("%s| %3d | %s"), secstr, blockno, sprint_hex_ascii(d, MFBLOCK_SIZE));
|
PrintAndLogEx(INFO, _BACK_BLUE_("%s| %3d | %s"), secstr, blockno, sprint_hex_ascii(d, MFBLOCK_SIZE));
|
||||||
|
} else {
|
||||||
|
int32_t value = 0;
|
||||||
|
if (verbose && mfc_value(d, &value)) {
|
||||||
|
PrintAndLogEx(INFO, "%s| %3d | " _CYAN_("%s") " %"PRIi32, secstr, blockno, sprint_hex_ascii(d, MFBLOCK_SIZE), value);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(INFO, "%s| %3d | %s", secstr, blockno, sprint_hex_ascii(d, MFBLOCK_SIZE));
|
PrintAndLogEx(INFO, "%s| %3d | %s", secstr, blockno, sprint_hex_ascii(d, MFBLOCK_SIZE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mf_print_blocks(uint16_t n, uint8_t *d, bool verbose) {
|
static void mf_print_blocks(uint16_t n, uint8_t *d, bool verbose) {
|
||||||
|
|
@ -746,6 +738,7 @@ static int mfc_read_tag(iso14a_card_select_t *card, uint8_t *carddata, uint8_t n
|
||||||
free(fptr);
|
free(fptr);
|
||||||
free(keyA);
|
free(keyA);
|
||||||
free(keyB);
|
free(keyB);
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "\nSucceeded in dumping all blocks");
|
PrintAndLogEx(SUCCESS, "\nSucceeded in dumping all blocks");
|
||||||
return PM3_SUCCESS ;
|
return PM3_SUCCESS ;
|
||||||
}
|
}
|
||||||
|
|
@ -2138,7 +2131,7 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) {
|
||||||
e_sector[sectorNo].foundKey[trgKeyType] = 1;
|
e_sector[sectorNo].foundKey[trgKeyType] = 1;
|
||||||
e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6);
|
e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6);
|
||||||
|
|
||||||
// mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false, false);
|
// mf_check_keys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false, false);
|
||||||
continue;
|
continue;
|
||||||
default :
|
default :
|
||||||
PrintAndLogEx(ERR, "unknown error.\n");
|
PrintAndLogEx(ERR, "unknown error.\n");
|
||||||
|
|
@ -2542,8 +2535,8 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
||||||
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
int outfnlen = 0;
|
int outfnlen = 0;
|
||||||
char outfilename[127] = {0};
|
char outfilename[FILE_PATH_SIZE] = {0};
|
||||||
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)outfilename, 127, &outfnlen);
|
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)outfilename, FILE_PATH_SIZE, &outfnlen);
|
||||||
|
|
||||||
|
|
||||||
bool slow = arg_get_lit(ctx, 7);
|
bool slow = arg_get_lit(ctx, 7);
|
||||||
|
|
@ -2739,7 +2732,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// read uid to generate a filename for the key file
|
// read uid to generate a filename for the key file
|
||||||
char suffix[FILE_PATH_SIZE];
|
char suffix[FILE_PATH_SIZE + strlen(outfilename)];
|
||||||
if (outfnlen) {
|
if (outfnlen) {
|
||||||
snprintf(suffix, sizeof(suffix) - strlen(outfilename), "-key-%s.bin", outfilename);
|
snprintf(suffix, sizeof(suffix) - strlen(outfilename), "-key-%s.bin", outfilename);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2955,7 +2948,7 @@ noValidKeyFound:
|
||||||
|
|
||||||
// Try the found keys are reused
|
// Try the found keys are reused
|
||||||
if (bytes_to_num(tmp_key, MIFARE_KEY_SIZE) != 0) {
|
if (bytes_to_num(tmp_key, MIFARE_KEY_SIZE) != 0) {
|
||||||
// <!> The fast check --> mfCheckKeys_fast(sector_cnt, true, true, 2, 1, tmp_key, e_sector, false, verbose);
|
// <!> The fast check --> mf_check_keys_fast(sector_cnt, true, true, 2, 1, tmp_key, e_sector, false, verbose);
|
||||||
// <!> Returns false keys, so we just stick to the slower mfchk.
|
// <!> Returns false keys, so we just stick to the slower mfchk.
|
||||||
for (int i = 0; i < sector_cnt; i++) {
|
for (int i = 0; i < sector_cnt; i++) {
|
||||||
for (int j = MF_KEY_A; j <= MF_KEY_B; j++) {
|
for (int j = MF_KEY_A; j <= MF_KEY_B; j++) {
|
||||||
|
|
@ -4251,6 +4244,7 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "Note: option -e implies -i");
|
PrintAndLogEx(INFO, "Note: option -e implies -i");
|
||||||
flags |= FLAG_INTERACTIVE;
|
flags |= FLAG_INTERACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK) {
|
if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK) {
|
||||||
PrintAndLogEx(WARNING, "Option -e requires -x or -y");
|
PrintAndLogEx(WARNING, "Option -e requires -x or -y");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
|
|
@ -4263,8 +4257,9 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
||||||
, (uidlen == 0) ? "n/a" : sprint_hex(uid, uidlen)
|
, (uidlen == 0) ? "n/a" : sprint_hex(uid, uidlen)
|
||||||
);
|
);
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Options [ numreads: %d, flags: 0x%04x ]"
|
PrintAndLogEx(INFO, "Options [ numreads: %d, flags: %d (0x%04x) ]"
|
||||||
, exitAfterNReads
|
, exitAfterNReads
|
||||||
|
, flags
|
||||||
, flags);
|
, flags);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -4277,46 +4272,56 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
||||||
|
|
||||||
payload.flags = flags;
|
payload.flags = flags;
|
||||||
payload.exitAfter = exitAfterNReads;
|
payload.exitAfter = exitAfterNReads;
|
||||||
|
|
||||||
memcpy(payload.uid, uid, uidlen);
|
memcpy(payload.uid, uid, uidlen);
|
||||||
|
|
||||||
payload.atqa = (atqa[1] << 8) | atqa[0];
|
payload.atqa = (atqa[1] << 8) | atqa[0];
|
||||||
payload.sak = sak[0];
|
payload.sak = sak[0];
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
|
|
||||||
if (flags & FLAG_INTERACTIVE) {
|
if ((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE) {
|
||||||
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or a key to abort simulation");
|
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or a key to abort simulation");
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or send another cmd to abort simulation");
|
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or send another cmd to abort simulation");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cont;
|
bool cont;
|
||||||
do {
|
do {
|
||||||
|
|
||||||
cont = false;
|
cont = false;
|
||||||
SendCommandNG(CMD_HF_MIFARE_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
SendCommandNG(CMD_HF_MIFARE_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
||||||
if (flags & FLAG_INTERACTIVE) {
|
|
||||||
|
if ((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE) {
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
sector_t *k_sector = NULL;
|
sector_t *k_sector = NULL;
|
||||||
|
|
||||||
bool keypress = kbd_enter_pressed();
|
bool keypress = kbd_enter_pressed();
|
||||||
while (keypress == false) {
|
while (keypress == false) {
|
||||||
|
|
||||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) {
|
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == false) {
|
||||||
keypress = kbd_enter_pressed();
|
keypress = kbd_enter_pressed();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp.status != PM3_SUCCESS)
|
if (resp.status != PM3_SUCCESS) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK)
|
if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const nonces_t *data = (nonces_t *)resp.data.asBytes;
|
const nonces_t *data = (nonces_t *)resp.data.asBytes;
|
||||||
readerAttack(k_sector, k_sectors_cnt, data[0], setEmulatorMem, verbose);
|
readerAttack(k_sector, k_sectors_cnt, data[0], setEmulatorMem, verbose);
|
||||||
|
|
||||||
if (setEmulatorMem) {
|
if (setEmulatorMem) {
|
||||||
cont = true;
|
cont = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keypress) {
|
if (keypress) {
|
||||||
if ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) {
|
if ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) {
|
||||||
// inform device to break the sim loop since client has exited
|
// inform device to break the sim loop since client has exited
|
||||||
|
|
@ -5485,7 +5490,7 @@ static int CmdHF14AMfCLoad(const char *Cmd) {
|
||||||
return PM3_EFILE;
|
return PM3_EFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Copying to magic gen1a card");
|
PrintAndLogEx(INFO, "Copying to magic gen1a MIFARE Classic " _GREEN_("%s"), s);
|
||||||
PrintAndLogEx(INFO, "." NOLF);
|
PrintAndLogEx(INFO, "." NOLF);
|
||||||
|
|
||||||
int blockno = 0;
|
int blockno = 0;
|
||||||
|
|
@ -5533,7 +5538,11 @@ static int CmdHF14AMfCLoad(const char *Cmd) {
|
||||||
return PM3_EFILE;
|
return PM3_EFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Card loaded " _YELLOW_("%d") " blocks from file", block_cnt);
|
PrintAndLogEx(SUCCESS,
|
||||||
|
"Card loaded " _YELLOW_("%d") " blocks from %s"
|
||||||
|
, block_cnt
|
||||||
|
, (fill_from_emulator ? "emulator memory" : "file")
|
||||||
|
);
|
||||||
PrintAndLogEx(INFO, "Done!");
|
PrintAndLogEx(INFO, "Done!");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
@ -6293,8 +6302,7 @@ static int CmdHF14AMfMAD(const char *Cmd) {
|
||||||
PrintAndLogEx(SUCCESS, "Binary... " _GREEN_("%s"), pbin);
|
PrintAndLogEx(SUCCESS, "Binary... " _GREEN_("%s"), pbin);
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Wiegand decode");
|
PrintAndLogEx(INFO, "Wiegand decode");
|
||||||
wiegand_message_t packed = initialize_message_object(top, mid, bot, 0);
|
decode_wiegand(top, mid, bot, 0);
|
||||||
HIDTryUnpack(&packed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8252,13 +8260,14 @@ static int CmdHF14AGen4Load(const char *cmd) {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
|
arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
|
||||||
arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
|
arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
|
||||||
|
arg_lit0(NULL, "1k+", "MIFARE Classic Ev1 1k / S50"),
|
||||||
arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
|
arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
|
||||||
arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
|
arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
|
||||||
arg_str0("p", "pwd", "<hex>", "password 4bytes"),
|
arg_str0("p", "pwd", "<hex>", "password 4bytes"),
|
||||||
arg_lit0("v", "verbose", "verbose output"),
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
|
arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
|
||||||
arg_lit0(NULL, "emu", "from emulator memory"),
|
arg_lit0(NULL, "emu", "from emulator memory"),
|
||||||
arg_int0(NULL, "start", "<dec>", "index of block to start writing (default 0)"),
|
arg_int0(NULL, "start", "<dec>", "index of block to start writing (def 0)"),
|
||||||
arg_int0(NULL, "end", "<dec>", "index of block to end writing (default last block)"),
|
arg_int0(NULL, "end", "<dec>", "index of block to end writing (default last block)"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
|
|
@ -8266,23 +8275,24 @@ static int CmdHF14AGen4Load(const char *cmd) {
|
||||||
CLIExecWithReturn(ctx, cmd, argtable, false);
|
CLIExecWithReturn(ctx, cmd, argtable, false);
|
||||||
bool m0 = arg_get_lit(ctx, 1);
|
bool m0 = arg_get_lit(ctx, 1);
|
||||||
bool m1 = arg_get_lit(ctx, 2);
|
bool m1 = arg_get_lit(ctx, 2);
|
||||||
bool m2 = arg_get_lit(ctx, 3);
|
bool m1ev1 = arg_get_lit(ctx, 3);
|
||||||
bool m4 = arg_get_lit(ctx, 4);
|
bool m2 = arg_get_lit(ctx, 4);
|
||||||
|
bool m4 = arg_get_lit(ctx, 5);
|
||||||
|
|
||||||
int pwd_len = 0;
|
int pwd_len = 0;
|
||||||
uint8_t pwd[4] = {0};
|
uint8_t pwd[4] = {0};
|
||||||
CLIGetHexWithReturn(ctx, 5, pwd, &pwd_len);
|
CLIGetHexWithReturn(ctx, 6, pwd, &pwd_len);
|
||||||
|
|
||||||
bool verbose = arg_get_lit(ctx, 6);
|
bool verbose = arg_get_lit(ctx, 7);
|
||||||
|
|
||||||
int fnlen = 0;
|
int fnlen = 0;
|
||||||
char filename[FILE_PATH_SIZE] = {0};
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
CLIParamStrToBuf(arg_get_str(ctx, 7), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
CLIParamStrToBuf(arg_get_str(ctx, 8), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
bool fill_from_emulator = arg_get_lit(ctx, 8);
|
bool fill_from_emulator = arg_get_lit(ctx, 9);
|
||||||
|
|
||||||
int start = arg_get_int_def(ctx, 9, 0);
|
int start = arg_get_int_def(ctx, 10, 0);
|
||||||
int end = arg_get_int_def(ctx, 10, -1);
|
int end = arg_get_int_def(ctx, 11, -1);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
|
@ -8292,14 +8302,14 @@ static int CmdHF14AGen4Load(const char *cmd) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m0 + m1 + m2 + m4) > 1) {
|
if ((m0 + m1 + m2 + m4 + m1ev1) > 1) {
|
||||||
PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
|
PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
} else if ((m0 + m1 + m2 + m4) == 0) {
|
} else if ((m0 + m1 + m2 + m4 + m1ev1) == 0) {
|
||||||
m1 = true;
|
m1 = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char s[6];
|
char s[8];
|
||||||
memset(s, 0, sizeof(s));
|
memset(s, 0, sizeof(s));
|
||||||
uint16_t block_cnt = MIFARE_1K_MAXBLOCK;
|
uint16_t block_cnt = MIFARE_1K_MAXBLOCK;
|
||||||
if (m0) {
|
if (m0) {
|
||||||
|
|
@ -8308,6 +8318,9 @@ static int CmdHF14AGen4Load(const char *cmd) {
|
||||||
} else if (m1) {
|
} else if (m1) {
|
||||||
block_cnt = MIFARE_1K_MAXBLOCK;
|
block_cnt = MIFARE_1K_MAXBLOCK;
|
||||||
strncpy(s, "1K", 3);
|
strncpy(s, "1K", 3);
|
||||||
|
} else if (m1ev1) {
|
||||||
|
block_cnt = MIFARE_1K_EV1_MAXBLOCK;
|
||||||
|
strncpy(s, "1K Ev1", 7);
|
||||||
} else if (m2) {
|
} else if (m2) {
|
||||||
block_cnt = MIFARE_2K_MAXBLOCK;
|
block_cnt = MIFARE_2K_MAXBLOCK;
|
||||||
strncpy(s, "2K", 3);
|
strncpy(s, "2K", 3);
|
||||||
|
|
@ -8386,16 +8399,13 @@ static int CmdHF14AGen4Load(const char *cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
if (fnlen != 0) {
|
if (fnlen == 0) {
|
||||||
PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename);
|
|
||||||
PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, block_cnt, block_cnt);
|
|
||||||
} else {
|
|
||||||
PrintAndLogEx(INFO, "Read %d blocks from emulator memory", block_cnt);
|
PrintAndLogEx(INFO, "Read %d blocks from emulator memory", block_cnt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Copying to magic gen4 GTU MIFARE Classic " _GREEN_("%s"), s);
|
PrintAndLogEx(INFO, "Copying to magic gen4 GTU MIFARE Classic " _GREEN_("%s"), s);
|
||||||
PrintAndLogEx(INFO, "Starting block: %d. Ending block: %d.", start, end);
|
PrintAndLogEx(INFO, "Block... %d - %d", start, end);
|
||||||
|
|
||||||
// copy to card
|
// copy to card
|
||||||
for (uint16_t blockno = start; blockno <= end; blockno++) {
|
for (uint16_t blockno = start; blockno <= end; blockno++) {
|
||||||
|
|
@ -8423,10 +8433,15 @@ static int CmdHF14AGen4Load(const char *cmd) {
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "\n");
|
PrintAndLogEx(NORMAL, "\n");
|
||||||
|
|
||||||
if (data != NULL) free(data);
|
if (data != NULL) {
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Card loaded " _YELLOW_("%d") " blocks from %s", end - start + 1,
|
PrintAndLogEx(SUCCESS,
|
||||||
(fill_from_emulator ? "emulator memory" : "file"));
|
"Card loaded " _YELLOW_("%d") " blocks from %s"
|
||||||
|
, end - start + 1
|
||||||
|
, (fill_from_emulator ? "emulator memory" : "file")
|
||||||
|
);
|
||||||
PrintAndLogEx(INFO, "Done!");
|
PrintAndLogEx(INFO, "Done!");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
@ -9623,7 +9638,7 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
||||||
PrintAndLogEx(DEBUG, "iso14443a card select timeout");
|
PrintAndLogEx(DEBUG, "iso14443a card select timeout");
|
||||||
return 0;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
iso14a_card_select_t card;
|
iso14a_card_select_t card;
|
||||||
|
|
@ -9721,9 +9736,9 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t k08s[6] = {0xA3, 0x96, 0xEF, 0xA4, 0xE2, 0x4F};
|
uint8_t k08s[MIFARE_KEY_SIZE] = {0xA3, 0x96, 0xEF, 0xA4, 0xE2, 0x4F};
|
||||||
uint8_t k08[6] = {0xA3, 0x16, 0x67, 0xA8, 0xCE, 0xC1};
|
uint8_t k08[MIFARE_KEY_SIZE] = {0xA3, 0x16, 0x67, 0xA8, 0xCE, 0xC1};
|
||||||
uint8_t k32[6] = {0x51, 0x8B, 0x33, 0x54, 0xE7, 0x60};
|
uint8_t k32[MIFARE_KEY_SIZE] = {0x51, 0x8B, 0x33, 0x54, 0xE7, 0x60};
|
||||||
if (mf_read_block(0, 4, k08s, blockdata) == PM3_SUCCESS) {
|
if (mf_read_block(0, 4, k08s, blockdata) == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k08s, sizeof(k08s)));
|
PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k08s, sizeof(k08s)));
|
||||||
fKeyType = MF_KEY_BD;
|
fKeyType = MF_KEY_BD;
|
||||||
|
|
@ -9818,7 +9833,7 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e_sector[1].foundKey[MF_KEY_A] && (e_sector[1].Key[MF_KEY_A] == 0x2A2C13CC242A)) {
|
if (e_sector[1].foundKey[MF_KEY_A] && (e_sector[1].Key[MF_KEY_A] == 0x2A2C13CC242A)) {
|
||||||
PrintAndLogEx(SUCCESS, "Dorma Kaba SAFLOK detected");
|
PrintAndLogEx(SUCCESS, "dormakaba Saflok detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -9841,7 +9856,7 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
||||||
|
|
||||||
res = detect_classic_static_nonce();
|
res = detect_classic_static_nonce();
|
||||||
if (res == NONCE_STATIC) {
|
if (res == NONCE_STATIC) {
|
||||||
PrintAndLogEx(SUCCESS, "Static nonce......... " _YELLOW_("yes"));
|
PrintAndLogEx(SUCCESS, "Static nonce... " _YELLOW_("yes"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -10219,7 +10234,6 @@ static command_t CommandTable[] = {
|
||||||
{"gdmparsecfg", CmdHF14AGen4_GDM_ParseCfg, AlwaysAvailable, "Parse config block to card"},
|
{"gdmparsecfg", CmdHF14AGen4_GDM_ParseCfg, AlwaysAvailable, "Parse config block to card"},
|
||||||
{"gdmsetblk", CmdHF14AGen4_GDM_SetBlk, IfPm3Iso14443a, "Write block to card"},
|
{"gdmsetblk", CmdHF14AGen4_GDM_SetBlk, IfPm3Iso14443a, "Write block to card"},
|
||||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"},
|
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"},
|
||||||
// {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
|
|
||||||
{"ndefformat", CmdHFMFNDEFFormat, IfPm3Iso14443a, "Format MIFARE Classic Tag as NFC Tag"},
|
{"ndefformat", CmdHFMFNDEFFormat, IfPm3Iso14443a, "Format MIFARE Classic Tag as NFC Tag"},
|
||||||
{"ndefread", CmdHFMFNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"},
|
{"ndefread", CmdHFMFNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"},
|
||||||
{"ndefwrite", CmdHFMFNDEFWrite, IfPm3Iso14443a, "Write NDEF records to card"},
|
{"ndefwrite", CmdHFMFNDEFWrite, IfPm3Iso14443a, "Write NDEF records to card"},
|
||||||
|
|
|
||||||
|
|
@ -175,14 +175,26 @@ typedef struct aidhdr {
|
||||||
} PACKED aidhdr_t;
|
} PACKED aidhdr_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
const uint32_t aidnum;
|
||||||
const char *aid;
|
const char *aid;
|
||||||
const char *comment;
|
const char *comment;
|
||||||
} mfdesCommonAID_t;
|
} mfdesCommonAID_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
PACS application id(s) - HID Factory, CP1000 Standard, Mobile, Custom and Elite
|
||||||
|
We have HID Factory, Field Encoder == CP1000 (?)
|
||||||
|
No mobile, Custom or Elite
|
||||||
|
*/
|
||||||
|
|
||||||
static const mfdesCommonAID_t commonAids[] = {
|
static const mfdesCommonAID_t commonAids[] = {
|
||||||
// AID, name/comment
|
{ 0x53494F, "\x53\x49\x4F", "SIO DESFire EV1 - HID Factory" },
|
||||||
{ "\xf4\x81\x2f", "Gallagher card data application" },
|
{ 0xD3494F, "\xD3\x49\x4F", "SIO DESFire EV1 - Field Encoder" },
|
||||||
{ "\xf4\x81\x20", "Gallagher card application directory" }, // Can be 0xF48120 - 0xF4812B, but I've only ever seen 0xF48120
|
{ 0xD9494F, "\xD9\x49\x4F", "SIO DESFire EV1 - Field Encoder" },
|
||||||
|
{ 0xF484E3, "\xF4\x84\xE3", "SE Enhanced" },
|
||||||
|
{ 0xF484E4, "\xF4\x84\xE4", "SE Enhanced" },
|
||||||
|
{ 0xF4812F, "\xf4\x81\x2f", "Gallagher card data application" },
|
||||||
|
{ 0xF48120, "\xf4\x81\x20", "Gallagher card application directory" }, // Can be 0xF48120 - 0xF4812B, but I've only ever seen 0xF48120
|
||||||
|
{ 0xF47300, "\xf4\x73\x00", "Inner Range card application" },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
@ -311,15 +323,13 @@ static char *getTypeStr(uint8_t type) {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *getAidCommentStr(uint32_t aid) {
|
||||||
static char noCommentStr[1] = { 0x00 };
|
|
||||||
static const char *getAidCommentStr(uint8_t *aid) {
|
|
||||||
for (int i = 0; i < ARRAYLEN(commonAids); i++) {
|
for (int i = 0; i < ARRAYLEN(commonAids); i++) {
|
||||||
if (memcmp(aid, commonAids[i].aid, 3) == 0) {
|
if (aid == commonAids[i].aidnum) {
|
||||||
return commonAids[i].comment;
|
return commonAids[i].comment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return noCommentStr;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static nxp_cardtype_t getCardType(uint8_t type, uint8_t major, uint8_t minor) {
|
static nxp_cardtype_t getCardType(uint8_t type, uint8_t major, uint8_t minor) {
|
||||||
|
|
@ -355,6 +365,10 @@ static nxp_cardtype_t getCardType(uint8_t type, uint8_t major, uint8_t minor) {
|
||||||
if (type == 0x81 && major == 0x42 && minor == 0x00)
|
if (type == 0x81 && major == 0x42 && minor == 0x00)
|
||||||
return DESFIRE_EV2;
|
return DESFIRE_EV2;
|
||||||
|
|
||||||
|
// Apple Wallet DESFire Applet
|
||||||
|
if (type == 0x91 && major == 0x62 && minor == 0x01)
|
||||||
|
return DESFIRE_EV2;
|
||||||
|
|
||||||
// Plus EV1
|
// Plus EV1
|
||||||
if (type == 0x02 && major == 0x11 && minor == 0x00)
|
if (type == 0x02 && major == 0x11 && minor == 0x00)
|
||||||
return PLUS_EV1;
|
return PLUS_EV1;
|
||||||
|
|
@ -377,7 +391,7 @@ static nxp_cardtype_t getCardType(uint8_t type, uint8_t major, uint8_t minor) {
|
||||||
// ref: https://www.nxp.com/docs/en/application-note/AN12343.pdf p7
|
// ref: https://www.nxp.com/docs/en/application-note/AN12343.pdf p7
|
||||||
static nxp_producttype_t getProductType(const uint8_t *versionhw) {
|
static nxp_producttype_t getProductType(const uint8_t *versionhw) {
|
||||||
|
|
||||||
uint8_t product = versionhw[2];
|
uint8_t product = versionhw[1];
|
||||||
|
|
||||||
if (product == 0x01)
|
if (product == 0x01)
|
||||||
return DESFIRE_PHYSICAL;
|
return DESFIRE_PHYSICAL;
|
||||||
|
|
@ -394,7 +408,7 @@ static nxp_producttype_t getProductType(const uint8_t *versionhw) {
|
||||||
|
|
||||||
static const char *getProductTypeStr(const uint8_t *versionhw) {
|
static const char *getProductTypeStr(const uint8_t *versionhw) {
|
||||||
|
|
||||||
uint8_t product = versionhw[2];
|
uint8_t product = versionhw[1];
|
||||||
|
|
||||||
if (product == 0x01)
|
if (product == 0x01)
|
||||||
return "MIFARE DESFire native IC (physical card)";
|
return "MIFARE DESFire native IC (physical card)";
|
||||||
|
|
@ -454,7 +468,6 @@ int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, si
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = originality_check_verify(uid, uidlen, signature, signature_len, PK_MFDES);
|
int index = originality_check_verify(uid, uidlen, signature, signature_len, PK_MFDES);
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return originality_check_print(signature, signature_len, index);
|
return originality_check_print(signature, signature_len, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -752,7 +765,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
if (major == 2 && minor == 2)
|
if (major == 2 && minor == 2)
|
||||||
PrintAndLogEx(INFO, "\t2.2 - DESFire Ev2 XL, Originality check, proximity check, EAL5");
|
PrintAndLogEx(INFO, "\t2.2 - DESFire Ev2 XL, Originality check, proximity check, EAL5");
|
||||||
if (major == 3 && minor == 0)
|
if (major == 3 && minor == 0)
|
||||||
PrintAndLogEx(INFO, "\t3.0 - DESFire Ev3, Originality check, proximity check, badass EAL6 ?");
|
PrintAndLogEx(INFO, "\t3.0 - DESFire Ev3, Originality check, proximity check, badass EAL6");
|
||||||
if (major == 0xA0 && minor == 0)
|
if (major == 0xA0 && minor == 0)
|
||||||
PrintAndLogEx(INFO, "\tx.x - DUOX, Originality check, proximity check, EAL6++");
|
PrintAndLogEx(INFO, "\tx.x - DUOX, Originality check, proximity check, EAL6++");
|
||||||
|
|
||||||
|
|
@ -801,12 +814,16 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aidbuflen > 2) {
|
if (aidbuflen > 2) {
|
||||||
|
|
||||||
|
uint8_t j = aidbuflen / 3;
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(SUCCESS, "--- " _CYAN_("AID list"));
|
PrintAndLogEx(SUCCESS, "--- " _CYAN_("AID list") " ( " _YELLOW_("%u") " found )", j);
|
||||||
PrintAndLogEx(SUCCESS, "AIDs: " NOLF);
|
|
||||||
for (int i = 0; i < aidbuflen; i += 3)
|
j = 0;
|
||||||
PrintAndLogEx(NORMAL, "%s %06x" NOLF, (i == 0) ? "" : ",", DesfireAIDByteToUint(&aidbuf[i]));
|
for (int i = 0; i < aidbuflen; i += 3, j++) {
|
||||||
PrintAndLogEx(NORMAL, "\n");
|
uint32_t aid = DesfireAIDByteToUint(&aidbuf[i]);
|
||||||
|
PrintAndLogEx(SUCCESS, _YELLOW_("%06X") ", %s", aid, getAidCommentStr(aid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DesfireFillPICCInfo(&dctx, &PICCInfo, true);
|
DesfireFillPICCInfo(&dctx, &PICCInfo, true);
|
||||||
|
|
@ -817,7 +834,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Free memory"));
|
PrintAndLogEx(INFO, "--- " _CYAN_("Free memory"));
|
||||||
if (PICCInfo.freemem != 0xffffffff) {
|
if (PICCInfo.freemem != 0xffffffff) {
|
||||||
PrintAndLogEx(SUCCESS, " Available free memory on card : " _GREEN_("%d bytes"), PICCInfo.freemem);
|
PrintAndLogEx(SUCCESS, " Available free memory on card... " _GREEN_("%d") " bytes", PICCInfo.freemem);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd");
|
PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd");
|
||||||
}
|
}
|
||||||
|
|
@ -1805,7 +1822,7 @@ static int CmdHF14aDesMAD(const char *Cmd) {
|
||||||
AppListS AppList = {{0}};
|
AppListS AppList = {{0}};
|
||||||
DesfireFillAppList(&dctx, &PICCInfo, AppList, false, false, false); // no deep scan, no scan files
|
DesfireFillAppList(&dctx, &PICCInfo, AppList, false, false, false); // no deep scan, no scan files
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "# Applications... " _GREEN_("%zu"), PICCInfo.appCount);
|
PrintAndLogEx(SUCCESS, "# Applications.... " _GREEN_("%zu"), PICCInfo.appCount);
|
||||||
if (PICCInfo.freemem == 0xffffffff) {
|
if (PICCInfo.freemem == 0xffffffff) {
|
||||||
PrintAndLogEx(SUCCESS, "Free memory...... " _YELLOW_("n/a"));
|
PrintAndLogEx(SUCCESS, "Free memory...... " _YELLOW_("n/a"));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -3265,11 +3282,8 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) {
|
||||||
if (buflen >= 3) {
|
if (buflen >= 3) {
|
||||||
PrintAndLogEx(INFO, "---- " _CYAN_("AID list") " ----");
|
PrintAndLogEx(INFO, "---- " _CYAN_("AID list") " ----");
|
||||||
for (int i = 0; i < buflen; i += 3) {
|
for (int i = 0; i < buflen; i += 3) {
|
||||||
const char *commentStr = getAidCommentStr(&buf[i]);
|
uint32_t aid = DesfireAIDByteToUint(&buf[i]);
|
||||||
if ((void *) commentStr == &noCommentStr)
|
PrintAndLogEx(SUCCESS, _YELLOW_("%06X") " %s", aid, getAidCommentStr(aid));
|
||||||
PrintAndLogEx(INFO, "AID: %06x", DesfireAIDByteToUint(&buf[i]));
|
|
||||||
else
|
|
||||||
PrintAndLogEx(INFO, "AID: %06x (%s)", DesfireAIDByteToUint(&buf[i]), commentStr);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(INFO, "There is no applications on the card");
|
PrintAndLogEx(INFO, "There is no applications on the card");
|
||||||
|
|
@ -5590,7 +5604,7 @@ static int CmdHF14ADesLsApp(const char *Cmd) {
|
||||||
SetAPDULogging(APDULogging);
|
SetAPDULogging(APDULogging);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
PrintAndLogEx(INPLACE, _YELLOW_("It may take up to 15 seconds. Processing...."));
|
PrintAndLogEx(INFO, "It may take up to " _YELLOW_("15") " seconds. Processing...");
|
||||||
|
|
||||||
res = DesfireSelectAndAuthenticateEx(&dctx, securechann, 0x000000, noauth, verbose);
|
res = DesfireSelectAndAuthenticateEx(&dctx, securechann, 0x000000, noauth, verbose);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
|
|
@ -5602,7 +5616,6 @@ static int CmdHF14ADesLsApp(const char *Cmd) {
|
||||||
AppListS AppList = {{0}};
|
AppListS AppList = {{0}};
|
||||||
DesfireFillAppList(&dctx, &PICCInfo, AppList, !nodeep, scanfiles, true);
|
DesfireFillAppList(&dctx, &PICCInfo, AppList, !nodeep, scanfiles, true);
|
||||||
|
|
||||||
printf("\33[2K\r"); // clear current line before printing
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
// print zone
|
// print zone
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,6 @@ static nxp_cardtype_t getCardType(uint8_t type, uint8_t major, uint8_t minor) {
|
||||||
// --- GET SIGNATURE
|
// --- GET SIGNATURE
|
||||||
static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) {
|
static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) {
|
||||||
int index = originality_check_verify(uid, uidlen, signature, signature_len, PK_MFP);
|
int index = originality_check_verify(uid, uidlen, signature, signature_len, PK_MFP);
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return originality_check_print(signature, signature_len, index);
|
return originality_check_print(signature, signature_len, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1813,7 +1812,7 @@ static int CmdHFMFPMAD(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sector0[16 * 4] = {0};
|
uint8_t sector0[16 * 4] = {0};
|
||||||
uint8_t sector10[16 * 4] = {0};
|
uint8_t sector16[16 * 4] = {0};
|
||||||
|
|
||||||
if (mfpReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector0, verbose)) {
|
if (mfpReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector0, verbose)) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
@ -1833,19 +1832,19 @@ static int CmdHFMFPMAD(const char *Cmd) {
|
||||||
MAD1DecodeAndPrint(sector0, swapmad, verbose, &haveMAD2);
|
MAD1DecodeAndPrint(sector0, swapmad, verbose, &haveMAD2);
|
||||||
|
|
||||||
if (haveMAD2) {
|
if (haveMAD2) {
|
||||||
if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) {
|
if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector16, verbose)) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(ERR, "error, read sector " _YELLOW_("0x10") ". Card doesn't have MAD or doesn't have MAD on default keys");
|
PrintAndLogEx(ERR, "error, read sector " _YELLOW_("0x10") ". Card doesn't have MAD or doesn't have MAD on default keys");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
MAD2DecodeAndPrint(sector10, swapmad, verbose);
|
MAD2DecodeAndPrint(sector16, swapmad, verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aidlen == 2 || decodeholder) {
|
if (aidlen == 2 || decodeholder) {
|
||||||
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
|
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
|
||||||
size_t madlen = 0;
|
size_t madlen = 0;
|
||||||
if (MADDecode(sector0, sector10, mad, &madlen, swapmad)) {
|
if (MADDecode(sector0, sector16, mad, &madlen, swapmad)) {
|
||||||
PrintAndLogEx(ERR, "can't decode MAD");
|
PrintAndLogEx(ERR, "can't decode MAD");
|
||||||
return PM3_EWRONGANSWER;
|
return PM3_EWRONGANSWER;
|
||||||
}
|
}
|
||||||
|
|
@ -1990,9 +1989,9 @@ int CmdHFMFPNDEFRead(const char *Cmd) {
|
||||||
memcpy(ndefkey, key, 16);
|
memcpy(ndefkey, key, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sector0[16 * 4] = {0};
|
uint8_t sector0[MIFARE_1K_MAXBLOCK] = {0};
|
||||||
uint8_t sector10[16 * 4] = {0};
|
uint8_t sector16[MIFARE_1K_MAXBLOCK] = {0};
|
||||||
uint8_t data[4096] = {0};
|
uint8_t data[MIFARE_4K_MAX_BYTES] = {0};
|
||||||
int datalen = 0;
|
int datalen = 0;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
|
|
@ -2016,7 +2015,7 @@ int CmdHFMFPNDEFRead(const char *Cmd) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(INFO, "reading MAD v2 sector");
|
PrintAndLogEx(INFO, "reading MAD v2 sector");
|
||||||
|
|
||||||
if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) {
|
if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector16, verbose)) {
|
||||||
PrintAndLogEx(ERR, "error, read sector 0x10. card doesn't have MAD or doesn't have MAD on default keys");
|
PrintAndLogEx(ERR, "error, read sector 0x10. card doesn't have MAD or doesn't have MAD on default keys");
|
||||||
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfp ndefread -k `") " with your custom key");
|
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfp ndefread -k `") " with your custom key");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
|
|
@ -2025,7 +2024,7 @@ int CmdHFMFPNDEFRead(const char *Cmd) {
|
||||||
|
|
||||||
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
|
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
|
||||||
size_t madlen = 0;
|
size_t madlen = 0;
|
||||||
res = MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen, false);
|
res = MADDecode(sector0, (haveMAD2 ? sector16 : NULL), mad, &madlen, false);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(ERR, "can't decode MAD");
|
PrintAndLogEx(ERR, "can't decode MAD");
|
||||||
return res;
|
return res;
|
||||||
|
|
@ -2034,7 +2033,7 @@ int CmdHFMFPNDEFRead(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "reading data from tag");
|
PrintAndLogEx(INFO, "reading data from tag");
|
||||||
for (int i = 0; i < madlen; i++) {
|
for (int i = 0; i < madlen; i++) {
|
||||||
if (ndefAID == mad[i]) {
|
if (ndefAID == mad[i]) {
|
||||||
uint8_t vsector[16 * 4] = {0};
|
uint8_t vsector[MIFARE_1K_MAXBLOCK] = {0};
|
||||||
if (mfpReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector, false)) {
|
if (mfpReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector, false)) {
|
||||||
PrintAndLogEx(ERR, "error, reading sector %d", i + 1);
|
PrintAndLogEx(ERR, "error, reading sector %d", i + 1);
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ static uint8_t default_aes_keys[][16] = {
|
||||||
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, // all FF
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, // all FF
|
||||||
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }, // 11 22 33
|
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }, // 11 22 33
|
||||||
{ 0x47, 0x45, 0x4D, 0x58, 0x50, 0x52, 0x45, 0x53, 0x53, 0x4F, 0x53, 0x41, 0x4D, 0x50, 0x4C, 0x45 }, // gemalto
|
{ 0x47, 0x45, 0x4D, 0x58, 0x50, 0x52, 0x45, 0x53, 0x53, 0x4F, 0x53, 0x41, 0x4D, 0x50, 0x4C, 0x45 }, // gemalto
|
||||||
{ 0x56, 0x4c, 0x67, 0x56, 0x99, 0x69, 0x64, 0x9f, 0x17, 0xC6, 0xC6, 0x16, 0x01, 0x10, 0x4D, 0xCA } // Virtual Dorma Kaba
|
{ 0x56, 0x4c, 0x67, 0x56, 0x99, 0x69, 0x64, 0x9f, 0x17, 0xC6, 0xC6, 0x16, 0x01, 0x10, 0x4D, 0xCA } // Virtual dormakaba
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint8_t default_3des_keys[][16] = {
|
static uint8_t default_3des_keys[][16] = {
|
||||||
|
|
@ -669,6 +669,9 @@ static int try_default_aes_keys(bool override) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ul_auth_select(iso14a_card_select_t *card, uint64_t tagtype, bool hasAuthKey, uint8_t *authkey, uint8_t *pack, uint8_t packSize) {
|
static int ul_auth_select(iso14a_card_select_t *card, uint64_t tagtype, bool hasAuthKey, uint8_t *authkey, uint8_t *pack, uint8_t packSize) {
|
||||||
|
if (ul_select(card) == false) {
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
if (hasAuthKey && (tagtype & MFU_TT_UL_C)) {
|
if (hasAuthKey && (tagtype & MFU_TT_UL_C)) {
|
||||||
//will select card automatically and close connection on error
|
//will select card automatically and close connection on error
|
||||||
|
|
@ -676,12 +679,7 @@ static int ul_auth_select(iso14a_card_select_t *card, uint64_t tagtype, bool has
|
||||||
PrintAndLogEx(WARNING, "Authentication Failed UL-C");
|
PrintAndLogEx(WARNING, "Authentication Failed UL-C");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (ul_select(card) == false) {
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasAuthKey) {
|
if (hasAuthKey) {
|
||||||
if (ulev1_requestAuthentication(authkey, pack, packSize) == PM3_EWRONGANSWER) {
|
if (ulev1_requestAuthentication(authkey, pack, packSize) == PM3_EWRONGANSWER) {
|
||||||
DropField();
|
DropField();
|
||||||
|
|
@ -1419,7 +1417,6 @@ static int ulev1_print_signature(uint64_t tagtype, uint8_t *uid, uint8_t *signat
|
||||||
} else if (signature_len == 48) {
|
} else if (signature_len == 48) {
|
||||||
index = originality_check_verify(uid, 7, signature, signature_len, PK_MFULAES);
|
index = originality_check_verify(uid, 7, signature, signature_len, PK_MFULAES);
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return originality_check_print(signature, signature_len, index);
|
return originality_check_print(signature, signature_len, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2069,6 +2066,7 @@ uint64_t GetHF14AMfU_Type(void) {
|
||||||
uint8_t version[10] = {0x00};
|
uint8_t version[10] = {0x00};
|
||||||
int len = ulev1_getVersion(version, sizeof(version));
|
int len = ulev1_getVersion(version, sizeof(version));
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case 0x0A: {
|
case 0x0A: {
|
||||||
/*
|
/*
|
||||||
|
|
@ -2160,6 +2158,7 @@ uint64_t GetHF14AMfU_Type(void) {
|
||||||
tagtype = MFU_TT_UNKNOWN;
|
tagtype = MFU_TT_UNKNOWN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a test from cards that doesn't answer to GET_VERSION command
|
// This is a test from cards that doesn't answer to GET_VERSION command
|
||||||
// UL vs UL-C vs NTAG203 vs FUDAN FM11NT021 (which is NTAG213 compatiable)
|
// UL vs UL-C vs NTAG203 vs FUDAN FM11NT021 (which is NTAG213 compatiable)
|
||||||
if (tagtype & (MFU_TT_UL | MFU_TT_UL_C | MFU_TT_NTAG_203)) {
|
if (tagtype & (MFU_TT_UL | MFU_TT_UL_C | MFU_TT_NTAG_203)) {
|
||||||
|
|
@ -2451,7 +2450,6 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
// check signature
|
// check signature
|
||||||
int index = originality_check_verify_ex(card.uid, 7, signature, sizeof(signature), PK_ST25TN, false, true);
|
int index = originality_check_verify_ex(card.uid, 7, signature, sizeof(signature), PK_ST25TN, false, true);
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
originality_check_print(signature, sizeof(signature), index);
|
originality_check_print(signature, sizeof(signature), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4071,8 +4069,8 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_MIFAREU_READBL, 2, 0, 0, NULL, 0);
|
SendCommandMIX(CMD_HF_MIFAREU_READBL, 2, 0, 0, NULL, 0);
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4084,8 +4082,8 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
||||||
// block 1 write and block2 write
|
// block 1 write and block2 write
|
||||||
hf14a_config config;
|
hf14a_config config;
|
||||||
SendCommandNG(CMD_HF_ISO14443A_GET_CONFIG, NULL, 0);
|
SendCommandNG(CMD_HF_ISO14443A_GET_CONFIG, NULL, 0);
|
||||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443A_GET_CONFIG, &resp, 2000)) {
|
if (WaitForResponseTimeout(CMD_HF_ISO14443A_GET_CONFIG, &resp, 2000) == false) {
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
PrintAndLogEx(WARNING, "command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
memcpy(&config, resp.data.asBytes, sizeof(hf14a_config));
|
memcpy(&config, resp.data.asBytes, sizeof(hf14a_config));
|
||||||
|
|
@ -4103,8 +4101,8 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
||||||
data[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2];
|
data[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2];
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 0, 0, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 0, 0, 0, data, sizeof(data));
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4115,8 +4113,8 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
||||||
data[3] = uid[6];
|
data[3] = uid[6];
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 1, 0, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 1, 0, 0, data, sizeof(data));
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4127,8 +4125,8 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
||||||
data[3] = oldblock2[3];
|
data[3] = oldblock2[3];
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 2, 0, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 2, 0, 0, data, sizeof(data));
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -753,16 +753,15 @@ static int select_ADF_decrypt(const char *selectADFOID, uint8_t *CRYPTOGRAM_encr
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PM3_SUCCESS;
|
return PM3_ESOFT;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int seos_mutual_auth(uint8_t *randomICC, uint8_t *CRYPTOGRAM_Diversifier, uint8_t diversifier_len, uint8_t *mutual_auth_randomIFD, uint8_t *mutual_auth_keyICC, uint8_t *randomIFD, uint8_t randomIFD_len, uint8_t *keyIFD, uint8_t keyIFD_len, int encryption_algorithm, int hash_algorithm, int key_index) {
|
static int seos_mutual_auth(uint8_t *randomICC, uint8_t *CRYPTOGRAM_Diversifier, uint8_t diversifier_len, uint8_t *mutual_auth_randomIFD, uint8_t *mutual_auth_keyICC, uint8_t *randomIFD, uint8_t randomIFD_len, uint8_t *keyIFD, uint8_t keyIFD_len, int encryption_algorithm, int hash_algorithm, int key_index) {
|
||||||
uint8_t response[PM3_CMD_DATA_SIZE];
|
uint8_t response[PM3_CMD_DATA_SIZE];
|
||||||
|
|
||||||
// ---------------- Diversify Keys ----------------
|
// ---------------- Diversify Keys ----------------
|
||||||
uint8_t undiversified_key[16] = { 0x00 };
|
uint8_t mk[16] = { 0x00 };
|
||||||
memcpy(undiversified_key, keys[key_index].readKey, 16);
|
memcpy(mk, keys[key_index].readKey, 16);
|
||||||
|
|
||||||
uint8_t keyslot = 0x01; // up to 0x0F
|
uint8_t keyslot = 0x01; // up to 0x0F
|
||||||
uint8_t AES_key[24] = {0x00};
|
uint8_t AES_key[24] = {0x00};
|
||||||
uint8_t MAC_key[24] = {0x00};
|
uint8_t MAC_key[24] = {0x00};
|
||||||
|
|
@ -776,8 +775,8 @@ static int seos_mutual_auth(uint8_t *randomICC, uint8_t *CRYPTOGRAM_Diversifier,
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
seos_kdf(true, undiversified_key, keyslot, adfOID, sizeof(adfOID), CRYPTOGRAM_Diversifier, diversifier_len, AES_key, encryption_algorithm, hash_algorithm);
|
seos_kdf(true, mk, keyslot, adfOID, sizeof(adfOID), CRYPTOGRAM_Diversifier, diversifier_len, AES_key, encryption_algorithm, hash_algorithm);
|
||||||
seos_kdf(false, undiversified_key, keyslot, adfOID, sizeof(adfOID), CRYPTOGRAM_Diversifier, diversifier_len, MAC_key, encryption_algorithm, hash_algorithm);
|
seos_kdf(false, mk, keyslot, adfOID, sizeof(adfOID), CRYPTOGRAM_Diversifier, diversifier_len, MAC_key, encryption_algorithm, hash_algorithm);
|
||||||
|
|
||||||
memcpy(&MAC_key[16], &MAC_key[0], 8);
|
memcpy(&MAC_key[16], &MAC_key[0], 8);
|
||||||
memcpy(&AES_key[16], &AES_key[0], 8);
|
memcpy(&AES_key[16], &AES_key[0], 8);
|
||||||
|
|
@ -843,7 +842,7 @@ static int seos_mutual_auth(uint8_t *randomICC, uint8_t *CRYPTOGRAM_Diversifier,
|
||||||
bool activate_field = false;
|
bool activate_field = false;
|
||||||
bool keep_field_on = true;
|
bool keep_field_on = true;
|
||||||
|
|
||||||
uint8_t aMUTUAL_AUTH[102];
|
uint8_t aMUTUAL_AUTH[102] = {0};
|
||||||
int aMUTUAL_AUTH_n = 0;
|
int aMUTUAL_AUTH_n = 0;
|
||||||
param_gethex_to_eol(mutual_auth, 0, aMUTUAL_AUTH, sizeof(aMUTUAL_AUTH), &aMUTUAL_AUTH_n);
|
param_gethex_to_eol(mutual_auth, 0, aMUTUAL_AUTH, sizeof(aMUTUAL_AUTH), &aMUTUAL_AUTH_n);
|
||||||
int res = ExchangeAPDU14a(aMUTUAL_AUTH, aMUTUAL_AUTH_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
int res = ExchangeAPDU14a(aMUTUAL_AUTH, aMUTUAL_AUTH_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
|
@ -976,7 +975,9 @@ static int seos_aid_select(void) {
|
||||||
// if we made it here, its a success and we break :)
|
// if we made it here, its a success and we break :)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (i == ARRAYLEN(known_AID_map)) {
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1000,7 +1001,7 @@ static int seos_pacs_adf_select(char *oid, int oid_len, uint8_t *get_data, int g
|
||||||
|
|
||||||
uint16_t selectedOIDLen = strlen(selectedOID);
|
uint16_t selectedOIDLen = strlen(selectedOID);
|
||||||
char selectedOIDLenHex[3];
|
char selectedOIDLenHex[3];
|
||||||
snprintf(selectedOIDLenHex, sizeof(selectedOIDLenHex), "%02X", (selectedOIDLen) / 2);
|
snprintf(selectedOIDLenHex, sizeof(selectedOIDLenHex), "%02X", (selectedOIDLen >> 1) & 0xFF);
|
||||||
|
|
||||||
char selectedADF[strlen(ADFprefix) + strlen(selectedOIDLenHex) + selectedOIDLen + 1];
|
char selectedADF[strlen(ADFprefix) + strlen(selectedOIDLenHex) + selectedOIDLen + 1];
|
||||||
snprintf(selectedADF, sizeof(selectedADF), "%s%s%s", ADFprefix, selectedOIDLenHex, selectedOID);
|
snprintf(selectedADF, sizeof(selectedADF), "%s%s%s", ADFprefix, selectedOIDLenHex, selectedOID);
|
||||||
|
|
@ -1112,10 +1113,9 @@ static int seos_adf_select(char *oid, int oid_len, int key_index) {
|
||||||
const char *ADFprefix = "06";
|
const char *ADFprefix = "06";
|
||||||
char selectedOID[100];
|
char selectedOID[100];
|
||||||
snprintf(selectedOID, sizeof(selectedOID), "%s", oid);
|
snprintf(selectedOID, sizeof(selectedOID), "%s", oid);
|
||||||
|
|
||||||
uint16_t selectedOIDLen = strlen(selectedOID);
|
uint16_t selectedOIDLen = strlen(selectedOID);
|
||||||
char selectedOIDLenHex[3];
|
char selectedOIDLenHex[3];
|
||||||
snprintf(selectedOIDLenHex, sizeof(selectedOIDLenHex), "%02X", (selectedOIDLen) / 2);
|
snprintf(selectedOIDLenHex, sizeof(selectedOIDLenHex), "%02X", (selectedOIDLen >> 1) & 0xFF);
|
||||||
|
|
||||||
char selectedADF[strlen(ADFprefix) + strlen(selectedOIDLenHex) + selectedOIDLen + 1];
|
char selectedADF[strlen(ADFprefix) + strlen(selectedOIDLenHex) + selectedOIDLen + 1];
|
||||||
snprintf(selectedADF, sizeof(selectedADF), "%s%s%s", ADFprefix, selectedOIDLenHex, selectedOID);
|
snprintf(selectedADF, sizeof(selectedADF), "%s%s%s", ADFprefix, selectedOIDLenHex, selectedOID);
|
||||||
|
|
@ -1381,7 +1381,7 @@ static int CmdHfSeosPACS(const char *Cmd) {
|
||||||
uint8_t get_data[] = {0x5c, 0x02, 0xff, 0x00};
|
uint8_t get_data[] = {0x5c, 0x02, 0xff, 0x00};
|
||||||
|
|
||||||
int oid_len = 0;
|
int oid_len = 0;
|
||||||
uint8_t oid_hex[256] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x01, 0x18, 0x01, 0x01, 0x02};
|
uint8_t oid_hex[256] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x01, 0x18, 0x01, 0x01, 0x02, 0x02};
|
||||||
CLIGetHexWithReturn(ctx, 1, oid_hex, &oid_len);
|
CLIGetHexWithReturn(ctx, 1, oid_hex, &oid_len);
|
||||||
|
|
||||||
int key_index = arg_get_int_def(ctx, 2, 0);
|
int key_index = arg_get_int_def(ctx, 2, 0);
|
||||||
|
|
@ -1390,7 +1390,7 @@ static int CmdHfSeosPACS(const char *Cmd) {
|
||||||
|
|
||||||
// Fall back to default OID
|
// Fall back to default OID
|
||||||
if (oid_len == 0) {
|
if (oid_len == 0) {
|
||||||
oid_len = 16;
|
oid_len = 17;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert OID hex to literal string
|
// convert OID hex to literal string
|
||||||
|
|
@ -1440,7 +1440,7 @@ static int CmdHfSeosADF(const char *Cmd) {
|
||||||
CLIGetHexWithReturn(ctx, 1, get_data, &get_data_len);
|
CLIGetHexWithReturn(ctx, 1, get_data, &get_data_len);
|
||||||
|
|
||||||
int oid_len = 0;
|
int oid_len = 0;
|
||||||
uint8_t oid_hex[256] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x01, 0x18, 0x01, 0x01, 0x02};
|
uint8_t oid_hex[256] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x01, 0x18, 0x01, 0x01, 0x02, 0x02};
|
||||||
CLIGetHexWithReturn(ctx, 2, oid_hex, &oid_len);
|
CLIGetHexWithReturn(ctx, 2, oid_hex, &oid_len);
|
||||||
|
|
||||||
int key_index = arg_get_int_def(ctx, 3, 0);
|
int key_index = arg_get_int_def(ctx, 3, 0);
|
||||||
|
|
@ -1453,7 +1453,7 @@ static int CmdHfSeosADF(const char *Cmd) {
|
||||||
|
|
||||||
// Catching when the OID value is not supplied
|
// Catching when the OID value is not supplied
|
||||||
if (oid_len == 0) {
|
if (oid_len == 0) {
|
||||||
oid_len = 16;
|
oid_len = 17;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert OID hex to literal string
|
// convert OID hex to literal string
|
||||||
|
|
@ -1669,7 +1669,7 @@ static int CmdHfSeosSAM(const char *Cmd) {
|
||||||
data[0] = flags;
|
data[0] = flags;
|
||||||
|
|
||||||
int cmdlen = 0;
|
int cmdlen = 0;
|
||||||
if (CLIParamHexToBuf(arg_get_str(ctx, 5), data+1, PM3_CMD_DATA_SIZE-1, &cmdlen) != PM3_SUCCESS){
|
if (CLIParamHexToBuf(arg_get_str(ctx, 5), data + 1, PM3_CMD_DATA_SIZE - 1, &cmdlen) != PM3_SUCCESS) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
@ -1681,7 +1681,7 @@ static int CmdHfSeosSAM(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_SAM_SEOS, data, cmdlen+1);
|
SendCommandNG(CMD_HF_SAM_SEOS, data, cmdlen + 1);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_HF_SAM_SEOS, &resp, 4000) == false) {
|
if (WaitForResponseTimeout(CMD_HF_SAM_SEOS, &resp, 4000) == false) {
|
||||||
PrintAndLogEx(WARNING, "SAM timeout");
|
PrintAndLogEx(WARNING, "SAM timeout");
|
||||||
|
|
@ -1756,7 +1756,7 @@ static command_t CommandTable[] = {
|
||||||
{"list", CmdHfSeosList, AlwaysAvailable, "List SEOS history"},
|
{"list", CmdHfSeosList, AlwaysAvailable, "List SEOS history"},
|
||||||
{"sam", CmdHfSeosSAM, IfPm3Smartcard, "SAM tests"},
|
{"sam", CmdHfSeosSAM, IfPm3Smartcard, "SAM tests"},
|
||||||
{"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("Operations") " -----------------------"},
|
{"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("Operations") " -----------------------"},
|
||||||
{"info", CmdHfSeosInfo, IfPm3NfcBarcode, "Tag information"},
|
{"info", CmdHfSeosInfo, IfPm3Iso14443a, "Tag information"},
|
||||||
{"pacs", CmdHfSeosPACS, AlwaysAvailable, "Extract PACS Information from card"},
|
{"pacs", CmdHfSeosPACS, AlwaysAvailable, "Extract PACS Information from card"},
|
||||||
{"adf", CmdHfSeosADF, AlwaysAvailable, "Read an ADF from the card"},
|
{"adf", CmdHfSeosADF, AlwaysAvailable, "Read an ADF from the card"},
|
||||||
{"gdf", CmdHfSeosGDF, AlwaysAvailable, "Read an GDF from card"},
|
{"gdf", CmdHfSeosGDF, AlwaysAvailable, "Read an GDF from card"},
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,12 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
#define SEOS_ENCRYPTION_2K3DES 0x02
|
||||||
|
#define SEOS_ENCRYPTION_3K3DES 0x03
|
||||||
|
#define SEOS_ENCRYPTION_AES 0x09
|
||||||
|
|
||||||
|
#define SEOS_HASHING_SHA1 0x06
|
||||||
|
#define SEOS_HASHING_SHA256 0x07
|
||||||
int infoSeos(bool verbose);
|
int infoSeos(bool verbose);
|
||||||
int CmdHFSeos(const char *Cmd);
|
int CmdHFSeos(const char *Cmd);
|
||||||
int seos_kdf(bool encryption, uint8_t *masterKey, uint8_t keyslot,
|
int seos_kdf(bool encryption, uint8_t *masterKey, uint8_t keyslot,
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,6 @@ static void print_st25ta_system_info(uint8_t *d, uint8_t n) {
|
||||||
|
|
||||||
static int print_st25ta_signature(uint8_t *uid, uint8_t *signature) {
|
static int print_st25ta_signature(uint8_t *uid, uint8_t *signature) {
|
||||||
int index = originality_check_verify_ex(uid, 7, signature, 32, PK_ST25TA, false, true);
|
int index = originality_check_verify_ex(uid, 7, signature, 32, PK_ST25TA, false, true);
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return originality_check_print(signature, 32, index);
|
return originality_check_print(signature, 32, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,8 @@ static void em410x_construct_emul_graph(uint8_t *uid, uint8_t clock, uint8_t gap
|
||||||
// print 64 bit EM410x ID in multiple formats
|
// print 64 bit EM410x ID in multiple formats
|
||||||
void printEM410x(uint32_t hi, uint64_t id, bool verbose, int type) {
|
void printEM410x(uint32_t hi, uint64_t id, bool verbose, int type) {
|
||||||
|
|
||||||
|
if (!id && !hi) return;
|
||||||
|
|
||||||
if (verbose == false) {
|
if (verbose == false) {
|
||||||
if (type & 0x1) { // Short ID
|
if (type & 0x1) { // Short ID
|
||||||
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id);
|
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id);
|
||||||
|
|
@ -252,6 +254,11 @@ static int ask_em410x_binary_decode(bool verbose, uint32_t *hi, uint64_t *lo, ui
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!lo && !hi) {
|
||||||
|
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x decoded to all zeros");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
PrintAndLogEx(DEBUG, "DEBUG: Em410x idx: %zu, Len: %zu, Printing DemodBuffer:", *idx, *size);
|
PrintAndLogEx(DEBUG, "DEBUG: Em410x idx: %zu, Len: %zu, Printing DemodBuffer:", *idx, *size);
|
||||||
if (g_debugMode) {
|
if (g_debugMode) {
|
||||||
printDemodBuff(0, false, false, true);
|
printDemodBuff(0, false, false, true);
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,10 @@
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
// Each record is 4 bytes long ... a single line in the dump output
|
static void em4x50_prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) {
|
||||||
// Reads each record from `data`, reverses the four bytes, and writes to `words`
|
|
||||||
static void em4x50_prepare_result(const uint8_t *data, int first_record_inclusive, int last_record_inclusive, em4x50_word_t *words) {
|
|
||||||
|
|
||||||
// restructure received result in "em4x50_word_t" structure
|
// restructure received result in "em4x50_word_t" structure
|
||||||
for (int i = first_record_inclusive; i <= last_record_inclusive; i++) {
|
for (int i = fwr; i <= lwr; i++) {
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
words[i].byte[j] = data[i * 4 + (3 - j)];
|
words[i].byte[j] = data[i * 4 + (3 - j)];
|
||||||
}
|
}
|
||||||
|
|
@ -641,8 +639,10 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
em4x50_read_data_response_t *o = (em4x50_read_data_response_t *)resp.data.asBytes;
|
||||||
|
|
||||||
em4x50_word_t words[EM4X50_NO_WORDS] = {0};
|
em4x50_word_t words[EM4X50_NO_WORDS] = {0};
|
||||||
em4x50_prepare_result(resp.data.asBytes, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF, words);
|
em4x50_prepare_result((uint8_t *)o->words, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF, words);
|
||||||
|
|
||||||
if (out != NULL) {
|
if (out != NULL) {
|
||||||
memcpy(out, &words, sizeof(em4x50_word_t) * EM4X50_NO_WORDS);
|
memcpy(out, &words, sizeof(em4x50_word_t) * EM4X50_NO_WORDS);
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ static int demod_guard_raw(uint8_t *raw, uint8_t rlen) {
|
||||||
// but will leave the g_GraphBuffer intact.
|
// but will leave the g_GraphBuffer intact.
|
||||||
// if successful it will push askraw data back to g_DemodBuffer ready for emulation
|
// if successful it will push askraw data back to g_DemodBuffer ready for emulation
|
||||||
int demodGuard(bool verbose) {
|
int demodGuard(bool verbose) {
|
||||||
(void) verbose; // unused so far
|
(void) verbose;
|
||||||
//Differential Biphase
|
//Differential Biphase
|
||||||
//get binary from ask wave
|
//get binary from ask wave
|
||||||
if (ASKbiphaseDemod(0, 64, 0, 0, false) != PM3_SUCCESS) {
|
if (ASKbiphaseDemod(0, 64, 0, 0, false) != PM3_SUCCESS) {
|
||||||
|
|
@ -285,7 +285,7 @@ static int CmdGuardClone(const char *Cmd) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmtlen &= 0x7f;
|
fmtlen &= 0x7F;
|
||||||
uint32_t facilitycode = (fc & 0x000000FF);
|
uint32_t facilitycode = (fc & 0x000000FF);
|
||||||
uint32_t cardnumber = (cn & 0x00FFFFFF);
|
uint32_t cardnumber = (cn & 0x00FFFFFF);
|
||||||
|
|
||||||
|
|
@ -317,7 +317,7 @@ static int CmdGuardClone(const char *Cmd) {
|
||||||
|
|
||||||
free(bs);
|
free(bs);
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Preparing to clone Guardall to " _YELLOW_("%s") " with Facility Code: " _GREEN_("%u") " Card Number: " _GREEN_("%u") " xorKey: " _GREEN_("%u")
|
PrintAndLogEx(INFO, "Preparing to clone Guardall to " _YELLOW_("%s") " with fc: " _GREEN_("%u") " cn: " _GREEN_("%u") " xor: " _GREEN_("%u")
|
||||||
, cardtype
|
, cardtype
|
||||||
, facilitycode
|
, facilitycode
|
||||||
, cardnumber
|
, cardnumber
|
||||||
|
|
@ -375,7 +375,7 @@ static int CmdGuardSim(const char *Cmd) {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Simulating Guardall Prox - xorKey: " _YELLOW_("%u") " Facility Code: " _YELLOW_("%u") " CardNumber: " _YELLOW_("%u")
|
PrintAndLogEx(SUCCESS, "Simulating Guardall Prox - xorKey: " _YELLOW_("%u") " fc: " _YELLOW_("%u") " cn: " _YELLOW_("%u")
|
||||||
, xorval
|
, xorval
|
||||||
, facilitycode
|
, facilitycode
|
||||||
, cardnumber
|
, cardnumber
|
||||||
|
|
|
||||||
|
|
@ -160,8 +160,7 @@ int demodHID(bool verbose) {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
wiegand_message_t packed = initialize_message_object(hi2, hi, lo, 0);
|
if (!decode_wiegand(hi2, hi, lo, 0)) { // if failed to unpack wiegand
|
||||||
if (HIDTryUnpack(&packed) == false) {
|
|
||||||
printDemodBuff(0, false, false, true);
|
printDemodBuff(0, false, false, true);
|
||||||
}
|
}
|
||||||
PrintAndLogEx(INFO, "raw: " _GREEN_("%08x%08x%08x"), hi2, hi, lo);
|
PrintAndLogEx(INFO, "raw: " _GREEN_("%08x%08x%08x"), hi2, hi, lo);
|
||||||
|
|
@ -544,6 +543,7 @@ static int CmdHIDBrute(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wiegand_card_t card_hi, card_low;
|
wiegand_card_t card_hi, card_low;
|
||||||
|
cardformatdescriptor_t card_descriptor = HIDGetCardFormat(format_idx).Fields;
|
||||||
memset(&card_hi, 0, sizeof(wiegand_card_t));
|
memset(&card_hi, 0, sizeof(wiegand_card_t));
|
||||||
|
|
||||||
char field[3] = {0};
|
char field[3] = {0};
|
||||||
|
|
@ -575,11 +575,13 @@ static int CmdHIDBrute(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "Facility code.... %u", card_hi.FacilityCode);
|
PrintAndLogEx(INFO, "Facility code.... %u", card_hi.FacilityCode);
|
||||||
PrintAndLogEx(INFO, "Card number...... %" PRIu64, card_hi.CardNumber);
|
PrintAndLogEx(INFO, "Card number...... %" PRIu64, card_hi.CardNumber);
|
||||||
PrintAndLogEx(INFO, "Delay............ " _YELLOW_("%d"), delay);
|
PrintAndLogEx(INFO, "Delay............ " _YELLOW_("%d"), delay);
|
||||||
|
|
||||||
if (strcmp(field, "fc") == 0) {
|
if (strcmp(field, "fc") == 0) {
|
||||||
PrintAndLogEx(INFO, "Field............ " _YELLOW_("fc"));
|
PrintAndLogEx(INFO, "Field............ " _YELLOW_("fc"));
|
||||||
} else if (strcmp(field, "cn") == 0) {
|
} else if (strcmp(field, "cn") == 0) {
|
||||||
PrintAndLogEx(INFO, "Field............ " _YELLOW_("cn"));
|
PrintAndLogEx(INFO, "Field............ " _YELLOW_("cn"));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case 0:
|
case 0:
|
||||||
PrintAndLogEx(INFO, "Direction........ " _YELLOW_("both"));
|
PrintAndLogEx(INFO, "Direction........ " _YELLOW_("both"));
|
||||||
|
|
@ -594,6 +596,7 @@ static int CmdHIDBrute(const char *Cmd) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "Started bruteforcing HID Prox reader");
|
PrintAndLogEx(INFO, "Started bruteforcing HID Prox reader");
|
||||||
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or " _GREEN_("<Enter>") " to abort simulation");
|
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or " _GREEN_("<Enter>") " to abort simulation");
|
||||||
|
|
@ -623,13 +626,13 @@ static int CmdHIDBrute(const char *Cmd) {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
if (strcmp(field, "fc") == 0) {
|
if (strcmp(field, "fc") == 0) {
|
||||||
if (card_hi.FacilityCode < 0xFF) {
|
if (card_hi.FacilityCode < card_descriptor.MaxFC) {
|
||||||
card_hi.FacilityCode++;
|
card_hi.FacilityCode++;
|
||||||
} else {
|
} else {
|
||||||
fin_hi = true;
|
fin_hi = true;
|
||||||
}
|
}
|
||||||
} else if (strcmp(field, "cn") == 0) {
|
} else if (strcmp(field, "cn") == 0) {
|
||||||
if (card_hi.CardNumber < 0xFFFF) {
|
if (card_hi.CardNumber < card_descriptor.MaxCN) {
|
||||||
card_hi.CardNumber++;
|
card_hi.CardNumber++;
|
||||||
} else {
|
} else {
|
||||||
fin_hi = true;
|
fin_hi = true;
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,8 @@ static int CmdLFPCF7931Config(const char *Cmd) {
|
||||||
arg_lit0("r", "reset", "Reset configuration to default values"),
|
arg_lit0("r", "reset", "Reset configuration to default values"),
|
||||||
arg_str0("p", "pwd", "<hex>", "Password, 7bytes, LSB-order"),
|
arg_str0("p", "pwd", "<hex>", "Password, 7bytes, LSB-order"),
|
||||||
arg_u64_0("d", "delay", "<dec>", "Tag initialization delay (in us)"),
|
arg_u64_0("d", "delay", "<dec>", "Tag initialization delay (in us)"),
|
||||||
arg_int0(NULL, "lw", "<dec>", "offset, low pulses width (in us)"),
|
arg_int0(NULL, "lw", "<dec>", "offset, low pulses width (in us), optional!"),
|
||||||
arg_int0(NULL, "lp", "<dec>", "offset, low pulses position (in us)"),
|
arg_int0(NULL, "lp", "<dec>", "offset, low pulses position (in us), optional!"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
|
||||||
|
|
@ -305,6 +305,7 @@ static int CmdPyramidClone(const char *Cmd) {
|
||||||
|
|
||||||
uint8_t *bs = calloc(128, sizeof(uint8_t));
|
uint8_t *bs = calloc(128, sizeof(uint8_t));
|
||||||
if (bs == NULL) {
|
if (bs == NULL) {
|
||||||
|
PrintAndLogEx(WARNING, "failed to allocate memory");
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1550,6 +1550,7 @@ bool testKnownConfigBlock(uint32_t block0) {
|
||||||
case T55X7_NEXWATCH_CONFIG_BLOCK:
|
case T55X7_NEXWATCH_CONFIG_BLOCK:
|
||||||
case T55X7_JABLOTRON_CONFIG_BLOCK:
|
case T55X7_JABLOTRON_CONFIG_BLOCK:
|
||||||
case T55X7_PYRONIX_CONFIG_BLOCK:
|
case T55X7_PYRONIX_CONFIG_BLOCK:
|
||||||
|
case T55X7_TEXECOM_CONFIG_BLOCK:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -2298,6 +2299,9 @@ static void printT5x7KnownBlock0(uint32_t b0) {
|
||||||
case T55X7_PYRONIX_CONFIG_BLOCK:
|
case T55X7_PYRONIX_CONFIG_BLOCK:
|
||||||
snprintf(s + strlen(s), sizeof(s) - strlen(s), "Pyronix ");
|
snprintf(s + strlen(s), sizeof(s) - strlen(s), "Pyronix ");
|
||||||
break;
|
break;
|
||||||
|
case T55X7_TEXECOM_CONFIG_BLOCK:
|
||||||
|
snprintf(s + strlen(s), sizeof(s) - strlen(s), "Texecom ");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
#define T55X7_SECURAKEY_CONFIG_BLOCK 0x000C8060 // ASK, Manchester, data rate 40, 3 data blocks
|
#define T55X7_SECURAKEY_CONFIG_BLOCK 0x000C8060 // ASK, Manchester, data rate 40, 3 data blocks
|
||||||
#define T55X7_UNK_CONFIG_BLOCK 0x000880FA // ASK, Manchester, data rate 32, 7 data blocks STT, Inverse ...
|
#define T55X7_UNK_CONFIG_BLOCK 0x000880FA // ASK, Manchester, data rate 32, 7 data blocks STT, Inverse ...
|
||||||
#define T55X7_PYRONIX_CONFIG_BLOCK 0x00088C40 // ASK, Manchester, data rate 32, 2 data blocks
|
#define T55X7_PYRONIX_CONFIG_BLOCK 0x00088C40 // ASK, Manchester, data rate 32, 2 data blocks
|
||||||
|
#define T55X7_TEXECOM_CONFIG_BLOCK 0x001C8020 // ASK, Manchester, data rate 128, 1 data block
|
||||||
|
|
||||||
// FDXB requires data inversion and BiPhase 57 is simply BiPhase 50 inverted, so we can either do it using the modulation scheme or the inversion flag
|
// FDXB requires data inversion and BiPhase 57 is simply BiPhase 50 inverted, so we can either do it using the modulation scheme or the inversion flag
|
||||||
// we've done both below to prove that it works either way, and the modulation value for BiPhase 50 in the Atmel data sheet of binary "10001" (17) is a typo,
|
// we've done both below to prove that it works either way, and the modulation value for BiPhase 50 in the Atmel data sheet of binary "10001" (17) is a typo,
|
||||||
|
|
|
||||||
|
|
@ -596,8 +596,8 @@ static int PivGetData(Iso7816CommandChannel channel, const uint8_t tag[], size_t
|
||||||
// Answer can be chained. Let's use a dynamically allocated buffer.
|
// Answer can be chained. Let's use a dynamically allocated buffer.
|
||||||
size_t capacity = PM3_CMD_DATA_SIZE;
|
size_t capacity = PM3_CMD_DATA_SIZE;
|
||||||
struct tlvdb_root *root = calloc(1, sizeof(*root) + capacity);
|
struct tlvdb_root *root = calloc(1, sizeof(*root) + capacity);
|
||||||
|
|
||||||
if (root == NULL) {
|
if (root == NULL) {
|
||||||
|
PrintAndLogEx(WARNING, "failed to allocate memory");
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
root->len = 0;
|
root->len = 0;
|
||||||
|
|
|
||||||
|
|
@ -1067,8 +1067,10 @@ static int CmdSmartBruteforceSFI(const char *Cmd) {
|
||||||
smart_loadjson("aidlist", &root);
|
smart_loadjson("aidlist", &root);
|
||||||
|
|
||||||
uint8_t *buf = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
|
uint8_t *buf = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
|
||||||
if (!buf)
|
if (buf == NULL) {
|
||||||
|
PrintAndLogEx(WARNING, "failed to allocate memory");
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Selecting card");
|
PrintAndLogEx(INFO, "Selecting card");
|
||||||
if (!smart_select(false, NULL)) {
|
if (!smart_select(false, NULL)) {
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,7 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract MFC
|
// extract MFC
|
||||||
|
/*
|
||||||
switch (frame[0]) {
|
switch (frame[0]) {
|
||||||
case MIFARE_AUTH_KEYA: {
|
case MIFARE_AUTH_KEYA: {
|
||||||
if (data_len > 3) {
|
if (data_len > 3) {
|
||||||
|
|
@ -176,9 +177,11 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// extract MFU-C
|
// extract MFU-C KEY when written.
|
||||||
switch (frame[0]) {
|
switch (frame[0]) {
|
||||||
|
|
||||||
case MIFARE_ULC_AUTH_1: {
|
case MIFARE_ULC_AUTH_1: {
|
||||||
if (data_len != 4) {
|
if (data_len != 4) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -195,7 +198,7 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "MFU-C AUTH");
|
PrintAndLogEx(INFO, "Found a MFU-C authententication attempt");
|
||||||
PrintAndLogEx(INFO, "3DES %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, 8));
|
PrintAndLogEx(INFO, "3DES %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, 8));
|
||||||
|
|
||||||
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
|
@ -203,6 +206,8 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
||||||
|
|
||||||
if (next_hdr->frame[0] == MIFARE_ULC_AUTH_2 && next_hdr->data_len == 19) {
|
if (next_hdr->frame[0] == MIFARE_ULC_AUTH_2 && next_hdr->data_len == 19) {
|
||||||
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + 1, 16));
|
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + 1, 16));
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(NORMAL, "( " _RED_("partial") " )");
|
||||||
}
|
}
|
||||||
|
|
||||||
return tracepos;
|
return tracepos;
|
||||||
|
|
@ -323,7 +328,7 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
||||||
case MFDES_AUTHENTICATE: {
|
case MFDES_AUTHENTICATE: {
|
||||||
|
|
||||||
// Assume wrapped or unwrapped
|
// Assume wrapped or unwrapped
|
||||||
PrintAndLogEx(INFO, "AUTH NATIVE (keyNo %d)", frame[pos + long_jmp]);
|
PrintAndLogEx(INFO, "Found a MFDES Auth NATIVE (keyNo %d)", frame[pos + long_jmp]);
|
||||||
if (next_record_is_response(tracepos, trace) == false) {
|
if (next_record_is_response(tracepos, trace) == false) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -348,7 +353,7 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
||||||
}
|
}
|
||||||
case MFDES_AUTHENTICATE_ISO: {
|
case MFDES_AUTHENTICATE_ISO: {
|
||||||
// Assume wrapped or unwrapped
|
// Assume wrapped or unwrapped
|
||||||
PrintAndLogEx(INFO, "AUTH ISO (keyNo %d)", frame[pos + long_jmp]);
|
PrintAndLogEx(INFO, "Found a MFDES Auth ISO (keyNo %d)", frame[pos + long_jmp]);
|
||||||
if (next_record_is_response(tracepos, trace) == false) {
|
if (next_record_is_response(tracepos, trace) == false) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -379,7 +384,7 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
||||||
}
|
}
|
||||||
case MFDES_AUTHENTICATE_AES: {
|
case MFDES_AUTHENTICATE_AES: {
|
||||||
// Assume wrapped or unwrapped
|
// Assume wrapped or unwrapped
|
||||||
PrintAndLogEx(INFO, "AUTH AES (keyNo %d)", frame[pos + long_jmp]);
|
PrintAndLogEx(INFO, "Found a MFDES Auth AES (keyNo %d)", frame[pos + long_jmp]);
|
||||||
if (next_record_is_response(tracepos, trace)) {
|
if (next_record_is_response(tracepos, trace)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -403,7 +408,7 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
||||||
return tracepos;
|
return tracepos;
|
||||||
}
|
}
|
||||||
case MFDES_AUTHENTICATE_EV2F: {
|
case MFDES_AUTHENTICATE_EV2F: {
|
||||||
PrintAndLogEx(INFO, "AUTH EV2 First");
|
PrintAndLogEx(INFO, "Found a MFDES Auth EV2 First");
|
||||||
uint16_t tmp = extractChall_ev2(tracepos, trace, pos, long_jmp);
|
uint16_t tmp = extractChall_ev2(tracepos, trace, pos, long_jmp);
|
||||||
if (tmp == 0)
|
if (tmp == 0)
|
||||||
break;
|
break;
|
||||||
|
|
@ -412,7 +417,7 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
||||||
|
|
||||||
}
|
}
|
||||||
case MFDES_AUTHENTICATE_EV2NF: {
|
case MFDES_AUTHENTICATE_EV2NF: {
|
||||||
PrintAndLogEx(INFO, "AUTH EV2 Non First");
|
PrintAndLogEx(INFO, "Found a MFDES Auth EV2 Non First");
|
||||||
uint16_t tmp = extractChall_ev2(tracepos, trace, pos, long_jmp);
|
uint16_t tmp = extractChall_ev2(tracepos, trace, pos, long_jmp);
|
||||||
if (tmp == 0)
|
if (tmp == 0)
|
||||||
break;
|
break;
|
||||||
|
|
@ -556,9 +561,11 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
case ISO_14443A:
|
case ISO_14443A:
|
||||||
case MFDES:
|
case MFDES:
|
||||||
case LTO:
|
case LTO:
|
||||||
case SEOS:
|
|
||||||
crcStatus = iso14443A_CRC_check(hdr->isResponse, frame, data_len);
|
crcStatus = iso14443A_CRC_check(hdr->isResponse, frame, data_len);
|
||||||
break;
|
break;
|
||||||
|
case SEOS:
|
||||||
|
crcStatus = seos_CRC_check(hdr->isResponse, frame, data_len);
|
||||||
|
break;
|
||||||
case ISO_7816_4:
|
case ISO_7816_4:
|
||||||
crcStatus = iso14443A_CRC_check(hdr->isResponse, frame, data_len) == 1 ? 3 : 0;
|
crcStatus = iso14443A_CRC_check(hdr->isResponse, frame, data_len) == 1 ? 3 : 0;
|
||||||
crcStatus = iso14443B_CRC_check(frame, data_len) == 1 ? 4 : crcStatus;
|
crcStatus = iso14443B_CRC_check(frame, data_len) == 1 ? 4 : crcStatus;
|
||||||
|
|
@ -798,6 +805,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
case ICLASS:
|
case ICLASS:
|
||||||
annotateIclass(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
|
annotateIclass(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
|
||||||
break;
|
break;
|
||||||
|
case SEOS:
|
||||||
|
annotateSeos(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -834,9 +844,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
case PROTO_CRYPTORF:
|
case PROTO_CRYPTORF:
|
||||||
annotateCryptoRF(explanation, sizeof(explanation), frame, data_len);
|
annotateCryptoRF(explanation, sizeof(explanation), frame, data_len);
|
||||||
break;
|
break;
|
||||||
case SEOS:
|
|
||||||
annotateSeos(explanation, sizeof(explanation), frame, data_len);
|
|
||||||
break;
|
|
||||||
case PROTO_FMCOS20:
|
case PROTO_FMCOS20:
|
||||||
annotateFMCOS20(explanation, sizeof(explanation), frame, data_len);
|
annotateFMCOS20(explanation, sizeof(explanation), frame, data_len);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,46 @@
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
|
#define PACS_EXTRA_LONG_FORMAT 18 // 144 bits
|
||||||
|
#define PACS_LONG_FORMAT 12 // 96 bits
|
||||||
|
#define PACS_FORMAT 6 // 44 bits
|
||||||
|
static int wiegand_new_pacs(uint8_t *padded_pacs, uint8_t plen) {
|
||||||
|
|
||||||
|
uint8_t d[PACS_EXTRA_LONG_FORMAT] = {0};
|
||||||
|
memcpy(d, padded_pacs, plen);
|
||||||
|
|
||||||
|
uint8_t pad = d[0];
|
||||||
|
|
||||||
|
char *binstr = (char *)calloc((PACS_EXTRA_LONG_FORMAT * 8) + 1, sizeof(uint8_t));
|
||||||
|
if (binstr == NULL) {
|
||||||
|
PrintAndLogEx(INFO, "failed to allocate memory");
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t n = plen - 1;
|
||||||
|
|
||||||
|
bytes_2_binstr(binstr, d + 1, n);
|
||||||
|
|
||||||
|
binstr[strlen(binstr) - pad] = '\0';
|
||||||
|
|
||||||
|
size_t tlen = 0;
|
||||||
|
uint8_t tmp[16] = {0};
|
||||||
|
binstr_2_bytes(tmp, &tlen, binstr);
|
||||||
|
PrintAndLogEx(SUCCESS, "Wiegand raw.... " _YELLOW_("%s"), sprint_hex_inrow(tmp, tlen));
|
||||||
|
|
||||||
|
uint32_t top = 0, mid = 0, bot = 0;
|
||||||
|
if (binstring_to_u96(&top, &mid, &bot, binstr) != strlen(binstr)) {
|
||||||
|
PrintAndLogEx(ERR, "Binary string contains none <0|1> chars");
|
||||||
|
free(binstr);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, "------------------------- " _CYAN_("SIO - Wiegand") " ---------------------------");
|
||||||
|
decode_wiegand(top, mid, bot, strlen(binstr));
|
||||||
|
free(binstr);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
int CmdWiegandList(const char *Cmd) {
|
int CmdWiegandList(const char *Cmd) {
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
|
|
@ -116,16 +156,18 @@ int CmdWiegandDecode(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "wiegand decode",
|
CLIParserInit(&ctx, "wiegand decode",
|
||||||
"Decode raw hex or binary to wiegand format",
|
"Decode raw hex or binary to wiegand format",
|
||||||
"wiegand decode --raw 2006f623ae"
|
"wiegand decode --raw 2006F623AE\n"
|
||||||
|
"wiegand decode --new 06BD88EB80 -> 4..8 bytes, new padded format "
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str0("r", "raw", "<hex>", "raw hex to be decoded"),
|
arg_str0("r", "raw", "<hex>", "raw hex to be decoded"),
|
||||||
arg_str0("b", "bin", "<bin>", "binary string to be decoded"),
|
arg_str0("b", "bin", "<bin>", "binary string to be decoded"),
|
||||||
|
arg_str0("n", "new", "<hex>", "new padded pacs as raw hex to be decoded"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
int hlen = 0;
|
int hlen = 0;
|
||||||
char hex[40] = {0};
|
char hex[40] = {0};
|
||||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)hex, sizeof(hex), &hlen);
|
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)hex, sizeof(hex), &hlen);
|
||||||
|
|
@ -133,6 +175,11 @@ int CmdWiegandDecode(const char *Cmd) {
|
||||||
int blen = 0;
|
int blen = 0;
|
||||||
uint8_t binarr[100] = {0x00};
|
uint8_t binarr[100] = {0x00};
|
||||||
int res = CLIParamBinToBuf(arg_get_str(ctx, 2), binarr, sizeof(binarr), &blen);
|
int res = CLIParamBinToBuf(arg_get_str(ctx, 2), binarr, sizeof(binarr), &blen);
|
||||||
|
|
||||||
|
int plen = 0;
|
||||||
|
uint8_t phex[8] = {0};
|
||||||
|
res = CLIParamHexToBuf(arg_get_str(ctx, 3), phex, sizeof(phex), &plen);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
|
|
@ -155,13 +202,20 @@ int CmdWiegandDecode(const char *Cmd) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(INFO, "Input bin len... %d", blen);
|
PrintAndLogEx(INFO, "Input bin len... %d", blen);
|
||||||
|
|
||||||
|
} else if (plen) {
|
||||||
|
|
||||||
|
return wiegand_new_pacs(phex, plen);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(ERR, "Empty input");
|
PrintAndLogEx(ERR, "Empty input");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
wiegand_message_t packed = initialize_message_object(top, mid, bot, blen);
|
PrintAndLogEx(NORMAL, "");
|
||||||
HIDTryUnpack(&packed);
|
PrintAndLogEx(INFO, "------------------------- " _CYAN_("Wiegand") " ---------------------------");
|
||||||
|
|
||||||
|
decode_wiegand(top, mid, bot, blen);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,37 @@ int asn1_print(uint8_t *asn1buf, size_t asn1buflen, const char *indent) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int asn1_get_tag_length(const uint8_t *data, size_t *n, size_t *offset, size_t total_length) {
|
||||||
|
|
||||||
|
if (*offset >= total_length) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[*offset] & 0x80) {
|
||||||
|
|
||||||
|
// Long form: number of length bytes is indicated by the lower 7 bits
|
||||||
|
size_t len_bytes = data[*offset] & 0x7F;
|
||||||
|
|
||||||
|
*offset += 1;
|
||||||
|
|
||||||
|
if (*offset + len_bytes > total_length) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*n = 0;
|
||||||
|
for (size_t i = 0; i < len_bytes; i++) {
|
||||||
|
*n = (*n << 8) | data[*offset];
|
||||||
|
*offset += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Short form: length is directly represented
|
||||||
|
*n = data[*offset];
|
||||||
|
*offset += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *hex;
|
const char *hex;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
int asn1_print(uint8_t *asn1buf, size_t asn1buflen, const char *indent);
|
int asn1_print(uint8_t *asn1buf, size_t asn1buflen, const char *indent);
|
||||||
int ecdsa_asn1_get_signature(uint8_t *signature, size_t signaturelen, uint8_t *rval, uint8_t *sval);
|
int ecdsa_asn1_get_signature(uint8_t *signature, size_t signaturelen, uint8_t *rval, uint8_t *sval);
|
||||||
|
|
||||||
|
int asn1_get_tag_length(const uint8_t *data, size_t *n, size_t *offset, size_t total_length);
|
||||||
int asn1_selftest(void);
|
int asn1_selftest(void);
|
||||||
|
|
||||||
#endif /* asn1utils.h */
|
#endif /* asn1utils.h */
|
||||||
|
|
|
||||||
|
|
@ -136,25 +136,28 @@ const ecdsa_publickey_ng_t manufacturer_public_keys[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// return pk if match index else -1
|
// returns index of pk if match else -1
|
||||||
int originality_check_verify(uint8_t *data, uint8_t data_len, uint8_t *signature, uint8_t signature_len, pk_type_t type) {
|
int originality_check_verify(uint8_t *data, uint8_t data_len, uint8_t *signature, uint8_t signature_len, pk_type_t type) {
|
||||||
return originality_check_verify_ex(data, data_len, signature, signature_len, type, false, false);
|
return originality_check_verify_ex(data, data_len, signature, signature_len, type, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int originality_check_verify_ex(uint8_t *data, uint8_t data_len, uint8_t *signature, uint8_t signature_len, pk_type_t type, bool reverse, bool hash) {
|
int originality_check_verify_ex(uint8_t *data, uint8_t data_len, uint8_t *signature, uint8_t signature_len, pk_type_t type, bool reverse, bool hash) {
|
||||||
// test if signature is null
|
// test if signature is all zeros
|
||||||
bool is_zero = true;
|
bool is_zero = true;
|
||||||
for (uint8_t i = 0; i < signature_len; i++) {
|
for (uint8_t i = 0; i < signature_len; i++) {
|
||||||
if (signature[i] != 0) {
|
if (signature[i] != 0) {
|
||||||
is_zero = false;
|
is_zero = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_zero) {
|
if (is_zero) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t tmp_data[data_len];
|
uint8_t tmp_data[data_len];
|
||||||
uint8_t tmp_signature[signature_len];
|
uint8_t tmp_signature[signature_len];
|
||||||
|
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
reverse_array_copy(data, data_len, tmp_data);
|
reverse_array_copy(data, data_len, tmp_data);
|
||||||
reverse_array_copy(signature, signature_len, tmp_signature);
|
reverse_array_copy(signature, signature_len, tmp_signature);
|
||||||
|
|
@ -180,17 +183,24 @@ int originality_check_verify_ex(uint8_t *data, uint8_t data_len, uint8_t *signat
|
||||||
}
|
}
|
||||||
|
|
||||||
int originality_check_print(uint8_t *signature, int signature_len, int index) {
|
int originality_check_print(uint8_t *signature, int signature_len, int index) {
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
if ((index < 0) || (index >= ARRAYLEN(manufacturer_public_keys))) {
|
if ((index < 0) || (index >= ARRAYLEN(manufacturer_public_keys))) {
|
||||||
|
|
||||||
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16));
|
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16));
|
||||||
if (signature_len > 16) {
|
if (signature_len > 16) {
|
||||||
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16));
|
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signature_len > 32) {
|
if (signature_len > 32) {
|
||||||
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16));
|
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signature_len > 48) {
|
if (signature_len > 48) {
|
||||||
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48));
|
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48));
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed"));
|
PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed"));
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
@ -200,23 +210,30 @@ int originality_check_print(uint8_t *signature, int signature_len, int index) {
|
||||||
if (manufacturer_public_keys[index].keylen > 16) {
|
if (manufacturer_public_keys[index].keylen > 16) {
|
||||||
PrintAndLogEx(INFO, " : %.32s", manufacturer_public_keys[index].value + 32);
|
PrintAndLogEx(INFO, " : %.32s", manufacturer_public_keys[index].value + 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (manufacturer_public_keys[index].keylen > 32) {
|
if (manufacturer_public_keys[index].keylen > 32) {
|
||||||
PrintAndLogEx(INFO, " : %.32s", manufacturer_public_keys[index].value + 64);
|
PrintAndLogEx(INFO, " : %.32s", manufacturer_public_keys[index].value + 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (manufacturer_public_keys[index].keylen > 48) {
|
if (manufacturer_public_keys[index].keylen > 48) {
|
||||||
PrintAndLogEx(INFO, " : %.32s", manufacturer_public_keys[index].value + 96);
|
PrintAndLogEx(INFO, " : %.32s", manufacturer_public_keys[index].value + 96);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, " Elliptic curve parameters: %s", mbedtls_ecp_curve_info_from_grp_id(manufacturer_public_keys[index].grp_id)->name);
|
PrintAndLogEx(INFO, " Elliptic curve parameters: %s", mbedtls_ecp_curve_info_from_grp_id(manufacturer_public_keys[index].grp_id)->name);
|
||||||
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16));
|
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16));
|
||||||
|
|
||||||
if (signature_len > 16) {
|
if (signature_len > 16) {
|
||||||
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16));
|
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signature_len > 32) {
|
if (signature_len > 32) {
|
||||||
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16));
|
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signature_len > 48) {
|
if (signature_len > 48) {
|
||||||
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48));
|
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48));
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful"));
|
PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful"));
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2122,9 +2122,9 @@ static int CmdEMVScan(const char *Cmd) {
|
||||||
|
|
||||||
uint8_t psenum = (channel == CC_CONTACT) ? 1 : 2;
|
uint8_t psenum = (channel == CC_CONTACT) ? 1 : 2;
|
||||||
|
|
||||||
char filename[FILE_PATH_SIZE] = {0};
|
uint8_t filename[FILE_PATH_SIZE] = {0};
|
||||||
int fnlen = 0;
|
int filenamelen = sizeof(filename) - 1; // CLIGetStrWithReturn does not guarantee string to be null-terminated
|
||||||
CLIParamStrToBuf(arg_get_str(ctx, 12), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
CLIGetStrWithReturn(ctx, 12, filename, &filenamelen);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
|
@ -2507,7 +2507,7 @@ static int CmdEMVRoca(const char *Cmd) {
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("t", "selftest", "Self test"),
|
arg_lit0(NULL, "test", "Perform self tests"),
|
||||||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||||
arg_lit0("w", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
arg_lit0("w", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
|
|
@ -2981,7 +2981,7 @@ static command_t CommandTable[] = {
|
||||||
{"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"},
|
{"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"},
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
{"list", CmdEMVList, AlwaysAvailable, "List ISO7816 history"},
|
{"list", CmdEMVList, AlwaysAvailable, "List ISO7816 history"},
|
||||||
{"test", CmdEMVTest, AlwaysAvailable, "Crypto logic selftest"},
|
{"test", CmdEMVTest, AlwaysAvailable, "Perform crypto logic self tests"},
|
||||||
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("Operations") " ---------------------"},
|
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("Operations") " ---------------------"},
|
||||||
{"challenge", CmdEMVGenerateChallenge, IfPm3Iso14443, "Generate challenge"},
|
{"challenge", CmdEMVGenerateChallenge, IfPm3Iso14443, "Generate challenge"},
|
||||||
{"exec", CmdEMVExec, IfPm3Iso14443, "Executes EMV contactless transaction"},
|
{"exec", CmdEMVExec, IfPm3Iso14443, "Executes EMV contactless transaction"},
|
||||||
|
|
|
||||||
|
|
@ -809,7 +809,7 @@ int saveFileJSONrootEx(const char *preferredName, const void *root, size_t flags
|
||||||
|
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(SUCCESS, "Saved to json file `" _YELLOW_("%s") "`", filename);
|
PrintAndLogEx(SUCCESS, "Saved to json file " _YELLOW_("%s"), filename);
|
||||||
}
|
}
|
||||||
free(filename);
|
free(filename);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
|
@ -1105,7 +1105,9 @@ int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) {
|
||||||
|
|
||||||
int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, nfc_df_e ft) {
|
int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, nfc_df_e ft) {
|
||||||
|
|
||||||
if (data == NULL) return PM3_EINVARG;
|
if (data == NULL) {
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
*datalen = 0;
|
*datalen = 0;
|
||||||
int retval = PM3_SUCCESS;
|
int retval = PM3_SUCCESS;
|
||||||
|
|
@ -1137,16 +1139,17 @@ int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, s
|
||||||
memset(line, 0, sizeof(line));
|
memset(line, 0, sizeof(line));
|
||||||
|
|
||||||
if (fgets(line, sizeof(line), f) == NULL) {
|
if (fgets(line, sizeof(line), f) == NULL) {
|
||||||
if (feof(f))
|
if (feof(f)) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
PrintAndLogEx(FAILED, "file reading error");
|
PrintAndLogEx(FAILED, "file reading error");
|
||||||
return PM3_EFILE;
|
return PM3_EFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line[0] == '#')
|
if (line[0] == '#') {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
str_cleanrn(line, sizeof(line));
|
str_cleanrn(line, sizeof(line));
|
||||||
str_lower(line);
|
str_lower(line);
|
||||||
|
|
@ -2409,7 +2412,6 @@ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, vo
|
||||||
|
|
||||||
// larger keys than expected is skipped
|
// larger keys than expected is skipped
|
||||||
if (strlen(line) > keylen) {
|
if (strlen(line) > keylen) {
|
||||||
PrintAndLogEx(INFO, "larger %zu - %s", strlen(line), line);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2626,6 +2628,7 @@ int detect_nfc_dump_format(const char *preferredName, nfc_df_e *dump_type, bool
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
|
||||||
switch (*dump_type) {
|
switch (*dump_type) {
|
||||||
case NFC_DF_MFU:
|
case NFC_DF_MFU:
|
||||||
PrintAndLogEx(INFO, "Detected MIFARE Ultralight / NTAG based dump format");
|
PrintAndLogEx(INFO, "Detected MIFARE Ultralight / NTAG based dump format");
|
||||||
|
|
@ -3081,6 +3084,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
|
||||||
PrintAndLogEx(WARNING, "fail, cannot allocate memory");
|
PrintAndLogEx(WARNING, "fail, cannot allocate memory");
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = loadFileJSON(fn, *pdump, maxdumplen, dumplen, NULL);
|
res = loadFileJSON(fn, *pdump, maxdumplen, dumplen, NULL);
|
||||||
if (res == PM3_SUCCESS) {
|
if (res == PM3_SUCCESS) {
|
||||||
return res;
|
return res;
|
||||||
|
|
@ -3107,7 +3111,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FLIPPER: {
|
case FLIPPER: {
|
||||||
nfc_df_e dumptype;
|
nfc_df_e dumptype = NFC_DF_UNKNOWN;
|
||||||
res = detect_nfc_dump_format(fn, &dumptype, true);
|
res = detect_nfc_dump_format(fn, &dumptype, true);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -282,8 +282,31 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale
|
||||||
*/
|
*/
|
||||||
int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t keylen, uint32_t *keycnt);
|
int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t keylen, uint32_t *keycnt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Utility function to load data safely from a DICTIONARY textfile. This method takes a preferred name.
|
||||||
|
* E.g. mfc_default_keys.dic
|
||||||
|
*
|
||||||
|
* @param preferredName
|
||||||
|
* @param suffix
|
||||||
|
* @param pdata A pointer to a pointer (for reverencing the loaded dictionary)
|
||||||
|
* @param keylen the number of bytes a key per row is
|
||||||
|
* @param verbose print messages if true
|
||||||
|
* @return 0 for ok, 1 for failz
|
||||||
|
*/
|
||||||
int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, void **pdata, uint8_t keylen, uint32_t *keycnt, bool verbose);
|
int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, void **pdata, uint8_t keylen, uint32_t *keycnt, bool verbose);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Utility function to load data from a XML textfile. This method takes a preferred name.
|
||||||
|
* E.g. dumpdata-15.xml
|
||||||
|
*
|
||||||
|
* @param preferredName
|
||||||
|
* @param data The data array to store the loaded bytes from file
|
||||||
|
* @param maxdatalen maximum size of data array in bytes
|
||||||
|
* @param datalen the number of bytes loaded from file
|
||||||
|
* @return 0 for ok, 1 for failz
|
||||||
|
*/
|
||||||
|
int loadFileXML_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen);
|
||||||
|
|
||||||
int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya, void **keyb, size_t *alen, size_t *blen);
|
int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya, void **keyb, size_t *alen, size_t *blen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1008,7 +1008,7 @@ void DesfirePrintAIDFunctions(uint32_t appid) {
|
||||||
if ((aid[2] >> 4) == 0xF) {
|
if ((aid[2] >> 4) == 0xF) {
|
||||||
uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4);
|
uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4);
|
||||||
PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid);
|
PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid);
|
||||||
PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, nxp_cluster_to_text(short_aid >> 8));
|
PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X..... " _YELLOW_("%s"), short_aid >> 8, nxp_cluster_to_text(short_aid >> 8));
|
||||||
MADDFDecodeAndPrint(short_aid, false);
|
MADDFDecodeAndPrint(short_aid, false);
|
||||||
} else {
|
} else {
|
||||||
AIDDFDecodeAndPrint(aid);
|
AIDDFDecodeAndPrint(aid);
|
||||||
|
|
@ -1016,53 +1016,64 @@ void DesfirePrintAIDFunctions(uint32_t appid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int DesfireSelectAndAuthenticateEx(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose) {
|
int DesfireSelectAndAuthenticateEx(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose) {
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
DesfirePrintContext(dctx);
|
DesfirePrintContext(dctx);
|
||||||
|
}
|
||||||
|
|
||||||
// needs card uid for diversification
|
// needs card uid for diversification
|
||||||
if (dctx->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER)
|
if (dctx->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER) {
|
||||||
DesfireGetCardUID(dctx);
|
DesfireGetCardUID(dctx);
|
||||||
|
}
|
||||||
|
|
||||||
bool isosw = false;
|
bool isosw = false;
|
||||||
if (dctx->cmdSet == DCCISO) {
|
if (dctx->cmdSet == DCCISO) {
|
||||||
dctx->cmdSet = DCCNativeISO;
|
dctx->cmdSet = DCCNativeISO;
|
||||||
isosw = true;
|
isosw = true;
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
PrintAndLogEx(INFO, "Switch to " _CYAN_("native") " for select");
|
PrintAndLogEx(INFO, "Switch to " _CYAN_("native") " for select");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int res;
|
int res;
|
||||||
if (aid == 0x000000) {
|
if (aid == 0x000000) {
|
||||||
res = DesfireAnticollision(verbose);
|
res = DesfireAnticollision(verbose);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(ERR, "Desfire anticollision " _RED_("error") ".");
|
PrintAndLogEx(ERR, "Desfire anticollision " _RED_("fail"));
|
||||||
return 200;
|
return 200;
|
||||||
}
|
}
|
||||||
if (verbose)
|
|
||||||
|
if (verbose) {
|
||||||
PrintAndLogEx(INFO, "Anticollision " _GREEN_("ok"));
|
PrintAndLogEx(INFO, "Anticollision " _GREEN_("ok"));
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
res = DesfireSelectAIDHex(dctx, aid, false, 0);
|
res = DesfireSelectAIDHex(dctx, aid, false, 0);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(ERR, "Desfire select " _RED_("error") ".");
|
PrintAndLogEx(ERR, "Desfire select " _RED_("fail"));
|
||||||
return 200;
|
return 200;
|
||||||
}
|
}
|
||||||
if (verbose)
|
|
||||||
|
if (verbose) {
|
||||||
PrintAndLogEx(INFO, "App %06x " _GREEN_("selected"), aid);
|
PrintAndLogEx(INFO, "App %06x " _GREEN_("selected"), aid);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isosw)
|
if (isosw) {
|
||||||
dctx->cmdSet = DCCISO;
|
dctx->cmdSet = DCCISO;
|
||||||
|
}
|
||||||
|
|
||||||
if (noauth == false) {
|
if (noauth == false) {
|
||||||
|
|
||||||
res = DesfireAuthenticate(dctx, secureChannel, verbose);
|
res = DesfireAuthenticate(dctx, secureChannel, verbose);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: [%d] %s", res, DesfireAuthErrorToStr(res));
|
PrintAndLogEx(ERR, "Desfire authenticate " _RED_("fail") ". Result: [%d] %s", res, DesfireAuthErrorToStr(res));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DesfireIsAuthenticated(dctx)) {
|
if (DesfireIsAuthenticated(dctx)) {
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated"));
|
PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated"));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return 201;
|
return 201;
|
||||||
}
|
}
|
||||||
|
|
@ -1087,7 +1098,7 @@ int DesfireSelectAndAuthenticateW(DesfireContext_t *dctx, DesfireSecureChannel s
|
||||||
|
|
||||||
res = DesfireSelectAIDHex(dctx, id, false, 0);
|
res = DesfireSelectAIDHex(dctx, id, false, 0);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(ERR, "Desfire select " _RED_("error") ".");
|
PrintAndLogEx(ERR, "Desfire select " _RED_("error"));
|
||||||
return 200;
|
return 200;
|
||||||
}
|
}
|
||||||
if (verbose)
|
if (verbose)
|
||||||
|
|
@ -1097,7 +1108,7 @@ int DesfireSelectAndAuthenticateW(DesfireContext_t *dctx, DesfireSecureChannel s
|
||||||
} else {
|
} else {
|
||||||
res = DesfireSelectEx(dctx, true, way, id, NULL);
|
res = DesfireSelectEx(dctx, true, way, id, NULL);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(ERR, "Desfire %s select " _RED_("error") ".", DesfireSelectWayToStr(way));
|
PrintAndLogEx(ERR, "Desfire %s select " _RED_("error"), DesfireSelectWayToStr(way));
|
||||||
return 202;
|
return 202;
|
||||||
}
|
}
|
||||||
if (verbose)
|
if (verbose)
|
||||||
|
|
@ -1107,13 +1118,14 @@ int DesfireSelectAndAuthenticateW(DesfireContext_t *dctx, DesfireSecureChannel s
|
||||||
if (selectfile) {
|
if (selectfile) {
|
||||||
res = DesfireSelectEx(dctx, false, ISWIsoID, isofileid, NULL);
|
res = DesfireSelectEx(dctx, false, ISWIsoID, isofileid, NULL);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(ERR, "Desfire iso file select " _RED_("error") ".");
|
PrintAndLogEx(ERR, "Desfire iso file select " _RED_("error"));
|
||||||
return 203;
|
return 203;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
PrintAndLogEx(INFO, "Application %s file iso id %04x is " _GREEN_("selected"), DesfireWayIDStr(way, id), isofileid);
|
PrintAndLogEx(INFO, "Application %s file iso id %04x is " _GREEN_("selected"), DesfireWayIDStr(way, id), isofileid);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!noauth) {
|
if (!noauth) {
|
||||||
res = DesfireAuthenticate(dctx, secureChannel, verbose);
|
res = DesfireAuthenticate(dctx, secureChannel, verbose);
|
||||||
|
|
@ -1123,8 +1135,9 @@ int DesfireSelectAndAuthenticateW(DesfireContext_t *dctx, DesfireSecureChannel s
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DesfireIsAuthenticated(dctx)) {
|
if (DesfireIsAuthenticated(dctx)) {
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated"));
|
PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated"));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return 201;
|
return 201;
|
||||||
}
|
}
|
||||||
|
|
@ -1864,17 +1877,21 @@ int DesfireFillAppList(DesfireContext_t *dctx, PICCInfo_t *PICCInfo, AppListS ap
|
||||||
|
|
||||||
void DesfirePrintPICCInfo(DesfireContext_t *dctx, PICCInfo_t *PICCInfo) {
|
void DesfirePrintPICCInfo(DesfireContext_t *dctx, PICCInfo_t *PICCInfo) {
|
||||||
PrintAndLogEx(SUCCESS, "------------------------------------ " _CYAN_("PICC level") " -------------------------------------");
|
PrintAndLogEx(SUCCESS, "------------------------------------ " _CYAN_("PICC level") " -------------------------------------");
|
||||||
if (PICCInfo->freemem == 0xffffffff)
|
if (PICCInfo->freemem == 0xffffffff) {
|
||||||
PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _YELLOW_("n/a"), PICCInfo->appCount);
|
PrintAndLogEx(SUCCESS, "# applications....... " _YELLOW_("%zu"), PICCInfo->appCount);
|
||||||
else
|
} else {
|
||||||
PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d") " bytes", PICCInfo->appCount, PICCInfo->freemem);
|
PrintAndLogEx(SUCCESS, "# applications....... " _YELLOW_("%zu"), PICCInfo->appCount);
|
||||||
|
}
|
||||||
|
PrintAndLogEx(SUCCESS, "");
|
||||||
|
|
||||||
if (PICCInfo->authCmdCheck.checked) {
|
if (PICCInfo->authCmdCheck.checked) {
|
||||||
PrintAndLogEx(SUCCESS, "PICC level auth commands: ");
|
PrintAndLogEx(SUCCESS, "PICC level auth commands");
|
||||||
DesfireCheckAuthCommandsPrint(&PICCInfo->authCmdCheck);
|
DesfireCheckAuthCommandsPrint(&PICCInfo->authCmdCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PICCInfo->numberOfKeys > 0) {
|
if (PICCInfo->numberOfKeys > 0) {
|
||||||
PrintKeySettings(PICCInfo->keySettings, PICCInfo->numKeysRaw, false, true);
|
PrintKeySettings(PICCInfo->keySettings, PICCInfo->numKeysRaw, false, true);
|
||||||
PrintAndLogEx(SUCCESS, "PICC key 0 version: %d (0x%02x)", PICCInfo->keyVersion0, PICCInfo->keyVersion0);
|
PrintAndLogEx(SUCCESS, "PICC key "_YELLOW_("0") " version: %d (0x%02x)", PICCInfo->keyVersion0, PICCInfo->keyVersion0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1886,14 +1903,14 @@ void DesfirePrintAppList(DesfireContext_t *dctx, PICCInfo_t *PICCInfo, AppListS
|
||||||
PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("Applications list") " ---------------------------------");
|
PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("Applications list") " ---------------------------------");
|
||||||
|
|
||||||
for (int i = 0; i < PICCInfo->appCount; i++) {
|
for (int i = 0; i < PICCInfo->appCount; i++) {
|
||||||
PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02X"), appList[i].appNum);
|
PrintAndLogEx(SUCCESS, "Application ID....... " _CYAN_("0x%02X"), appList[i].appNum);
|
||||||
PrintAndLogEx(SUCCESS, " ISO id.... " _GREEN_("0x%04X"), appList[i].appISONum);
|
PrintAndLogEx(SUCCESS, " ISO id............ " _GREEN_("0x%04X"), appList[i].appISONum);
|
||||||
PrintAndLogEx(SUCCESS, " DF name... " _GREEN_("%s") " ( %s)", appList[i].appDFName, sprint_hex((uint8_t *)appList[i].appDFName, sizeof(appList[i].appDFName)));
|
PrintAndLogEx(SUCCESS, " DF name........... " _GREEN_("%s") " ( %s )", appList[i].appDFName, sprint_hex_inrow((uint8_t *)appList[i].appDFName, sizeof(appList[i].appDFName)));
|
||||||
|
|
||||||
DesfirePrintAIDFunctions(appList[i].appNum);
|
DesfirePrintAIDFunctions(appList[i].appNum);
|
||||||
|
|
||||||
if (PICCInfo->authCmdCheck.checked) {
|
if (PICCInfo->authCmdCheck.checked) {
|
||||||
PrintAndLogEx(SUCCESS, "Auth commands: ");
|
PrintAndLogEx(SUCCESS, "Auth commands");
|
||||||
DesfireCheckAuthCommandsPrint(&appList[i].authCmdCheck);
|
DesfireCheckAuthCommandsPrint(&appList[i].authCmdCheck);
|
||||||
PrintAndLogEx(SUCCESS, "");
|
PrintAndLogEx(SUCCESS, "");
|
||||||
}
|
}
|
||||||
|
|
@ -1902,7 +1919,7 @@ void DesfirePrintAppList(DesfireContext_t *dctx, PICCInfo_t *PICCInfo, AppListS
|
||||||
PrintKeySettings(appList[i].keySettings, appList[i].numKeysRaw, true, true);
|
PrintKeySettings(appList[i].keySettings, appList[i].numKeysRaw, true, true);
|
||||||
|
|
||||||
if (appList[i].numberOfKeys > 0) {
|
if (appList[i].numberOfKeys > 0) {
|
||||||
PrintAndLogEx(SUCCESS, "Key versions [0..%d]: " NOLF, appList[i].numberOfKeys - 1);
|
PrintAndLogEx(SUCCESS, "Key versions [0..%d] " NOLF, appList[i].numberOfKeys - 1);
|
||||||
for (uint8_t keyn = 0; keyn < appList[i].numberOfKeys; keyn++) {
|
for (uint8_t keyn = 0; keyn < appList[i].numberOfKeys; keyn++) {
|
||||||
PrintAndLogEx(NORMAL, "%s %02x" NOLF, (keyn == 0) ? "" : ",", appList[i].keyVersions[keyn]);
|
PrintAndLogEx(NORMAL, "%s %02x" NOLF, (keyn == 0) ? "" : ",", appList[i].keyVersions[keyn]);
|
||||||
}
|
}
|
||||||
|
|
@ -2254,7 +2271,7 @@ int DesfireUpdateRecord(DesfireContext_t *dctx, uint8_t fnum, uint32_t recnum, u
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintKeySettingsPICC(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) {
|
static void PrintKeySettingsPICC(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) {
|
||||||
PrintAndLogEx(SUCCESS, "PICC level rights:");
|
PrintAndLogEx(SUCCESS, "PICC level rights");
|
||||||
PrintAndLogEx(SUCCESS, "[%c...] CMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
|
PrintAndLogEx(SUCCESS, "[%c...] CMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
|
||||||
PrintAndLogEx(SUCCESS, "[.%c..] CMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES");
|
PrintAndLogEx(SUCCESS, "[.%c..] CMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES");
|
||||||
PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with CMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES");
|
PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with CMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES");
|
||||||
|
|
@ -2263,27 +2280,27 @@ static void PrintKeySettingsPICC(uint8_t keysettings, uint8_t numkeys, bool prin
|
||||||
|
|
||||||
if (print2ndbyte) {
|
if (print2ndbyte) {
|
||||||
DesfirePrintCardKeyType(numkeys >> 6);
|
DesfirePrintCardKeyType(numkeys >> 6);
|
||||||
PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f);
|
PrintAndLogEx(SUCCESS, "Key cnt.... " _YELLOW_("%d"), numkeys & 0x0F);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) {
|
static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) {
|
||||||
// Access rights.
|
// Access rights.
|
||||||
PrintAndLogEx(SUCCESS, "Application level rights:");
|
PrintAndLogEx(SUCCESS, "Application level rights");
|
||||||
uint8_t rights = ((keysettings >> 4) & 0x0F);
|
uint8_t rights = ((keysettings >> 4) & 0x0F);
|
||||||
switch (rights) {
|
switch (rights) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
PrintAndLogEx(SUCCESS, "-- AMK authentication is necessary to change any key (default)");
|
PrintAndLogEx(SUCCESS, " - AMK authentication is necessary to change any key (default)");
|
||||||
break;
|
break;
|
||||||
case 0xE:
|
case 0xE:
|
||||||
PrintAndLogEx(SUCCESS, "-- Authentication with the key to be changed (same KeyNo) is necessary to change a key");
|
PrintAndLogEx(SUCCESS, " - Authentication with the key to be changed (same KeyNo) is necessary to change a key");
|
||||||
break;
|
break;
|
||||||
case 0xF:
|
case 0xF:
|
||||||
PrintAndLogEx(SUCCESS, "-- All keys (except AMK,see Bit0) within this application are frozen");
|
PrintAndLogEx(SUCCESS, " - All keys (except AMK,see Bit0) within this application are frozen");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(SUCCESS,
|
PrintAndLogEx(SUCCESS,
|
||||||
"-- Authentication with the specified key " _YELLOW_("(0x%02x)") " is necessary to change any key.\n"
|
" - Authentication with the specified key " _YELLOW_("(0x%02x)") " is necessary to change any key.\n"
|
||||||
"A change key and a PICC master key (CMK) can only be changed after authentication with the master key.\n"
|
"A change key and a PICC master key (CMK) can only be changed after authentication with the master key.\n"
|
||||||
"For keys other then the master or change key, an authentication with the same key is needed.",
|
"For keys other then the master or change key, an authentication with the same key is needed.",
|
||||||
rights & 0x0f
|
rights & 0x0f
|
||||||
|
|
@ -2299,10 +2316,10 @@ static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print
|
||||||
|
|
||||||
if (print2ndbyte) {
|
if (print2ndbyte) {
|
||||||
DesfirePrintCardKeyType(numkeys >> 6);
|
DesfirePrintCardKeyType(numkeys >> 6);
|
||||||
PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f);
|
PrintAndLogEx(SUCCESS, "Key cnt.... " _YELLOW_("%d"), numkeys & 0x0F);
|
||||||
if (numkeys & 0x20)
|
if (numkeys & 0x20) {
|
||||||
PrintAndLogEx(SUCCESS, "iso file id: enabled");
|
PrintAndLogEx(SUCCESS, "iso file id: enabled");
|
||||||
PrintAndLogEx(SUCCESS, "");
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -504,16 +504,16 @@ uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorithm keyType) {
|
||||||
void DesfirePrintCardKeyType(uint8_t keyType) {
|
void DesfirePrintCardKeyType(uint8_t keyType) {
|
||||||
switch (keyType) {
|
switch (keyType) {
|
||||||
case 00:
|
case 00:
|
||||||
PrintAndLogEx(SUCCESS, "Key: 2TDEA");
|
PrintAndLogEx(SUCCESS, "Key type... " _YELLOW_("2TDEA"));
|
||||||
break;
|
break;
|
||||||
case 01:
|
case 01:
|
||||||
PrintAndLogEx(SUCCESS, "Key: 3TDEA");
|
PrintAndLogEx(SUCCESS, "Key type... " _YELLOW_("3TDEA"));
|
||||||
break;
|
break;
|
||||||
case 02:
|
case 02:
|
||||||
PrintAndLogEx(SUCCESS, "Key: AES");
|
PrintAndLogEx(SUCCESS, "Key type... " _YELLOW_("AES"));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(SUCCESS, "Key: unknown: 0x%02x", keyType);
|
PrintAndLogEx(SUCCESS, "Key type... " _YELLOW_("unknown") " - 0x%02x", keyType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,13 @@ static int open_mad_file(json_t **root, bool verbose) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
PrintAndLogEx(SUCCESS, "Loaded file " _YELLOW_("`%s`") " (%s) %zu records.", path, _GREEN_("ok"), json_array_size(*root));
|
PrintAndLogEx(SUCCESS, "Loaded file `" _YELLOW_("%s") "` " _GREEN_("%zu") " records ( " _GREEN_("ok") " )"
|
||||||
|
, path
|
||||||
|
, json_array_size(*root)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
free(path);
|
free(path);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -183,7 +188,7 @@ static uint16_t madGetAID(const uint8_t *sector, bool swapmad, int MADver, int s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2) {
|
int MADCheck(uint8_t *sector0, uint8_t *sector16, bool verbose, bool *haveMAD2) {
|
||||||
|
|
||||||
if (sector0 == NULL)
|
if (sector0 == NULL)
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
|
|
@ -217,13 +222,13 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2)
|
||||||
PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( %s )", sector0[16], _GREEN_("ok"));
|
PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( %s )", sector0[16], _GREEN_("ok"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mad_ver == 2 && sector10) {
|
if (mad_ver == 2 && sector16) {
|
||||||
int res2 = madCRCCheck(sector10, true, 2);
|
int res2 = madCRCCheck(sector16, true, 2);
|
||||||
if (res == PM3_SUCCESS)
|
if (res == PM3_SUCCESS)
|
||||||
res = res2;
|
res = res2;
|
||||||
|
|
||||||
if (verbose && !res2)
|
if (verbose && !res2)
|
||||||
PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( %s )", sector10[0], _GREEN_("ok"));
|
PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( %s )", sector16[0], _GREEN_("ok"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MA (multi-application card)
|
// MA (multi-application card)
|
||||||
|
|
@ -236,27 +241,30 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen, bool swapmad) {
|
int MADDecode(uint8_t *sector0, uint8_t *sector16, uint16_t *mad, size_t *madlen, bool swapmad) {
|
||||||
*madlen = 0;
|
*madlen = 0;
|
||||||
bool haveMAD2 = false;
|
bool haveMAD2 = false;
|
||||||
int res = MADCheck(sector0, sector10, false, &haveMAD2);
|
int res = MADCheck(sector0, sector16, false, &haveMAD2);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(WARNING, "Not a valid MAD");
|
PrintAndLogEx(WARNING, "Not a valid MAD");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i < 16; i++) {
|
// 7 + 8 == 15
|
||||||
|
for (int i = 1; i <= 16; i++) {
|
||||||
mad[*madlen] = madGetAID(sector0, swapmad, 1, i);
|
mad[*madlen] = madGetAID(sector0, swapmad, 1, i);
|
||||||
(*madlen)++;
|
(*madlen)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (haveMAD2) {
|
if (haveMAD2) {
|
||||||
// mad2 sector (0x10 == 16dec) here
|
// mad2 sector (0x10 == 16) here
|
||||||
mad[*madlen] = 0x0005;
|
mad[*madlen] = 0x0005;
|
||||||
(*madlen)++;
|
(*madlen)++;
|
||||||
|
|
||||||
|
// 7 + 8 + 8 == 23
|
||||||
for (int i = 1; i < 24; i++) {
|
for (int i = 1; i < 24; i++) {
|
||||||
mad[*madlen] = madGetAID(sector10, swapmad, 2, i);
|
mad[*madlen] = madGetAID(sector16, swapmad, 2, i);
|
||||||
|
|
||||||
(*madlen)++;
|
(*madlen)++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -347,8 +355,16 @@ int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMA
|
||||||
aid
|
aid
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
char fmt[60];
|
char fmt[80];
|
||||||
snprintf(fmt, sizeof(fmt), (ibs == i) ? _MAGENTA_(" %02d [%04X]%s") : " %02d [" _GREEN_("%04X") "]%s", i, aid, "%s");
|
snprintf(fmt
|
||||||
|
, sizeof(fmt)
|
||||||
|
, (ibs == i) ?
|
||||||
|
_MAGENTA_(" %02d [%04X] %s") :
|
||||||
|
" %02d [" _GREEN_("%04X") "] %s"
|
||||||
|
, i
|
||||||
|
, aid
|
||||||
|
, "%s"
|
||||||
|
);
|
||||||
print_aid_description(mad_known_aids, aid, fmt, verbose);
|
print_aid_description(mad_known_aids, aid, fmt, verbose);
|
||||||
prev_aid = aid;
|
prev_aid = aid;
|
||||||
}
|
}
|
||||||
|
|
@ -400,8 +416,16 @@ int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) {
|
||||||
aid
|
aid
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
char fmt[60];
|
char fmt[80];
|
||||||
snprintf(fmt, sizeof(fmt), (ibs == i) ? _MAGENTA_(" %02d [%04X]%s") : " %02d [" _GREEN_("%04X") "]%s", i + 16, aid, "%s");
|
snprintf(fmt
|
||||||
|
, sizeof(fmt)
|
||||||
|
, (ibs == i) ?
|
||||||
|
_MAGENTA_(" %02d [%04X] %s") :
|
||||||
|
" %02d [" _GREEN_("%04X") "] %s"
|
||||||
|
, i + 16
|
||||||
|
, aid
|
||||||
|
, "%s"
|
||||||
|
);
|
||||||
print_aid_description(mad_known_aids, aid, fmt, verbose);
|
print_aid_description(mad_known_aids, aid, fmt, verbose);
|
||||||
prev_aid = aid;
|
prev_aid = aid;
|
||||||
}
|
}
|
||||||
|
|
@ -415,7 +439,7 @@ int MADDFDecodeAndPrint(uint32_t short_aid, bool verbose) {
|
||||||
open_mad_file(&mad_known_aids, false);
|
open_mad_file(&mad_known_aids, false);
|
||||||
|
|
||||||
char fmt[128];
|
char fmt[128];
|
||||||
snprintf(fmt, sizeof(fmt), " MAD AID Function 0x%04X :" _YELLOW_("%s"), short_aid, "%s");
|
snprintf(fmt, sizeof(fmt), " MAD AID Function 0x%04X... " _YELLOW_("%s"), short_aid, "%s");
|
||||||
print_aid_description(mad_known_aids, short_aid, fmt, verbose);
|
print_aid_description(mad_known_aids, short_aid, fmt, verbose);
|
||||||
close_mad_file(mad_known_aids);
|
close_mad_file(mad_known_aids);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
|
@ -429,8 +453,9 @@ bool HasMADKey(uint8_t *d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int DetectHID(uint8_t *d, uint16_t manufacture) {
|
int DetectHID(uint8_t *d, uint16_t manufacture) {
|
||||||
if (d == NULL)
|
if (d == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// find HID
|
// find HID
|
||||||
for (int i = 1; i < 16; i++) {
|
for (int i = 1; i < 16; i++) {
|
||||||
|
|
@ -456,16 +481,16 @@ int convert_mad_to_arr(uint8_t *in, uint16_t ilen, uint8_t *out, uint16_t *olen)
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sector0[MFBLOCK_SIZE * 4] = {0};
|
uint8_t sector0[MFBLOCK_SIZE * 4] = {0};
|
||||||
uint8_t sector10[MFBLOCK_SIZE * 4] = {0};
|
uint8_t sector16[MFBLOCK_SIZE * 4] = {0};
|
||||||
|
|
||||||
memcpy(sector0, in, sizeof(sector0));
|
memcpy(sector0, in, sizeof(sector0));
|
||||||
if (ilen == MIFARE_4K_MAX_BYTES) {
|
if (ilen == MIFARE_4K_MAX_BYTES) {
|
||||||
memcpy(sector10, in + (MF_MAD2_SECTOR * 4 * MFBLOCK_SIZE), sizeof(sector10));
|
memcpy(sector16, in + (MF_MAD2_SECTOR * 4 * MFBLOCK_SIZE), sizeof(sector16));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
|
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
|
||||||
size_t madlen = 0;
|
size_t madlen = 0;
|
||||||
if (MADDecode(sector0, sector10, mad, &madlen, false)) {
|
if (MADDecode(sector0, sector16, mad, &madlen, false)) {
|
||||||
PrintAndLogEx(ERR, "can't decode MAD");
|
PrintAndLogEx(ERR, "can't decode MAD");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2);
|
int MADCheck(uint8_t *sector0, uint8_t *sector16, bool verbose, bool *haveMAD2);
|
||||||
int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen, bool swapmad);
|
int MADDecode(uint8_t *sector0, uint8_t *sector16, uint16_t *mad, size_t *madlen, bool swapmad);
|
||||||
int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMAD2);
|
int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMAD2);
|
||||||
int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose);
|
int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose);
|
||||||
int MADDFDecodeAndPrint(uint32_t short_aid, bool verbose);
|
int MADDFDecodeAndPrint(uint32_t short_aid, bool verbose);
|
||||||
|
|
|
||||||
|
|
@ -291,9 +291,16 @@ int mf_check_keys_fast_ex(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastCh
|
||||||
|
|
||||||
if ((singleSectorParams >> 15) & 1) {
|
if ((singleSectorParams >> 15) & 1) {
|
||||||
if (curr_keys) {
|
if (curr_keys) {
|
||||||
uint64_t foo = bytes_to_num(resp.data.asBytes, 6);
|
// uint64_t foo = bytes_to_num(resp.data.asBytes, 6);
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(SUCCESS, _GREEN_("Key %s for block %2i found: %012" PRIx64), (singleSectorParams >> 8) & 1 ? "B" : "A", singleSectorParams & 0xFF, foo);
|
// PrintAndLogEx(SUCCESS, "found Key %s for block %2i found: " _GREEN_("%012" PRIx64), (singleSectorParams >> 8) & 1 ? "B" : "A", singleSectorParams & 0xFF, foo);
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "\nTarget block %4u key type %c -- found valid key [ " _GREEN_("%s") " ]",
|
||||||
|
singleSectorParams & 0xFF,
|
||||||
|
((singleSectorParams >> 8) & 1) ? 'B' : 'A',
|
||||||
|
sprint_hex_inrow(resp.data.asBytes, MIFARE_KEY_SIZE)
|
||||||
|
);
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1029,19 +1036,25 @@ int mf_write_sector(uint8_t sectorNo, uint8_t keyType, const uint8_t *key, uint8
|
||||||
|
|
||||||
// EMULATOR
|
// EMULATOR
|
||||||
int mf_eml_get_mem(uint8_t *data, int blockNum, int blocksCount) {
|
int mf_eml_get_mem(uint8_t *data, int blockNum, int blocksCount) {
|
||||||
|
return mf_eml_get_mem_xt(data, blockNum, blocksCount, MFBLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
size_t size = blocksCount * MFBLOCK_SIZE;
|
int mf_eml_get_mem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth) {
|
||||||
|
|
||||||
|
size_t size = ((size_t) blocksCount) * blockBtWidth;
|
||||||
if (size > PM3_CMD_DATA_SIZE) {
|
if (size > PM3_CMD_DATA_SIZE) {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t blockno;
|
uint16_t blockno;
|
||||||
uint8_t blockcnt;
|
uint8_t blockcnt;
|
||||||
|
uint8_t blockwidth;
|
||||||
} PACKED payload;
|
} PACKED payload;
|
||||||
|
|
||||||
payload.blockno = blockNum;
|
payload.blockno = blockNum;
|
||||||
payload.blockcnt = blocksCount;
|
payload.blockcnt = blocksCount;
|
||||||
|
payload.blockwidth = blockBtWidth;
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_MIFARE_EML_MEMGET, (uint8_t *)&payload, sizeof(payload));
|
SendCommandNG(CMD_HF_MIFARE_EML_MEMGET, (uint8_t *)&payload, sizeof(payload));
|
||||||
|
|
@ -1052,8 +1065,9 @@ int mf_eml_get_mem(uint8_t *data, int blockNum, int blocksCount) {
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp.status == PM3_SUCCESS)
|
if (resp.status == PM3_SUCCESS) {
|
||||||
memcpy(data, resp.data.asBytes, size);
|
memcpy(data, resp.data.asBytes, size);
|
||||||
|
}
|
||||||
|
|
||||||
return resp.status;
|
return resp.status;
|
||||||
}
|
}
|
||||||
|
|
@ -1065,7 +1079,7 @@ int mf_elm_set_mem(uint8_t *data, int blockNum, int blocksCount) {
|
||||||
int mf_eml_set_mem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth) {
|
int mf_eml_set_mem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth) {
|
||||||
|
|
||||||
struct p {
|
struct p {
|
||||||
uint8_t blockno;
|
uint16_t blockno;
|
||||||
uint8_t blockcnt;
|
uint8_t blockcnt;
|
||||||
uint8_t blockwidth;
|
uint8_t blockwidth;
|
||||||
uint8_t data[];
|
uint8_t data[];
|
||||||
|
|
@ -1219,7 +1233,7 @@ int mf_chinese_set_block(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t p
|
||||||
if (!isOK) {
|
if (!isOK) {
|
||||||
|
|
||||||
uint8_t reason = (resp.oldarg[1] & 0xFF);
|
uint8_t reason = (resp.oldarg[1] & 0xFF);
|
||||||
if ( reason == 4) {
|
if (reason == 4) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(WARNING, "GDM magic write signature block failed");
|
PrintAndLogEx(WARNING, "GDM magic write signature block failed");
|
||||||
} else if (reason == 5) {
|
} else if (reason == 5) {
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,7 @@ int mf_write_block(uint8_t blockno, uint8_t keyType, const uint8_t *key, uint8_t
|
||||||
int mf_write_sector(uint8_t sectorNo, uint8_t keyType, const uint8_t *key, uint8_t *sector);
|
int mf_write_sector(uint8_t sectorNo, uint8_t keyType, const uint8_t *key, uint8_t *sector);
|
||||||
|
|
||||||
int mf_eml_get_mem(uint8_t *data, int blockNum, int blocksCount);
|
int mf_eml_get_mem(uint8_t *data, int blockNum, int blocksCount);
|
||||||
|
int mf_eml_get_mem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth);
|
||||||
int mf_elm_set_mem(uint8_t *data, int blockNum, int blocksCount);
|
int mf_elm_set_mem(uint8_t *data, int blockNum, int blocksCount);
|
||||||
int mf_eml_set_mem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth);
|
int mf_eml_set_mem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,7 @@ const static vocabulary_t vocabulary[] = {
|
||||||
{ 0, "hf 15 slixeasenable" },
|
{ 0, "hf 15 slixeasenable" },
|
||||||
{ 0, "hf 15 slixprivacydisable" },
|
{ 0, "hf 15 slixprivacydisable" },
|
||||||
{ 0, "hf 15 slixprivacyenable" },
|
{ 0, "hf 15 slixprivacyenable" },
|
||||||
|
{ 0, "hf 15 slixprotectpage" },
|
||||||
{ 0, "hf 15 passprotectafi" },
|
{ 0, "hf 15 passprotectafi" },
|
||||||
{ 0, "hf 15 passprotecteas" },
|
{ 0, "hf 15 passprotecteas" },
|
||||||
{ 0, "hf 15 findafi" },
|
{ 0, "hf 15 findafi" },
|
||||||
|
|
|
||||||
|
|
@ -344,12 +344,14 @@ static int l_WaitForResponseTimeout(lua_State *L) {
|
||||||
return returnToLuaWithError(L, "You need to supply at least command to wait for");
|
return returnToLuaWithError(L, "You need to supply at least command to wait for");
|
||||||
|
|
||||||
// extract first param. cmd byte to look for
|
// extract first param. cmd byte to look for
|
||||||
if (n >= 1)
|
if (n >= 1) {
|
||||||
cmd = (uint32_t)luaL_checkinteger(L, 1);
|
cmd = (uint32_t)luaL_checkinteger(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// extract second param. timeout value
|
// extract second param. timeout value
|
||||||
if (n >= 2)
|
if (n >= 2) {
|
||||||
ms_timeout = luaL_checkinteger(L, 2);
|
ms_timeout = (size_t)luaL_checkinteger(L, 2);
|
||||||
|
}
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(cmd, &resp, ms_timeout) == false) {
|
if (WaitForResponseTimeout(cmd, &resp, ms_timeout) == false) {
|
||||||
|
|
@ -740,8 +742,9 @@ static int l_reveng_models(lua_State *L) {
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
uint8_t in_width = (uint8_t)luaL_checkinteger(L, 1);
|
uint8_t in_width = (uint8_t)luaL_checkinteger(L, 1);
|
||||||
if (in_width > 89)
|
if (in_width > 89) {
|
||||||
return returnToLuaWithError(L, "Width cannot exceed 89, got %d", in_width);
|
return returnToLuaWithError(L, "Width cannot exceed 89, got %d", in_width);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t width[NMODELS];
|
uint8_t width[NMODELS];
|
||||||
memset(width, 0, sizeof(width));
|
memset(width, 0, sizeof(width));
|
||||||
|
|
@ -749,8 +752,9 @@ static int l_reveng_models(lua_State *L) {
|
||||||
|
|
||||||
width[0] = in_width;
|
width[0] = in_width;
|
||||||
|
|
||||||
if (!GetModels(models, &count, width))
|
if (!GetModels(models, &count, width)) {
|
||||||
return returnToLuaWithError(L, "didn't find any models");
|
return returnToLuaWithError(L, "didn't find any models");
|
||||||
|
}
|
||||||
|
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
|
|
|
||||||
|
|
@ -152,10 +152,10 @@ void FillFileNameByUID(char *filenamePrefix, const uint8_t *uid, const char *ext
|
||||||
|
|
||||||
int len = strlen(filenamePrefix);
|
int len = strlen(filenamePrefix);
|
||||||
|
|
||||||
for (int j = 0; j < uidlen; j++) {
|
for (int i = 0; i < uidlen; i++) {
|
||||||
// This is technically not the safest option, but there is no way to make this work without changing the function signature
|
// This is technically not the safest option, but there is no way to make this work without changing the function signature
|
||||||
// Possibly todo for future PR, but given UID lenghts are defined by program and not variable, should not be an issue
|
// Possibly todo for future PR, but given UID lenghts are defined by program and not variable, should not be an issue
|
||||||
snprintf(filenamePrefix + len + j * 2, 3, "%02X", uid[j]);
|
snprintf(filenamePrefix + len + i * 2, 3, "%02X", uid[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
strcat(filenamePrefix, ext);
|
strcat(filenamePrefix, ext);
|
||||||
|
|
@ -196,7 +196,7 @@ bool CheckStringIsHEXValue(const char *value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < strlen(value); i++) {
|
for (size_t i = 0; i < strlen(value); i++) {
|
||||||
if (!isxdigit(value[i])) {
|
if (isxdigit(value[i]) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -220,11 +220,13 @@ void ascii_to_buffer(uint8_t *buf, const uint8_t *hex_data, const size_t hex_len
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t m = (min_str_len > i) ? min_str_len : 0;
|
size_t m = (min_str_len > i) ? min_str_len : 0;
|
||||||
if (m > hex_max_len)
|
if (m > hex_max_len) {
|
||||||
m = hex_max_len;
|
m = hex_max_len;
|
||||||
|
}
|
||||||
|
|
||||||
for (; i < m; i++, tmp++)
|
for (; i < m; i++, tmp++) {
|
||||||
*tmp = ' ';
|
*tmp = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
// remove last space
|
// remove last space
|
||||||
*tmp = '\0';
|
*tmp = '\0';
|
||||||
|
|
@ -234,8 +236,9 @@ void hex_to_buffer(uint8_t *buf, const uint8_t *hex_data, const size_t hex_len,
|
||||||
const size_t min_str_len, const size_t spaces_between, bool uppercase) {
|
const size_t min_str_len, const size_t spaces_between, bool uppercase) {
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (buf == NULL || hex_len < 1)
|
if (buf == NULL || hex_len < 1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 1. hex string length.
|
// 1. hex string length.
|
||||||
// 2. byte array to be converted to string
|
// 2. byte array to be converted to string
|
||||||
|
|
@ -252,18 +255,22 @@ void hex_to_buffer(uint8_t *buf, const uint8_t *hex_data, const size_t hex_len,
|
||||||
*(tmp++) = b2s((hex_data[i] >> 4), uppercase);
|
*(tmp++) = b2s((hex_data[i] >> 4), uppercase);
|
||||||
*(tmp++) = b2s(hex_data[i], uppercase);
|
*(tmp++) = b2s(hex_data[i], uppercase);
|
||||||
|
|
||||||
for (size_t j = 0; j < spaces_between; j++)
|
for (size_t j = 0; j < spaces_between; j++) {
|
||||||
*(tmp++) = ' ';
|
*(tmp++) = ' ';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
i *= (2 + spaces_between);
|
i *= (2 + spaces_between);
|
||||||
|
|
||||||
size_t m = (min_str_len > i) ? min_str_len : 0;
|
size_t m = (min_str_len > i) ? min_str_len : 0;
|
||||||
if (m > hex_max_len)
|
|
||||||
m = hex_max_len;
|
|
||||||
|
|
||||||
while (m--)
|
if (m > hex_max_len) {
|
||||||
|
m = hex_max_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (m--) {
|
||||||
*(tmp++) = ' ';
|
*(tmp++) = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
// remove last space
|
// remove last space
|
||||||
*tmp = '\0';
|
*tmp = '\0';
|
||||||
|
|
@ -274,9 +281,9 @@ void hex_to_buffer(uint8_t *buf, const uint8_t *hex_data, const size_t hex_len,
|
||||||
void print_hex(const uint8_t *data, const size_t len) {
|
void print_hex(const uint8_t *data, const size_t len) {
|
||||||
if (data == NULL || len == 0) return;
|
if (data == NULL || len == 0) return;
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i++)
|
for (size_t i = 0; i < len; i++) {
|
||||||
PrintAndLogEx(NORMAL, "%02x " NOLF, data[i]);
|
PrintAndLogEx(NORMAL, "%02x " NOLF, data[i]);
|
||||||
|
}
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -621,10 +628,13 @@ char *sprint_breakdown_bin(color_t color, const char *bs, int width, int padn, i
|
||||||
}
|
}
|
||||||
|
|
||||||
int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen) {
|
int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen) {
|
||||||
|
|
||||||
char buf[4] = {0};
|
char buf[4] = {0};
|
||||||
int indx = 0;
|
int indx = 0;
|
||||||
int bytesValueLen = 0;
|
int bytesValueLen = 0;
|
||||||
|
|
||||||
while (hexValue[indx]) {
|
while (hexValue[indx]) {
|
||||||
|
|
||||||
if (hexValue[indx] == '\t' || hexValue[indx] == ' ') {
|
if (hexValue[indx] == '\t' || hexValue[indx] == ' ') {
|
||||||
indx++;
|
indx++;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -684,6 +694,7 @@ void bytes_to_bytebits(const void *src, const size_t srclen, void *dest) {
|
||||||
|
|
||||||
uint32_t i = srclen * 8;
|
uint32_t i = srclen * 8;
|
||||||
size_t j = srclen;
|
size_t j = srclen;
|
||||||
|
|
||||||
while (j--) {
|
while (j--) {
|
||||||
uint8_t b = s[j];
|
uint8_t b = s[j];
|
||||||
d[--i] = (b >> 0) & 1;
|
d[--i] = (b >> 0) & 1;
|
||||||
|
|
@ -740,20 +751,33 @@ int param_getptr(const char *line, int *bg, int *en, int paramnum) {
|
||||||
*en = 0;
|
*en = 0;
|
||||||
|
|
||||||
// skip spaces
|
// skip spaces
|
||||||
while (line[*bg] == ' ' || line[*bg] == '\t')(*bg)++;
|
while (line[*bg] == ' ' || line[*bg] == '\t') {
|
||||||
|
(*bg)++;
|
||||||
|
}
|
||||||
|
|
||||||
if (*bg >= len) {
|
if (*bg >= len) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < paramnum; i++) {
|
for (i = 0; i < paramnum; i++) {
|
||||||
while (line[*bg] != ' ' && line[*bg] != '\t' && line[*bg] != '\0')(*bg)++;
|
|
||||||
while (line[*bg] == ' ' || line[*bg] == '\t')(*bg)++;
|
|
||||||
|
|
||||||
if (line[*bg] == '\0') return 1;
|
while (line[*bg] != ' ' && line[*bg] != '\t' && line[*bg] != '\0') {
|
||||||
|
(*bg)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (line[*bg] == ' ' || line[*bg] == '\t') {
|
||||||
|
(*bg)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line[*bg] == '\0') {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*en = *bg;
|
*en = *bg;
|
||||||
while (line[*en] != ' ' && line[*en] != '\t' && line[*en] != '\0')(*en)++;
|
while (line[*en] != ' ' && line[*en] != '\t' && line[*en] != '\0') {
|
||||||
|
(*en)++;
|
||||||
|
}
|
||||||
|
|
||||||
(*en)--;
|
(*en)--;
|
||||||
|
|
||||||
|
|
@ -763,7 +787,9 @@ int param_getptr(const char *line, int *bg, int *en, int paramnum) {
|
||||||
int param_getlength(const char *line, int paramnum) {
|
int param_getlength(const char *line, int paramnum) {
|
||||||
int bg, en;
|
int bg, en;
|
||||||
|
|
||||||
if (param_getptr(line, &bg, &en, paramnum)) return 0;
|
if (param_getptr(line, &bg, &en, paramnum)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return en - bg + 1;
|
return en - bg + 1;
|
||||||
}
|
}
|
||||||
|
|
@ -775,10 +801,13 @@ char param_getchar(const char *line, int paramnum) {
|
||||||
char param_getchar_indx(const char *line, int indx, int paramnum) {
|
char param_getchar_indx(const char *line, int indx, int paramnum) {
|
||||||
int bg, en;
|
int bg, en;
|
||||||
|
|
||||||
if (param_getptr(line, &bg, &en, paramnum)) return 0x00;
|
if (param_getptr(line, &bg, &en, paramnum)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (bg + indx > en)
|
if (bg + indx > en) {
|
||||||
return '\0';
|
return '\0';
|
||||||
|
}
|
||||||
|
|
||||||
return line[bg + indx];
|
return line[bg + indx];
|
||||||
}
|
}
|
||||||
|
|
@ -795,7 +824,9 @@ uint8_t param_get8(const char *line, int paramnum) {
|
||||||
*/
|
*/
|
||||||
uint8_t param_getdec(const char *line, int paramnum, uint8_t *destination) {
|
uint8_t param_getdec(const char *line, int paramnum, uint8_t *destination) {
|
||||||
uint8_t val = param_get8ex(line, paramnum, 255, 10);
|
uint8_t val = param_get8ex(line, paramnum, 255, 10);
|
||||||
if ((int8_t) val == -1) return 1;
|
if ((int8_t) val == -1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
(*destination) = val;
|
(*destination) = val;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -808,49 +839,56 @@ uint8_t param_getdec(const char *line, int paramnum, uint8_t *destination) {
|
||||||
uint8_t param_isdec(const char *line, int paramnum) {
|
uint8_t param_isdec(const char *line, int paramnum) {
|
||||||
int bg, en;
|
int bg, en;
|
||||||
//TODO, check more thorougly
|
//TODO, check more thorougly
|
||||||
if (!param_getptr(line, &bg, &en, paramnum)) return 1;
|
if (!param_getptr(line, &bg, &en, paramnum)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
// return strtoul(&line[bg], NULL, 10) & 0xff;
|
// return strtoul(&line[bg], NULL, 10) & 0xff;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base) {
|
uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base) {
|
||||||
int bg, en;
|
int bg, en;
|
||||||
if (!param_getptr(line, &bg, &en, paramnum))
|
if (param_getptr(line, &bg, &en, paramnum) == 0) {
|
||||||
return strtoul(&line[bg], NULL, base) & 0xff;
|
return strtoul(&line[bg], NULL, base) & 0xff;
|
||||||
else
|
} else {
|
||||||
return deflt;
|
return deflt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t param_get32ex(const char *line, int paramnum, int deflt, int base) {
|
uint32_t param_get32ex(const char *line, int paramnum, int deflt, int base) {
|
||||||
int bg, en;
|
int bg, en;
|
||||||
if (!param_getptr(line, &bg, &en, paramnum))
|
if (param_getptr(line, &bg, &en, paramnum) == 0) {
|
||||||
return strtoul(&line[bg], NULL, base);
|
return strtoul(&line[bg], NULL, base);
|
||||||
else
|
} else {
|
||||||
return deflt;
|
return deflt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base) {
|
uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base) {
|
||||||
int bg, en;
|
int bg, en;
|
||||||
if (!param_getptr(line, &bg, &en, paramnum))
|
if (param_getptr(line, &bg, &en, paramnum) == 0) {
|
||||||
return strtoull(&line[bg], NULL, base);
|
return strtoull(&line[bg], NULL, base);
|
||||||
else
|
} else {
|
||||||
return deflt;
|
return deflt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float param_getfloat(const char *line, int paramnum, float deflt) {
|
float param_getfloat(const char *line, int paramnum, float deflt) {
|
||||||
int bg, en;
|
int bg, en;
|
||||||
if (!param_getptr(line, &bg, &en, paramnum))
|
if (param_getptr(line, &bg, &en, paramnum) == 0) {
|
||||||
return strtof(&line[bg], NULL);
|
return strtof(&line[bg], NULL);
|
||||||
else
|
} else {
|
||||||
return deflt;
|
return deflt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int param_gethex_ex(const char *line, int paramnum, uint8_t *data, int *hexcnt) {
|
int param_gethex_ex(const char *line, int paramnum, uint8_t *data, int *hexcnt) {
|
||||||
int bg, en, i;
|
int bg, en, i;
|
||||||
uint32_t temp;
|
uint32_t temp;
|
||||||
|
|
||||||
if (param_getptr(line, &bg, &en, paramnum)) return 1;
|
if (param_getptr(line, &bg, &en, paramnum)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
*hexcnt = en - bg + 1;
|
*hexcnt = en - bg + 1;
|
||||||
|
|
||||||
|
|
@ -860,7 +898,9 @@ int param_gethex_ex(const char *line, int paramnum, uint8_t *data, int *hexcnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < *hexcnt; i += 2) {
|
for (i = 0; i < *hexcnt; i += 2) {
|
||||||
if (!(isxdigit(line[bg + i]) && isxdigit(line[bg + i + 1]))) return 1;
|
if (!(isxdigit(line[bg + i]) && isxdigit(line[bg + i + 1]))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
sscanf((char[]) {line[bg + i], line[bg + i + 1], 0}, "%X", &temp);
|
sscanf((char[]) {line[bg + i], line[bg + i + 1], 0}, "%X", &temp);
|
||||||
data[i / 2] = temp & 0xff;
|
data[i / 2] = temp & 0xff;
|
||||||
|
|
@ -873,14 +913,16 @@ int param_gethex_to_eol(const char *line, int paramnum, uint8_t *data, int maxda
|
||||||
|
|
||||||
int bg, en;
|
int bg, en;
|
||||||
|
|
||||||
if (param_getptr(line, &bg, &en, paramnum))
|
if (param_getptr(line, &bg, &en, paramnum)) {
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
*datalen = 0;
|
*datalen = 0;
|
||||||
char buf[5] = {0};
|
char buf[5] = {0};
|
||||||
|
|
||||||
int indx = bg;
|
int indx = bg;
|
||||||
while (line[indx]) {
|
while (line[indx]) {
|
||||||
|
|
||||||
if (line[indx] == '\t' || line[indx] == ' ') {
|
if (line[indx] == '\t' || line[indx] == ' ') {
|
||||||
indx++;
|
indx++;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -910,9 +952,10 @@ int param_gethex_to_eol(const char *line, int paramnum, uint8_t *data, int maxda
|
||||||
indx++;
|
indx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(buf) > 0)
|
if (strlen(buf) > 0) {
|
||||||
//error when not completed hex bytes
|
//error when not completed hex bytes
|
||||||
return 3;
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -927,6 +970,7 @@ int param_getbin_to_eol(const char *line, int paramnum, uint8_t *data, int maxda
|
||||||
char buf[5] = {0};
|
char buf[5] = {0};
|
||||||
int indx = bg;
|
int indx = bg;
|
||||||
while (line[indx]) {
|
while (line[indx]) {
|
||||||
|
|
||||||
if (line[indx] == '\t' || line[indx] == ' ') {
|
if (line[indx] == '\t' || line[indx] == ' ') {
|
||||||
indx++;
|
indx++;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -992,11 +1036,14 @@ int hextobinarray_n(char *target, char *source, int sourcelen) {
|
||||||
char *start = source;
|
char *start = source;
|
||||||
// process 4 bits (1 hex digit) at a time
|
// process 4 bits (1 hex digit) at a time
|
||||||
while (sourcelen--) {
|
while (sourcelen--) {
|
||||||
|
|
||||||
char x = *(source++);
|
char x = *(source++);
|
||||||
|
|
||||||
// capitalize
|
// capitalize
|
||||||
if (x >= 'a' && x <= 'f') {
|
if (x >= 'a' && x <= 'f') {
|
||||||
x -= 32;
|
x -= 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert to numeric value
|
// convert to numeric value
|
||||||
if (x >= '0' && x <= '9') {
|
if (x >= '0' && x <= '9') {
|
||||||
x -= '0';
|
x -= '0';
|
||||||
|
|
@ -1006,6 +1053,7 @@ int hextobinarray_n(char *target, char *source, int sourcelen) {
|
||||||
PrintAndLogEx(INFO, "(hextobinarray) discovered unknown character %c %d at idx %d of %s", x, x, (int16_t)(source - start), start);
|
PrintAndLogEx(INFO, "(hextobinarray) discovered unknown character %c %d at idx %d of %s", x, x, (int16_t)(source - start), start);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// output
|
// output
|
||||||
for (i = 0 ; i < 4 ; ++i, ++count) {
|
for (i = 0 ; i < 4 ; ++i, ++count) {
|
||||||
*(target++) = (x >> (3 - i)) & 1;
|
*(target++) = (x >> (3 - i)) & 1;
|
||||||
|
|
@ -1053,15 +1101,20 @@ int binarray_2_hex(char *target, const size_t targetlen, const char *source, siz
|
||||||
uint32_t t = 0; // written target chars
|
uint32_t t = 0; // written target chars
|
||||||
uint32_t r = 0; // consumed bits
|
uint32_t r = 0; // consumed bits
|
||||||
uint8_t w = 0; // wrong bits separator printed
|
uint8_t w = 0; // wrong bits separator printed
|
||||||
|
|
||||||
for (size_t s = 0 ; s < srclen; s++) {
|
for (size_t s = 0 ; s < srclen; s++) {
|
||||||
|
|
||||||
if ((source[s] == 0) || (source[s] == 1)) {
|
if ((source[s] == 0) || (source[s] == 1)) {
|
||||||
w = 0;
|
w = 0;
|
||||||
x += (source[s] << (3 - i));
|
x += (source[s] << (3 - i));
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (i == 4) {
|
if (i == 4) {
|
||||||
|
|
||||||
if (t >= targetlen - 2) {
|
if (t >= targetlen - 2) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(target + t, targetlen - t, "%X", x);
|
snprintf(target + t, targetlen - t, "%X", x);
|
||||||
t++;
|
t++;
|
||||||
r += 4;
|
r += 4;
|
||||||
|
|
@ -1069,10 +1122,13 @@ int binarray_2_hex(char *target, const size_t targetlen, const char *source, siz
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
|
|
||||||
if (t >= targetlen - 5) {
|
if (t >= targetlen - 5) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(target + t, targetlen - t, "%X[%i]", x, i);
|
snprintf(target + t, targetlen - t, "%X[%i]", x, i);
|
||||||
t += 4;
|
t += 4;
|
||||||
r += i;
|
r += i;
|
||||||
|
|
@ -1080,13 +1136,17 @@ int binarray_2_hex(char *target, const size_t targetlen, const char *source, siz
|
||||||
i = 0;
|
i = 0;
|
||||||
w = 1;
|
w = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w == 0) {
|
if (w == 0) {
|
||||||
|
|
||||||
if (t >= targetlen - 2) {
|
if (t >= targetlen - 2) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(target + t, targetlen - t, " ");
|
snprintf(target + t, targetlen - t, " ");
|
||||||
t++;
|
t++;
|
||||||
}
|
}
|
||||||
|
|
||||||
r++;
|
r++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1107,9 +1167,9 @@ int binstr_2_binarray(uint8_t *target, char *source, int length) {
|
||||||
while (length--) {
|
while (length--) {
|
||||||
char x = *(source++);
|
char x = *(source++);
|
||||||
// convert from binary value
|
// convert from binary value
|
||||||
if (x >= '0' && x <= '1')
|
if (x >= '0' && x <= '1') {
|
||||||
x -= '0';
|
x -= '0';
|
||||||
else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "(binstring2binarray) discovered unknown character %c %d at idx %d of %s", x, x, (int16_t)(source - start), start);
|
PrintAndLogEx(WARNING, "(binstring2binarray) discovered unknown character %c %d at idx %d of %s", x, x, (int16_t)(source - start), start);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1165,8 +1225,9 @@ void hex_xor_token(uint8_t *d, const uint8_t *x, int dn, int xn) {
|
||||||
// return parity bit required to match type
|
// return parity bit required to match type
|
||||||
uint8_t GetParity(const uint8_t *bits, uint8_t type, int length) {
|
uint8_t GetParity(const uint8_t *bits, uint8_t type, int length) {
|
||||||
int x;
|
int x;
|
||||||
for (x = 0 ; length > 0 ; --length)
|
for (x = 0 ; length > 0 ; --length) {
|
||||||
x += bits[length - 1];
|
x += bits[length - 1];
|
||||||
|
}
|
||||||
x %= 2;
|
x %= 2;
|
||||||
return x ^ type;
|
return x ^ type;
|
||||||
}
|
}
|
||||||
|
|
@ -1190,24 +1251,30 @@ void wiegand_add_parity_swapped(uint8_t *target, const uint8_t *source, uint8_t
|
||||||
// Pack a bitarray into a uint32_t.
|
// Pack a bitarray into a uint32_t.
|
||||||
uint32_t PackBits(uint8_t start, uint8_t len, const uint8_t *bits) {
|
uint32_t PackBits(uint8_t start, uint8_t len, const uint8_t *bits) {
|
||||||
|
|
||||||
if (len > 32) return 0;
|
if (len > 32) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int i = start;
|
int i = start;
|
||||||
int j = len - 1;
|
int j = len - 1;
|
||||||
uint32_t tmp = 0;
|
uint32_t tmp = 0;
|
||||||
|
|
||||||
for (; j >= 0; --j, ++i)
|
for (; j >= 0; --j, ++i) {
|
||||||
tmp |= bits[i] << j;
|
tmp |= bits[i] << j;
|
||||||
|
}
|
||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t HornerScheme(uint64_t num, uint64_t divider, uint64_t factor) {
|
uint64_t HornerScheme(uint64_t num, uint64_t divider, uint64_t factor) {
|
||||||
|
|
||||||
uint64_t remaind = 0, quotient = 0, result = 0;
|
uint64_t remaind = 0, quotient = 0, result = 0;
|
||||||
remaind = num % divider;
|
remaind = num % divider;
|
||||||
quotient = num / divider;
|
quotient = num / divider;
|
||||||
if (!(quotient == 0 && remaind == 0))
|
|
||||||
|
if (!(quotient == 0 && remaind == 0)) {
|
||||||
result += HornerScheme(quotient, divider, factor) * factor + remaind;
|
result += HornerScheme(quotient, divider, factor) * factor + remaind;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1228,15 +1295,17 @@ int detect_num_CPUs(void) {
|
||||||
return sysinfo.dwNumberOfProcessors;
|
return sysinfo.dwNumberOfProcessors;
|
||||||
#else
|
#else
|
||||||
int count = sysconf(_SC_NPROCESSORS_ONLN);
|
int count = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
if (count <= 0)
|
if (count <= 0) {
|
||||||
count = 1;
|
count = 1;
|
||||||
|
}
|
||||||
return count;
|
return count;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void str_lower(char *s) {
|
void str_lower(char *s) {
|
||||||
for (size_t i = 0; i < strlen(s); i++)
|
for (size_t i = 0; i < strlen(s); i++) {
|
||||||
s[i] = tolower(s[i]);
|
s[i] = tolower(s[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void str_upper(char *s) {
|
void str_upper(char *s) {
|
||||||
|
|
@ -1244,8 +1313,9 @@ void str_upper(char *s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void strn_upper(char *s, size_t n) {
|
void strn_upper(char *s, size_t n) {
|
||||||
for (size_t i = 0; i < n; i++)
|
for (size_t i = 0; i < n; i++) {
|
||||||
s[i] = toupper(s[i]);
|
s[i] = toupper(s[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// check for prefix in string
|
// check for prefix in string
|
||||||
bool str_startswith(const char *s, const char *pre) {
|
bool str_startswith(const char *s, const char *pre) {
|
||||||
|
|
@ -1265,9 +1335,10 @@ bool str_endswith(const char *s, const char *suffix) {
|
||||||
// Replace unprintable characters with a dot in char buffer
|
// Replace unprintable characters with a dot in char buffer
|
||||||
void clean_ascii(unsigned char *buf, size_t len) {
|
void clean_ascii(unsigned char *buf, size_t len) {
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
if (!isprint(buf[i]))
|
if (isprint(buf[i]) == 0) {
|
||||||
buf[i] = '.';
|
buf[i] = '.';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace \r \n to \0
|
// replace \r \n to \0
|
||||||
|
|
@ -1279,12 +1350,12 @@ void str_cleanrn(char *buf, size_t len) {
|
||||||
// replace char in buffer
|
// replace char in buffer
|
||||||
void str_creplace(char *buf, size_t len, char from, char to) {
|
void str_creplace(char *buf, size_t len, char from, char to) {
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
if (buf[i] == from)
|
if (buf[i] == from) {
|
||||||
buf[i] = to;
|
buf[i] = to;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char *str_dup(const char *src) {
|
char *str_dup(const char *src) {
|
||||||
return str_ndup(src, strlen(src));
|
return str_ndup(src, strlen(src));
|
||||||
}
|
}
|
||||||
|
|
@ -1365,8 +1436,9 @@ int binstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str)
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
int res = sscanf(&str[i], "%1u", &n);
|
int res = sscanf(&str[i], "%1u", &n);
|
||||||
if ((res != 1) || (n > 1))
|
if ((res != 1) || (n > 1)) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
*hi2 = (*hi2 << 1) | (*hi >> 31);
|
*hi2 = (*hi2 << 1) | (*hi >> 31);
|
||||||
*hi = (*hi << 1) | (*lo >> 31);
|
*hi = (*hi << 1) | (*lo >> 31);
|
||||||
|
|
@ -1388,8 +1460,9 @@ int binarray_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const uint8_t *ar
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < arrlen; i++) {
|
for (; i < arrlen; i++) {
|
||||||
uint8_t n = arr[i];
|
uint8_t n = arr[i];
|
||||||
if (n > 1)
|
if (n > 1) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
*hi2 = (*hi2 << 1) | (*hi >> 31);
|
*hi2 = (*hi2 << 1) | (*hi >> 31);
|
||||||
*hi = (*hi << 1) | (*lo >> 31);
|
*hi = (*hi << 1) | (*lo >> 31);
|
||||||
|
|
@ -1445,19 +1518,22 @@ int byte_strstr(const uint8_t *src, size_t srclen, const uint8_t *pattern, size_
|
||||||
for (size_t i = 0; i < max; i++) {
|
for (size_t i = 0; i < max; i++) {
|
||||||
|
|
||||||
// compare only first byte
|
// compare only first byte
|
||||||
if (src[i] != pattern[0])
|
if (src[i] != pattern[0]) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// try to match rest of the pattern
|
// try to match rest of the pattern
|
||||||
for (int j = plen - 1; j >= 1; j--) {
|
for (int j = plen - 1; j >= 1; j--) {
|
||||||
|
|
||||||
if (src[i + j] != pattern[j])
|
if (src[i + j] != pattern[j]) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (j == 1)
|
if (j == 1) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1467,19 +1543,22 @@ int byte_strstr(const uint8_t *src, size_t srclen, const uint8_t *pattern, size_
|
||||||
int byte_strrstr(const uint8_t *src, size_t srclen, const uint8_t *pattern, size_t plen) {
|
int byte_strrstr(const uint8_t *src, size_t srclen, const uint8_t *pattern, size_t plen) {
|
||||||
for (int i = srclen - plen; i >= 0; i--) {
|
for (int i = srclen - plen; i >= 0; i--) {
|
||||||
// compare only first byte
|
// compare only first byte
|
||||||
if (src[i] != pattern[0])
|
if (src[i] != pattern[0]) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// try to match rest of the pattern
|
// try to match rest of the pattern
|
||||||
for (int j = plen - 1; j >= 1; j--) {
|
for (int j = plen - 1; j >= 1; j--) {
|
||||||
|
|
||||||
if (src[i + j] != pattern[j])
|
if (src[i + j] != pattern[j]) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (j == 1)
|
if (j == 1) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -36,17 +36,23 @@ typedef struct {
|
||||||
bool hasIssueLevel;
|
bool hasIssueLevel;
|
||||||
bool hasOEMCode;
|
bool hasOEMCode;
|
||||||
bool hasParity;
|
bool hasParity;
|
||||||
|
uint32_t MaxFC; // max Facility Code
|
||||||
|
uint64_t MaxCN; // max CardNumber
|
||||||
|
uint32_t MaxIL; // max IssueLevel
|
||||||
|
uint32_t MaxOEM;// max OEM
|
||||||
} cardformatdescriptor_t;
|
} cardformatdescriptor_t;
|
||||||
|
|
||||||
// Structure for defined Wiegand card formats available for packing/unpacking
|
// Structure for defined Wiegand card formats available for packing/unpacking
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *Name;
|
const char *Name;
|
||||||
bool (*Pack)(wiegand_card_t *card, wiegand_message_t *packed, bool preamble);
|
bool (*Pack)(int format_idx, wiegand_card_t *card, wiegand_message_t *packed, bool preamble);
|
||||||
bool (*Unpack)(wiegand_message_t *packed, wiegand_card_t *card);
|
bool (*Unpack)(wiegand_message_t *packed, wiegand_card_t *card);
|
||||||
const char *Descrp;
|
const char *Description;
|
||||||
|
uint32_t Bits; // Number of bits in this format
|
||||||
cardformatdescriptor_t Fields;
|
cardformatdescriptor_t Fields;
|
||||||
} cardformat_t;
|
} cardformat_t;
|
||||||
|
|
||||||
|
bool validate_card_limit(int format_idx, wiegand_card_t *card);
|
||||||
void HIDListFormats(void);
|
void HIDListFormats(void);
|
||||||
int HIDFindCardFormat(const char *format);
|
int HIDFindCardFormat(const char *format);
|
||||||
cardformat_t HIDGetCardFormat(int idx);
|
cardformat_t HIDGetCardFormat(int idx);
|
||||||
|
|
@ -54,6 +60,7 @@ bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed, bo
|
||||||
bool HIDTryUnpack(wiegand_message_t *packed);
|
bool HIDTryUnpack(wiegand_message_t *packed);
|
||||||
void HIDPackTryAll(wiegand_card_t *card, bool preamble);
|
void HIDPackTryAll(wiegand_card_t *card, bool preamble);
|
||||||
void HIDUnpack(int idx, wiegand_message_t *packed);
|
void HIDUnpack(int idx, wiegand_message_t *packed);
|
||||||
|
bool decode_wiegand(uint32_t top, uint32_t mid, uint32_t bot, int n);
|
||||||
int HIDDumpPACSBits(const uint8_t *const data, const uint8_t length, bool verbose);
|
int HIDDumpPACSBits(const uint8_t *const data, const uint8_t length, bool verbose);
|
||||||
void print_wiegand_code(wiegand_message_t *packed);
|
void print_wiegand_code(wiegand_message_t *packed);
|
||||||
void print_desc_wiegand(cardformat_t *fmt, wiegand_message_t *packed);
|
void print_desc_wiegand(cardformat_t *fmt, wiegand_message_t *packed);
|
||||||
|
|
|
||||||
|
|
@ -128,11 +128,25 @@ bool set_nonlinear_field(wiegand_message_t *data, uint64_t value, uint8_t numBit
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t get_length_from_header(wiegand_message_t *data) {
|
uint8_t get_length_from_header(wiegand_message_t *data) {
|
||||||
/**
|
/**
|
||||||
* detect if message has "preamble" / "sentinel bit"
|
* detect if message has "preamble" / "sentinel bit"
|
||||||
* Right now we just calculate the highest bit set
|
* Right now we just calculate the highest bit set
|
||||||
* 37 bit formats is hard to detect since it doesnt have a sentinel bit
|
*
|
||||||
|
* (from http://www.proxmark.org/forum/viewtopic.php?pid=5368#p5368)
|
||||||
|
* 0000 0010 0000 0000 01xx xxxx xxxx xxxx xxxx xxxx xxxx 26-bit
|
||||||
|
* 0000 0010 0000 0000 1xxx xxxx xxxx xxxx xxxx xxxx xxxx 27-bit
|
||||||
|
* 0000 0010 0000 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx 28-bit
|
||||||
|
* 0000 0010 0000 001x xxxx xxxx xxxx xxxx xxxx xxxx xxxx 29-bit
|
||||||
|
* 0000 0010 0000 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 30-bit
|
||||||
|
* 0000 0010 0000 1xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 31-bit
|
||||||
|
* 0000 0010 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 32-bit
|
||||||
|
* 0000 0010 001x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 33-bit
|
||||||
|
* 0000 0010 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 34-bit
|
||||||
|
* 0000 0010 1xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 35-bit
|
||||||
|
* 0000 0011 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 36-bit
|
||||||
|
* 0000 000x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 37-bit
|
||||||
|
* 0000 00xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 38-bit
|
||||||
*/
|
*/
|
||||||
uint8_t len = 0;
|
uint8_t len = 0;
|
||||||
uint32_t hfmt = 0; // for calculating card length
|
uint32_t hfmt = 0; // for calculating card length
|
||||||
|
|
@ -140,29 +154,15 @@ static uint8_t get_length_from_header(wiegand_message_t *data) {
|
||||||
if ((data->Top & 0x000FFFFF) > 0) { // > 64 bits
|
if ((data->Top & 0x000FFFFF) > 0) { // > 64 bits
|
||||||
hfmt = data->Top & 0x000FFFFF;
|
hfmt = data->Top & 0x000FFFFF;
|
||||||
len = 64;
|
len = 64;
|
||||||
} else if (data->Mid > 0) { // < 63-32 bits
|
} else if (data->Mid & 0xFFFFFFC0) { // handle 38bit and above format
|
||||||
|
|
||||||
// detect HID format b38 set
|
|
||||||
if (data->Mid & 0xFFFFFFC0) {
|
|
||||||
hfmt = data->Mid;
|
hfmt = data->Mid;
|
||||||
len = 32;
|
len = 31; // remove leading 1 (preamble) in 38-64 bits format
|
||||||
} else {
|
} else if (((data->Mid >> 5) & 1) == 1) { // bit 38 is set => 26-36bit format
|
||||||
|
hfmt = (((data->Mid & 31) << 6) | (data->Bot >> 26)); // get bits 27-37 to check for format len bit
|
||||||
PrintAndLogEx(DEBUG, "hid preamble detected");
|
len = 25;
|
||||||
len = 32;
|
} else { // if bit 38 is not set => 37bit format
|
||||||
|
hfmt = 0;
|
||||||
if ((data->Mid ^ 0x20) == 0) { hfmt = data->Bot; len = 0; }
|
len = 37;
|
||||||
else if ((data->Mid & 0x10) == 0) { hfmt = data->Mid & 0x1F; }
|
|
||||||
else if ((data->Mid & 0x08) == 0) { hfmt = data->Mid & 0x0F; }
|
|
||||||
else if ((data->Mid & 0x04) == 0) { hfmt = data->Mid & 0x07; }
|
|
||||||
else if ((data->Mid & 0x02) == 0) { hfmt = data->Mid & 0x03; }
|
|
||||||
else if ((data->Mid & 0x01) == 0) { hfmt = data->Mid & 0x01; }
|
|
||||||
else { hfmt = data->Mid & 0x3F;}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
hfmt = data->Bot;
|
|
||||||
len = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (hfmt > 0) {
|
while (hfmt > 0) {
|
||||||
|
|
@ -170,10 +170,6 @@ static uint8_t get_length_from_header(wiegand_message_t *data) {
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// everything less than 26 bits found, assume 26 bits
|
|
||||||
if (len < 26)
|
|
||||||
len = 26;
|
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,13 +189,15 @@ wiegand_message_t initialize_message_object(uint32_t top, uint32_t mid, uint32_t
|
||||||
|
|
||||||
bool add_HID_header(wiegand_message_t *data) {
|
bool add_HID_header(wiegand_message_t *data) {
|
||||||
// Invalid value
|
// Invalid value
|
||||||
if (data->Length > 84 || data->Length == 0)
|
if (data->Length > 84 || data->Length == 0) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (data->Length == 48) {
|
if (data->Length == 48) {
|
||||||
data->Mid |= 1U << (data->Length - 32); // Example leading 1: start bit
|
data->Mid |= 1U << (data->Length - 32); // Example leading 1: start bit
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->Length >= 64) {
|
if (data->Length >= 64) {
|
||||||
data->Top |= 0x09e00000; // Extended-length header
|
data->Top |= 0x09e00000; // Extended-length header
|
||||||
data->Top |= 1U << (data->Length - 64); // leading 1: start bit
|
data->Top |= 1U << (data->Length - 64); // leading 1: start bit
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ bool set_nonlinear_field(wiegand_message_t *data, uint64_t value, uint8_t numBit
|
||||||
|
|
||||||
wiegand_message_t initialize_message_object(uint32_t top, uint32_t mid, uint32_t bot, int n);
|
wiegand_message_t initialize_message_object(uint32_t top, uint32_t mid, uint32_t bot, int n);
|
||||||
|
|
||||||
|
uint8_t get_length_from_header(wiegand_message_t *data);
|
||||||
bool add_HID_header(wiegand_message_t *data);
|
bool add_HID_header(wiegand_message_t *data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,133 +0,0 @@
|
||||||
local os = require("os")
|
|
||||||
local ac = require('ansicolors')
|
|
||||||
local getopt = require('getopt')
|
|
||||||
local dir = os.getenv('HOME') .. '/proxmark3/client/dictionaries/'
|
|
||||||
local dictionary_path = dir .. 'T5577date.dic'
|
|
||||||
local cyan = ac.cyan
|
|
||||||
local res = ac.reset
|
|
||||||
|
|
||||||
author = ' Author: jareckib - created 02.02.2025'
|
|
||||||
version = ' version v1.01'
|
|
||||||
desc = [[
|
|
||||||
A simple script for searching the password for T5577. The script creates a
|
|
||||||
dictionary starting from the entered starting year to the entered ending year.
|
|
||||||
There are two search methods - DDMMYYYY or YYYYMMDD. Checking the entire year
|
|
||||||
takes about 1 minute and 50 seconds. Date from 1900 to 2100. The script may be
|
|
||||||
useful if the password is, for example, a date of birth.
|
|
||||||
]]
|
|
||||||
|
|
||||||
usage = [[
|
|
||||||
script run t55_chk [-s start_year] [-e end_year] [-d | -y]
|
|
||||||
]]
|
|
||||||
options = [[
|
|
||||||
-h Show this help message
|
|
||||||
-s Starting year (required)
|
|
||||||
-e Ending year (default: current year)
|
|
||||||
-d Search method: DDMMYYYY
|
|
||||||
-y Search method: YYYYMMDD
|
|
||||||
]]
|
|
||||||
examples = [[
|
|
||||||
script run t55_chk -s 1999 -d - start from 1999, end year is current year, method 01011999
|
|
||||||
script run t55_chk -s 1999 -y - start from 1999, end year is current year, method 19990101
|
|
||||||
script run t55_chk -s 1999 -e 2001 -y - start from 1999, end year 2001, method 19990101
|
|
||||||
script run t55_chk -s 1999 -e 2001 -d - start from 1999, end year 2001, method 01011999
|
|
||||||
]]
|
|
||||||
|
|
||||||
local function help()
|
|
||||||
print(ac.green..author..res)
|
|
||||||
print(version)
|
|
||||||
print(desc)
|
|
||||||
print(cyan..' Usage:'..res)
|
|
||||||
print(usage)
|
|
||||||
print(cyan..' Options:'..res)
|
|
||||||
print(options)
|
|
||||||
print(cyan..' Examples:'..res)
|
|
||||||
print(examples)
|
|
||||||
end
|
|
||||||
|
|
||||||
local days_in_month = {
|
|
||||||
[1] = 31, [2] = 28, [3] = 31, [4] = 30, [5] = 31, [6] = 30,
|
|
||||||
[7] = 31, [8] = 31, [9] = 30, [10] = 31, [11] = 30, [12] = 31
|
|
||||||
}
|
|
||||||
|
|
||||||
local function generate_dictionary(start_year, end_year, mode)
|
|
||||||
local file = io.open(dictionary_path, "w")
|
|
||||||
if not file then
|
|
||||||
print(ac.yellow .. ' ERROR: ' .. ac.reset .. 'Cannot create T5577date.dic')
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
for year = start_year, end_year do
|
|
||||||
for month = 1, 12 do
|
|
||||||
local days_in_current_month = days_in_month[month]
|
|
||||||
if month == 2 and ((year % 4 == 0 and year % 100 ~= 0) or (year % 400 == 0)) then
|
|
||||||
days_in_current_month = 29
|
|
||||||
end
|
|
||||||
|
|
||||||
for day = 1, days_in_current_month do
|
|
||||||
local month_str = string.format("%02d", month)
|
|
||||||
local day_str = string.format("%02d", day)
|
|
||||||
local year_str = tostring(year)
|
|
||||||
local entry = (mode == "1") and (year_str .. month_str .. day_str) or (day_str .. month_str .. year_str)
|
|
||||||
file:write(entry .. "\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
file:close()
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function oops(err)
|
|
||||||
core.console('clear')
|
|
||||||
print( string.rep('--',39) )
|
|
||||||
print( string.rep('--',39) )
|
|
||||||
print(ac.red..' ERROR:'..res.. err)
|
|
||||||
print( string.rep('--',39) )
|
|
||||||
print( string.rep('--',39) )
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
|
|
||||||
local function main(args)
|
|
||||||
if #args == 0 then return help() end
|
|
||||||
|
|
||||||
local start_year, end_year, mode = nil, nil, nil
|
|
||||||
local current_year = tonumber(os.date("%Y"))
|
|
||||||
|
|
||||||
for o, a in getopt.getopt(args, 'hs:e:dy') do
|
|
||||||
if o == 'h' then return help() end
|
|
||||||
if o == 's' then
|
|
||||||
start_year = tonumber(a)
|
|
||||||
if not start_year then return oops('Invalid start year') end
|
|
||||||
end
|
|
||||||
if o == 'e' then
|
|
||||||
end_year = tonumber(a)
|
|
||||||
if not end_year then return oops('Invalid end year (-e)') end
|
|
||||||
end
|
|
||||||
if o == 'd' then mode = "d" end
|
|
||||||
if o == 'y' then mode = "y" end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not start_year then return oops('Starting year is required') end
|
|
||||||
if start_year < 1900 or start_year > 2100 then
|
|
||||||
return oops('Start year must be between 1900 and 2100')
|
|
||||||
end
|
|
||||||
if args[#args] == "-e" then return oops('Ending year cannot be empty') end
|
|
||||||
if not end_year then end_year = current_year end
|
|
||||||
if end_year < 1900 or end_year > 2100 then
|
|
||||||
return oops('End year must be between 1900 and 2100')
|
|
||||||
end
|
|
||||||
|
|
||||||
if end_year < start_year then return oops('End year cannot be earlier than start year') end
|
|
||||||
if not mode then return oops('You must select searching method'..cyan..' -d'..res.. ' or '..cyan.. '-y'..res) end
|
|
||||||
|
|
||||||
if generate_dictionary(start_year, end_year, mode) then
|
|
||||||
print(ac.green .. " File created: " .. dictionary_path .. res)
|
|
||||||
print(cyan .. " Starting password testing on T5577..." .. res)
|
|
||||||
core.console('lf t55 chk -f ' .. dictionary_path)
|
|
||||||
else
|
|
||||||
return oops('Problem saving the file')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
main(args)
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
#include "commonutil.h"
|
#include "commonutil.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "stdbool.h"
|
||||||
|
|
||||||
/* Similar to FpgaGatherVersion this formats stored version information
|
/* Similar to FpgaGatherVersion this formats stored version information
|
||||||
* into a string representation. It takes a pointer to the struct version_information_t,
|
* into a string representation. It takes a pointer to the struct version_information_t,
|
||||||
|
|
@ -403,25 +404,34 @@ void Uint8byteToMemBe(uint8_t *data, uint64_t value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotate Left - Ultralight, Desfire
|
// Rotate Left - Ultralight, Desfire
|
||||||
void rol(uint8_t *data, const size_t len) {
|
void rol(uint8_t *data, const size_t n) {
|
||||||
uint8_t first = data[0];
|
uint8_t first = data[0];
|
||||||
for (size_t i = 0; i < len - 1; i++) {
|
for (size_t i = 0; i < n - 1; i++) {
|
||||||
data[i] = data[i + 1];
|
data[i] = data[i + 1];
|
||||||
}
|
}
|
||||||
data[len - 1] = first;
|
data[n - 1] = first;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotate Right - Ultralight, Desfire
|
// Rotate Right - Ultralight, Desfire
|
||||||
void ror(uint8_t *data, const size_t len) {
|
void ror(uint8_t *data, const size_t n) {
|
||||||
uint8_t last = data[len - 1];
|
uint8_t last = data[n - 1];
|
||||||
|
|
||||||
for (int i = len - 1; i > 0; i--) {
|
for (int i = n - 1; i > 0; i--) {
|
||||||
data[i] = data[i - 1];
|
data[i] = data[i - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
data[0] = last;
|
data[0] = last;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void xor(uint8_t *dest, const uint8_t *src, size_t n) {
|
||||||
|
|
||||||
|
const uint8_t *s = src;
|
||||||
|
uint8_t *d = dest;
|
||||||
|
|
||||||
|
for (; n > 0; n--) {
|
||||||
|
*d++ ^= *s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void lsl(uint8_t *data, size_t len) {
|
void lsl(uint8_t *data, size_t len) {
|
||||||
for (size_t n = 0; n < len - 1; n++) {
|
for (size_t n = 0; n < len - 1; n++) {
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue