mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
Merge branch 'RfidResearchGroup:master' into update_workbench_driver
This commit is contained in:
+15
-12
@@ -21,6 +21,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Set Git http.postBuffer to something high
|
||||
run: git config --global http.postBuffer 524288000
|
||||
|
||||
@@ -39,10 +43,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install setuptools ansicolors sslcrypto
|
||||
if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi
|
||||
run: pip install -r tools/requirements.txt
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
@@ -61,6 +62,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Set Git http.postBuffer to something high
|
||||
run: git config --global http.postBuffer 524288000
|
||||
|
||||
@@ -79,10 +84,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install setuptools ansicolors sslcrypto
|
||||
if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi
|
||||
run: pip install -r tools/requirements.txt
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
@@ -102,6 +104,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Set Git http.postBuffer to something high
|
||||
run: git config --global http.postBuffer 524288000
|
||||
|
||||
@@ -120,10 +126,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install setuptools ansicolors sslcrypto
|
||||
if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi
|
||||
run: pip install -r tools/requirements.txt
|
||||
|
||||
- name: Prepare Build Folders
|
||||
run: |
|
||||
|
||||
@@ -22,6 +22,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Update apt repos
|
||||
run: sudo apt-get update
|
||||
|
||||
@@ -29,11 +33,7 @@ jobs:
|
||||
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.2-dev liblua5.2-0 lua5.2 sed libssl-dev libgd-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
|
||||
run: pip install -r tools/requirements.txt
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
@@ -52,6 +52,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Update apt repos
|
||||
run: sudo apt-get update
|
||||
|
||||
@@ -59,11 +63,7 @@ jobs:
|
||||
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.2-dev liblua5.2-0 lua5.2 sed libssl-dev libgd-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
|
||||
run: pip install -r tools/requirements.txt
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
@@ -83,6 +83,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Update apt repos
|
||||
run: sudo apt-get update
|
||||
|
||||
@@ -90,11 +94,7 @@ jobs:
|
||||
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.2-dev liblua5.2-0 lua5.2 sed libssl-dev libgd-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
|
||||
run: pip install -r tools/requirements.txt
|
||||
|
||||
- name: Prepare Build Folders
|
||||
run: |
|
||||
|
||||
@@ -122,3 +122,7 @@ fpga_version_info.c
|
||||
|
||||
# docs
|
||||
!doc/*.json
|
||||
|
||||
# local codeql
|
||||
_codeql*
|
||||
/codeql
|
||||
@@ -3,6 +3,34 @@ All notable changes to this project will be documented in this file.
|
||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- fixed breaking of client when trying to load a non-supported .picopass file (@iceman100) Thanks to Jump for suggested fixes!
|
||||
- Changed `mf_nonce_brute` tool to handle the odd case of multiple key candidates (@iceman1001)
|
||||
- Fixed a bad memory erase (@iceman1001)
|
||||
- Fixed BT serial comms (@iceman1001)
|
||||
- Changed `intertic.py` - updated and code clean up (@gentilkiwi)
|
||||
- Added `pm3_tears_for_fears.py` - a ISO14443b tear off script by Pierre Granier
|
||||
- Added new t55xx password (002BCFCF) sniffed from cheap cloner (@davidbeauchamp)
|
||||
- Fixed 'hf 14b sim' - now works (@michi-jung)
|
||||
- Added VB6 Rng for iclass elite keys `hf iclass lookup` and `hf iclass chk` functions by porting @bettse work in the Flipper Zero Picopass App (@antiklesys)
|
||||
- Added MFC Keys for Laugardalslaug in Iceland (@dandri)
|
||||
- Added key for Orkan keyfobs(@dandri)
|
||||
|
||||
## [Aurora.4.18589][2024-05-28]
|
||||
- Fixed the pm3 regressiontests for Hitag2Crack (@iceman1001)
|
||||
- Changed `mem spiffs tree` - adapted to bigbuff and show if empty (@iceman1001)
|
||||
- Changed `lf hitag info` - now tries to identify different key fob emulators (@iceman1001)
|
||||
- Added `lf hitag reader` - act as a Hitag2 reader (@iceman1001)
|
||||
- Fixed `lf hitag crack2` - now works. (@iceman1001)
|
||||
- Fixed wrong use of free() in desfire crypto on arm src, thanks @jlitewski! (@iceman1001)
|
||||
- Added `lf em 4x70 calc` - calculate `frn`/`grn` for a given `key` + `rnd`
|
||||
- Fixed `hf 15 dump` memory leaks (@jlitewski)
|
||||
- Changed `hf search` - topaz is detect before ISO14443a and commented out WIP ICT code path (@iceman1001)
|
||||
- Fixed `hf search` - where felica reader now doesnt timeout and give wrong response (@iceman1001)
|
||||
- Fixed overflow in deps/jansson library (@iceman1001)
|
||||
- Added `lf hitag crack2` - WIP. Trying to add the second attack vector against Hitag2 (@iceman1001)
|
||||
- Changed `hf 14b reader --plot` - made the anticollision signal trace download optional (@iceman1001)
|
||||
- Added `lf_hitag_crypto.trace` - trace file of a complete read out of a Hitag2 in crypto mode (@iceman1001)
|
||||
- Fix `lf cmdread` - uninitialised memory usage (@iceman1001)
|
||||
- Changed `hf st info` - now tries to check signature if available (@iceman1001)
|
||||
- Added `hf 14b mobib` - try to read out all data from a MOBIB card (@iceman1001)
|
||||
- Added `hf 14b calyso` - try to read out all data from a Calypso card (@iceman1001)
|
||||
@@ -28,6 +56,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||
- Changed `data load` - now shows loaded number as comma printed. (@iceman1001)
|
||||
- Updated `/tools/hitag2crack/common/OpenCL-Headers/CL` with latest from KhronosGroup github page (@iceman1001)
|
||||
- Fixed `lf hitag list` - improved HITAG2 protocol annotation (@iceman1001)
|
||||
- Added AIDs `002000` and `FF30FF` from Metrolinx Presto Card (@RunTheBot)
|
||||
|
||||
## [Zenith.4.18340][2024-03-20]
|
||||
- Changed `hf mf info` - some detections (@iceman1001)
|
||||
|
||||
@@ -41,7 +41,7 @@ void ModInfo(void) {
|
||||
DbpString(" LF EM4100 simulator standalone mode");
|
||||
}
|
||||
|
||||
static uint64_t rev_quads(uint64_t bits) {
|
||||
static uint64_t em4100emul_rev_quads(uint64_t bits) {
|
||||
uint64_t result = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
result += ((bits >> (60 - 4 * i)) & 0xf) << (4 * i);
|
||||
@@ -49,7 +49,7 @@ static uint64_t rev_quads(uint64_t bits) {
|
||||
return result >> 24;
|
||||
}
|
||||
|
||||
static void fill_buff(uint8_t bit) {
|
||||
static void em4100emul_fill_buff(uint8_t bit) {
|
||||
uint8_t *bba = BigBuf_get_addr();
|
||||
memset(bba + em4100emul_buflen, bit, LF_CLOCK / 2);
|
||||
em4100emul_buflen += (LF_CLOCK / 2);
|
||||
@@ -57,7 +57,7 @@ static void fill_buff(uint8_t bit) {
|
||||
em4100emul_buflen += (LF_CLOCK / 2);
|
||||
}
|
||||
|
||||
static void construct_EM410x_emul(uint64_t id) {
|
||||
static void em4100emul_construct_EM410x_emul(uint64_t id) {
|
||||
|
||||
int i, j;
|
||||
int binary[4] = {0, 0, 0, 0};
|
||||
@@ -65,24 +65,24 @@ static void construct_EM410x_emul(uint64_t id) {
|
||||
em4100emul_buflen = 0;
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
fill_buff(1);
|
||||
em4100emul_fill_buff(1);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
for (j = 3; j >= 0; j--, id /= 2)
|
||||
binary[j] = id % 2;
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
fill_buff(binary[j]);
|
||||
em4100emul_fill_buff(binary[j]);
|
||||
|
||||
fill_buff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
|
||||
em4100emul_fill_buff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
|
||||
for (j = 0; j < 4; j++)
|
||||
parity[j] ^= binary[j];
|
||||
}
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
fill_buff(parity[j]);
|
||||
em4100emul_fill_buff(parity[j]);
|
||||
|
||||
fill_buff(0);
|
||||
em4100emul_fill_buff(0);
|
||||
}
|
||||
|
||||
static void LED_Slot(int i) {
|
||||
@@ -108,8 +108,18 @@ void RunMod(void) {
|
||||
SpinDelay(100);
|
||||
SpinUp(100);
|
||||
LED_Slot(selected);
|
||||
construct_EM410x_emul(rev_quads(em4100emul_low[selected]));
|
||||
Dbprintf("Emulating 0x%010llX", em4100emul_low[selected]);
|
||||
em4100emul_construct_EM410x_emul(em4100emul_rev_quads(em4100emul_low[selected]));
|
||||
SimulateTagLowFrequency(em4100emul_buflen, 0, true);
|
||||
|
||||
//Exit! Button hold break
|
||||
int button_pressed = BUTTON_HELD(500);
|
||||
if (button_pressed == BUTTON_HOLD) {
|
||||
Dbprintf("Button hold, Break!");
|
||||
LEDsoff();
|
||||
Dbprintf("[=] >> LF EM4100 simulator stopped due to button hold <<");
|
||||
return; // RunMod end
|
||||
}
|
||||
selected = (selected + 1) % em4100emul_slots_count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ void RunMod(void) {
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
|
||||
const uint32_t high = 0x20; // LF high value is always 0x20 here
|
||||
uint32_t low = 0;
|
||||
|
||||
uint32_t fac = FACILITY_CODE, cardnum = 0;
|
||||
|
||||
@@ -80,7 +79,7 @@ void RunMod(void) {
|
||||
if (BUTTON_HELD(1000) == BUTTON_HOLD) break; // long button press (>=1sec) exit
|
||||
|
||||
// calculate the new LF low value including Card number, Facility code and checksum
|
||||
low = (cardnum << 1) | (fac << 17);
|
||||
uint32_t low = (cardnum << 1) | (fac << 17);
|
||||
low |= oddparity32((low >> 1) & 0xFFF);
|
||||
low |= evenparity32((low >> 13) & 0xFFF) << 25;
|
||||
|
||||
|
||||
+6
-1
@@ -1141,7 +1141,12 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
}
|
||||
case CMD_LF_HITAG2_CRACK: {
|
||||
lf_hitag_data_t *payload = (lf_hitag_data_t *) packet->data.asBytes;
|
||||
ht2_crack(payload->NrAr);
|
||||
ht2_crack1(payload->NrAr);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HITAG2_CRACK_2: {
|
||||
lf_hitag_data_t *payload = (lf_hitag_data_t *) packet->data.asBytes;
|
||||
ht2_crack2(payload->NrAr);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HITAG_READER: { // Reader for Hitag tags, args = type and function
|
||||
|
||||
+3
-2
@@ -102,8 +102,9 @@ void Dbhexdump(int len, const uint8_t *d, bool bAsci) {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void print_result(const char *name, const uint8_t *d, size_t
|
||||
|
||||
void print_result(const char *name, const uint8_t *d, size_t n) {
|
||||
n) {
|
||||
|
||||
const uint8_t *p = d;
|
||||
uint16_t tmp = n & 0xFFF0;
|
||||
@@ -129,7 +130,7 @@ void print_result(const char *name, const uint8_t *d, size_t n) {
|
||||
}
|
||||
|
||||
// Prints message and hexdump
|
||||
void print_dbg(char *msg, uint8_t *d, uint16_t n) {
|
||||
void print_dbg(const char *msg, const uint8_t *d, uint16_t n) {
|
||||
if (g_dbglevel == DBG_DEBUG) {
|
||||
print_result(msg, d, n);
|
||||
}
|
||||
|
||||
+2
-2
@@ -27,8 +27,8 @@ void DbpStringEx(uint32_t flags, const char *src, size_t srclen);
|
||||
void Dbprintf(const char *fmt, ...);
|
||||
void DbprintfEx(uint32_t flags, const char *fmt, ...);
|
||||
void Dbhexdump(int len, const uint8_t *d, bool bAsci);
|
||||
void print_result(const char *name, const uint8_t *buf, size_t len);
|
||||
void print_dbg(char *msg, uint8_t *d, uint16_t n);
|
||||
void print_result(const char *name, const uint8_t *d, size_t n);
|
||||
void print_dbg(const char *msg, const uint8_t *d, uint16_t n);
|
||||
//void PrintToSendBuffer(void);
|
||||
|
||||
#endif
|
||||
|
||||
+67
-44
@@ -543,30 +543,35 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||
|
||||
void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes, int communication_settings) {
|
||||
void *res = data;
|
||||
void *edata = NULL;
|
||||
uint8_t first_cmac_byte = 0x00;
|
||||
|
||||
desfirekey_t key = DESFIRE(tag)->session_key;
|
||||
|
||||
if (!key)
|
||||
if (!key) {
|
||||
return data;
|
||||
}
|
||||
|
||||
// Return directly if we just have a status code.
|
||||
if (1 == *nbytes)
|
||||
if (1 == *nbytes) {
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
/* pass through */
|
||||
case MDCM_MACED:
|
||||
case MDCM_MACED: {
|
||||
switch (DESFIRE(tag)->authentication_scheme) {
|
||||
case AS_LEGACY:
|
||||
if (communication_settings & MAC_VERIFY) {
|
||||
case AS_LEGACY: {
|
||||
|
||||
if ((communication_settings & MAC_VERIFY) == MAC_VERIFY) {
|
||||
|
||||
*nbytes -= key_macing_length(key);
|
||||
|
||||
if (*nbytes == 0) {
|
||||
*nbytes = -1;
|
||||
res = NULL;
|
||||
@@ -577,18 +582,17 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
}
|
||||
|
||||
size_t edl = enciphered_data_length(tag, *nbytes - 1, communication_settings);
|
||||
edata = BigBuf_malloc(edl);
|
||||
|
||||
uint8_t edata[edl];
|
||||
memset(edata, 0, sizeof(edata));
|
||||
memcpy(edata, data, *nbytes - 1);
|
||||
memset((uint8_t *)edata + *nbytes - 1, 0, edl - *nbytes + 1);
|
||||
|
||||
mifare_cypher_blocks_chained(tag, NULL, NULL, edata, edl, MCD_SEND, MCO_ENCYPHER);
|
||||
|
||||
if (0 != memcmp((uint8_t *)data + *nbytes - 1, (uint8_t *)edata + edl - 8, 4)) {
|
||||
if (0 != memcmp((uint8_t *)data + *nbytes - 1, edata + edl - 8, 4)) {
|
||||
#ifdef WITH_DEBUG
|
||||
Dbprintf("MACing not verified");
|
||||
hexdump((uint8_t *)data + *nbytes - 1, key_macing_length(key), "Expect ", 0);
|
||||
hexdump((uint8_t *)edata + edl - 8, key_macing_length(key), "Actual ", 0);
|
||||
hexdump(edata + edl - 8, key_macing_length(key), "Actual ", 0);
|
||||
#endif
|
||||
DESFIRE(tag)->last_pcd_error = CRYPTO_ERROR;
|
||||
*nbytes = -1;
|
||||
@@ -596,10 +600,16 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AS_NEW:
|
||||
if (!(communication_settings & CMAC_COMMAND))
|
||||
}
|
||||
case AS_NEW: {
|
||||
|
||||
if ((communication_settings & CMAC_COMMAND) != CMAC_COMMAND) {
|
||||
break;
|
||||
if (communication_settings & CMAC_VERIFY) {
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
|
||||
if ((communication_settings & CMAC_VERIFY) == CMAC_VERIFY) {
|
||||
if (*nbytes < 9) {
|
||||
*nbytes = -1;
|
||||
res = NULL;
|
||||
@@ -607,13 +617,16 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
}
|
||||
first_cmac_byte = ((uint8_t *)data)[*nbytes - 9];
|
||||
((uint8_t *)data)[*nbytes - 9] = ((uint8_t *)data)[*nbytes - 1];
|
||||
|
||||
n = 8;
|
||||
}
|
||||
|
||||
int n = (communication_settings & CMAC_VERIFY) ? 8 : 0;
|
||||
cmac(key, DESFIRE(tag)->ivect, ((uint8_t *)data), *nbytes - n, DESFIRE(tag)->cmac);
|
||||
|
||||
if (communication_settings & CMAC_VERIFY) {
|
||||
if ((communication_settings & CMAC_VERIFY) == CMAC_VERIFY) {
|
||||
|
||||
((uint8_t *)data)[*nbytes - 9] = first_cmac_byte;
|
||||
|
||||
if (0 != memcmp(DESFIRE(tag)->cmac, (uint8_t *)data + *nbytes - 9, 8)) {
|
||||
#ifdef WITH_DEBUG
|
||||
Dbprintf("CMAC NOT verified :-(");
|
||||
@@ -628,12 +641,11 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(edata);
|
||||
|
||||
break;
|
||||
case MDCM_ENCIPHERED:
|
||||
}
|
||||
case MDCM_ENCIPHERED: {
|
||||
(*nbytes)--;
|
||||
bool verified = false;
|
||||
int crc_pos = 0x00;
|
||||
@@ -670,48 +682,50 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
* verified, and accumulating 0's in it should not change it.
|
||||
*/
|
||||
switch (DESFIRE(tag)->authentication_scheme) {
|
||||
case AS_LEGACY:
|
||||
case AS_LEGACY: {
|
||||
crc_pos = *nbytes - 8 - 1; // The CRC can be over two blocks
|
||||
if (crc_pos < 0) {
|
||||
/* Single block */
|
||||
crc_pos = 0;
|
||||
crc_pos = 0; // Single block
|
||||
}
|
||||
break;
|
||||
case AS_NEW:
|
||||
}
|
||||
case AS_NEW: {
|
||||
/* Move status between payload and CRC */
|
||||
res = DESFIRE(tag)->crypto_buffer;
|
||||
memcpy(res, data, *nbytes);
|
||||
|
||||
crc_pos = (*nbytes) - 16 - 3;
|
||||
if (crc_pos < 0) {
|
||||
/* Single block */
|
||||
crc_pos = 0;
|
||||
crc_pos = 0; // Single block
|
||||
}
|
||||
|
||||
memcpy((uint8_t *)res + crc_pos + 1, (uint8_t *)res + crc_pos, *nbytes - crc_pos);
|
||||
((uint8_t *)res)[crc_pos] = 0x00;
|
||||
crc_pos++;
|
||||
*nbytes += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
uint16_t crc_16 = 0x00;
|
||||
uint32_t crc = 0x00;
|
||||
|
||||
switch (DESFIRE(tag)->authentication_scheme) {
|
||||
case AS_LEGACY:
|
||||
case AS_LEGACY: {
|
||||
AddCrc14A((uint8_t *)res, end_crc_pos);
|
||||
end_crc_pos = crc_pos + 2;
|
||||
//
|
||||
|
||||
|
||||
crc = crc_16;
|
||||
break;
|
||||
case AS_NEW:
|
||||
}
|
||||
case AS_NEW: {
|
||||
end_crc_pos = crc_pos + 4;
|
||||
crc32_ex(res, end_crc_pos, (uint8_t *)&crc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!crc) {
|
||||
|
||||
if (crc == 0) {
|
||||
verified = true;
|
||||
for (int n = end_crc_pos; n < *nbytes - 1; n++) {
|
||||
uint8_t byte = ((uint8_t *)res)[n];
|
||||
@@ -719,31 +733,40 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
verified = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (verified) {
|
||||
|
||||
*nbytes = crc_pos;
|
||||
|
||||
switch (DESFIRE(tag)->authentication_scheme) {
|
||||
case AS_LEGACY:
|
||||
case AS_LEGACY: {
|
||||
((uint8_t *)data)[(*nbytes)++] = 0x00;
|
||||
break;
|
||||
case AS_NEW:
|
||||
}
|
||||
case AS_NEW: {
|
||||
/* The status byte was already before the CRC */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
switch (DESFIRE(tag)->authentication_scheme) {
|
||||
case AS_LEGACY:
|
||||
case AS_LEGACY: {
|
||||
break;
|
||||
case AS_NEW:
|
||||
}
|
||||
case AS_NEW: {
|
||||
x = ((uint8_t *)res)[crc_pos - 1];
|
||||
((uint8_t *)res)[crc_pos - 1] = ((uint8_t *)res)[crc_pos];
|
||||
((uint8_t *)res)[crc_pos] = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
crc_pos++;
|
||||
}
|
||||
} while (!verified && (end_crc_pos < *nbytes));
|
||||
|
||||
if (!verified) {
|
||||
} while (verified == false && (end_crc_pos < *nbytes));
|
||||
|
||||
if (verified == false) {
|
||||
#ifdef WITH_DEBUG
|
||||
/* FIXME In some configurations, the file is transmitted PLAIN */
|
||||
Dbprintf("CRC not verified in decyphered stream");
|
||||
@@ -752,14 +775,14 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
*nbytes = -1;
|
||||
res = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
Dbprintf("Unknown communication settings");
|
||||
*nbytes = -1;
|
||||
res = NULL;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
+5
-1
@@ -1255,7 +1255,11 @@ static int em4x50_sim_read_bit(void) {
|
||||
int cycles = 0;
|
||||
int timeout = EM4X50_T_SIMULATION_TIMEOUT_READ;
|
||||
|
||||
while (cycles < EM4X50_T_TAG_FULL_PERIOD) {
|
||||
// wait 16 cycles to make sure there is no field when reading a "0" bit
|
||||
uint32_t waitval = GetTicks();
|
||||
while (GetTicks() - waitval < EM4X50_T_TAG_QUARTER_PERIOD * CYCLES2TICKS);
|
||||
|
||||
while (cycles < EM4X50_T_TAG_THREE_QUARTER_PERIOD) {
|
||||
|
||||
// wait until reader field disappears
|
||||
while ((timeout--) && !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK));
|
||||
|
||||
+109
-64
@@ -30,6 +30,8 @@ static em4x70_tag_t tag = { 0 };
|
||||
// EM4170 requires a parity bit on commands, other variants do not.
|
||||
static bool command_parity = true;
|
||||
|
||||
|
||||
#if 1 // Calculation of ticks for timing functions
|
||||
// Conversion from Ticks to RF periods
|
||||
// 1 us = 1.5 ticks
|
||||
// 1RF Period = 8us = 12 Ticks
|
||||
@@ -55,11 +57,15 @@ static bool command_parity = true;
|
||||
|
||||
#define EM4X70_COMMAND_RETRIES 5 // Attempts to send/read command
|
||||
#define EM4X70_MAX_RECEIVE_LENGTH 96 // Maximum bits to expect from any command
|
||||
#endif // Calculation of ticks for timing functions
|
||||
|
||||
#if 1 // EM4x70 Command IDs
|
||||
/**
|
||||
* These IDs are from the EM4170 datasheet
|
||||
* These IDs are from the EM4170 datasheet.
|
||||
* Some versions of the chip require a
|
||||
* (even) parity bit, others do not
|
||||
* (even) parity bit, others do not.
|
||||
* The command is thus stored only in the
|
||||
* three least significant bits (mask 0x07).
|
||||
*/
|
||||
#define EM4X70_COMMAND_ID 0x01
|
||||
#define EM4X70_COMMAND_UM1 0x02
|
||||
@@ -67,6 +73,7 @@ static bool command_parity = true;
|
||||
#define EM4X70_COMMAND_PIN 0x04
|
||||
#define EM4X70_COMMAND_WRITE 0x05
|
||||
#define EM4X70_COMMAND_UM2 0x07
|
||||
#endif // EM4x70 Command IDs
|
||||
|
||||
// Constants used to determine high/low state of signal
|
||||
#define EM4X70_NOISE_THRESHOLD 13 // May depend on noise in environment
|
||||
@@ -80,9 +87,9 @@ static bool command_parity = true;
|
||||
#define IS_TIMEOUT(timeout_ticks) (GetTicks() > timeout_ticks)
|
||||
#define TICKS_ELAPSED(start_ticks) (GetTicks() - start_ticks)
|
||||
|
||||
static uint8_t bits2byte(const uint8_t *bits, int length);
|
||||
static void bits2bytes(const uint8_t *bits, int length, uint8_t *out);
|
||||
static int em4x70_receive(uint8_t *bits, size_t length);
|
||||
static uint8_t encoded_bit_array_to_byte(const uint8_t *bits, int count_of_bits);
|
||||
static void encoded_bit_array_to_bytes(const uint8_t *bits, int count_of_bits, uint8_t *out);
|
||||
static int em4x70_receive(uint8_t *bits, size_t maximum_bits_to_read);
|
||||
static bool find_listen_window(bool command);
|
||||
|
||||
static void init_tag(void) {
|
||||
@@ -207,9 +214,10 @@ static uint32_t get_pulse_length(edge_detection_t edge) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool check_pulse_length(uint32_t pl, uint32_t length) {
|
||||
// check if pulse length <pl> corresponds to given length <length>
|
||||
return ((pl >= (length - EM4X70_T_TAG_TOLERANCE)) && (pl <= (length + EM4X70_T_TAG_TOLERANCE)));
|
||||
static bool check_pulse_length(uint32_t pulse_tick_length, uint32_t target_tick_length) {
|
||||
// check if pulse tick length corresponds to target length (+/- tolerance)
|
||||
return ((pulse_tick_length >= (target_tick_length - EM4X70_T_TAG_TOLERANCE)) &&
|
||||
(pulse_tick_length <= (target_tick_length + EM4X70_T_TAG_TOLERANCE)));
|
||||
}
|
||||
|
||||
static void em4x70_send_bit(bool bit) {
|
||||
@@ -344,7 +352,11 @@ static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *respon
|
||||
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Auth failed");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
bits2bytes(grnd, 24, response);
|
||||
// although only received 20 bits
|
||||
// ask for 24 bits converted because
|
||||
// this utility function requires
|
||||
// decoding in multiples of 8 bits
|
||||
encoded_bit_array_to_bytes(grnd, 24, response);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -455,12 +467,12 @@ static int send_pin(const uint32_t pin) {
|
||||
WaitTicks(EM4X70_T_TAG_WEE);
|
||||
// <-- Receive header + ID
|
||||
uint8_t tag_id[EM4X70_MAX_RECEIVE_LENGTH];
|
||||
int num = em4x70_receive(tag_id, 32);
|
||||
if (num < 32) {
|
||||
int count_of_bits_received = em4x70_receive(tag_id, 32);
|
||||
if (count_of_bits_received < 32) {
|
||||
Dbprintf("Invalid ID Received");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
bits2bytes(tag_id, num, &tag.data[4]);
|
||||
encoded_bit_array_to_bytes(tag_id, count_of_bits_received, &tag.data[4]);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -537,36 +549,38 @@ static bool find_listen_window(bool command) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void bits2bytes(const uint8_t *bits, int length, uint8_t *out) {
|
||||
// *bits == array of bytes, each byte storing a single bit.
|
||||
// *out == array of bytes, storing converted bits --> bytes.
|
||||
//
|
||||
// [in, bcount(count_of_bits) ] const uint8_t *bits
|
||||
// [out, bcount(count_of_bits/8)] uint8_t *out
|
||||
static void encoded_bit_array_to_bytes(const uint8_t *bits, int count_of_bits, uint8_t *out) {
|
||||
|
||||
if (length % 8 != 0) {
|
||||
Dbprintf("Should have a multiple of 8 bits, was sent %d", length);
|
||||
if (count_of_bits % 8 != 0) {
|
||||
Dbprintf("Should have a multiple of 8 bits, was sent %d", count_of_bits);
|
||||
}
|
||||
|
||||
int num_bytes = length / 8; // We should have a multiple of 8 here
|
||||
int num_bytes = count_of_bits / 8; // We should have a multiple of 8 here
|
||||
|
||||
for (int i = 1; i <= num_bytes; i++) {
|
||||
out[num_bytes - i] = bits2byte(bits, 8);
|
||||
out[num_bytes - i] = encoded_bit_array_to_byte(bits, 8);
|
||||
bits += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t bits2byte(const uint8_t *bits, int length) {
|
||||
static uint8_t encoded_bit_array_to_byte(const uint8_t *bits, int count_of_bits) {
|
||||
|
||||
// converts <length> separate bits into a single "byte"
|
||||
// converts <count_of_bits> separate bits into a single "byte"
|
||||
uint8_t byte = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
||||
for (int i = 0; i < count_of_bits; i++) {
|
||||
byte <<= 1;
|
||||
byte |= bits[i];
|
||||
|
||||
if (i != length - 1)
|
||||
byte <<= 1;
|
||||
}
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
static bool send_command_and_read(uint8_t command, uint8_t *bytes, size_t length) {
|
||||
static bool send_command_and_read(uint8_t command, uint8_t *bytes, size_t expected_byte_count) {
|
||||
|
||||
int retries = EM4X70_COMMAND_RETRIES;
|
||||
while (retries) {
|
||||
@@ -574,19 +588,14 @@ static bool send_command_and_read(uint8_t command, uint8_t *bytes, size_t length
|
||||
|
||||
if (find_listen_window(true)) {
|
||||
uint8_t bits[EM4X70_MAX_RECEIVE_LENGTH] = {0};
|
||||
size_t out_length_bits = length * 8;
|
||||
size_t out_length_bits = expected_byte_count * 8;
|
||||
em4x70_send_nibble(command, command_parity);
|
||||
int len = em4x70_receive(bits, out_length_bits);
|
||||
if (len < out_length_bits) {
|
||||
Dbprintf("Invalid data received length: %d, expected %d", len, out_length_bits);
|
||||
return false;
|
||||
}
|
||||
// TODO: Figure out why getting an extra bit (quite often) here
|
||||
// e.g., write block and info commands both reach here and output:
|
||||
// [#] Should have a multiple of 8 bits, was sent 33
|
||||
// [#] Should have a multiple of 8 bits, was sent 65
|
||||
// Extra bits are currently just dropped, with no ill effect noticed.
|
||||
bits2bytes(bits, len, bytes);
|
||||
encoded_bit_array_to_bytes(bits, len, bytes);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -617,7 +626,6 @@ static bool em4x70_read_um1(void) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* em4x70_read_um2
|
||||
*
|
||||
@@ -635,7 +643,7 @@ static bool find_em4x70_tag(void) {
|
||||
return find_listen_window(false);
|
||||
}
|
||||
|
||||
static int em4x70_receive(uint8_t *bits, size_t length) {
|
||||
static int em4x70_receive(uint8_t *bits, size_t maximum_bits_to_read) {
|
||||
|
||||
uint32_t pl;
|
||||
int bit_pos = 0;
|
||||
@@ -673,7 +681,7 @@ static int em4x70_receive(uint8_t *bits, size_t length) {
|
||||
|
||||
// identify remaining bits based on pulse lengths
|
||||
// between listen windows only pulse lengths of 1, 1.5 and 2 are possible
|
||||
while (bit_pos < length) {
|
||||
while (bit_pos < maximum_bits_to_read) {
|
||||
|
||||
pl = get_pulse_length(edge);
|
||||
|
||||
@@ -687,13 +695,13 @@ static int em4x70_receive(uint8_t *bits, size_t length) {
|
||||
// pulse length 1.5 -> 2 bits + flip edge detection
|
||||
if (edge == FALLING_EDGE) {
|
||||
bits[bit_pos++] = 0;
|
||||
if (bit_pos < length) {
|
||||
if (bit_pos < maximum_bits_to_read) {
|
||||
bits[bit_pos++] = 0;
|
||||
}
|
||||
edge = RISING_EDGE;
|
||||
} else {
|
||||
bits[bit_pos++] = 1;
|
||||
if (bit_pos < length) {
|
||||
if (bit_pos < maximum_bits_to_read) {
|
||||
bits[bit_pos++] = 1;
|
||||
}
|
||||
edge = FALLING_EDGE;
|
||||
@@ -704,12 +712,12 @@ static int em4x70_receive(uint8_t *bits, size_t length) {
|
||||
// pulse length of 2 -> two bits
|
||||
if (edge == FALLING_EDGE) {
|
||||
bits[bit_pos++] = 0;
|
||||
if (bit_pos < length) {
|
||||
if (bit_pos < maximum_bits_to_read) {
|
||||
bits[bit_pos++] = 1;
|
||||
}
|
||||
} else {
|
||||
bits[bit_pos++] = 1;
|
||||
if (bit_pos < length) {
|
||||
if (bit_pos < maximum_bits_to_read) {
|
||||
bits[bit_pos++] = 0;
|
||||
}
|
||||
}
|
||||
@@ -725,7 +733,7 @@ static int em4x70_receive(uint8_t *bits, size_t length) {
|
||||
|
||||
void em4x70_info(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
uint8_t status = 0;
|
||||
bool success = false;
|
||||
|
||||
// Support tags with and without command parity bits
|
||||
command_parity = etd->parity;
|
||||
@@ -736,20 +744,27 @@ void em4x70_info(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
// Find the Tag
|
||||
if (get_signalproperties() && find_em4x70_tag()) {
|
||||
// Read ID, UM1 and UM2
|
||||
status = em4x70_read_id() && em4x70_read_um1() && em4x70_read_um2();
|
||||
success = em4x70_read_id() && em4x70_read_um1() && em4x70_read_um2();
|
||||
}
|
||||
|
||||
StopTicks();
|
||||
lf_finalize(ledcontrol);
|
||||
int status = success ? PM3_SUCCESS : PM3_ESOFT;
|
||||
reply_ng(CMD_LF_EM4X70_INFO, status, tag.data, sizeof(tag.data));
|
||||
}
|
||||
|
||||
void em4x70_write(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
uint8_t status = 0;
|
||||
int status = PM3_ESOFT;
|
||||
|
||||
command_parity = etd->parity;
|
||||
|
||||
// Disable to prevent sending corrupted data to the tag.
|
||||
if (command_parity) {
|
||||
Dbprintf("Use of `--par` option with `lf em 4x70 write` is disabled to prevent corrupting tag data");
|
||||
reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
init_tag();
|
||||
em4x70_setup_read();
|
||||
|
||||
@@ -757,16 +772,15 @@ void em4x70_write(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
if (get_signalproperties() && find_em4x70_tag()) {
|
||||
|
||||
// Write
|
||||
status = write(etd->word, etd->address) == PM3_SUCCESS;
|
||||
status = write(etd->word, etd->address);
|
||||
|
||||
if (status) {
|
||||
if (status == PM3_SUCCESS) {
|
||||
// Read Tag after writing
|
||||
if (em4x70_read_id()) {
|
||||
em4x70_read_um1();
|
||||
em4x70_read_um2();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StopTicks();
|
||||
@@ -776,7 +790,7 @@ void em4x70_write(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
void em4x70_unlock(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
uint8_t status = 0;
|
||||
int status = PM3_ESOFT;
|
||||
|
||||
command_parity = etd->parity;
|
||||
|
||||
@@ -790,10 +804,10 @@ void em4x70_unlock(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
if (em4x70_read_id()) {
|
||||
|
||||
// Send PIN
|
||||
status = send_pin(etd->pin) == PM3_SUCCESS;
|
||||
status = send_pin(etd->pin);
|
||||
|
||||
// If the write succeeded, read the rest of the tag
|
||||
if (status) {
|
||||
if (status == PM3_SUCCESS) {
|
||||
// Read Tag
|
||||
// ID doesn't change
|
||||
em4x70_read_um1();
|
||||
@@ -809,11 +823,19 @@ void em4x70_unlock(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
void em4x70_auth(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
uint8_t status = 0;
|
||||
int status = PM3_ESOFT;
|
||||
|
||||
uint8_t response[3] = {0};
|
||||
|
||||
command_parity = etd->parity;
|
||||
|
||||
// Disable to prevent sending corrupted data to the tag.
|
||||
if (command_parity) {
|
||||
Dbprintf("Use of `--par` option with `lf em 4x70 auth` is disabled to prevent corrupting tag data");
|
||||
reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
init_tag();
|
||||
em4x70_setup_read();
|
||||
|
||||
@@ -821,7 +843,7 @@ void em4x70_auth(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
if (get_signalproperties() && find_em4x70_tag()) {
|
||||
|
||||
// Authenticate and get tag response
|
||||
status = authenticate(etd->rnd, etd->frnd, response) == PM3_SUCCESS;
|
||||
status = authenticate(etd->rnd, etd->frnd, response);
|
||||
}
|
||||
|
||||
StopTicks();
|
||||
@@ -830,11 +852,18 @@ void em4x70_auth(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
}
|
||||
|
||||
void em4x70_brute(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
uint8_t status = 0;
|
||||
int status = PM3_ESOFT;
|
||||
uint8_t response[2] = {0};
|
||||
|
||||
command_parity = etd->parity;
|
||||
|
||||
// Disable to prevent sending corrupted data to the tag.
|
||||
if (command_parity) {
|
||||
Dbprintf("Use of `--par` option with `lf em 4x70 brute` is disabled to prevent corrupting tag data");
|
||||
reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
init_tag();
|
||||
em4x70_setup_read();
|
||||
|
||||
@@ -842,7 +871,7 @@ void em4x70_brute(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
if (get_signalproperties() && find_em4x70_tag()) {
|
||||
|
||||
// Bruteforce partial key
|
||||
status = bruteforce(etd->address, etd->rnd, etd->frnd, etd->start_key, response) == PM3_SUCCESS;
|
||||
status = bruteforce(etd->address, etd->rnd, etd->frnd, etd->start_key, response);
|
||||
}
|
||||
|
||||
StopTicks();
|
||||
@@ -852,10 +881,17 @@ void em4x70_brute(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
void em4x70_write_pin(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
uint8_t status = 0;
|
||||
int status = PM3_ESOFT;
|
||||
|
||||
command_parity = etd->parity;
|
||||
|
||||
// Disable to prevent sending corrupted data to the tag.
|
||||
if (command_parity) {
|
||||
Dbprintf("Use of `--par` option with `lf em 4x70 setpin` is disabled to prevent corrupting tag data");
|
||||
reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
init_tag();
|
||||
em4x70_setup_read();
|
||||
|
||||
@@ -865,17 +901,19 @@ void em4x70_write_pin(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
// Read ID (required for send_pin command)
|
||||
if (em4x70_read_id()) {
|
||||
|
||||
// Write new PIN
|
||||
if ((write((etd->pin) & 0xFFFF, EM4X70_PIN_WORD_UPPER) == PM3_SUCCESS) &&
|
||||
(write((etd->pin >> 16) & 0xFFFF, EM4X70_PIN_WORD_LOWER) == PM3_SUCCESS)) {
|
||||
|
||||
// Write the pin
|
||||
status = write((etd->pin) & 0xFFFF, EM4X70_PIN_WORD_UPPER);
|
||||
if (status == PM3_SUCCESS) {
|
||||
status = write((etd->pin >> 16) & 0xFFFF, EM4X70_PIN_WORD_LOWER);
|
||||
}
|
||||
if (status == PM3_SUCCESS) {
|
||||
// Now Try to authenticate using the new PIN
|
||||
|
||||
// Send PIN
|
||||
status = send_pin(etd->pin) == PM3_SUCCESS;
|
||||
status = send_pin(etd->pin);
|
||||
|
||||
// If the write succeeded, read the rest of the tag
|
||||
if (status) {
|
||||
if (status == PM3_SUCCESS) {
|
||||
// Read Tag
|
||||
// ID doesn't change
|
||||
em4x70_read_um1();
|
||||
@@ -892,10 +930,17 @@ void em4x70_write_pin(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
void em4x70_write_key(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
uint8_t status = 0;
|
||||
int status = PM3_ESOFT;
|
||||
|
||||
command_parity = etd->parity;
|
||||
|
||||
// Disable to prevent sending corrupted data to the tag.
|
||||
if (command_parity) {
|
||||
Dbprintf("Use of `--par` option with `lf em 4x70 setkey` is disabled to prevent corrupting tag data");
|
||||
reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
init_tag();
|
||||
em4x70_setup_read();
|
||||
|
||||
@@ -904,15 +949,15 @@ void em4x70_write_key(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
// Read ID to ensure we can write to card
|
||||
if (em4x70_read_id()) {
|
||||
status = 1;
|
||||
status = PM3_SUCCESS;
|
||||
|
||||
// Write each crypto block
|
||||
for (int i = 0; i < 6; i++) {
|
||||
|
||||
uint16_t key_word = (etd->crypt_key[(i * 2) + 1] << 8) + etd->crypt_key[i * 2];
|
||||
// Write each word, abort if any failure occurs
|
||||
if (write(key_word, 9 - i) != PM3_SUCCESS) {
|
||||
status = 0;
|
||||
status = write(key_word, 9 - i);
|
||||
if (status != PM3_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+53
-65
@@ -236,9 +236,10 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
||||
// 0x00 = timeslot
|
||||
// 0x09 0x21 = crc
|
||||
static uint8_t poll[10] = {0xb2, 0x4d, 0x06, FELICA_POLL_REQ, 0xFF, 0xFF, 0x00, 0x00, 0x09, 0x21};
|
||||
int len = 10;
|
||||
|
||||
|
||||
// We try 10 times, or if answer was received.
|
||||
int len = 25;
|
||||
do {
|
||||
// end-of-reception response packet data, wait approx. 501μs
|
||||
// end-of-transmission command packet data, wait approx. 197μs
|
||||
@@ -246,45 +247,40 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
||||
TransmitFor18092_AsReader(poll, sizeof(poll), NULL, 1, 0);
|
||||
|
||||
// polling card, break if success
|
||||
if (WaitForFelicaReply(1024) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK)
|
||||
if (WaitForFelicaReply(1024) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK) {
|
||||
break;
|
||||
}
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
} while (--len);
|
||||
|
||||
// timed-out
|
||||
// 1. timed-out
|
||||
if (len == 0) {
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
Dbprintf("Error: Time out card selection!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// wrong answer
|
||||
// 2. wrong answer
|
||||
if (FelicaFrame.framebytes[3] != FELICA_POLL_ACK) {
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
Dbprintf("Error: Wrong answer selecting card!");
|
||||
return 2;
|
||||
}
|
||||
|
||||
// VALIDATE CRC residue is 0, hence if crc is a value it failed.
|
||||
if (!check_crc(CRC_FELICA, FelicaFrame.framebytes + 2, FelicaFrame.len - 2)) {
|
||||
// 3. wrong crc. residue is 0, hence if crc is a value it failed.
|
||||
if (check_crc(CRC_FELICA, FelicaFrame.framebytes + 2, FelicaFrame.len - 2) == false) {
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("Error: CRC check failed!");
|
||||
Dbprintf("CRC check was done on Frame: ");
|
||||
Dbhexdump(FelicaFrame.len - 2, FelicaFrame.framebytes + 2, 0);
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
Dbprintf("Card selection successful!");
|
||||
// copy UID
|
||||
// idm 8
|
||||
if (card) {
|
||||
memcpy(card->IDm, FelicaFrame.framebytes + 4, 8);
|
||||
memcpy(card->PMm, FelicaFrame.framebytes + 4 + 8, 8);
|
||||
//memcpy(card->servicecode, FelicaFrame.framebytes + 4 + 8 + 8, 2);
|
||||
// memcpy(card->servicecode, FelicaFrame.framebytes + 4 + 8 + 8, 2);
|
||||
memcpy(card->code, card->IDm, 2);
|
||||
memcpy(card->uid, card->IDm + 2, 6);
|
||||
memcpy(card->iccode, card->PMm, 2);
|
||||
@@ -294,7 +290,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
||||
Dbhexdump(FelicaFrame.len, FelicaFrame.framebytes, 0);
|
||||
}
|
||||
}
|
||||
// more status bytes?
|
||||
// 0. OK
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -311,8 +307,10 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
||||
// 8-byte IDm, number of blocks, blocks numbers
|
||||
// number of blocks limited to 4 for FelicaLite(S)
|
||||
static void BuildFliteRdblk(const uint8_t *idm, uint8_t blocknum, const uint16_t *blocks) {
|
||||
if (blocknum > 4 || blocknum == 0)
|
||||
|
||||
if (blocknum > 4 || blocknum == 0) {
|
||||
Dbprintf("Invalid number of blocks, %d != 4", blocknum);
|
||||
}
|
||||
|
||||
uint8_t c = 0, i = 0;
|
||||
|
||||
@@ -320,11 +318,11 @@ static void BuildFliteRdblk(const uint8_t *idm, uint8_t blocknum, const uint16_t
|
||||
frameSpace[c++] = 0xb2;
|
||||
frameSpace[c++] = 0x4d;
|
||||
|
||||
c++; //set length later
|
||||
c++; // set length later
|
||||
|
||||
frameSpace[c++] = FELICA_RDBLK_REQ; //command number
|
||||
frameSpace[c++] = FELICA_RDBLK_REQ; // command number
|
||||
|
||||
//card IDm, from poll
|
||||
// card IDm, from poll
|
||||
frameSpace[c++] = idm[0];
|
||||
frameSpace[c++] = idm[1];
|
||||
frameSpace[c++] = idm[2];
|
||||
@@ -334,22 +332,22 @@ static void BuildFliteRdblk(const uint8_t *idm, uint8_t blocknum, const uint16_t
|
||||
frameSpace[c++] = idm[6];
|
||||
frameSpace[c++] = idm[7];
|
||||
|
||||
//number of services
|
||||
// number of services
|
||||
frameSpace[c++] = 0x01;
|
||||
|
||||
//service code
|
||||
// service code
|
||||
frameSpace[c++] = (SERVICE_FELICA_LITE_READONLY >> 8);
|
||||
frameSpace[c++] = SERVICE_FELICA_LITE_READONLY & 0xFF;
|
||||
|
||||
//number of blocks
|
||||
// number of blocks
|
||||
frameSpace[c++] = blocknum;
|
||||
|
||||
for (i = 0; i < blocknum; i++) {
|
||||
|
||||
//3-byte block
|
||||
// 3-byte block
|
||||
if (blocks[i] >= 256) {
|
||||
frameSpace[c++] = 0x00;
|
||||
frameSpace[c++] = (blocks[i] >> 8); //block number, little endian....
|
||||
frameSpace[c++] = (blocks[i] >> 8); // block number, little endian....
|
||||
frameSpace[c++] = (blocks[i] & 0xff);
|
||||
} else {
|
||||
frameSpace[c++] = 0x80;
|
||||
@@ -357,16 +355,16 @@ static void BuildFliteRdblk(const uint8_t *idm, uint8_t blocknum, const uint16_t
|
||||
}
|
||||
}
|
||||
|
||||
//set length
|
||||
// set length
|
||||
frameSpace[2] = c - 2;
|
||||
//Add CRC
|
||||
// Add CRC
|
||||
AddCrc(frameSpace + 2, c - 2);
|
||||
}
|
||||
|
||||
static void TransmitFor18092_AsReader(const uint8_t *frame, uint16_t len, const uint32_t *NYI_timing_NYI, uint8_t power, uint8_t highspeed) {
|
||||
|
||||
if (NYI_timing_NYI != NULL) {
|
||||
Dbprintf("Error: TransmitFor18092_AsReader does not check or set parameter NYI_timing_NYI");
|
||||
DbpString("Error: TransmitFor18092_AsReader does not check or set parameter NYI_timing_NYI");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -400,10 +398,6 @@ static void TransmitFor18092_AsReader(const uint8_t *frame, uint16_t len, const
|
||||
}
|
||||
// sending data with sync bytes
|
||||
c = 0;
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("Sending frame:");
|
||||
Dbhexdump(len, frame, 0);
|
||||
}
|
||||
|
||||
while (c < len) {
|
||||
// Put byte into tx holding register as soon as it is ready
|
||||
@@ -438,9 +432,7 @@ static void TransmitFor18092_AsReader(const uint8_t *frame, uint16_t len, const
|
||||
// or return TRUE when command is captured
|
||||
bool WaitForFelicaReply(uint16_t maxbytes) {
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("WaitForFelicaReply Start");
|
||||
}
|
||||
// if (g_dbglevel >= DBG_DEBUG) { Dbprintf("WaitForFelicaReply Start"); }
|
||||
|
||||
uint32_t c = 0;
|
||||
|
||||
@@ -478,14 +470,11 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
|
||||
NULL,
|
||||
false
|
||||
);
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("All bytes received! STATE_FULL");
|
||||
|
||||
return true;
|
||||
|
||||
} else if (c++ > timeout && (FelicaFrame.state == STATE_UNSYNCD || FelicaFrame.state == STATE_TRYING_SYNC)) {
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Error: Timeout! STATE_UNSYNCD");
|
||||
// if (g_dbglevel >= DBG_DEBUG) Dbprintf("Error: Timeout! STATE_UNSYNCD");
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -496,7 +485,6 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
|
||||
// Set up FeliCa communication (similar to iso14443a_setup)
|
||||
// field is setup for "Sending as Reader"
|
||||
static void iso18092_setup(uint8_t fpga_minor_mode) {
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Start iso18092_setup");
|
||||
|
||||
LEDsoff();
|
||||
#if defined XC3
|
||||
@@ -510,7 +498,7 @@ static void iso18092_setup(uint8_t fpga_minor_mode) {
|
||||
|
||||
// Initialize Demod and Uart structs
|
||||
// DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
|
||||
FelicaFrameinit(BigBuf_malloc(FELICA_MAX_FRAME_SIZE));
|
||||
FelicaFrameinit(BigBuf_calloc(FELICA_MAX_FRAME_SIZE));
|
||||
|
||||
felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER; // 418
|
||||
// iso18092_set_timeout(2120); // 106 * 20ms maximum start-up time of card
|
||||
@@ -553,63 +541,63 @@ static void felica_reset_frame_mode(void) {
|
||||
// arg1 len of commandbytes
|
||||
// d.asBytes command bytes to send
|
||||
void felica_sendraw(const PacketCommandNG *c) {
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("FeliCa_sendraw Enter");
|
||||
|
||||
felica_command_t param = c->oldarg[0];
|
||||
size_t len = c->oldarg[1] & 0xffff;
|
||||
const uint8_t *cmd = c->data.asBytes;
|
||||
uint32_t arg0;
|
||||
|
||||
felica_card_select_t card;
|
||||
|
||||
if ((param & FELICA_CONNECT))
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Clear trace");
|
||||
clear_trace();
|
||||
|
||||
if ((param & FELICA_CONNECT) == FELICA_CONNECT) {
|
||||
clear_trace();
|
||||
}
|
||||
set_tracing(true);
|
||||
|
||||
iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
|
||||
if ((param & FELICA_CONNECT)) {
|
||||
if ((param & FELICA_CONNECT) == FELICA_CONNECT) {
|
||||
|
||||
// notify client selecting status.
|
||||
// if failed selecting, turn off antenna and quite.
|
||||
if (!(param & FELICA_NO_SELECT)) {
|
||||
if ((param & FELICA_NO_SELECT) != FELICA_NO_SELECT) {
|
||||
|
||||
felica_card_select_t card;
|
||||
arg0 = felica_select_card(&card);
|
||||
reply_mix(CMD_ACK, arg0, sizeof(card.uid), 0, &card, sizeof(felica_card_select_t));
|
||||
if (arg0 > 0) {
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Error: Failed selecting card! ");
|
||||
if (arg0) {
|
||||
felica_reset_frame_mode();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("No card selection");
|
||||
|
||||
}
|
||||
|
||||
if ((param & FELICA_RAW)) {
|
||||
if ((param & FELICA_RAW) == FELICA_RAW) {
|
||||
|
||||
// 2 sync, 1 len, 2crc == 5
|
||||
uint8_t *buf = BigBuf_malloc(len + 5);
|
||||
uint8_t *buf = BigBuf_calloc(len + 5);
|
||||
// add sync bits
|
||||
buf[0] = 0xb2;
|
||||
buf[1] = 0x4d;
|
||||
buf[2] = len;
|
||||
|
||||
// copy command
|
||||
memcpy(buf + 2, cmd, len);
|
||||
memcpy(buf + 2, c->data.asBytes, len);
|
||||
|
||||
if ((param & FELICA_APPEND_CRC)) {
|
||||
if ((param & FELICA_APPEND_CRC) == FELICA_APPEND_CRC) {
|
||||
// Don't append crc on empty bytearray...
|
||||
if (len > 0) {
|
||||
AddCrc(buf + 2, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("Transmit Frame (no CRC shown):");
|
||||
Dbhexdump(len, buf, 0);
|
||||
Dbprintf("Buffer Length: %i", buf[2] + 4);
|
||||
};
|
||||
|
||||
TransmitFor18092_AsReader(buf, buf[2] + 4, NULL, 1, 0);
|
||||
arg0 = WaitForFelicaReply(1024);
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("Received Frame Code: %d", arg0);
|
||||
Dbhexdump(FelicaFrame.len, FelicaFrame.framebytes, 0);
|
||||
@@ -620,11 +608,11 @@ void felica_sendraw(const PacketCommandNG *c) {
|
||||
Dbprintf("Reply to Client Error Code: %i", result);
|
||||
}
|
||||
}
|
||||
if ((param & FELICA_NO_DISCONNECT)) {
|
||||
Dbprintf("Disconnect");
|
||||
|
||||
if ((param & FELICA_NO_DISCONNECT) == FELICA_NO_DISCONNECT) {
|
||||
return;
|
||||
}
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
Dbprintf("FeliCa_sendraw Exit");
|
||||
|
||||
felica_reset_frame_mode();
|
||||
return;
|
||||
}
|
||||
@@ -641,7 +629,7 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) {
|
||||
int remFrames = (samplesToSkip) ? samplesToSkip : 0;
|
||||
int trigger_cnt = 0;
|
||||
uint32_t timeout = iso18092_get_timeout();
|
||||
bool isReaderFrame = true;
|
||||
bool isReaderFrame;
|
||||
|
||||
uint8_t flip = 0;
|
||||
uint16_t checker = 0;
|
||||
@@ -744,7 +732,7 @@ void felica_sim_lite(const uint8_t *uid) {
|
||||
|
||||
int retval = PM3_SUCCESS;
|
||||
int curlen = 0;
|
||||
uint8_t *curresp = NULL;
|
||||
const uint8_t *curresp = NULL;
|
||||
bool listenmode = true;
|
||||
// uint32_t frtm = GetCountSspClk();
|
||||
|
||||
@@ -894,7 +882,7 @@ void felica_dump_lite_s(void) {
|
||||
|
||||
dest[cnt++] = liteblks[blknum];
|
||||
|
||||
uint8_t *fb = FelicaFrame.framebytes;
|
||||
const uint8_t *fb = FelicaFrame.framebytes;
|
||||
dest[cnt++] = fb[12];
|
||||
dest[cnt++] = fb[13];
|
||||
|
||||
|
||||
+19
-20
@@ -17,7 +17,7 @@
|
||||
#define DBG if (g_dbglevel >= DBG_EXTENDED)
|
||||
|
||||
#include "hitag2.h"
|
||||
#include "hitag2_crypto.h"
|
||||
#include "hitag2/hitag2_crypto.h"
|
||||
#include "string.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "cmd.h"
|
||||
@@ -120,7 +120,7 @@ static void hitag2_init(void) {
|
||||
#define HITAG_FRAME_LEN 20
|
||||
#define HITAG_FRAME_BIT_COUNT (8 * HITAG_FRAME_LEN)
|
||||
#define HITAG_T_STOP 36 /* T_EOF should be > 36 */
|
||||
#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */
|
||||
#define HITAG_T_LOW 6 /* T_LOW should be 4..10 */
|
||||
#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */
|
||||
#define HITAG_T_0 20 /* T[0] should be 18..22 */
|
||||
#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */
|
||||
@@ -322,8 +322,6 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_
|
||||
// reader/writer
|
||||
// returns how long it took
|
||||
static uint32_t hitag_reader_send_bit(int bit) {
|
||||
uint32_t wait = 0;
|
||||
|
||||
// Binary pulse length modulation (BPLM) is used to encode the data stream
|
||||
// This means that a transmission of a one takes longer than that of a zero
|
||||
|
||||
@@ -331,8 +329,8 @@ static uint32_t hitag_reader_send_bit(int bit) {
|
||||
lf_modulation(true);
|
||||
|
||||
// Wait for 4-10 times the carrier period
|
||||
lf_wait_periods(8); // wait for 4-10 times the carrier period
|
||||
wait += 8;
|
||||
lf_wait_periods(HITAG_T_LOW); // wait for 4-10 times the carrier period
|
||||
uint32_t wait = HITAG_T_LOW;
|
||||
|
||||
// Disable modulation, just activates the field again
|
||||
lf_modulation(false);
|
||||
@@ -353,6 +351,7 @@ static uint32_t hitag_reader_send_bit(int bit) {
|
||||
// reader / writer commands
|
||||
// frame_len is in number of bits?
|
||||
static uint32_t hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) {
|
||||
WDT_HIT();
|
||||
|
||||
uint32_t wait = 0;
|
||||
// Send the content of the frame
|
||||
@@ -360,6 +359,7 @@ static uint32_t hitag_reader_send_frame(const uint8_t *frame, size_t frame_len)
|
||||
wait += hitag_reader_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1);
|
||||
}
|
||||
|
||||
// Send EOF
|
||||
// Enable modulation, which means, drop the field
|
||||
lf_modulation(true);
|
||||
|
||||
@@ -373,6 +373,7 @@ static uint32_t hitag_reader_send_frame(const uint8_t *frame, size_t frame_len)
|
||||
// t_stop, high field for stop condition (> 36)
|
||||
lf_wait_periods(HITAG_T_STOP);
|
||||
wait += HITAG_T_STOP;
|
||||
WDT_HIT();
|
||||
return wait;
|
||||
}
|
||||
|
||||
@@ -380,13 +381,17 @@ static uint32_t hitag_reader_send_frame(const uint8_t *frame, size_t frame_len)
|
||||
// frame_len is in number of bits?
|
||||
static uint32_t hitag_reader_send_framebits(const uint8_t *frame, size_t frame_len) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
uint32_t wait = 0;
|
||||
// Send the content of the frame
|
||||
for (size_t i = 0; i < frame_len; i++) {
|
||||
wait += hitag_reader_send_bit(frame[i]);
|
||||
}
|
||||
|
||||
// Send EOF
|
||||
// Enable modulation, which means, drop the field
|
||||
// set GPIO_SSC_DOUT to HIGH
|
||||
lf_modulation(true);
|
||||
|
||||
// Wait for 4-10 times the carrier period
|
||||
@@ -394,12 +399,14 @@ static uint32_t hitag_reader_send_framebits(const uint8_t *frame, size_t frame_l
|
||||
wait += HITAG_T_LOW;
|
||||
|
||||
// Disable modulation, just activates the field again
|
||||
// set GPIO_SSC_DOUT to LOW
|
||||
lf_modulation(false);
|
||||
|
||||
// t_stop, high field for stop condition (> 36)
|
||||
lf_wait_periods(HITAG_T_STOP);
|
||||
wait += HITAG_T_STOP;
|
||||
|
||||
WDT_HIT();
|
||||
return wait;
|
||||
}
|
||||
|
||||
@@ -768,6 +775,8 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *
|
||||
}
|
||||
|
||||
if (bCrypto && (bAuthenticating == false) && write) {
|
||||
|
||||
SpinDelay(2);
|
||||
if (hitag2_write_page(rx, rxlen, tx, txlen) == false) {
|
||||
return false;
|
||||
}
|
||||
@@ -2409,7 +2418,7 @@ static void ht2_send(bool turn_on, uint32_t *cmd_start
|
||||
, uint8_t *tx, size_t txlen, bool send_bits) {
|
||||
|
||||
// Tag specific configuration settings (sof, timings, etc.) HITAG2 Settings
|
||||
#define T_WAIT_1_GUARD 8
|
||||
#define T_WAIT_1_GUARD 7
|
||||
|
||||
if (turn_on) {
|
||||
// Wait 50ms with field off to be sure the transponder gets reset
|
||||
@@ -2583,8 +2592,7 @@ bool ht2_packbits(uint8_t *nrz_samples, size_t nrzs, uint8_t *rx, size_t *rxlen)
|
||||
|
||||
int ht2_read_uid(uint8_t *uid, bool ledcontrol, bool send_answer, bool keep_field_up) {
|
||||
|
||||
// Clean up trace and prepare it for storing frames
|
||||
set_tracing(true);
|
||||
g_logging = false;
|
||||
|
||||
// keep field up indicates there are more traffic to be done.
|
||||
if (keep_field_up == false) {
|
||||
@@ -2685,12 +2693,7 @@ int ht2_tx_rx(uint8_t *tx, size_t txlen, uint8_t *rx, size_t *rxlen, bool ledcon
|
||||
|
||||
int res = PM3_EFAILED;
|
||||
size_t nrzs = 0;
|
||||
uint8_t samples[HT2_MAX_NRSZ];
|
||||
|
||||
// waith between sending commands
|
||||
lf_wait_periods(HITAG_T_WAIT_2_MIN);
|
||||
|
||||
WDT_HIT();
|
||||
uint8_t samples[HT2_MAX_NRSZ] = {0};
|
||||
|
||||
uint32_t command_start = 0, command_duration = 0;
|
||||
uint32_t response_start = 0, response_duration = 0;
|
||||
@@ -2709,19 +2712,15 @@ int ht2_tx_rx(uint8_t *tx, size_t txlen, uint8_t *rx, size_t *rxlen, bool ledcon
|
||||
}
|
||||
|
||||
// pack bits to bytes
|
||||
if (ht2_packbits(samples, nrzs, rx, rxlen) == false) {
|
||||
if (rx && (ht2_packbits(samples, nrzs, rx, rxlen) == false)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
// log Receive data
|
||||
LogTraceBits(rx, *rxlen, response_start, response_start + response_duration, false);
|
||||
|
||||
res = PM3_SUCCESS;
|
||||
|
||||
out:
|
||||
if (keep_field_up == false) {
|
||||
lf_finalize(false);
|
||||
BigBuf_free_keep_EM();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
+156
-71
@@ -19,7 +19,7 @@
|
||||
|
||||
|
||||
#include "hitag2_crack.h"
|
||||
#include "hitag2_crypto.h"
|
||||
#include "hitag2/hitag2_crypto.h"
|
||||
#include "hitag2.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "commonutil.h"
|
||||
@@ -28,16 +28,15 @@
|
||||
#include "string.h"
|
||||
#include "BigBuf.h"
|
||||
#include "cmd.h"
|
||||
|
||||
const static uint8_t ERROR_RESPONSE[] = { 0xF4, 0x02, 0x88, 0x9C };
|
||||
#include "lfadc.h"
|
||||
|
||||
// #define READP0CMD "1100000111"
|
||||
const static uint8_t read_p0_cmd[] = {1, 1, 0, 0, 0, 0, 0, 1, 1, 1};
|
||||
|
||||
// hitag2crack_xor XORs the source with the pad to produce the target.
|
||||
// source, target and pad are binarrays of length len.
|
||||
static void hitag2crack_xor(uint8_t *target, const uint8_t *source, const uint8_t *pad, uint16_t len) {
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
static void hitag2crack_xor(uint8_t *target, const uint8_t *source, const uint8_t *pad, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
target[i] = source[i] ^ pad[i];
|
||||
}
|
||||
}
|
||||
@@ -48,20 +47,18 @@ static void hitag2crack_xor(uint8_t *target, const uint8_t *source, const uint8_
|
||||
// nrar is the 64 bit binarray of the nR aR pair;
|
||||
// cmd is the binarray of the encrypted command to send;
|
||||
// len is the length of the encrypted command.
|
||||
static bool hitag2crack_send_e_cmd(uint8_t *resp, uint8_t *nrar, uint8_t *cmd, int len) {
|
||||
static bool hitag2crack_send_e_cmd(uint8_t *resp, uint8_t *nrar, uint8_t *cmd, size_t len) {
|
||||
|
||||
memset(resp, 0, 4);
|
||||
|
||||
// Get UID
|
||||
uint8_t uid[4];
|
||||
if (ht2_read_uid(uid, false, false, true) != PM3_SUCCESS) {
|
||||
if (ht2_read_uid(NULL, true, false, true) != PM3_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// send nrar and receive (useless) encrypted page 3 value
|
||||
uint8_t e_page3[4];
|
||||
size_t n = 0;
|
||||
if (ht2_tx_rx(nrar, 64, e_page3, &n, true, true) != PM3_SUCCESS) {
|
||||
if (ht2_tx_rx(nrar, 64, NULL, &n, true, true) != PM3_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -114,22 +111,18 @@ static bool hitag2crack_read_page(uint8_t *resp, uint8_t pagenum, uint8_t *nrar,
|
||||
uint8_t e_resp[4];
|
||||
if (hitag2crack_send_e_cmd(e_resp, nrar, e_cmd, 10)) {
|
||||
|
||||
// check if it is valid OBS!
|
||||
if (memcmp(e_resp, ERROR_RESPONSE, 4)) {
|
||||
uint8_t e_response[32] = {0};
|
||||
uint8_t response[32] = {0};
|
||||
|
||||
uint8_t e_response[32];
|
||||
uint8_t response[32];
|
||||
// convert to binarray
|
||||
hex2binarray_n((char *)e_response, (char *)e_resp, 4);
|
||||
// decrypt response
|
||||
hitag2crack_xor(response, e_response, keybits + 10, 32);
|
||||
|
||||
// convert to binarray
|
||||
hex2binarray((char *)e_response, (char *)e_resp);
|
||||
// decrypt response
|
||||
hitag2crack_xor(response, e_response, keybits + 10, 32);
|
||||
// convert to hexstring
|
||||
binarray2hex(response, 32, resp);
|
||||
|
||||
// convert to hexstring
|
||||
binarray2hex(response, 32, resp);
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -146,12 +139,12 @@ static bool hitag2crack_read_page(uint8_t *resp, uint8_t pagenum, uint8_t *nrar,
|
||||
// e_uid is the binarray of the encrypted version of the UID.
|
||||
static bool hitag2crack_test_e_p0cmd(uint8_t *keybits, uint8_t *nrar, uint8_t *e_cmd, uint8_t *uid, uint8_t *e_uid) {
|
||||
|
||||
uint8_t cipherbits[42];
|
||||
uint8_t cipherbits[42] = {0};
|
||||
memcpy(cipherbits, e_cmd, 10); // copy encrypted cmd to cipherbits
|
||||
memcpy(cipherbits + 10, e_uid, 32); // copy encrypted uid to cipherbits
|
||||
|
||||
|
||||
uint8_t plainbits[42];
|
||||
uint8_t plainbits[42] = {0};
|
||||
memcpy(plainbits, read_p0_cmd, sizeof(read_p0_cmd)); // copy cmd to plainbits
|
||||
memcpy(plainbits + 10, uid, 32); // copy uid to plainbits
|
||||
|
||||
@@ -159,24 +152,17 @@ static bool hitag2crack_test_e_p0cmd(uint8_t *keybits, uint8_t *nrar, uint8_t *e
|
||||
hitag2crack_xor(keybits, plainbits, cipherbits, 42);
|
||||
|
||||
// create extended cmd -> 4 * READP0CMD = 40 bits
|
||||
uint8_t ext_cmd[40];
|
||||
memcpy(ext_cmd, read_p0_cmd, sizeof(read_p0_cmd));
|
||||
memcpy(ext_cmd + 10, read_p0_cmd, sizeof(read_p0_cmd));
|
||||
memcpy(ext_cmd + 20, read_p0_cmd, sizeof(read_p0_cmd));
|
||||
memcpy(ext_cmd + 30, read_p0_cmd, sizeof(read_p0_cmd));
|
||||
|
||||
// xor extended cmd with keybits
|
||||
uint8_t e_ext_cmd[40];
|
||||
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits, 40);
|
||||
uint8_t e_ext_cmd[40] = {0};
|
||||
hitag2crack_xor(e_ext_cmd, read_p0_cmd, keybits, 10);
|
||||
hitag2crack_xor(e_ext_cmd + 10, read_p0_cmd, keybits + 10, 10);
|
||||
hitag2crack_xor(e_ext_cmd + 20, read_p0_cmd, keybits + 20, 10);
|
||||
hitag2crack_xor(e_ext_cmd + 30, read_p0_cmd, keybits + 30, 10);
|
||||
|
||||
// send extended encrypted cmd
|
||||
uint8_t resp[4];
|
||||
uint8_t resp[4] = {0};
|
||||
if (hitag2crack_send_e_cmd(resp, nrar, e_ext_cmd, 40)) {
|
||||
|
||||
// test if it was valid
|
||||
if (memcmp(resp, ERROR_RESPONSE, 4)) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -202,6 +188,7 @@ static bool hitag2crack_find_e_page0_cmd(uint8_t *keybits, uint8_t *e_firstcmd,
|
||||
// encrypted command.
|
||||
uint8_t guess[10];
|
||||
memcpy(guess, e_firstcmd, 10);
|
||||
|
||||
if (a) {
|
||||
guess[5] = !guess[5];
|
||||
guess[0] = !guess[0];
|
||||
@@ -223,20 +210,17 @@ static bool hitag2crack_find_e_page0_cmd(uint8_t *keybits, uint8_t *e_firstcmd,
|
||||
}
|
||||
|
||||
// try the guess
|
||||
uint8_t resp[4];
|
||||
uint8_t resp[4] = {0};
|
||||
if (hitag2crack_send_e_cmd(resp, nrar, guess, 10)) {
|
||||
|
||||
// check if it was valid
|
||||
if (memcmp(resp, ERROR_RESPONSE, 4)) {
|
||||
// convert response to binarray
|
||||
// response should been encrypted UID
|
||||
uint8_t e_uid[32] = {0};
|
||||
hex2binarray_n((char *)e_uid, (char *)resp, 4);
|
||||
|
||||
// convert response to binarray
|
||||
uint8_t e_uid[32];
|
||||
hex2binarray((char *)e_uid, (char *)resp);
|
||||
|
||||
// test if the guess was 'read page 0' command
|
||||
if (hitag2crack_test_e_p0cmd(keybits, nrar, guess, uid, e_uid)) {
|
||||
return true;
|
||||
}
|
||||
// test if the guess was 'read page 0' command
|
||||
if (hitag2crack_test_e_p0cmd(keybits, nrar, guess, uid, e_uid)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -263,29 +247,15 @@ static bool hitag2crack_find_valid_e_cmd(uint8_t *e_cmd, uint8_t *nrar) {
|
||||
for (uint8_t g = 0; g < 2; g++) {
|
||||
|
||||
// build binarray
|
||||
//uint8_t guess[10] = { a, b, c, d, e, 0, g, 0, 0, 0 };
|
||||
uint8_t guess[10];
|
||||
guess[0] = a;
|
||||
guess[1] = b;
|
||||
guess[2] = c;
|
||||
guess[3] = d;
|
||||
guess[4] = e;
|
||||
guess[5] = 0;
|
||||
guess[6] = g;
|
||||
guess[7] = 0;
|
||||
guess[8] = 0;
|
||||
guess[9] = 0;
|
||||
uint8_t guess[10] = { a, b, c, d, e, 0, g, 0, 0, 0 };
|
||||
|
||||
// send guess
|
||||
uint8_t resp[4];
|
||||
uint8_t resp[4] = {0};
|
||||
if (hitag2crack_send_e_cmd(resp, nrar, guess, sizeof(guess))) {
|
||||
|
||||
// check if it was valid
|
||||
if (memcmp(resp, ERROR_RESPONSE, 4)) {
|
||||
// return the guess as the encrypted command
|
||||
memcpy(e_cmd, guess, 10);
|
||||
return true;
|
||||
}
|
||||
// return the guess as the encrypted command
|
||||
memcpy(e_cmd, guess, 10);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -296,11 +266,18 @@ static bool hitag2crack_find_valid_e_cmd(uint8_t *e_cmd, uint8_t *nrar) {
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint8_t keybits[2080];
|
||||
uint8_t uid[32];
|
||||
uint8_t nrar[64];
|
||||
uint8_t e_ext_cmd[2080];
|
||||
} PACKED lf_hitag_crack2_t;
|
||||
|
||||
// hitag2_crack implements the first crack algorithm described in the paper,
|
||||
// Gone In 360 Seconds by Verdult, Garcia and Balasch.
|
||||
// response is a multi-line text response containing the 8 pages of the cracked tag
|
||||
// nrarhex is a string containing hex representations of the 32 bit nR and aR values
|
||||
void ht2_crack(uint8_t *nrar_hex) {
|
||||
void ht2_crack1(uint8_t *nrar_hex) {
|
||||
|
||||
clear_trace();
|
||||
|
||||
@@ -340,7 +317,6 @@ void ht2_crack(uint8_t *nrar_hex) {
|
||||
res = PM3_EFAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// read all pages using key stream
|
||||
for (uint8_t i = 1; i < 8; i++) {
|
||||
hitag2crack_read_page(packet.data + (i * 4), i, nrar, keybits);
|
||||
@@ -354,3 +330,112 @@ void ht2_crack(uint8_t *nrar_hex) {
|
||||
out:
|
||||
reply_ng(CMD_LF_HITAG2_CRACK, res, (uint8_t *)&packet, sizeof(lf_hitag_crack_response_t));
|
||||
}
|
||||
|
||||
// hitag2_keystream uses the first crack algorithm described in the paper,
|
||||
// Gone In 360 Seconds by Verdult, Garcia and Balasch, to retrieve 2048 bits of keystream.
|
||||
// response is a multi-line text response containing the hex of the keystream;
|
||||
// nrar_hex is the 32 bit nR and aR in hex
|
||||
void ht2_crack2(uint8_t *nrar_hex) {
|
||||
|
||||
BigBuf_free();
|
||||
|
||||
uint8_t *e_response = BigBuf_calloc(32);
|
||||
lf_hitag_crack2_t *c2 = (lf_hitag_crack2_t *)BigBuf_calloc(sizeof(lf_hitag_crack2_t));
|
||||
|
||||
g_logging = false;
|
||||
LEDsoff();
|
||||
set_tracing(false);
|
||||
clear_trace();
|
||||
|
||||
// find the 'read page 0' command and recover key stream
|
||||
|
||||
// get uid as hexstring
|
||||
uint8_t uid_hex[4] = {0};
|
||||
if (ht2_read_uid(uid_hex, false, false, false) != PM3_SUCCESS) {
|
||||
BigBuf_free();
|
||||
reply_ng(CMD_LF_HITAG2_CRACK_2, PM3_EFAILED, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
hex2binarray_n((char *)c2->uid, (char *)uid_hex, 4);
|
||||
hex2binarray_n((char *)c2->nrar, (char *)nrar_hex, 8);
|
||||
|
||||
DbpString("looking for encrypted command");
|
||||
|
||||
// find a valid encrypted command
|
||||
uint8_t e_firstcmd[10] = {0};
|
||||
if (hitag2crack_find_valid_e_cmd(e_firstcmd, c2->nrar) == false) {
|
||||
BigBuf_free();
|
||||
reply_ng(CMD_LF_HITAG2_CRACK_2, PM3_EFAILED, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
DbpString("looking for encrypted page 0");
|
||||
// find encrypted page0 commnd
|
||||
if (hitag2crack_find_e_page0_cmd(c2->keybits, e_firstcmd, c2->nrar, c2->uid) == false) {
|
||||
BigBuf_free();
|
||||
reply_ng(CMD_LF_HITAG2_CRACK_2, PM3_EFAILED, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// We got 42 bits of keystream in c2->keybits.
|
||||
// using the 40 bits of keystream in keybits, sending commands with ever
|
||||
// increasing lengths to acquire 2048 bits of key stream.
|
||||
int kslen = 40;
|
||||
int res = PM3_SUCCESS;
|
||||
|
||||
while (kslen < 2048 && BUTTON_PRESS() == false) {
|
||||
|
||||
hitag2crack_xor(c2->e_ext_cmd, read_p0_cmd, c2->keybits, 10);
|
||||
hitag2crack_xor(c2->e_ext_cmd + 10, read_p0_cmd, c2->keybits + 10, 10);
|
||||
hitag2crack_xor(c2->e_ext_cmd + 20, read_p0_cmd, c2->keybits + 20, 10);
|
||||
hitag2crack_xor(c2->e_ext_cmd + 30, read_p0_cmd, c2->keybits + 30, 10);
|
||||
|
||||
Dbprintf("Recovered " _YELLOW_("%4i") " bits of keystream", kslen);
|
||||
|
||||
// Get UID
|
||||
if (ht2_read_uid(NULL, true, false, true) != PM3_SUCCESS) {
|
||||
res = PM3_EFAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
// send nrar and receive (useless) encrypted page 3 value
|
||||
size_t n = 0;
|
||||
if (ht2_tx_rx(c2->nrar, 64, NULL, &n, true, true) != PM3_SUCCESS) {
|
||||
res = PM3_EFAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t resp[4] = {0};
|
||||
res = ht2_tx_rx(c2->e_ext_cmd, kslen, resp, &n, true, false);
|
||||
if (res != PM3_SUCCESS) {
|
||||
Dbprintf("tx/rx failed, got %zu (res... %i)", n, res);
|
||||
break;
|
||||
}
|
||||
|
||||
// convert response to binarray
|
||||
hex2binarray_n((char *)e_response, (char *)resp, 4);
|
||||
|
||||
// recover keystream from encrypted response
|
||||
hitag2crack_xor(c2->keybits + kslen, e_response, c2->uid, 32);
|
||||
|
||||
// extented with 30 bits or 3 * 10 read_p0_cmds
|
||||
hitag2crack_xor(c2->e_ext_cmd + kslen, read_p0_cmd, c2->keybits + kslen, 10);
|
||||
kslen += 10;
|
||||
hitag2crack_xor(c2->e_ext_cmd + kslen, read_p0_cmd, c2->keybits + kslen, 10);
|
||||
kslen += 10;
|
||||
hitag2crack_xor(c2->e_ext_cmd + kslen, read_p0_cmd, c2->keybits + kslen, 10);
|
||||
kslen += 10;
|
||||
}
|
||||
|
||||
Dbprintf("Recovered " _YELLOW_("%4i") " bits of keystream", kslen);
|
||||
|
||||
lf_hitag_crack_response_t *packet = (lf_hitag_crack_response_t *)BigBuf_calloc(sizeof(lf_hitag_crack_response_t));
|
||||
|
||||
packet->status = 1;
|
||||
binarray2hex(c2->keybits, kslen, packet->data);
|
||||
|
||||
reply_ng(CMD_LF_HITAG2_CRACK_2, res, (uint8_t *)packet, sizeof(lf_hitag_crack_response_t));
|
||||
BigBuf_free();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,6 @@
|
||||
#include <stdbool.h>
|
||||
#include "common.h"
|
||||
|
||||
void ht2_crack(uint8_t *nrar_hex);
|
||||
|
||||
void ht2_crack1(uint8_t *nrar_hex);
|
||||
void ht2_crack2(uint8_t *nrar_hex);
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -29,7 +29,7 @@
|
||||
#include "util.h"
|
||||
#include "string.h"
|
||||
#include "commonutil.h"
|
||||
#include "hitag2_crypto.h"
|
||||
#include "hitag2/hitag2_crypto.h"
|
||||
#include "lfadc.h"
|
||||
#include "crc.h"
|
||||
|
||||
@@ -1090,7 +1090,7 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui
|
||||
// Dbprintf("RX0 %i:%02X.. err:%i resptime:%i", *rxlen, rx[0], errorCount, *resptime);
|
||||
}
|
||||
|
||||
static void sendReceiveHitagS(uint8_t *tx, size_t txlen, uint8_t *rx, size_t sizeofrx, size_t *prxbits, int t_wait, bool ledcontrol, bool ac_seq) {
|
||||
static void sendReceiveHitagS(const uint8_t *tx, size_t txlen, uint8_t *rx, size_t sizeofrx, size_t *prxbits, int t_wait, bool ledcontrol, bool ac_seq) {
|
||||
|
||||
LogTraceBits(tx, txlen, HITAG_T_WAIT_2, HITAG_T_WAIT_2, true);
|
||||
|
||||
@@ -1557,7 +1557,7 @@ void WritePageHitagS(const lf_hitag_data_t *payload, bool ledcontrol) {
|
||||
break;
|
||||
default: {
|
||||
res = PM3_EINVARG;
|
||||
return;
|
||||
goto write_end;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -764,7 +764,7 @@ bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen, uint32_t wait) {
|
||||
break;
|
||||
} else if (len == 1) {
|
||||
continue;
|
||||
} else if (len <= 0) {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -937,7 +937,7 @@ void SmartCardUpgrade(uint64_t arg0) {
|
||||
|
||||
bool isOK = true;
|
||||
uint16_t length = arg0, pos = 0;
|
||||
uint8_t *fwdata = BigBuf_get_addr();
|
||||
const uint8_t *fwdata = BigBuf_get_addr();
|
||||
uint8_t *verfiydata = BigBuf_malloc(I2C_BLOCK_SIZE);
|
||||
|
||||
while (length) {
|
||||
|
||||
+1
-1
@@ -68,6 +68,6 @@ void SmartCardUpgrade(uint64_t arg0);
|
||||
void SmartCardSetBaud(uint64_t arg0);
|
||||
void SmartCardSetClock(uint64_t arg0);
|
||||
void I2C_print_status(void);
|
||||
int I2C_get_version(uint8_t *maj, uint8_t *min);
|
||||
int I2C_get_version(uint8_t *major, uint8_t *minor);
|
||||
|
||||
#endif
|
||||
|
||||
+98
-78
@@ -186,7 +186,7 @@
|
||||
#endif
|
||||
|
||||
// 4sample
|
||||
#define SEND4STUFFBIT(x) tosend_stuffbit(x);tosend_stuffbit(x);tosend_stuffbit(x);tosend_stuffbit(x);
|
||||
#define SEND4STUFFBIT(x) tosend_stuffbit(!(x));tosend_stuffbit(!(x));tosend_stuffbit(!(x));tosend_stuffbit(!(x));
|
||||
|
||||
static void iso14b_set_timeout(uint32_t timeout_etu);
|
||||
static void iso14b_set_maxframesize(uint16_t size);
|
||||
@@ -702,10 +702,11 @@ static void TransmitFor14443b_AsTag(const uint8_t *response, uint16_t len) {
|
||||
// Signal field is off with the appropriate LED
|
||||
LED_D_OFF();
|
||||
|
||||
// TR0: min - 1024 cycles = 75.52 us - max 4096 cycles = 302.08 us
|
||||
SpinDelayUs(76);
|
||||
|
||||
// Modulate BPSK
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK);
|
||||
AT91C_BASE_SSC->SSC_THR = 0xFF;
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
|
||||
|
||||
// Transmit the response.
|
||||
for (uint16_t i = 0; i < len;) {
|
||||
@@ -713,6 +714,11 @@ static void TransmitFor14443b_AsTag(const uint8_t *response, uint16_t len) {
|
||||
// Put byte into tx holding register as soon as it is ready
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
|
||||
AT91C_BASE_SSC->SSC_THR = response[i++];
|
||||
|
||||
// Start-up SSC once first byte is in SSC_THR
|
||||
if (i == 1) {
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -771,10 +777,10 @@ void SimulateIso14443bTag(const uint8_t *pupi) {
|
||||
static const uint8_t respOK[] = {0x00, 0x78, 0xF0};
|
||||
|
||||
uint16_t len, cmdsReceived = 0;
|
||||
int cardSTATE = SIM_NOFIELD;
|
||||
int cardSTATE = SIM_POWER_OFF;
|
||||
int vHf = 0; // in mV
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
const tosend_t *ts = get_tosend();
|
||||
|
||||
uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE);
|
||||
|
||||
@@ -801,16 +807,18 @@ void SimulateIso14443bTag(const uint8_t *pupi) {
|
||||
}
|
||||
|
||||
// find reader field
|
||||
if (cardSTATE == SIM_NOFIELD) {
|
||||
|
||||
vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
|
||||
if (vHf > MF_MINFIELDV) {
|
||||
vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
|
||||
if (vHf > MF_MINFIELDV) {
|
||||
if (cardSTATE == SIM_POWER_OFF) {
|
||||
cardSTATE = SIM_IDLE;
|
||||
LED_A_ON();
|
||||
}
|
||||
} else {
|
||||
cardSTATE = SIM_POWER_OFF;
|
||||
LED_A_OFF();
|
||||
}
|
||||
|
||||
if (cardSTATE == SIM_NOFIELD) {
|
||||
if (cardSTATE == SIM_POWER_OFF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -820,73 +828,85 @@ void SimulateIso14443bTag(const uint8_t *pupi) {
|
||||
break;
|
||||
}
|
||||
|
||||
// ISO14443-B protocol states:
|
||||
// REQ or WUP request in ANY state
|
||||
// WUP in HALTED state
|
||||
if (len == 5) {
|
||||
if (((receivedCmd[0] == ISO14443B_REQB) && ((receivedCmd[2] & 0x08) == 0x08) && (cardSTATE == SIM_HALTED)) ||
|
||||
(receivedCmd[0] == ISO14443B_REQB)) {
|
||||
LogTrace(receivedCmd, len, 0, 0, NULL, true);
|
||||
|
||||
LogTrace(receivedCmd, len, 0, 0, NULL, true);
|
||||
cardSTATE = SIM_SELECTING;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* How should this flow go?
|
||||
* REQB or WUPB
|
||||
* send response ( waiting for Attrib)
|
||||
* ATTRIB
|
||||
* send response ( waiting for commands 7816)
|
||||
* HALT
|
||||
send halt response ( waiting for wupb )
|
||||
*/
|
||||
|
||||
switch (cardSTATE) {
|
||||
//case SIM_NOFIELD:
|
||||
case SIM_HALTED:
|
||||
case SIM_IDLE: {
|
||||
LogTrace(receivedCmd, len, 0, 0, NULL, true);
|
||||
break;
|
||||
}
|
||||
case SIM_SELECTING: {
|
||||
TransmitFor14443b_AsTag(encodedATQB, encodedATQBLen);
|
||||
LogTrace(respATQB, sizeof(respATQB), 0, 0, NULL, false);
|
||||
cardSTATE = SIM_WORK;
|
||||
break;
|
||||
}
|
||||
case SIM_HALTING: {
|
||||
TransmitFor14443b_AsTag(encodedOK, encodedOKLen);
|
||||
LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false);
|
||||
cardSTATE = SIM_HALTED;
|
||||
break;
|
||||
}
|
||||
case SIM_ACKNOWLEDGE: {
|
||||
TransmitFor14443b_AsTag(encodedOK, encodedOKLen);
|
||||
LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false);
|
||||
cardSTATE = SIM_IDLE;
|
||||
break;
|
||||
}
|
||||
case SIM_WORK: {
|
||||
if (len == 7 && receivedCmd[0] == ISO14443B_HALT) {
|
||||
cardSTATE = SIM_HALTED;
|
||||
} else if (len == 11 && receivedCmd[0] == ISO14443B_ATTRIB) {
|
||||
cardSTATE = SIM_ACKNOWLEDGE;
|
||||
} else {
|
||||
// Todo:
|
||||
// - SLOT MARKER
|
||||
// - ISO7816
|
||||
// - emulate with a memory dump
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsReceived);
|
||||
}
|
||||
|
||||
cardSTATE = SIM_IDLE;
|
||||
if ((len == 5) && (receivedCmd[0] == ISO14443B_REQB) && (receivedCmd[2] & 0x08)) {
|
||||
// WUPB
|
||||
switch (cardSTATE) {
|
||||
case SIM_IDLE:
|
||||
case SIM_READY:
|
||||
case SIM_HALT: {
|
||||
TransmitFor14443b_AsTag(encodedATQB, encodedATQBLen);
|
||||
LogTrace(respATQB, sizeof(respATQB), 0, 0, NULL, false);
|
||||
cardSTATE = SIM_READY;
|
||||
break;
|
||||
}
|
||||
case SIM_ACTIVE:
|
||||
default: {
|
||||
TransmitFor14443b_AsTag(encodedATQB, encodedATQBLen);
|
||||
LogTrace(respATQB, sizeof(respATQB), 0, 0, NULL, false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
} else if ((len == 5) && (receivedCmd[0] == ISO14443B_REQB) && !(receivedCmd[2] & 0x08)) {
|
||||
// REQB
|
||||
switch (cardSTATE) {
|
||||
case SIM_IDLE:
|
||||
case SIM_READY: {
|
||||
TransmitFor14443b_AsTag(encodedATQB, encodedATQBLen);
|
||||
LogTrace(respATQB, sizeof(respATQB), 0, 0, NULL, false);
|
||||
cardSTATE = SIM_READY;
|
||||
break;
|
||||
}
|
||||
case SIM_ACTIVE: {
|
||||
TransmitFor14443b_AsTag(encodedATQB, encodedATQBLen);
|
||||
LogTrace(respATQB, sizeof(respATQB), 0, 0, NULL, false);
|
||||
break;
|
||||
}
|
||||
case SIM_HALT:
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if ((len == 7) && (receivedCmd[0] == ISO14443B_HALT)) {
|
||||
// HLTB
|
||||
switch (cardSTATE) {
|
||||
case SIM_READY: {
|
||||
TransmitFor14443b_AsTag(encodedOK, encodedOKLen);
|
||||
LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false);
|
||||
cardSTATE = SIM_HALT;
|
||||
break;
|
||||
}
|
||||
case SIM_IDLE:
|
||||
case SIM_ACTIVE: {
|
||||
TransmitFor14443b_AsTag(encodedOK, encodedOKLen);
|
||||
LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false);
|
||||
break;
|
||||
}
|
||||
case SIM_HALT:
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (len == 11 && receivedCmd[0] == ISO14443B_ATTRIB) {
|
||||
// ATTRIB
|
||||
switch (cardSTATE) {
|
||||
case SIM_READY: {
|
||||
TransmitFor14443b_AsTag(encodedOK, encodedOKLen);
|
||||
LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false);
|
||||
cardSTATE = SIM_ACTIVE;
|
||||
break;
|
||||
}
|
||||
case SIM_IDLE:
|
||||
case SIM_ACTIVE: {
|
||||
TransmitFor14443b_AsTag(encodedOK, encodedOKLen);
|
||||
LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false);
|
||||
break;
|
||||
}
|
||||
case SIM_HALT:
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1566,7 +1586,7 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len, bool framing) {
|
||||
* Convenience function to encode, transmit and trace iso 14443b comms
|
||||
*/
|
||||
static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t *start_time, uint32_t *eof_time, bool framing) {
|
||||
tosend_t *ts = get_tosend();
|
||||
const tosend_t *ts = get_tosend();
|
||||
CodeIso14443bAsReader(cmd, len, framing);
|
||||
TransmitFor14443b_AsReader(start_time);
|
||||
if (g_trigger) LED_A_ON();
|
||||
@@ -1582,7 +1602,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t
|
||||
/* Sends an APDU to the tag
|
||||
* TODO: check CRC and preamble
|
||||
*/
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *response_byte, uint16_t *reponselen) {
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *response_byte, uint16_t *responselen) {
|
||||
|
||||
uint8_t real_cmd[msg_len + 4];
|
||||
|
||||
@@ -1693,8 +1713,8 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
|
||||
}
|
||||
}
|
||||
|
||||
if (reponselen) {
|
||||
*reponselen = len;
|
||||
if (responselen) {
|
||||
*responselen = len;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user