diff --git a/.github/ISSUE_TEMPLATE/checklist-for-release.md b/.github/ISSUE_TEMPLATE/checklist-for-release.md
index 193516862..4825270d5 100644
--- a/.github/ISSUE_TEMPLATE/checklist-for-release.md
+++ b/.github/ISSUE_TEMPLATE/checklist-for-release.md
@@ -51,7 +51,8 @@ make hitag2crack/clean && make hitag2crack && tools/pm3_tests.sh hitag2crack ||
- [ ] Fedora
- [ ] OpenSuse Leap
- [ ] OpenSuse Tumbleweed
-- [ ] OSX
+- [ ] OSX (MacPorts)
+- [ ] OSX (Homebrew)
- [ ] Android
- [ ] Termux
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1421f9cbd..eebf307e2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,18 @@ 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]
+ - Changed drastically Hitag S ARM code to remove state machines and ease way to build new commands (@doegox)
+ - Fixed Hitag S crypto mode with key or NrAr, fixed `lf hitag cc`, fixed pwd dump in hitagS dump with LKP (@doegox)
+ - Changed `trace list -h` - textual change (@iceman1001)
+ - Fixed `hf iclass config` - not get stuck when trying to make a keyroll config card (@iceman1001)
+ - Changed textual output for iclass (@iceman1001)
+ - Changed `hf iclass reader` to use NG (@iceman1001)
+ - Changed various notes to have ToC and top links (@iceman1001)
+ - Added option `lf gprox demod --raw` - now supports decoding of raw bytes (@iceman1001)
+ - Added option `hf mf gview --pwd` - now supports user supplied password (@iceman1001)
+ - Added option `--force` to `hf mfu rdb/wrbl` to force operation even if address is out of range (@doegox)
+ - Added documentation for detailed usage of the Ultimate Magic Card (@doegox)
+ - Changed HitagS trace record and parsing to deal with partial bytes and to check CRC8 (@doegox)
- Added support for KS X 6924 (South Korea's T-money card) (@toucan12)
- Fixed `hf 15 dump` - now correctly dumps 256 blocks w/o crashing the client (@iceman1001)
- Changed `hf 14a sim -t 3` - anticollision for DESFire simulation now uses different RATS (@mosci)
diff --git a/README.md b/README.md
index 58b8a6f4a..5decd8b24 100644
--- a/README.md
+++ b/README.md
@@ -53,7 +53,7 @@
|[Notes on file formats used with Proxmark3](/doc/extensions_notes.md)|[Notes on MFU binary format](/doc/mfu_binary_format_notes.md)|[Notes on FPGA & ARM](/doc/fpga_arm_notes.md)|
|[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode)|[Notes on Magic cards](/doc/magic_cards_notes.md)|
|[Notes on Color usage](/doc/colors_notes.md)|[Makefile vs CMake](/doc/md/Development/Makefile-vs-CMake.md)|[Notes on Cloner guns](/doc/cloner_notes.md)|
-|[Notes on cliparser usage](/doc/cliparser.md)|[Notes on clocks](/doc/clocks.md)|[Notes on DESFire usage](/doc/desfire.md)|
+|[Notes on cliparser usage](/doc/cliparser.md)|[Notes on clocks](/doc/clocks.md)|[Notes on MIFARE DESFire](/doc/desfire.md)|
# How to build?
diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c
index 97c2ef5c4..126e6baf1 100644
--- a/armsrc/BigBuf.c
+++ b/armsrc/BigBuf.c
@@ -13,6 +13,7 @@
#include "string.h"
#include "dbprint.h"
#include "pm3_cmd.h"
+#include "util.h" // nbytes
extern uint32_t _stack_start[], __bss_end__[];
@@ -289,6 +290,13 @@ bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, ui
return LogTrace(bytes, len, ts_start, ts_end, parity, reader2tag);
}
+// specific LogTrace function for bitstreams: the partial byte size is stored in first parity byte. E.g. bitstream "1100 00100010" -> partial byte: 4 bits
+bool RAMFUNC LogTraceBits(const uint8_t *btBytes, uint16_t bitLen, uint32_t timestamp_start, uint32_t timestamp_end, bool readerToTag) {
+ uint8_t parity[(nbytes(bitLen) - 1) / 8 + 1];
+ memset(parity, 0x00, sizeof(parity));
+ parity[0] = bitLen % 8;
+ return LogTrace(btBytes, nbytes(bitLen), timestamp_start, timestamp_end, parity, readerToTag);
+}
// Emulator memory
uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length) {
diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h
index 6bdf4e331..435aeb80d 100644
--- a/armsrc/BigBuf.h
+++ b/armsrc/BigBuf.h
@@ -45,6 +45,7 @@ void set_tracelen(uint32_t value);
bool get_tracing(void);
bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
+bool RAMFUNC LogTraceBits(const uint8_t *btBytes, uint16_t bitLen, uint32_t timestamp_start, uint32_t timestamp_end, bool readerToTag);
bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, uint32_t ts_end, uint8_t *parity, bool reader2tag);
uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length);
diff --git a/armsrc/Standalone/hf_colin.c b/armsrc/Standalone/hf_colin.c
index 93c92f92a..a48d839db 100644
--- a/armsrc/Standalone/hf_colin.c
+++ b/armsrc/Standalone/hf_colin.c
@@ -564,7 +564,7 @@ failtag:
err = 1;
allKeysFound = false;
// used in portable imlementation on microcontroller: it reports back the fail and open the
- // standalone lock reply_old(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0);
+ // standalone lock reply_ng(CMD_CJB_FSMSTATE_MENU, NULL, 0);
break;
} else if (key == -2) {
err = 1; // Can't select card.
diff --git a/armsrc/Standalone/lf_nexid.c b/armsrc/Standalone/lf_nexid.c
index c921fb2bd..f255a79c9 100644
--- a/armsrc/Standalone/lf_nexid.c
+++ b/armsrc/Standalone/lf_nexid.c
@@ -109,7 +109,7 @@ static uint8_t nexwatch_checksum(uint8_t magic, uint32_t id, uint8_t parity) {
static int nexwatch_scamble(NexWatchScramble_t action, uint32_t *id, uint32_t *scambled) {
// 255 = Not used/Unknown other values are the bit offset in the ID/FC values
- uint8_t hex_2_id [] = {
+ const uint8_t hex_2_id [] = {
31, 27, 23, 19, 15, 11, 7, 3,
30, 26, 22, 18, 14, 10, 6, 2,
29, 25, 21, 17, 13, 9, 5, 1,
diff --git a/armsrc/Standalone/readme.md b/armsrc/Standalone/readme.md
index dee415ffa..dacf5057c 100644
--- a/armsrc/Standalone/readme.md
+++ b/armsrc/Standalone/readme.md
@@ -1,4 +1,19 @@
# Standalone Modes
+
+
+
+# Table of Contents
+- [Standalone Modes](#standalone-modes)
+- [Table of Contents](#table-of-contents)
+ - [Implementing a standalone mode](#implementing-a-standalone-mode)
+ - [Naming your standalone mode](#naming-your-standalone-mode)
+ - [Update MAKEFILE.HAL](#update-makefilehal)
+ - [Update MAKEFILE.INC](#update-makefileinc)
+ - [Adding identification string of your mode](#adding-identification-string-of-your-mode)
+ - [Compiling your standalone mode](#compiling-your-standalone-mode)
+ - [Submitting your code](#submitting-your-code)
+
+
This contains functionality for different StandAlone modes. The fullimage will be built given the correct compiler flags used. Build targets for these files are contained in `Makefile.inc` and `Makefile.hal`
@@ -8,7 +23,9 @@ Have a look at the skeleton standalone mode, in the file `lf_skeleton.c`.
As it is now, you can only have one standalone mode installed at the time unless you use the dankarmulti mode (see `dankarmulti.c` on how to use it).
To avoid clashes between standalone modes, protect all your static variables with a specific namespace. See how it is done in the existing standalone modes.
+
## Implementing a standalone mode
+^[Top](#top)
We suggest you keep your standalone code inside the `armsrc/Standalone` folder. And that you name your files according to your standalone mode name.
@@ -42,6 +59,7 @@ void RunMod(void) {
````
## Naming your standalone mode
+^[Top](#top)
We suggest that you follow these guidelines:
- Use HF/LF to denote which frequency your mode is targeting.
@@ -58,6 +76,7 @@ This leads to your next step, your DEFINE name needed in Makefile.
## Update MAKEFILE.HAL
+^[Top](#top)
Add your mode to the `Makefile.hal` help and modes list (alphabetically):
```
@@ -82,6 +101,8 @@ STANDALONE_MODES_REQ_BT :=
```
## Update MAKEFILE.INC
+^[Top](#top)
+
Add your source code files like the following sample in the `Makefile.inc`
```
@@ -97,6 +118,8 @@ endif
```
## Adding identification string of your mode
+^[Top](#top)
+
Do please add a identification string in a function called `ModInfo` inside your source code file.
This will enable an easy way to detect on client side which standalone mode has been installed on the device.
@@ -107,6 +130,8 @@ void ModInfo(void) {
````
## Compiling your standalone mode
+^[Top](#top)
+
Once all this is done, you and others can now easily compile different standalone modes by just selecting one of the standalone modes (list in `Makefile.hal` or ) , e.g.:
- rename Makefile.platform.sample -> Makefile.platform
@@ -143,6 +168,7 @@ When compiling you will see a header showing what configurations your project co
Make sure it says your standalone mode name.
## Submitting your code
+^[Top](#top)
Once you're ready to share your mode, please
diff --git a/armsrc/appmain.c b/armsrc/appmain.c
index c379951e6..da9c6b9f5 100644
--- a/armsrc/appmain.c
+++ b/armsrc/appmain.c
@@ -23,6 +23,7 @@
#include "printf.h"
#include "legicrf.h"
#include "BigBuf.h"
+#include "iclass_cmd.h"
#include "iso14443a.h"
#include "iso14443b.h"
#include "iso15693.h"
@@ -1093,7 +1094,7 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
case CMD_LF_HITAGS_TEST_TRACES: { // Tests every challenge within the given file
- check_challenges((bool)packet->oldarg[0], packet->data.asBytes, true);
+ Hitag_check_challenges(packet->data.asBytes, packet->oldarg[0], true);
break;
}
case CMD_LF_HITAGS_READ: { //Reader for only Hitag S tags, args = key or challenge
@@ -1574,12 +1575,13 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareGen3Freez();
break;
}
- case CMD_HF_MIFARE_G3_RDBL: {
+ case CMD_HF_MIFARE_G4_RDBL: {
struct p {
uint8_t blockno;
+ uint8_t pwd[4];
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
- MifareG3ReadBlk(payload->blockno);
+ MifareG4ReadBlk(payload->blockno, payload->pwd);
break;
}
case CMD_HF_MIFARE_PERSONALIZE_UID: {
@@ -1684,7 +1686,8 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
case CMD_HF_ICLASS_READER: {
- ReaderIClass(packet->oldarg[0]);
+ iclass_card_select_t *payload = (iclass_card_select_t *) packet->data.asBytes;
+ ReaderIClass(payload->flags);
break;
}
case CMD_HF_ICLASS_EML_MEMSET: {
diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c
index 53b96ae64..8c64baed7 100644
--- a/armsrc/em4x50.c
+++ b/armsrc/em4x50.c
@@ -682,8 +682,10 @@ void em4x50_login(uint32_t *password, bool ledcontrol) {
int status = PM3_EFAILED;
if (ledcontrol) LED_C_ON();
if (get_signalproperties() && find_em4x50_tag()) {
- if (ledcontrol) LED_C_OFF();
- if (ledcontrol) LED_D_ON();
+ if (ledcontrol) {
+ LED_C_OFF();
+ LED_D_ON();
+ }
status = login(*password);
}
@@ -700,8 +702,10 @@ void em4x50_brute(em4x50_data_t *etd, bool ledcontrol) {
uint32_t pwd = 0x0;
if (ledcontrol) LED_C_ON();
if (get_signalproperties() && find_em4x50_tag()) {
- if (ledcontrol) LED_C_OFF();
- if (ledcontrol) LED_D_ON();
+ if (ledcontrol) {
+ LED_C_OFF();
+ LED_D_ON();
+ }
bsuccess = brute(etd->password1, etd->password2, &pwd);
}
@@ -736,8 +740,10 @@ void em4x50_chk(uint8_t *filename, bool ledcontrol) {
if (ledcontrol) LED_C_ON();
if (get_signalproperties() && find_em4x50_tag()) {
- if (ledcontrol) LED_C_OFF();
- if (ledcontrol) LED_D_ON();
+ if (ledcontrol) {
+ LED_C_OFF();
+ LED_D_ON();
+ }
// try to login with current password
for (int i = 0; i < pwd_count; i++) {
@@ -859,8 +865,10 @@ void em4x50_read(em4x50_data_t *etd, bool ledcontrol) {
if (ledcontrol) LED_C_ON();
if (get_signalproperties() && find_em4x50_tag()) {
- if (ledcontrol) LED_C_OFF();
- if (ledcontrol) LED_D_ON();
+ if (ledcontrol) {
+ LED_C_OFF();
+ LED_D_ON();
+ }
bool blogin = true;
@@ -888,8 +896,10 @@ void em4x50_info(em4x50_data_t *etd, bool ledcontrol) {
if (ledcontrol) LED_C_ON();
if (get_signalproperties() && find_em4x50_tag()) {
- if (ledcontrol) LED_C_OFF();
- if (ledcontrol) LED_D_ON();
+ if (ledcontrol) {
+ LED_C_OFF();
+ LED_D_ON();
+ }
bool blogin = true;
// login with given password
@@ -917,8 +927,10 @@ void em4x50_reader(bool ledcontrol) {
if (ledcontrol) LED_C_ON();
if (get_signalproperties() && find_em4x50_tag()) {
- if (ledcontrol) LED_C_OFF();
- if (ledcontrol) LED_D_ON();
+ if (ledcontrol) {
+ LED_C_OFF();
+ LED_D_ON();
+ }
standard_read(&now, words);
}
@@ -1032,8 +1044,10 @@ void em4x50_write(em4x50_data_t *etd, bool ledcontrol) {
if (ledcontrol) LED_C_ON();
if (get_signalproperties() && find_em4x50_tag()) {
- if (ledcontrol) LED_C_OFF();
- if (ledcontrol) LED_D_ON();
+ if (ledcontrol) {
+ LED_C_OFF();
+ LED_D_ON();
+ }
// if password is given try to login first
status = PM3_SUCCESS;
@@ -1089,8 +1103,10 @@ void em4x50_writepwd(em4x50_data_t *etd, bool ledcontrol) {
if (ledcontrol) LED_C_ON();
if (get_signalproperties() && find_em4x50_tag()) {
- if (ledcontrol) LED_C_OFF();
- if (ledcontrol) LED_D_ON();
+ if (ledcontrol) {
+ LED_C_OFF();
+ LED_D_ON();
+ }
// login and change password
if (login(etd->password1) == PM3_SUCCESS) {
diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c
index 693a5f9d2..376971a97 100644
--- a/armsrc/hitag2.c
+++ b/armsrc/hitag2.c
@@ -314,8 +314,8 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_
break;
}
- // LogTrace(rx, nbytes(rxlen), 0, 0, NULL, false);
- // LogTrace(tx, nbytes(txlen), 0, 0, NULL, true);
+ // LogTraceBits(rx, rxlen, 0, 0, false);
+ // LogTraceBits(tx, txlen, 0, 0, true);
if (tag.crypto_active) {
hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen / 8, *txlen % 8);
@@ -1100,7 +1100,7 @@ void SniffHitag2(bool ledcontrol) {
if (rxlen == 0)
continue;
- LogTrace(rx, nbytes(rxlen), 0, 0, NULL, false);
+ LogTraceBits(rx, rxlen, 0, 0, false);
total_count += nbytes(rxlen);
} else {
// decode reader comms
@@ -1108,7 +1108,7 @@ void SniffHitag2(bool ledcontrol) {
total_count += rxlen;
// Pack the response into a byte array
- // LogTrace(rx, nbytes(rdr), 0, 0, NULL, true);
+ // LogTraceBits(rx, rdr, 0, 0, true);
// total_count += nbytes(rdr);
}
if (ledcontrol) LED_A_INV();
@@ -1265,7 +1265,7 @@ void SniffHitag2(bool ledcontrol) {
// Check if frame was captured
if (rxlen) {
frame_count++;
- LogTrace(rx, nbytes(rxlen), response, 0, NULL, reader_frame);
+ LogTraceBits(rx, rxlen, response, 0, reader_frame);
// Check if we recognize a valid authentication attempt
if (nbytes(rxlen) == 8) {
@@ -1369,10 +1369,12 @@ void SimulateHitag2(bool ledcontrol) {
// use malloc
initSampleBufferEx(&signal_size, true);
- if (ledcontrol) LED_D_ON();
+ if (ledcontrol) {
+ LED_D_ON();
+ LED_A_OFF();
+ }
// lf_reset_counter();
- if (ledcontrol) LED_A_OFF();
WDT_HIT();
/*
@@ -1495,7 +1497,7 @@ void SimulateHitag2(bool ledcontrol) {
// Check if frame was captured
if (rxlen > 4) {
- LogTrace(rx, nbytes(rxlen), response, response, NULL, true);
+ LogTraceBits(rx, rxlen, response, response, true);
// Process the incoming frame (rx) and prepare the outgoing frame (tx)
hitag2_handle_reader_command(rx, rxlen, tx, &txlen);
@@ -1514,7 +1516,7 @@ void SimulateHitag2(bool ledcontrol) {
lf_manchester_send_bytes(tx, txlen, ledcontrol);
// Store the frame in the trace
- LogTrace(tx, nbytes(txlen), 0, 0, NULL, false);
+ LogTraceBits(tx, txlen, 0, 0, false);
}
// Reset the received frame and response timing info
@@ -1844,7 +1846,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd, bool ledcontrol) {
// and to be able to overwrite the first samples with the trace (since they currently
// still use the same memory space)
if (txlen > 0) {
- LogTrace(tx, nbytes(txlen), command_start, command_start + command_duration, NULL, true);
+ LogTraceBits(tx, txlen, command_start, command_start + command_duration, true);
}
// Reset values for receiving frames
@@ -1904,7 +1906,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd, bool ledcontrol) {
// Check if frame was captured and store it
if (rxlen > 0) {
- LogTrace(rx, nbytes(rxlen), response_start, response_start + response_duration, NULL, false);
+ LogTraceBits(rx, rxlen, response_start, response_start + response_duration, false);
// TODO when using cumulative time for command_start, pm3 doesn't reply anymore, e.g. on lf hitag reader --23 -k 4F4E4D494B52
// Use delta time?
@@ -2167,7 +2169,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page, bool ledcontrol)
// and to be able to overwrite the first samples with the trace (since they currently
// still use the same memory space)
if (txlen > 0) {
- LogTrace(tx, nbytes(txlen), command_start, command_start + command_duration, NULL, true);
+ LogTraceBits(tx, txlen, command_start, command_start + command_duration, true);
}
// Reset values for receiving frames
@@ -2225,7 +2227,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page, bool ledcontrol)
// Check if frame was captured and store it
if (rxlen > 0) {
- LogTrace(rx, nbytes(rxlen), response_start, response_start + response_duration, NULL, false);
+ LogTraceBits(rx, rxlen, response_start, response_start + response_duration, false);
command_start = 0;
}
}
diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c
index 5ff3d9589..3a047738f 100644
--- a/armsrc/hitagS.c
+++ b/armsrc/hitagS.c
@@ -25,12 +25,11 @@
#include "commonutil.h"
#include "hitag2_crypto.h"
#include "lfadc.h"
+#include "crc.h"
#define CRC_PRESET 0xFF
#define CRC_POLYNOM 0x1D
-static bool bQuiet;
-static bool bSuccessful;
static struct hitagS_tag tag;
static uint8_t page_to_be_written = 0;
static int block_data_left = 0;
@@ -48,7 +47,6 @@ static int temp2 = 0;
static int sof_bits; // number of start-of-frame bits
static uint8_t pwdh0, pwdl0, pwdl1; // password bytes
static uint32_t rnd = 0x74124485; // randomnumber
-static bool end = false;
//#define SENDBIT_TEST
/* array index 3 2 1 0 // bytes in sim.bin file are 0 1 2 3
@@ -89,6 +87,7 @@ static bool end = false;
#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */
#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */
#define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */
+#define HITAG_T_PROG_MAX 750
#define HITAG_T_TAG_ONE_HALF_PERIOD 10
#define HITAG_T_TAG_TWO_HALF_PERIOD 25
@@ -320,10 +319,13 @@ static int check_select(uint8_t *rx, uint32_t uid) {
uint32_t ans = 0x0;
for (int i = 0; i < 48; i++)
resp[i] = (rx[i / 8] >> (7 - (i % 8))) & 0x1;
+
for (int i = 0; i < 32; i++)
ans += resp[5 + i] << (31 - i);
+ // global var?
temp_uid = ans;
+
if (ans == tag.uid)
return 1;
@@ -370,11 +372,13 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
//UID request with a selected response protocol mode
if (g_dbglevel >= DBG_EXTENDED)
Dbprintf("UID request: length: %i first byte: %02x", rxlen, rx[0]);
+
tag.pstate = HT_READY;
tag.tstate = HT_NO_OP;
if ((rx[0] & 0xf0) == 0x30) {
if (g_dbglevel >= DBG_EXTENDED)
Dbprintf("HT_STANDARD");
+
tag.mode = HT_STANDARD;
sof_bits = 1;
m = AC2K;
@@ -383,6 +387,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
tag.mode = HT_ADVANCED;
if (g_dbglevel >= DBG_EXTENDED)
Dbprintf("HT_ADVANCED");
+
sof_bits = 3;
m = AC2K;
}
@@ -390,36 +395,45 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
if ((rx[0] & 0xf0) == 0xd0) {
if (g_dbglevel >= DBG_EXTENDED)
Dbprintf("HT_FAST_ADVANCED");
+
tag.mode = HT_FAST_ADVANCED;
sof_bits = 3;
m = AC4K;
}
//send uid as a response
*txlen = 32;
- for (int i = 0; i < 4; i++)
- tx[i] = (tag.uid >> (24 - (i * 8))) & 0xff;
+ for (int i = 0; i < 4; i++) {
+ tx[i] = (tag.uid >> (24 - (i * 8))) & 0xFF;
+ }
}
break;
case 45: {
//select command from reader received
if (g_dbglevel >= DBG_EXTENDED)
DbpString("SELECT");
+
if (check_select(rx, tag.uid) == 1) {
if (g_dbglevel >= DBG_EXTENDED)
DbpString("SELECT match");
+
//if the right tag was selected
*txlen = 32;
hitagS_set_frame_modulation();
//send configuration
- for (int i = 0; i < 4; i++)
+ for (int i = 0; i < 4; i++) {
tx[i] = tag.pages[1][i];
+ }
+
tx[3] = 0xff;
+
if (tag.mode != HT_STANDARD) {
*txlen = 40;
crc = CRC_PRESET;
- for (int i = 0; i < 4; i++)
+ for (int i = 0; i < 4; i++) {
calc_crc(&crc, tx[i], 8);
+ }
+
tx[4] = crc;
}
}
@@ -435,18 +449,22 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
REV32((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0])
);
Dbprintf(",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}",
- rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]);
+ rx[0], rx[1], rx[2], rx[3],
+ rx[4], rx[5], rx[6], rx[7]
+ );
hitagS_set_frame_modulation();
- for (int i = 0; i < 4; i++)
+ for (int i = 0; i < 4; i++) {
_hitag2_byte(&state);
+ }
//send con2, pwdh0, pwdl0, pwdl1 encrypted as a response
tx[0] = _hitag2_byte(&state) ^ tag.pages[1][2];
tx[1] = _hitag2_byte(&state) ^ tag.pwdh0;
tx[2] = _hitag2_byte(&state) ^ tag.pwdl0;
tx[3] = _hitag2_byte(&state) ^ tag.pwdl1;
+
if (tag.mode != HT_STANDARD) {
//add crc8
*txlen = 40;
@@ -492,6 +510,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
tx[0] = 0x40;
page_to_be_written = 0;
hitagS_set_frame_modulation();
+
} else if (tag.tstate == HT_WRITING_BLOCK_DATA) {
tag.pages[page_to_be_written][0] = rx[0];
tag.pages[page_to_be_written][1] = rx[1];
@@ -503,6 +522,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
hitagS_set_frame_modulation();
page_to_be_written++;
block_data_left--;
+
if (block_data_left == 0) {
tag.tstate = HT_NO_OP;
page_to_be_written = 0;
@@ -519,8 +539,10 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
tx[1] = tag.pages[page][1];
tx[2] = tag.pages[page][2];
tx[3] = tag.pages[page][3];
- if (tag.LKP && page == 1)
- tx[3] = 0xff;
+
+ if (tag.LKP && page == 1) {
+ tx[3] = 0xFF;
+ }
hitagS_set_frame_modulation();
@@ -528,8 +550,9 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
//add crc8
*txlen = 40;
crc = CRC_PRESET;
- for (int i = 0; i < 4; i++)
+ for (int i = 0; i < 4; i++) {
calc_crc(&crc, tx[i], 8);
+ }
tx[4] = crc;
}
@@ -555,8 +578,9 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
//add crc8
*txlen = 32 * 4 + 8;
crc = CRC_PRESET;
- for (int i = 0; i < 16; i++)
+ for (int i = 0; i < 16; i++) {
calc_crc(&crc, tx[i], 8);
+ }
tx[16] = crc;
}
@@ -602,253 +626,6 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
}
}
-/*
- * to authenticate to a tag with the given key or challenge
- */
-static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrAr, uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) {
- uint8_t rx_air[HITAG_FRAME_LEN];
- int response_bit[200];
- unsigned char mask = 1;
- unsigned char uid[32];
- unsigned char crc;
- uint64_t state;
- uint8_t auth_ks[4];
- uint8_t conf_pages[3];
- memcpy(rx_air, rx, nbytes(rxlen));
- *txlen = 0;
-
- if (tag.pstate == HT_READY && rxlen >= 67) {
- //received uid
- if (end == true) {
- Dbprintf("authentication failed!");
- return -1;
- }
- int z = 0;
- for (int i = 0; i < 10; i++) {
- for (int j = 0; j < 8; j++) {
- response_bit[z] = 0;
- if ((rx[i] & ((mask << 7) >> j)) != 0)
- response_bit[z] = 1;
- z++;
- }
- }
- uint16_t k = 0;
- for (int i = 5; i < z; i += 2) {
- uid[k] = response_bit[i];
- k++;
- if (k > 31)
- break;
- }
- uint8_t uid1 = (uid[0] << 7)
- | (uid[1] << 6)
- | (uid[2] << 5)
- | (uid[3] << 4)
- | (uid[4] << 3)
- | (uid[5] << 2)
- | (uid[6] << 1)
- | uid[7];
-
- uint8_t uid2 = (uid[8] << 7)
- | (uid[9] << 6)
- | (uid[10] << 5)
- | (uid[11] << 4)
- | (uid[12] << 3)
- | (uid[13] << 2)
- | (uid[14] << 1)
- | uid[15];
-
- uint8_t uid3 = (uid[16] << 7)
- | (uid[17] << 6)
- | (uid[18] << 5)
- | (uid[19] << 4)
- | (uid[20] << 3)
- | (uid[21] << 2)
- | (uid[22] << 1)
- | uid[23];
-
- uint8_t uid4 = (uid[24] << 7)
- | (uid[25] << 6)
- | (uid[26] << 5)
- | (uid[27] << 4)
- | (uid[28] << 3)
- | (uid[29] << 2)
- | (uid[30] << 1)
- | uid[31];
-
- if (g_dbglevel >= DBG_EXTENDED)
- Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4);
-
- tag.uid = (uid4 << 24 | uid3 << 16 | uid2 << 8 | uid1);
-
- //select uid
- *txlen = 45;
- crc = CRC_PRESET;
- calc_crc(&crc, 0x00, 5);
- calc_crc(&crc, uid1, 8);
- calc_crc(&crc, uid2, 8);
- calc_crc(&crc, uid3, 8);
- calc_crc(&crc, uid4, 8);
-
- for (int i = 0; i < 100; i++) {
- response_bit[i] = 0;
- }
-
- for (int i = 0; i < 5; i++) {
- response_bit[i] = 0;
- }
- {
- int i = 5;
- for (; i < 37; i++) {
- response_bit[i] = uid[i - 5];
- }
-
- for (int j = 0; j < 8; j++) {
- response_bit[i] = 0;
- if ((crc & ((mask << 7) >> j)) != 0)
- response_bit[i] = 1;
- i++;
- }
- }
- k = 0;
- for (int i = 0; i < 6; i++) {
- tx[i] = (response_bit[k] << 7)
- | (response_bit[k + 1] << 6)
- | (response_bit[k + 2] << 5)
- | (response_bit[k + 3] << 4)
- | (response_bit[k + 4] << 3)
- | (response_bit[k + 5] << 2)
- | (response_bit[k + 6] << 1)
- | response_bit[k + 7];
-
- k += 8;
- }
-
- tag.pstate = HT_INIT;
- } else if (tag.pstate == HT_INIT && rxlen == 44) {
- // received configuration after select command
- int z = 0;
- for (int i = 0; i < 6; i++) {
- for (int j = 0; j < 8; j++) {
- response_bit[z] = 0;
- if ((rx[i] & ((mask << 7) >> j)) != 0)
- response_bit[z] = 1;
- z++;
- }
- }
- conf_pages[0] = ((response_bit[4] << 7) | (response_bit[5] << 6)
- | (response_bit[6] << 5) | (response_bit[7] << 4)
- | (response_bit[8] << 3) | (response_bit[9] << 2)
- | (response_bit[10] << 1) | response_bit[11]);
- //check which memorysize this tag has
- if (response_bit[10] == 0 && response_bit[11] == 0)
- tag.max_page = 32 / 32;
- if (response_bit[10] == 0 && response_bit[11] == 1)
- tag.max_page = 256 / 32;
- if (response_bit[10] == 1 && response_bit[11] == 0)
- tag.max_page = 2048 / 32;
- conf_pages[1] = ((response_bit[12] << 7) | (response_bit[13] << 6)
- | (response_bit[14] << 5) | (response_bit[15] << 4)
- | (response_bit[16] << 3) | (response_bit[17] << 2)
- | (response_bit[18] << 1) | response_bit[19]);
- tag.auth = response_bit[12];
- tag.TTFC = response_bit[13];
- //tag.TTFDR in response_bit[14] and response_bit[15]
- //tag.TTFM in response_bit[16] and response_bit[17]
- tag.LCON = response_bit[18];
- tag.LKP = response_bit[19];
- conf_pages[2] = ((response_bit[20] << 7) | (response_bit[21] << 6)
- | (response_bit[22] << 5) | (response_bit[23] << 4)
- | (response_bit[24] << 3) | (response_bit[25] << 2)
- | (response_bit[26] << 1) | response_bit[27]);
- tag.LCK7 = response_bit[20];
- tag.LCK6 = response_bit[21];
- tag.LCK5 = response_bit[22];
- tag.LCK4 = response_bit[23];
- tag.LCK3 = response_bit[24];
- tag.LCK2 = response_bit[25];
- tag.LCK1 = response_bit[26];
- tag.LCK0 = response_bit[27];
-
- if (g_dbglevel >= DBG_EXTENDED)
- Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], conf_pages[1], conf_pages[2]);
-
- if (tag.auth == 1) {
- //if the tag is in authentication mode try the key or challenge
- *txlen = 64;
- if (end != true) {
- if (htf == 02 || htf == 04) { //RHTS_KEY //WHTS_KEY
- state = _hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd));
-
- for (int i = 0; i < 4; i++) {
- auth_ks[i] = _hitag2_byte(&state) ^ 0xff;
- }
- *txlen = 64;
- tx[0] = rnd & 0xff;
- tx[1] = (rnd >> 8) & 0xff;
- tx[2] = (rnd >> 16) & 0xff;
- tx[3] = (rnd >> 24) & 0xff;
-
- tx[4] = auth_ks[0];
- tx[5] = auth_ks[1];
- tx[6] = auth_ks[2];
- tx[7] = auth_ks[3];
- if (g_dbglevel >= DBG_EXTENDED)
- 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 (htf == 01 || htf == 03) { //RHTS_CHALLENGE //WHTS_CHALLENGE
- for (int i = 0; i < 8; i++)
- tx[i] = ((NrAr >> (56 - (i * 8))) & 0xff);
- }
- end = true;
- tag.pstate = HT_AUTHENTICATE;
- } else {
- Dbprintf("authentication failed!");
- return -1;
- }
- } else if (tag.auth == 0) {
- tag.pstate = HT_SELECTED;
- }
-
- } else if (tag.pstate == HT_AUTHENTICATE && rxlen == 44) {
- //encrypted con2,password received.
- crc = CRC_PRESET;
- calc_crc(&crc, 0x80, 1);
- calc_crc(&crc, ((rx[0] & 0x0f) * 16 + ((rx[1] & 0xf0) / 16)), 8);
- calc_crc(&crc, ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)), 8);
- calc_crc(&crc, ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)), 8);
- calc_crc(&crc, ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)), 8);
- if (g_dbglevel >= DBG_EXTENDED) {
- Dbprintf("UID:::%X", tag.uid);
- Dbprintf("RND:::%X", rnd);
- }
-
- //decrypt password
- pwdh0 = 0;
- pwdl0 = 0;
- pwdl1 = 0;
- if (htf == 02 || htf == 04) { //RHTS_KEY //WHTS_KEY
- {
- state = _hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd));
- for (int i = 0; i < 5; i++)
- _hitag2_byte(&state);
-
- pwdh0 = ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)) ^ _hitag2_byte(&state);
- pwdl0 = ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)) ^ _hitag2_byte(&state);
- pwdl1 = ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)) ^ _hitag2_byte(&state);
- }
-
- if (g_dbglevel >= DBG_EXTENDED)
- Dbprintf("pwdh0 %02X pwdl0 %02X pwdl1 %02X", pwdh0, pwdl0, pwdl1);
-
- //Dbprintf("%X %02X", rnd, ((rx[4] & 0x0f) * 16) + ((rx[5] & 0xf0) / 16));
- //rnd += 1;
- }
- tag.pstate = HT_SELECTED; //tag is now ready for read/write commands
- }
- return 0;
-
-}
-
/*
* Emulates a Hitag S Tag with the given data from the .hts file
*/
@@ -860,7 +637,6 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data, bool ledcontrol) {
int response = 0, overflow = 0;
uint8_t rx[HITAG_FRAME_LEN];
size_t rxlen = 0;
- bQuiet = false;
uint8_t txbuf[HITAG_FRAME_LEN];
uint8_t *tx = txbuf;
size_t txlen = 0;
@@ -884,9 +660,11 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data, bool ledcontrol) {
// read tag data into memory
if (tag_mem_supplied) {
- for (int i = 0; i < 16; i++)
- for (int j = 0; j < 4; j++)
+ for (int i = 0; i < 16; i++) {
+ for (int j = 0; j < 4; j++) {
tag.pages[i][j] = 0x0;
+ }
+ }
DbpString("Loading hitagS memory...");
memcpy((uint8_t *)tag.pages, data, 4 * 64);
@@ -901,58 +679,87 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data, bool ledcontrol) {
(((uint64_t)tag.pages[3][0]) << 16) |
(((uint64_t)tag.pages[2][3]) << 8) |
(((uint64_t)tag.pages[2][2]));
+
tag.pwdl0 = tag.pages[2][0];
tag.pwdl1 = tag.pages[2][1];
tag.pwdh0 = tag.pages[1][3];
//con0
tag.max_page = 64;
- if ((tag.pages[1][0] & 0x2) == 0 && (tag.pages[1][0] & 0x1) == 1)
+
+ if ((tag.pages[1][0] & 0x2) == 0 && (tag.pages[1][0] & 0x1) == 1) {
tag.max_page = 8;
- if ((tag.pages[1][0] & 0x2) == 0 && (tag.pages[1][0] & 0x1) == 0)
+ }
+
+ if ((tag.pages[1][0] & 0x2) == 0 && (tag.pages[1][0] & 0x1) == 0) {
tag.max_page = 0;
+ }
+
if (g_dbglevel >= DBG_EXTENDED)
- for (int i = 0; i < tag.max_page; i++)
+ for (int i = 0; i < tag.max_page; i++) {
Dbprintf("Page[%2d]: %02X %02X %02X %02X", i,
- (tag.pages[i][3]) & 0xff,
- (tag.pages[i][2]) & 0xff,
- (tag.pages[i][1]) & 0xff,
- tag.pages[i][0] & 0xff);
+ (tag.pages[i][3]) & 0xFF,
+ (tag.pages[i][2]) & 0xFF,
+ (tag.pages[i][1]) & 0xFF,
+ tag.pages[i][0] & 0xFF
+ );
+ }
//con1
tag.auth = 0;
- if ((tag.pages[1][1] & 0x80) == 0x80)
+ if ((tag.pages[1][1] & 0x80) == 0x80) {
tag.auth = 1;
+ }
+
tag.LCON = 0;
- if ((tag.pages[1][1] & 0x2) == 0x02)
+ if ((tag.pages[1][1] & 0x2) == 0x02) {
tag.LCON = 1;
+ }
+
tag.LKP = 0;
- if ((tag.pages[1][1] & 0x1) == 0x01)
+ if ((tag.pages[1][1] & 0x1) == 0x01) {
tag.LKP = 1;
+ }
+
//con2
//0=read write 1=read only
tag.LCK7 = 0;
- if ((tag.pages[1][2] & 0x80) == 0x80)
+ if ((tag.pages[1][2] & 0x80) == 0x80) {
tag.LCK7 = 1;
+ }
+
tag.LCK6 = 0;
- if ((tag.pages[1][2] & 0x40) == 0x040)
+ if ((tag.pages[1][2] & 0x40) == 0x040) {
tag.LCK6 = 1;
+ }
+
tag.LCK5 = 0;
- if ((tag.pages[1][2] & 0x20) == 0x20)
+ if ((tag.pages[1][2] & 0x20) == 0x20) {
tag.LCK5 = 1;
+ }
+
tag.LCK4 = 0;
- if ((tag.pages[1][2] & 0x10) == 0x10)
+ if ((tag.pages[1][2] & 0x10) == 0x10) {
tag.LCK4 = 1;
+ }
+
tag.LCK3 = 0;
- if ((tag.pages[1][2] & 0x8) == 0x08)
+ if ((tag.pages[1][2] & 0x8) == 0x08) {
tag.LCK3 = 1;
+ }
+
tag.LCK2 = 0;
- if ((tag.pages[1][2] & 0x4) == 0x04)
+ if ((tag.pages[1][2] & 0x4) == 0x04) {
tag.LCK2 = 1;
+ }
+
tag.LCK1 = 0;
- if ((tag.pages[1][2] & 0x2) == 0x02)
+ if ((tag.pages[1][2] & 0x2) == 0x02) {
tag.LCK1 = 1;
+ }
+
tag.LCK0 = 0;
- if ((tag.pages[1][2] & 0x1) == 0x01)
+ if ((tag.pages[1][2] & 0x1) == 0x01) {
tag.LCK0 = 1;
+ }
// Set up simulator mode, frequency divisor which will drive the FPGA
@@ -1035,8 +842,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data, bool ledcontrol) {
// Check if frame was captured
if (rxlen > 0) {
-// frame_count++;
- LogTrace(rx, nbytes(rxlen), response, response, NULL, true);
+ LogTraceBits(rx, rxlen, response, response, true);
// Disable timer 1 with external trigger to avoid triggers during our own modulation
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
@@ -1055,7 +861,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data, bool ledcontrol) {
if (txlen > 0) {
// Transmit the tag frame
hitag_send_frame(tx, txlen, ledcontrol);
- LogTrace(tx, nbytes(txlen), 0, 0, NULL, false);
+ LogTraceBits(tx, txlen, 0, 0, false);
}
// Enable and reset external trigger in timer for capturing future frames
@@ -1084,37 +890,54 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data, bool ledcontrol) {
DbpString("Sim Stopped");
}
-static void hitagS_receive_frame(uint8_t *rx, size_t *rxlen, int *response, bool ledcontrol) {
+static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32_t *resptime, bool ledcontrol) {
// Reset values for receiving frames
- memset(rx, 0x00, HITAG_FRAME_LEN * sizeof(uint8_t));
+ memset(rx, 0x00, sizeofrx);
*rxlen = 0;
int lastbit = 1;
bool bSkip = true;
- int tag_sof = 1;
- *response = 0;
+ *resptime = 0;
uint32_t errorCount = 0;
+ // clk overflow but I failed moving TC0 & TC1 to
+ // slower clock AT91C_TC_CLKS_TIMER_DIV3_CLOCK
+ // so tracking overflow manually...
+ uint32_t overcount = 0;
+ uint32_t prevcv = 0;
+ bool bStarted = false;
// Receive frame, watch for at most T0*EOF periods
- while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) {
+ while (AT91C_BASE_TC0->TC_CV + (overcount << 16) < (T0 * HITAG_T_PROG_MAX)) {
+ // detect and track counter overflows
+
+ uint32_t tmpcv = AT91C_BASE_TC0->TC_CV;
+ if (tmpcv < prevcv) {
+ overcount++;
+ }
+ prevcv = tmpcv;
+
// Check if falling edge in tag modulation is detected
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
// Retrieve the new timing values
- int ra = (AT91C_BASE_TC1->TC_RA / T0);
-
+ uint32_t ra = (AT91C_BASE_TC1->TC_RA + (overcount << 16)) / T0;
// Reset timer every frame, we have to capture the last edge for timing
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
+ prevcv = 0;
+ overcount = 0;
if (ledcontrol) LED_B_ON();
// Capture tag frame (manchester decoding using only falling edges)
- if (ra >= HITAG_T_EOF) {
- if (*rxlen != 0) {
- //DbpString("weird1?");
+
+ if (!bStarted) {
+ if (ra >= HITAG_T_EOF) {
+ bStarted = true;
+ // Capture the T0 periods that have passed since last communication or field drop (reset)
+ // We always receive a 'one' first, which has the falling edge after a half period |-_|
+ *resptime = ra - HITAG_T_TAG_HALF_PERIOD;
+ } else {
+ errorCount++;
}
- // Capture the T0 periods that have passed since last communication or field drop (reset)
- // We always receive a 'one' first, which has the falling edge after a half period |-_|
- *response = ra - HITAG_T_TAG_HALF_PERIOD;
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
// Manchester coding example |-_|_-|-_| (101)
rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8));
@@ -1134,14 +957,9 @@ static void hitagS_receive_frame(uint8_t *rx, size_t *rxlen, int *response, bool
bSkip = !bSkip;
} else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
// Manchester coding example |_-|_-| (00) or |-_|-_| (11)
- if (tag_sof) {
- // Ignore bits that are transmitted during SOF
- tag_sof--;
- } else {
- // bit is same as last bit
- rx[(*rxlen) / 8] |= lastbit << (7 - ((*rxlen) % 8));
- (*rxlen)++;
- }
+ // bit is same as last bit
+ rx[(*rxlen) / 8] |= lastbit << (7 - ((*rxlen) % 8));
+ (*rxlen)++;
} else {
// Ignore weird value, is to small to mean anything
errorCount++;
@@ -1153,80 +971,90 @@ static void hitagS_receive_frame(uint8_t *rx, size_t *rxlen, int *response, bool
// We can break this loop if we received the last bit from a frame
if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) {
- if ((*rxlen) > 0)
+ if ((*rxlen) > 0) {
break;
+ }
}
}
+ // Dbprintf("RX0 %i:%02X.. err:%i resptime:%i", *rxlen, rx[0], errorCount, *resptime);
}
-/*
- * Authenticates to the Tag with the given key or challenge.
- * If the key was given the password will be decrypted.
- * Reads every page of a hitag S transpoder.
- */
-void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol) {
+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) {
+ LogTraceBits(tx, txlen, HITAG_T_WAIT_2, HITAG_T_WAIT_2, true);
+
+ // Send and store the reader command
+ // Disable timer 1 with external trigger to avoid triggers during our own modulation
+ AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
+
+ // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting,
+ // Since the clock counts since the last falling edge, a 'one' means that the
+ // falling edge occurred halfway the period. with respect to this falling edge,
+ // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'.
+ // All timer values are in terms of T0 units
+
+ while (AT91C_BASE_TC0->TC_CV < T0 * t_wait) {};
+
+ // Transmit the reader frame
+ hitag_reader_send_frame(tx, txlen, ledcontrol);
+
+ // Enable and reset external trigger in timer for capturing future frames
+ AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+
+ uint32_t resptime = 0;
+ size_t rxlen = 0;
+ hitagS_receive_frame(rx, sizeofrx, &rxlen, &resptime, ledcontrol);
+ int k = 0;
+ // Check if frame was captured and store it
+ if (rxlen > 0) {
+ uint8_t response_bit[sizeofrx * 8];
+ for (int i = 0; i < rxlen; i++) {
+ response_bit[i] = (rx[i / 8] >> (7 - (i % 8))) & 1;
+ }
+ memset(rx, 0x00, sizeofrx);
+ if (ac_seq) {
+ // Tag Response is AC encoded
+ for (int i = 6; i < rxlen; i += 2) {
+ rx[k / 8] |= response_bit[i] << (7 - (k % 8));
+ k++;
+ if (k >= 8 * sizeofrx)
+ break;
+ }
+ } else {
+ for (int i = 5; i < rxlen; i++) { // ignore first 5 bits: SOF (actually 1 or 6 depending on response protocol)
+ rx[k / 8] |= response_bit[i] << (7 - (k % 8));
+ k++;
+ if (k >= 8 * sizeofrx)
+ break;
+ }
+ }
+ LogTraceBits(rx, k, resptime, resptime, false);
+ }
+ *prxbits = k;
+}
+
+static size_t concatbits(uint8_t *dstbuf, size_t dstbufskip, uint8_t *srcbuf, size_t srcbufstart, size_t srcbuflen) {
+ // erase dstbuf bits that will be overriden
+ dstbuf[dstbufskip / 8] &= 0xFF - ((1 << (7 - (dstbufskip % 8) + 1)) - 1);
+ for (size_t i = (dstbufskip / 8) + 1; i <= (dstbufskip + srcbuflen) / 8; i++) {
+ dstbuf[i] = 0;
+ }
+ for (size_t i = 0; i < srcbuflen; i++) {
+ // equiv of dstbufbits[dstbufskip + i] = srcbufbits[srcbufstart + i]
+ dstbuf[(dstbufskip + i) / 8] |= ((srcbuf[(srcbufstart + i) / 8] >> (7 - ((srcbufstart + i) % 8))) & 1) << (7 - ((dstbufskip + i) % 8));
+ }
+ return dstbufskip + srcbuflen;
+}
+
+static int selectHitagS(hitag_function htf, hitag_data *htd, uint8_t *tx, size_t sizeoftx, uint8_t *rx, size_t sizeofrx, int t_wait, bool ledcontrol) {
StopTicks();
- int i, j, z, k;
-// int frame_count = 0;
- int response = 0;
- int response_bit[200];
- uint8_t rx[HITAG_FRAME_LEN];
- size_t rxlen = 0;
- uint8_t txbuf[HITAG_FRAME_LEN];
- uint8_t *tx = txbuf;
- size_t txlen = 0;
- int lastbit = 1;
- int t_wait = HITAG_T_WAIT_MAX;
- bool bStop = false;
- int pageNum = 0;
- unsigned char mask = 1;
- unsigned char crc;
- unsigned char pageData[32];
- page_to_be_written = 0;
-
- //read given key/challenge
- uint8_t NrAr_[8];
- uint64_t key = 0;
- uint64_t NrAr = 0;
- uint8_t key_[6];
-
- tag.pstate = HT_READY;
- tag.tstate = HT_NO_OP;
-
- switch (htf) {
- case RHTSF_CHALLENGE: {
- DbpString("Authenticating using nr,ar pair:");
- memcpy(NrAr_, htd->auth.NrAr, 8);
- Dbhexdump(8, NrAr_, false);
- NrAr = NrAr_[7] | ((uint64_t)NrAr_[6]) << 8 | ((uint64_t)NrAr_[5]) << 16 | ((uint64_t)NrAr_[4]) << 24 | ((uint64_t)NrAr_[3]) << 32 |
- ((uint64_t)NrAr_[2]) << 40 | ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56;
- break;
- }
- case RHTSF_KEY: {
- DbpString("Authenticating using key:");
- memcpy(key_, htd->crypto.key, 6);
- Dbhexdump(6, key_, false);
- key = key_[5] | ((uint64_t)key_[4]) << 8 | ((uint64_t)key_[3]) << 16 | ((uint64_t)key_[2]) << 24 | ((uint64_t)key_[1]) << 32 | ((uint64_t)key_[0]) << 40;
- break;
- }
- default: {
- Dbprintf("Error , unknown function: %d", htf);
- return;
- }
- }
-
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
- // Reset the return status
- bSuccessful = false;
// Clean up trace and prepare it for storing frames
set_tracing(true);
clear_trace();
- bQuiet = false;
-
if (ledcontrol) LED_D_ON();
// Set fpga in edge detect with reader field, we can modulate as reader now
@@ -1269,370 +1097,337 @@ void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol) {
// synchronized startup procedure
while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero
- // Reset the received frame, frame count and timing info
- t_wait = 200;
- while (!bStop && !BUTTON_PRESS() && !data_available()) {
+
+ //start authentication
+ size_t txlen = 0;
+ size_t rxlen = 0;
+ uint8_t cmd = 0x18;
+ txlen = concatbits(tx, txlen, &cmd, 8 - 5, 5);
+ sendReceiveHitagS(tx, txlen, rx, sizeofrx, &rxlen, t_wait, ledcontrol, true);
+
+ if (rxlen != 32) {
+ Dbprintf("UID Request failed!");
+ return -1;
+ }
+
+ tag.uid = (rx[3] << 24 | rx[2] << 16 | rx[1] << 8 | rx[0]);
+ if (g_dbglevel >= DBG_EXTENDED)
+ Dbprintf("UID: %02X %02X %02X %02X", rx[0], rx[1], rx[2], rx[3]);
+ //select uid
+ txlen = 0;
+ cmd = 0x00;
+ txlen = concatbits(tx, txlen, &cmd, 8 - 5, 5);
+ txlen = concatbits(tx, txlen, rx, 0, 32);
+ uint8_t crc = CRC8Hitag1Bits(tx, txlen);
+ txlen = concatbits(tx, txlen, &crc, 0, 8);
+
+ sendReceiveHitagS(tx, txlen, rx, sizeofrx, &rxlen, t_wait, ledcontrol, false);
+
+ if (rxlen != 40) {
+ Dbprintf("Select UID failed! %i", rxlen);
+ return -1;
+ }
+
+ uint8_t conf_pages[3];
+ conf_pages[0] = rx[0];
+
+ //check which memorysize this tag has
+ if ((conf_pages[0] & 0x3) == 0x00) {
+ tag.max_page = 32 / 32;
+ } else if ((conf_pages[0] & 0x3) == 0x1) {
+ tag.max_page = 256 / 32;
+ } else if ((conf_pages[0] & 0x3) == 0x2) {
+ tag.max_page = 2048 / 32;
+ }
+
+ conf_pages[1] = rx[1];
+ tag.auth = (conf_pages[1] >> 7) & 0x1;
+ tag.TTFC = (conf_pages[1] >> 6) & 0x1;
+ tag.TTFDR = (conf_pages[1] >> 5) & 0x3;
+ tag.TTFM = (conf_pages[1] >> 3) & 0x3;
+ tag.LCON = (conf_pages[1] >> 1) & 0x1;
+ tag.LKP = (conf_pages[1] >> 0) & 0x1;
+
+ conf_pages[2] = rx[2];
+
+ tag.LCK7 = (conf_pages[2] >> 7) & 0x1;
+ tag.LCK6 = (conf_pages[2] >> 6) & 0x1;
+ tag.LCK5 = (conf_pages[2] >> 5) & 0x1;
+ tag.LCK4 = (conf_pages[2] >> 4) & 0x1;
+ tag.LCK3 = (conf_pages[2] >> 3) & 0x1;
+ tag.LCK2 = (conf_pages[2] >> 2) & 0x1;
+ tag.LCK1 = (conf_pages[2] >> 1) & 0x1;
+ tag.LCK0 = (conf_pages[2] >> 0) & 0x1;
+
+ if (g_dbglevel >= DBG_EXTENDED)
+ Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], conf_pages[1], conf_pages[2]);
+
+ if (tag.auth == 1) {
+ uint64_t key = 0;
+ //if the tag is in authentication mode try the key or challenge
+ if (htf == RHTSF_KEY || htf == WHTSF_KEY) {
+ if (g_dbglevel >= DBG_EXTENDED) {
+ DbpString("Authenticating using key:");
+ Dbhexdump(6, htd->crypto.key, false);
+ }
+ key = ((uint64_t)htd->crypto.key[0]) << 0 |
+ ((uint64_t)htd->crypto.key[1]) << 8 |
+ ((uint64_t)htd->crypto.key[2]) << 16 |
+ ((uint64_t)htd->crypto.key[3]) << 24 |
+ ((uint64_t)htd->crypto.key[4]) << 32 |
+ ((uint64_t)htd->crypto.key[5]) << 40
+ ;
+ uint64_t state = _hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd));
+ uint8_t auth_ks[4];
+ for (int i = 0; i < 4; i++) {
+ auth_ks[i] = _hitag2_byte(&state) ^ 0xff;
+ }
+
+ txlen = 0;
+ uint8_t revrnd[4] = {rnd, rnd >> 8, rnd >> 16, rnd >> 24};
+ txlen = concatbits(tx, txlen, revrnd, 0, 32);
+ txlen = concatbits(tx, txlen, auth_ks, 0, 32);
+
+ if (g_dbglevel >= DBG_EXTENDED)
+ 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 (htf == RHTSF_CHALLENGE || htf == WHTSF_CHALLENGE) {
+ if (g_dbglevel >= DBG_EXTENDED) {
+ DbpString("Authenticating using nr,ar pair:");
+ Dbhexdump(8, htd->auth.NrAr, false);
+ }
+ uint64_t NrAr = 0;
+ NrAr = ((uint64_t)htd->auth.NrAr[7]) << 0 |
+ ((uint64_t)htd->auth.NrAr[6]) << 8 |
+ ((uint64_t)htd->auth.NrAr[5]) << 16 |
+ ((uint64_t)htd->auth.NrAr[4]) << 24 |
+ ((uint64_t)htd->auth.NrAr[3]) << 32 |
+ ((uint64_t)htd->auth.NrAr[2]) << 40 |
+ ((uint64_t)htd->auth.NrAr[1]) << 48 |
+ ((uint64_t)htd->auth.NrAr[0]) << 56;
+ txlen = 64;
+ for (int i = 0; i < 8; i++) {
+ tx[i] = ((NrAr >> (56 - (i * 8))) & 0xFF);
+ }
+ } else {
+ Dbprintf("Error , unknown function: %d", htf);
+ return -1;
+ }
+
+ sendReceiveHitagS(tx, txlen, rx, sizeofrx, &rxlen, t_wait, ledcontrol, false);
+
+ if (rxlen != 40) {
+ Dbprintf("Authenticate failed! %i", rxlen);
+ return -1;
+ }
+
+ //encrypted con2,password received.
+ if (g_dbglevel >= DBG_EXTENDED) {
+ Dbprintf("UID:::%X", tag.uid);
+ Dbprintf("RND:::%X", rnd);
+ }
+
+ //decrypt password
+ pwdh0 = 0;
+ pwdl0 = 0;
+ pwdl1 = 0;
+ if (htf == RHTSF_KEY || htf == WHTSF_KEY) {
+ uint64_t state = _hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd));
+ for (int i = 0; i < 4; i++) {
+ _hitag2_byte(&state);
+ }
+ uint8_t con2 = rx[0] ^ _hitag2_byte(&state);
+ pwdh0 = rx[1] ^ _hitag2_byte(&state);
+ pwdl0 = rx[2] ^ _hitag2_byte(&state);
+ pwdl1 = rx[3] ^ _hitag2_byte(&state);
+
+ if (g_dbglevel >= DBG_EXTENDED)
+ Dbprintf("con2 %02X pwdh0 %02X pwdl0 %02X pwdl1 %02X", con2, pwdh0, pwdl0, pwdl1);
+
+ //Dbprintf("%X %02X", rnd, ((rx[4] & 0x0f) * 16) + ((rx[5] & 0xf0) / 16));
+ //rnd += 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Authenticates to the Tag with the given key or challenge.
+ * If the key was given the password will be decrypted.
+ * Reads every page of a hitag S transpoder.
+ */
+void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol) {
+
+ uint8_t rx[HITAG_FRAME_LEN];
+ size_t rxlen = 0;
+ uint8_t tx[HITAG_FRAME_LEN];
+ size_t txlen = 0;
+ int t_wait = HITAG_T_WAIT_MAX;
+
+
+ if (selectHitagS(htf, htd, tx, ARRAYLEN(tx), rx, ARRAYLEN(rx), t_wait, ledcontrol) == -1) {
+ set_tracing(false);
+ lf_finalize(ledcontrol);
+ reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
+ return;
+ }
+ int pageNum = 0;
+ while (!BUTTON_PRESS() && !data_available()) {
WDT_HIT();
- // Check if frame was captured and store it
- if (rxlen > 0) {
-// frame_count++;
- LogTrace(rx, nbytes(rxlen), response, response, NULL, false);
- }
-
- // By default reset the transmission buffer
- tx = txbuf;
+ //send read request
txlen = 0;
+ uint8_t cmd = 0x0c;
+ txlen = concatbits(tx, txlen, &cmd, 8 - 4, 4);
+ uint8_t addr = pageNum;
+ txlen = concatbits(tx, txlen, &addr, 0, 8);
+ uint8_t crc = CRC8Hitag1Bits(tx, txlen);
+ txlen = concatbits(tx, txlen, &crc, 0, 8);
+
+ sendReceiveHitagS(tx, txlen, rx, ARRAYLEN(rx), &rxlen, t_wait, ledcontrol, false);
if (rxlen == 0) {
- //start authentication
- txlen = 5;
- memcpy(tx, "\xC0", nbytes(txlen));
- tag.pstate = HT_READY;
- tag.tstate = HT_NO_OP;
- } else if (tag.pstate != HT_SELECTED) {
- if (hitagS_handle_tag_auth(htf, key, NrAr, rx, rxlen, tx, &txlen) == -1)
- bStop = !false;
+ Dbprintf("Read page failed!");
+ break;
}
- if (tag.pstate == HT_SELECTED && tag.tstate == HT_NO_OP && rxlen > 0) {
- //send read request
- tag.tstate = HT_READING_PAGE;
- txlen = 20;
- crc = CRC_PRESET;
- tx[0] = 0xc0 + (pageNum / 16);
- calc_crc(&crc, tx[0], 8);
- calc_crc(&crc, 0x00 + ((pageNum % 16) * 16), 4);
- tx[1] = 0x00 + ((pageNum % 16) * 16) + (crc / 16);
- tx[2] = 0x00 + (crc % 16) * 16;
- } else if (tag.pstate == HT_SELECTED
- && tag.tstate == HT_READING_PAGE
- && rxlen > 0) {
- //save received data - 40 bits
- z = 0;
- for (i = 0; i < 5; i++) {
- for (j = 0; j < 8; j++) {
- response_bit[z] = 0;
- if ((rx[i] & ((mask << 7) >> j)) != 0)
- response_bit[z] = 1;
- z++;
- }
- }
- k = 0;
- for (i = 4; i < 36; i++) { // ignore first 4 bits: SOF (actually 1 or 6 depending on response protocol)
- pageData[k] = response_bit[i];
- k++;
- }
- for (i = 0; i < 4; i++) // set page bytes to 0
- tag.pages[pageNum][i] = 0x0;
- for (i = 0; i < 4; i++) { // set page bytes from received bits
- tag.pages[pageNum][i] += ((pageData[i * 8] << 7)
- | (pageData[1 + (i * 8)] << 6)
- | (pageData[2 + (i * 8)] << 5)
- | (pageData[3 + (i * 8)] << 4)
- | (pageData[4 + (i * 8)] << 3)
- | (pageData[5 + (i * 8)] << 2)
- | (pageData[6 + (i * 8)] << 1)
- | pageData[7 + (i * 8)]);
- }
- if (tag.auth && tag.LKP && pageNum == 1) {
- Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, pwdh0,
- (tag.pages[pageNum][2]) & 0xff,
- (tag.pages[pageNum][1]) & 0xff,
- tag.pages[pageNum][0] & 0xff);
+ //save received data - 40 bits
+ for (int i = 0; i < 4 && i < rxlen; i++) { // set page bytes from received bits
+ tag.pages[pageNum][i] = rx[i];
+ }
+
+ if (tag.auth && tag.LKP && pageNum == 1) {
+ Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, pwdh0,
+ (tag.pages[pageNum][2]) & 0xff,
+ (tag.pages[pageNum][1]) & 0xff,
+ tag.pages[pageNum][0] & 0xff);
+ } else {
+ Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum,
+ (tag.pages[pageNum][3]) & 0xff,
+ (tag.pages[pageNum][2]) & 0xff,
+ (tag.pages[pageNum][1]) & 0xff,
+ tag.pages[pageNum][0] & 0xff);
+ }
+
+ pageNum++;
+ //display key and password if possible
+ if (pageNum == 2 && tag.auth == 1 && tag.LKP) {
+ if (htf == RHTSF_KEY) {
+ Dbprintf("Page[ 2]: %02X %02X %02X %02X",
+ htd->crypto.key[1],
+ htd->crypto.key[0],
+ pwdl1,
+ pwdl0
+ );
+ Dbprintf("Page[ 3]: %02X %02X %02X %02X",
+ htd->crypto.key[5],
+ htd->crypto.key[4],
+ htd->crypto.key[3],
+ htd->crypto.key[2]
+ );
} else {
- Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum,
- (tag.pages[pageNum][3]) & 0xff,
- (tag.pages[pageNum][2]) & 0xff,
- (tag.pages[pageNum][1]) & 0xff,
- tag.pages[pageNum][0] & 0xff);
- }
-
- pageNum++;
- //display key and password if possible
- if (pageNum == 2 && tag.auth == 1 && tag.LKP) {
- if (htf == RHTSF_KEY) {
- Dbprintf("Page[ 2]: %02X %02X %02X %02X",
- (uint8_t)(key >> 8) & 0xff,
- (uint8_t) key & 0xff,
- pwdl1,
- pwdl0
- );
- Dbprintf("Page[ 3]: %02X %02X %02X %02X",
- (uint8_t)(key >> 40) & 0xff,
- (uint8_t)(key >> 32) & 0xff,
- (uint8_t)(key >> 24) & 0xff,
- (uint8_t)(key >> 16) & 0xff
- );
- } else {
- //if the authentication is done with a challenge the key and password are unknown
- Dbprintf("Page[ 2]: __ __ __ __");
- Dbprintf("Page[ 3]: __ __ __ __");
- }
- // since page 2+3 are not accessible when LKP == 1 and AUT == 1 fastforward to next readable page
- pageNum = 4;
- }
-
- txlen = 20;
- crc = CRC_PRESET;
- tx[0] = 0xc0 + (pageNum / 16);
- calc_crc(&crc, tx[0], 8);
- calc_crc(&crc, 0x00 + ((pageNum % 16) * 16), 4);
- tx[1] = 0x00 + ((pageNum % 16) * 16) + (crc / 16);
- tx[2] = 0x00 + (crc % 16) * 16;
- if (pageNum >= tag.max_page) {
- bStop = !false;
+ //if the authentication is done with a challenge the key and password are unknown
+ Dbprintf("Page[ 2]: __ __ __ __");
+ Dbprintf("Page[ 3]: __ __ __ __");
}
+ // since page 2+3 are not accessible when LKP == 1 and AUT == 1 fastforward to next readable page
+ pageNum = 4;
}
-
- // Send and store the reader command
- // Disable timer 1 with external trigger to avoid triggers during our own modulation
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
-
- // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting,
- // Since the clock counts since the last falling edge, a 'one' means that the
- // falling edge occurred halfway the period. with respect to this falling edge,
- // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'.
- // All timer values are in terms of T0 units
-
- while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) {};
-
- // Transmit the reader frame
- hitag_reader_send_frame(tx, txlen, ledcontrol);
-
- // Enable and reset external trigger in timer for capturing future frames
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-
- // Add transmitted frame to total count
- if (txlen > 0) {
-// frame_count++;
- LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, HITAG_T_WAIT_2, NULL, true);
+ if (pageNum >= tag.max_page) {
+ break;
}
-
- hitagS_receive_frame(rx, &rxlen, &response, ledcontrol);
}
- end = false;
set_tracing(false);
lf_finalize(ledcontrol);
- reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0);
+
+ // TODO reply_mix(CMD_ACK, 1, 0, 0, 0, 0); and send dump as well, to be decoded in the client
+ reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
}
/*
* Authenticates to the Tag with the given Key or Challenge.
* Writes the given 32Bit data into page_
*/
-void WritePageHitagS(hitag_function htf, hitag_data *htd, int page, bool ledcontrol) {
+void WritePageHitagS(hitag_function htf, hitag_data *htd, int pageNum, bool ledcontrol) {
- StopTicks();
+ bool bSuccessful = false;
+ //check for valid input
+ if (pageNum == 0) {
+ Dbprintf("Error, invalid page");
+ reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0);
+ return;
+ }
-// int frame_count = 0;
- int response = 0;
uint8_t rx[HITAG_FRAME_LEN];
size_t rxlen = 0;
- uint8_t txbuf[HITAG_FRAME_LEN];
- uint8_t *tx = txbuf;
+ uint8_t tx[HITAG_FRAME_LEN];
size_t txlen = 0;
- int lastbit;
int t_wait = HITAG_T_WAIT_MAX;
- bool bStop;
- unsigned char crc;
+
+ if (selectHitagS(htf, htd, tx, ARRAYLEN(tx), rx, ARRAYLEN(rx), t_wait, ledcontrol) == -1) {
+ goto write_end;
+ }
+
+ //check if the given page exists
+ if (pageNum > tag.max_page) {
+ Dbprintf("page number too big for this tag");
+ goto write_end;
+ }
+
+ //send write page request
+ txlen = 0;
+ uint8_t cmd = 0x08;
+ txlen = concatbits(tx, txlen, &cmd, 8 - 4, 4);
+ uint8_t addr = pageNum;
+ txlen = concatbits(tx, txlen, &addr, 0, 8);
+ uint8_t crc = CRC8Hitag1Bits(tx, txlen);
+ txlen = concatbits(tx, txlen, &crc, 0, 8);
+
+ sendReceiveHitagS(tx, txlen, rx, ARRAYLEN(rx), &rxlen, t_wait, ledcontrol, false);
+
+ if ((rxlen != 2) || (rx[0] >> (8 - 2) != 0x1)) {
+ Dbprintf("no write access on page %d", pageNum);
+ goto write_end;
+ }
+
+ //ACK received to write the page. send data
uint8_t data[4] = {0, 0, 0, 0};
-
- FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
-
- bSuccessful = false;
-
- // Clean up trace and prepare it for storing frames
- set_tracing(true);
- clear_trace();
-
- //read given key/challenge, the page and the data
- uint8_t NrAr_[8];
- uint64_t key = 0;
- uint64_t NrAr = 0;
- uint8_t key_[6];
switch (htf) {
- case WHTSF_CHALLENGE: {
- memcpy(data, htd->auth.data, 4);
- DbpString("Authenticating using nr,ar pair:");
- memcpy(NrAr_, htd->auth.NrAr, 8);
- Dbhexdump(8, NrAr_, false);
- NrAr = NrAr_[7] | ((uint64_t)NrAr_[6]) << 8 | ((uint64_t)NrAr_[5]) << 16 | ((uint64_t)NrAr_[4]) << 24 | ((uint64_t)NrAr_[3]) << 32 |
- ((uint64_t)NrAr_[2]) << 40 | ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56;
+ case WHTSF_CHALLENGE:
+ data[0] = htd->auth.data[3];
+ data[1] = htd->auth.data[2];
+ data[2] = htd->auth.data[1];
+ data[3] = htd->auth.data[0];
break;
- }
-
- case WHTSF_KEY: {
- memcpy(data, htd->crypto.data, 4);
- DbpString("Authenticating using key:");
- memcpy(key_, htd->crypto.key, 6);
- Dbhexdump(6, key_, false);
- key = key_[5] | ((uint64_t)key_[4]) << 8 | ((uint64_t)key_[3]) << 16 | ((uint64_t)key_[2]) << 24 | ((uint64_t)key_[1]) << 32 | ((uint64_t)key_[0]) << 40;
+ case WHTSF_KEY:
+ data[0] = htd->crypto.data[3];
+ data[1] = htd->crypto.data[2];
+ data[2] = htd->crypto.data[1];
+ data[3] = htd->crypto.data[0];
break;
- }
- default: {
- Dbprintf("Error , unknown function: %d", htf);
+ default:
return;
- }
+ }
+ txlen = 0;
+ txlen = concatbits(tx, txlen, data, 0, 32);
+ crc = CRC8Hitag1Bits(tx, txlen);
+ txlen = concatbits(tx, txlen, &crc, 0, 8);
+
+ sendReceiveHitagS(tx, txlen, rx, ARRAYLEN(rx), &rxlen, t_wait, ledcontrol, false);
+
+ if ((rxlen != 2) || (rx[0] >> (8 - 2) != 0x1)) {
+ Dbprintf("write on page %d failed", pageNum);
+ } else {
+ Dbprintf("write on page %d successful", pageNum);
+ bSuccessful = true;
}
- Dbprintf("Page: %d", page);
- Dbprintf("DATA: %02X %02X %02X %02X", data[0], data[1], data[2], data[3]);
-
- tag.pstate = HT_READY;
- tag.tstate = HT_NO_OP;
-
- if (ledcontrol) LED_D_ON();
-
- // Configure output and enable pin that is connected to the FPGA (for modulating)
- AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
- AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
-
- // Set fpga in edge detect with reader field, we can modulate as reader now
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD);
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz
- SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
-
- // Disable modulation at default, which means enable the field
- LOW(GPIO_SSC_DOUT);
-
- // Enable Peripheral Clock for
- // TIMER_CLOCK0, used to measure exact timing before answering
- // TIMER_CLOCK1, used to capture edges of the tag frames
- AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
-
- AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
-
- // Disable timer during configuration
- AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
-
- // Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
- AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
- // external trigger rising edge, load RA on falling edge of TIOA.
- AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK
- | AT91C_TC_ETRGEDG_FALLING
- | AT91C_TC_ABETRG
- | AT91C_TC_LDRA_FALLING;
-
- // Enable and reset counters
- AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-
- while (AT91C_BASE_TC0->TC_CV > 0);
-
- // Reset the received frame, frame count and timing info
- lastbit = 1;
- bStop = false;
- t_wait = 200;
-
- while (!bStop && !BUTTON_PRESS() && !data_available()) {
-
- WDT_HIT();
-
- // Check if frame was captured and store it
- if (rxlen > 0) {
-// frame_count++;
- LogTrace(rx, nbytes(rxlen), response, response, NULL, false);
- }
-
- //check for valid input
- if (page == 0) {
- Dbprintf(
- "usage: lf hitag writer [--03 | --04] [--nrar CHALLENGE | -k KEY] [-p page] -d [4 hex bytes]");
- bStop = !false;
- }
-
- // By default reset the transmission buffer
- tx = txbuf;
- txlen = 0;
-
- if (rxlen == 0 && tag.tstate == HT_WRITING_PAGE_ACK) {
- //no write access on this page
- Dbprintf("no write access on page %d", page);
- bStop = !false;
- } else if (rxlen == 0 && tag.tstate != HT_WRITING_PAGE_DATA) {
- //start the authentication
- txlen = 5;
- memcpy(tx, "\xc0", nbytes(txlen));
- tag.pstate = HT_READY;
- tag.tstate = HT_NO_OP;
- } else if (tag.pstate != HT_SELECTED) {
- //try to authenticate with the given key or challenge
- if (hitagS_handle_tag_auth(htf, key, NrAr, rx, rxlen, tx, &txlen) == -1)
- bStop = !false;
- }
- if (tag.pstate == HT_SELECTED && tag.tstate == HT_NO_OP && rxlen > 0) {
- //check if the given page exists
- if (page > tag.max_page) {
- Dbprintf("page number too big");
- bStop = !false;
- }
- //ask Tag for write permission
- tag.tstate = HT_WRITING_PAGE_ACK;
- txlen = 20;
- crc = CRC_PRESET;
- tx[0] = 0x90 + (page / 16);
- calc_crc(&crc, tx[0], 8);
- calc_crc(&crc, 0x00 + ((page % 16) * 16), 4);
- tx[1] = 0x00 + ((page % 16) * 16) + (crc / 16);
- tx[2] = 0x00 + (crc % 16) * 16;
- } else if (tag.pstate == HT_SELECTED && tag.tstate == HT_WRITING_PAGE_ACK
- && rxlen == 6 && rx[0] == 0xf4) {
- //ACK received to write the page. send data
- tag.tstate = HT_WRITING_PAGE_DATA;
- txlen = 40;
- crc = CRC_PRESET;
- calc_crc(&crc, data[3], 8);
- calc_crc(&crc, data[2], 8);
- calc_crc(&crc, data[1], 8);
- calc_crc(&crc, data[0], 8);
- tx[0] = data[3];
- tx[1] = data[2];
- tx[2] = data[1];
- tx[3] = data[0];
- tx[4] = crc;
- } else if (tag.pstate == HT_SELECTED && tag.tstate == HT_WRITING_PAGE_DATA
- && rxlen == 6 && rx[0] == 0xf4) {
- //received ACK
- Dbprintf("Successful!");
- bStop = !false;
- }
-
- // Send and store the reader command
- // Disable timer 1 with external trigger to avoid triggers during our own modulation
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
-
- // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting,
- // Since the clock counts since the last falling edge, a 'one' means that the
- // falling edge occurred halfway the period. with respect to this falling edge,
- // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'.
- // All timer values are in terms of T0 units
-
- while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) {};
-
- // Transmit the reader frame
- hitag_reader_send_frame(tx, txlen, ledcontrol);
-
- // Enable and reset external trigger in timer for capturing future frames
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-
- // Add transmitted frame to total count
- if (txlen > 0) {
-// frame_count++;
- LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, HITAG_T_WAIT_2, NULL, true);
- }
-
- hitagS_receive_frame(rx, &rxlen, &response, ledcontrol);
-
- }
- end = false;
+write_end:
set_tracing(false);
-
lf_finalize(ledcontrol);
-
reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0);
}
@@ -1643,231 +1438,48 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page, bool ledcont
* is not received correctly due to Antenna problems. This function
* detects these challenges.
*/
-void check_challenges(bool file_given, uint8_t *data, bool ledcontrol) {
- int i, j, z, k;
-// int frame_count = 0;
- int response = 0;
- uint8_t uid_byte[4];
- uint8_t rx[HITAG_FRAME_LEN];
- uint8_t unlocker[60][8];
- int u1 = 0;
- size_t rxlen = 0;
- uint8_t txbuf[HITAG_FRAME_LEN];
- int t_wait = HITAG_T_WAIT_MAX;
- int lastbit, STATE = 0;
- bool bStop;
- int response_bit[200];
- unsigned char mask = 1;
- unsigned char uid[32];
- unsigned char crc;
-
- FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
- // Reset the return status
- bSuccessful = false;
-
- // Clean up trace and prepare it for storing frames
- set_tracing(true);
- clear_trace();
-
- bQuiet = false;
-
- if (ledcontrol) LED_D_ON();
-
- // Configure output and enable pin that is connected to the FPGA (for modulating)
- AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
- AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
-
- // Set fpga in edge detect with reader field, we can modulate as reader now
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD);
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz
- SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
-
- // Disable modulation at default, which means enable the field
- LOW(GPIO_SSC_DOUT);
-
- // Enable Peripheral Clock for
- // TIMER_CLOCK0, used to measure exact timing before answering
- // TIMER_CLOCK1, used to capture edges of the tag frames
- AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
-
- AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
-
- // Disable timer during configuration
- AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
-
- // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers
- AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
-
- // TC1: Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
- // external trigger rising edge, load RA on falling edge of TIOA.
- AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK
- | AT91C_TC_ETRGEDG_FALLING
- | AT91C_TC_ABETRG
- | AT91C_TC_LDRA_FALLING;
-
- // Enable and reset counters
- AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-
- while (AT91C_BASE_TC0->TC_CV > 0) {};
-
- // Reset the received frame, frame count and timing info
- lastbit = 1;
- bStop = false;
- t_wait = 200;
-
- if (file_given) {
- DbpString("Loading challenges...");
- memcpy((uint8_t *)unlocker, data, 60 * 8);
+void Hitag_check_challenges(uint8_t *data, uint32_t datalen, bool ledcontrol) {
+ //check for valid input
+ if (datalen < 8) {
+ Dbprintf("Error, need chals");
+ reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
+ return;
}
+ uint32_t dataoffset = 0;
- while (file_given && !bStop && !BUTTON_PRESS()) {
+ uint8_t rx[HITAG_FRAME_LEN];
+ uint8_t tx[HITAG_FRAME_LEN];
+ int t_wait = HITAG_T_WAIT_MAX;
+
+ while (!BUTTON_PRESS() && !data_available()) {
// Watchdog hit
WDT_HIT();
- // Check if frame was captured and store it
- if (rxlen > 0) {
-// frame_count++;
- LogTrace(rx, nbytes(rxlen), response, response, NULL, false);
+ hitag_data htd;
+ memcpy(htd.auth.NrAr, data + dataoffset, 8);
+
+ int res = selectHitagS(RHTSF_CHALLENGE, &htd, tx, ARRAYLEN(tx), rx, ARRAYLEN(rx), t_wait, ledcontrol);
+ Dbprintf("Challenge %s: %02X %02X %02X %02X %02X %02X %02X %02X", res == -1 ? "failed " : "success",
+ htd.auth.NrAr[0], htd.auth.NrAr[1],
+ htd.auth.NrAr[2], htd.auth.NrAr[3],
+ htd.auth.NrAr[4], htd.auth.NrAr[5],
+ htd.auth.NrAr[6], htd.auth.NrAr[7]);
+ if (res == -1) {
+ // Need to do a dummy UID select that will fail
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ SpinDelay(2);
+ selectHitagS(RHTSF_CHALLENGE, &htd, tx, ARRAYLEN(tx), rx, ARRAYLEN(rx), t_wait, ledcontrol);
}
-
- uint8_t *tx = txbuf;
- size_t txlen = 0;
- if (rxlen == 0) {
- if (STATE == 2)
- // challenge failed
- Dbprintf("Challenge failed: %02X %02X %02X %02X %02X %02X %02X %02X",
- unlocker[u1 - 1][0], unlocker[u1 - 1][1],
- unlocker[u1 - 1][2], unlocker[u1 - 1][3],
- unlocker[u1 - 1][4], unlocker[u1 - 1][5],
- unlocker[u1 - 1][6], unlocker[u1 - 1][7]);
- STATE = 0;
- txlen = 5;
- //start new authentication
- memcpy(tx, "\xC0", nbytes(txlen));
- } else if (rxlen >= 67 && STATE == 0) {
- //received uid
- z = 0;
- for (i = 0; i < 10; i++) {
- for (j = 0; j < 8; j++) {
- response_bit[z] = 0;
- if ((rx[i] & ((mask << 7) >> j)) != 0)
- response_bit[z] = 1;
- z++;
- }
- }
- k = 0;
- for (i = 5; i < z; i += 2) {
- uid[k] = response_bit[i];
- k++;
- if (k > 31)
- break;
- }
- uid_byte[0] = (uid[0] << 7) | (uid[1] << 6) | (uid[2] << 5)
- | (uid[3] << 4) | (uid[4] << 3) | (uid[5] << 2)
- | (uid[6] << 1) | uid[7];
- uid_byte[1] = (uid[8] << 7) | (uid[9] << 6) | (uid[10] << 5)
- | (uid[11] << 4) | (uid[12] << 3) | (uid[13] << 2)
- | (uid[14] << 1) | uid[15];
- uid_byte[2] = (uid[16] << 7) | (uid[17] << 6) | (uid[18] << 5)
- | (uid[19] << 4) | (uid[20] << 3) | (uid[21] << 2)
- | (uid[22] << 1) | uid[23];
- uid_byte[3] = (uid[24] << 7) | (uid[25] << 6) | (uid[26] << 5)
- | (uid[27] << 4) | (uid[28] << 3) | (uid[29] << 2)
- | (uid[30] << 1) | uid[31];
- //Dbhexdump(10, rx, rxlen);
- STATE = 1;
- txlen = 45;
- crc = CRC_PRESET;
- calc_crc(&crc, 0x00, 5);
- calc_crc(&crc, uid_byte[0], 8);
- calc_crc(&crc, uid_byte[1], 8);
- calc_crc(&crc, uid_byte[2], 8);
- calc_crc(&crc, uid_byte[3], 8);
- for (i = 0; i < 100; i++) {
- response_bit[i] = 0;
- }
- for (i = 0; i < 5; i++) {
- response_bit[i] = 0;
- }
- for (i = 5; i < 37; i++) {
- response_bit[i] = uid[i - 5];
- }
- for (j = 0; j < 8; j++) {
- response_bit[i] = 0;
- if ((crc & ((mask << 7) >> j)) != 0)
- response_bit[i] = 1;
- i++;
- }
- k = 0;
- for (i = 0; i < 6; i++) {
- tx[i] = (response_bit[k] << 7) | (response_bit[k + 1] << 6)
- | (response_bit[k + 2] << 5)
- | (response_bit[k + 3] << 4)
- | (response_bit[k + 4] << 3)
- | (response_bit[k + 5] << 2)
- | (response_bit[k + 6] << 1) | response_bit[k + 7];
- k += 8;
- }
-
- } else if (STATE == 1 && rxlen == 44) {
- //received configuration
- STATE = 2;
- z = 0;
- for (i = 0; i < 6; i++) {
- for (j = 0; j < 8; j++) {
- response_bit[z] = 0;
- if ((rx[i] & ((mask << 7) >> j)) != 0)
- response_bit[z] = 1;
- z++;
- }
- }
- txlen = 64;
-
- if (u1 >= ARRAYLEN(unlocker))
- bStop = !false;
- for (i = 0; i < 8; i++)
- tx[i] = unlocker[u1][i];
- u1++;
-
- } else if (STATE == 2 && rxlen >= 44) {
- Dbprintf("Challenge success: %02X%02X%02X%02X %02X%02X%02X%02X",
- unlocker[u1 - 1][0], unlocker[u1 - 1][1],
- unlocker[u1 - 1][2], unlocker[u1 - 1][3],
- unlocker[u1 - 1][4], unlocker[u1 - 1][5],
- unlocker[u1 - 1][6], unlocker[u1 - 1][7]);
- STATE = 0;
- }
-
- // Send and store the reader command
- // Disable timer 1 with external trigger to avoid triggers during our own modulation
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
-
- // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting,
- // Since the clock counts since the last falling edge, a 'one' means that the
- // falling edge occurred halfway the period. with respect to this falling edge,
- // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'.
- // All timer values are in terms of T0 units
-
- while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) {};
-
- // Transmit the reader frame
- hitag_reader_send_frame(tx, txlen, ledcontrol);
-
- // Enable and reset external trigger in timer for capturing future frames
- AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-
- // Add transmitted frame to total count
- if (txlen > 0) {
-// frame_count++;
- LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, HITAG_T_WAIT_2, NULL, true);
- }
-
- hitagS_receive_frame(rx, &rxlen, &response, ledcontrol);
+ dataoffset += 8;
+ if (dataoffset >= datalen - 8)
+ break;
+ // reset field
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ // min t_reset = 2ms
+ SpinDelay(2);
}
-
set_tracing(false);
lf_finalize(ledcontrol);
- reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0);
+ reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
+ return;
}
diff --git a/armsrc/hitagS.h b/armsrc/hitagS.h
index 62db442ef..4bda3c75b 100644
--- a/armsrc/hitagS.h
+++ b/armsrc/hitagS.h
@@ -19,6 +19,5 @@
void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data, bool ledcontrol);
void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol);
void WritePageHitagS(hitag_function htf, hitag_data *htd, int page, bool ledcontrol);
-void check_challenges(bool file_given, uint8_t *data, bool ledcontrol);
-
+void Hitag_check_challenges(uint8_t *data, uint32_t datalen, bool ledcontrol);
#endif
diff --git a/armsrc/iclass.c b/armsrc/iclass.c
index 9fe238e6a..b7090ad9d 100644
--- a/armsrc/iclass.c
+++ b/armsrc/iclass.c
@@ -34,6 +34,7 @@
#include "protocols.h"
#include "ticks.h"
#include "iso15693.h"
+#include "iclass_cmd.h" /* iclass_card_select_t struct */
static uint8_t get_pagemap(const picopass_hdr_t *hdr) {
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
@@ -1402,13 +1403,8 @@ bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_t
// turn off afterwards
void ReaderIClass(uint8_t flags) {
- picopass_hdr_t hdr = {0};
-// uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0};
- uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
- memset(resp, 0xFF, sizeof(resp));
-
-// bool flag_readonce = flags & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully
- bool use_credit_key = flags & FLAG_ICLASS_READER_CREDITKEY; // flag to use credit key
+ // flag to use credit key
+ bool use_credit_key = ((flags & FLAG_ICLASS_READER_CREDITKEY) == FLAG_ICLASS_READER_CREDITKEY);
if ((flags & FLAG_ICLASS_READER_INIT) == FLAG_ICLASS_READER_INIT) {
Iso15693InitReader();
@@ -1418,13 +1414,14 @@ void ReaderIClass(uint8_t flags) {
clear_trace();
}
- uint8_t result_status = 0;
+
+ uint8_t res = 0;
uint32_t eof_time = 0;
- bool status = select_iclass_tag_ex(&hdr, use_credit_key, &eof_time, &result_status);
- if (status == false) {
- reply_mix(CMD_ACK, 0xFF, 0, 0, NULL, 0);
- switch_off();
- return;
+ picopass_hdr_t hdr = {0};
+
+ if (select_iclass_tag_ex(&hdr, use_credit_key, &eof_time, &res) == false) {
+ reply_ng(CMD_HF_ICLASS_READER, PM3_ERFTRANS, NULL, 0);
+ goto out;
}
// Page mapping for secure mode
@@ -1443,30 +1440,14 @@ void ReaderIClass(uint8_t flags) {
// Return to client, e 6 * 8 bytes of data.
// with 0xFF:s in block 3 and 4.
- LED_B_ON();
- reply_mix(CMD_ACK, result_status, 0, 0, (uint8_t *)&hdr, sizeof(hdr));
+ iclass_card_select_resp_t payload = {
+ .status = res
+ };
+ memcpy(&payload.header.hdr, &hdr, sizeof(picopass_hdr_t));
- //Send back to client, but don't bother if we already sent this -
- // only useful if looping in arm (not try_once && not abort_after_read)
- /*
- if (memcmp(last_csn, card_data, 8) != 0) {
-
- reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data));
- if (flag_readonce) {
- LED_B_OFF();
- return;
- }
- LED_B_OFF();
- }
- */
-
-// if (userCancelled) {
-// reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0);
-// switch_off();
-// } else {
-// reply_mix(CMD_ACK, result_status, 0, 0, card_data, 0);
-// }
+ reply_ng(CMD_HF_ICLASS_READER, PM3_SUCCESS, (uint8_t*)&payload, sizeof(iclass_card_select_resp_t));
+out:
switch_off();
}
diff --git a/armsrc/iclass.h b/armsrc/iclass.h
index 958382256..c0cbe9b3b 100644
--- a/armsrc/iclass.h
+++ b/armsrc/iclass.h
@@ -13,7 +13,7 @@
#define __ICLASS_H
#include "common.h"
-#include "pm3_cmd.h"
+#include "iclass_cmd.h"
void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string);
void ReaderIClass(uint8_t flags);
diff --git a/armsrc/lfzx.c b/armsrc/lfzx.c
index 364af4abc..b392eba0e 100644
--- a/armsrc/lfzx.c
+++ b/armsrc/lfzx.c
@@ -87,7 +87,6 @@ static void zx8211_setup_read(void) {
sample_config *sc = getSamplingConfig();
LFSetupFPGAForADC(sc->divisor, true);
-
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_ADC_READER_FIELD);
// 50ms for the resonant antenna to settle.
@@ -132,6 +131,26 @@ static void zx_send(uint8_t *cmd, uint8_t clen) {
turn_read_lf_on(ZX_TEOF * 8);
}
+static void zx_get(bool ledcontrol) {
+
+ while (BUTTON_PRESS() == false) {
+
+ WDT_HIT();
+
+ if (ledcontrol && (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY)) {
+ LED_D_ON();
+ }
+
+ if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
+ volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
+ (void)sample;
+
+ // Test point 8 (TP8) can be used to trigger oscilloscope
+ if (ledcontrol) LED_D_OFF();
+
+ }
+ }
+}
int zx8211_read(zx8211_data_t *zxd, bool ledcontrol) {
zx8211_setup_read();
@@ -144,13 +163,18 @@ int zx8211_read(zx8211_data_t *zxd, bool ledcontrol) {
// send GET_UID
zx_send(NULL, 0);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_ADC_READER_FIELD);
+
+ zx_get(ledcontrol);
+
//uint32_t cs = CRC8Hitag1(uint8_t *buff, size_t size);
if (ledcontrol) LEDsoff();
StopTicks();
lf_finalize(ledcontrol);
- //reply_ng(CMD_LF_ZX_READ, status, tag.data, sizeof(tag.data));
+
+ reply_ng(CMD_LF_ZX_READ, PM3_SUCCESS, NULL, 0);
return PM3_SUCCESS;
}
diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c
index 42eef11a0..38ba66548 100644
--- a/armsrc/mifarecmd.c
+++ b/armsrc/mifarecmd.c
@@ -2594,7 +2594,7 @@ OUT:
BigBuf_free();
}
-void MifareG3ReadBlk(uint8_t blockno) {
+void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd) {
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
@@ -2613,6 +2613,9 @@ void MifareG3ReadBlk(uint8_t blockno) {
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 1000); // 2 seconds timeout
uint8_t cmd[] = { 0xCF, 0x00, 0x00, 0x00, 0x00, 0xCE, blockno, 0x00, 0x00};
+
+ memcpy(cmd + 1, pwd, 4);
+
AddCrc14A(cmd, sizeof(cmd) - 2);
ReaderTransmit(cmd, sizeof(cmd), NULL);
@@ -2624,7 +2627,7 @@ void MifareG3ReadBlk(uint8_t blockno) {
LED_B_OFF();
OUT:
- reply_ng(CMD_HF_MIFARE_G3_RDBL, retval, buf, 18);
+ reply_ng(CMD_HF_MIFARE_G4_RDBL, retval, buf, 18);
// turns off
OnSuccessMagic();
BigBuf_free();
diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h
index bacb8405e..49f1832e7 100644
--- a/armsrc/mifarecmd.h
+++ b/armsrc/mifarecmd.h
@@ -49,8 +49,8 @@ void MifareGen3UID(uint8_t uidlen, uint8_t *uid); // Gen 3 magic card set UID wi
void MifareGen3Blk(uint8_t block_len, uint8_t *block); // Gen 3 magic card overwrite manufacturer block
void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes
-// MFC GEN3 GTU
-void MifareG3ReadBlk(uint8_t blockno);
+// MFC GEN4 GTU
+void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd);
void MifareSetMod(uint8_t *datain);
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);
diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic
index 61c94694c..be3a5a000 100644
--- a/client/dictionaries/mfc_default_keys.dic
+++ b/client/dictionaries/mfc_default_keys.dic
@@ -1464,4 +1464,14 @@ B5ADEFCA46C4
BF3FE47637EC
B290401B0CAD
AD11006B0601
-
+#
+# Data from Mifare Classic Tool repo
+# Armenian Metro
+E4410EF8ED2D
+6A68A7D83E11
+0D6057E8133B
+D3F3B958B8A3
+3E120568A35C
+2196FAD8115B
+7C469FE86855
+CE99FBC8BD26
diff --git a/client/src/cmdanalyse.c b/client/src/cmdanalyse.c
index c567b18c3..4d3352da8 100644
--- a/client/src/cmdanalyse.c
+++ b/client/src/cmdanalyse.c
@@ -1052,7 +1052,7 @@ static int CmdAnalyseFoo(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0("r", "raw", "", "raw bytes (strx)"),
+ arg_str1("r", "raw", "", "raw bytes"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
diff --git a/client/src/cmddata.c b/client/src/cmddata.c
index 1188b5308..70bc65b44 100644
--- a/client/src/cmddata.c
+++ b/client/src/cmddata.c
@@ -2407,7 +2407,7 @@ static int Cmdbin2hex(const char *Cmd) {
);
void *argtable[] = {
arg_param_begin,
- arg_strx0("d", "data", "", "binary string to convert"),
+ arg_str1("d", "data", "", "binary string to convert"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
diff --git a/client/src/cmdflashmem.c b/client/src/cmdflashmem.c
index c7af3141f..c2e5591a6 100644
--- a/client/src/cmdflashmem.c
+++ b/client/src/cmdflashmem.c
@@ -167,7 +167,7 @@ static int CmdFlashMemLoad(const char *Cmd) {
arg_lit0("m", "mifare,mfc", "upload 6 bytes keys (mifare key dictionary)"),
arg_lit0("i", "iclass", "upload 8 bytes keys (iClass key dictionary)"),
arg_lit0("t", "t55xx", "upload 4 bytes keys (password dictionary)"),
- arg_strx0("f", "file", "", "file name"),
+ arg_str1("f", "file", "", "file name"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@@ -327,7 +327,7 @@ static int CmdFlashMemDump(const char *Cmd) {
arg_int0("o", "offset", "", "offset in memory"),
arg_int0("l", "len", "", "length"),
arg_lit0("v", "view", "view dump"),
- arg_strx0("f", "file", "", "file name"),
+ arg_str0("f", "file", "", "save filename"),
arg_int0("c", "cols", "", "column breaks (def 32)"),
arg_param_end
};
diff --git a/client/src/cmdflashmemspiffs.c b/client/src/cmdflashmemspiffs.c
index 684165236..407f1e54c 100644
--- a/client/src/cmdflashmemspiffs.c
+++ b/client/src/cmdflashmemspiffs.c
@@ -196,7 +196,7 @@ static int CmdFlashMemSpiFFSRemove(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str1("f", "filename", "", "file to remove"),
+ arg_str1("f", "file", "", "file to remove"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c
index b55043ff9..d127010d5 100644
--- a/client/src/cmdhf14a.c
+++ b/client/src/cmdhf14a.c
@@ -743,13 +743,16 @@ int CmdHF14ASim(const char *Cmd) {
keypress = kbd_enter_pressed();
}
- if (keypress && (flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) {
- // inform device to break the sim loop since client has exited
- SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
- }
+ if (keypress) {
+ if ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) {
+ // inform device to break the sim loop since client has exited
+ SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
+ }
- if (resp.status == PM3_EOPABORTED && ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK))
- showSectorTable(k_sector, k_sectorsCount);
+ if (resp.status == PM3_EOPABORTED && ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK)) {
+ showSectorTable(k_sector, k_sectorsCount);
+ }
+ }
PrintAndLogEx(INFO, "Done");
return PM3_SUCCESS;
@@ -2274,7 +2277,7 @@ static int CmdHf14AFindapdu(const char *Cmd) {
arg_str0(NULL, "p2", "", "Start value of P2 (1 hex byte)"),
arg_u64_0("r", "reset", "", "Minimum secondes before resetting the tag (to prevent timeout issues). Default is 5 minutes"),
arg_u64_0("e", "error-limit", "", "Maximum times an status word other than 0x9000 or 0x6D00 is shown. Default is 512."),
- arg_strx0("s", "skip-ins", "", "Do not test an instructions (can be specified multiple times)"),
+ arg_strx0("s", "skip-ins", "", "Do not test an instruction (can be specified multiple times)"),
arg_lit0("l", "with-le", "Search for APDUs with Le=0 (case 2S) as well"),
arg_lit0("v", "verbose", "Verbose output"),
arg_param_end
diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c
index bd085210d..04e0a1a52 100644
--- a/client/src/cmdhf14b.c
+++ b/client/src/cmdhf14b.c
@@ -221,7 +221,7 @@ static int CmdHF14BSim(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0("u", "uid", "hex", "4byte UID/PUPI"),
+ arg_str1("u", "uid", "hex", "4byte UID/PUPI"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@@ -288,7 +288,7 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
arg_lit0("r", NULL, "do not read response from card"),
arg_int0("t", "timeout", "", "timeout in ms"),
arg_lit0("v", "verbose", "verbose"),
- arg_strx0("d", "data", "", "data, bytes to send"),
+ arg_str0("d", "data", "", "data, bytes to send"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@@ -1276,7 +1276,7 @@ static int CmdHF14BDump(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0("f", "file", "", "(optional) filename, if no UID will be used as filename"),
+ arg_str0("f", "file", "", "(optional) filename, if no UID will be used as filename"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -1822,7 +1822,7 @@ static int CmdHF14BAPDU(const char *Cmd) {
" must be 4 bytes: "),
arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"),
arg_int0("l", "le", "", "Le apdu parameter if `m` parameter included"),
- arg_strx1("d", "data", "", " if `m` parameter included"),
+ arg_str1("d", "data", "", " if `m` parameter included"),
arg_int0(NULL, "timeout", "", "timeout in ms"),
arg_param_end
};
diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c
index 73652837b..16071df8b 100644
--- a/client/src/cmdhf15.c
+++ b/client/src/cmdhf15.c
@@ -1450,7 +1450,7 @@ static int CmdHF15Raw(const char *Cmd) {
arg_lit0("c", "crc", "calculate and append CRC"),
arg_lit0("k", NULL, "keep signal field ON after receive"),
arg_lit0("r", NULL, "do not read response"),
- arg_strx1("d", "data", "", "raw bytes to send"),
+ arg_str1("d", "data", "", "raw bytes to send"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
diff --git a/client/src/cmdhfcryptorf.c b/client/src/cmdhfcryptorf.c
index 5edaa4cdd..1f68b9bd4 100644
--- a/client/src/cmdhfcryptorf.c
+++ b/client/src/cmdhfcryptorf.c
@@ -423,7 +423,7 @@ static int CmdHFCryptoRFELoad(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str1("f", "file", "", "filename of dump"),
+ arg_str1("f", "file", "", "filename of dump"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c
index 613c0a055..2afefff1d 100644
--- a/client/src/cmdhfemrtd.c
+++ b/client/src/cmdhfemrtd.c
@@ -201,7 +201,7 @@ static int emrtd_exchange_commands_noout(sAPDU_t apdu, bool activate_field, bool
}
static char emrtd_calculate_check_digit(char *data) {
- int mrz_weight[] = {7, 3, 1};
+ const int mrz_weight[] = {7, 3, 1};
int value, cd = 0;
for (int i = 0; i < strlen(data); i++) {
@@ -295,7 +295,7 @@ static void des3_decrypt_cbc(uint8_t *iv, uint8_t *key, uint8_t *input, int inpu
}
static int pad_block(uint8_t *input, int inputlen, uint8_t *output) {
- uint8_t padding[8] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ const uint8_t padding[8] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
memcpy(output, input, inputlen);
diff --git a/client/src/cmdhfepa.c b/client/src/cmdhfepa.c
index acc89d4c4..9864cc55e 100644
--- a/client/src/cmdhfepa.c
+++ b/client/src/cmdhfepa.c
@@ -132,7 +132,7 @@ static int CmdHFEPAPACEReplay(const char *Cmd) {
uint8_t apdu_lengths[5] = {msesa_len, gn_len, map_len, pka_len, ma_len};
// pointers to the arrays to be able to iterate
- uint8_t *apdus[] = {msesa_apdu, gn_apdu, map_apdu, pka_apdu, ma_apdu};
+ const uint8_t *apdus[] = {msesa_apdu, gn_apdu, map_apdu, pka_apdu, ma_apdu};
// Proxmark response
PacketResponseNG resp;
diff --git a/client/src/cmdhffelica.c b/client/src/cmdhffelica.c
index 02f14c893..d6a03f0ef 100644
--- a/client/src/cmdhffelica.c
+++ b/client/src/cmdhffelica.c
@@ -2122,7 +2122,7 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) {
arg_u64_0("n", NULL, "", "number of bits"),
arg_lit0("r", NULL, "do not read response"),
arg_lit0("s", NULL, "active signal field ON with select"),
- arg_strx1(NULL, NULL, "", "raw bytes to send"),
+ arg_str1(NULL, NULL, "", "raw bytes to send"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c
index 8c68833ab..b9945bf2e 100644
--- a/client/src/cmdhficlass.c
+++ b/client/src/cmdhficlass.c
@@ -32,10 +32,11 @@
#include "wiegand_formatutils.h"
#include "cmdsmartcard.h" // smart select fct
#include "proxendian.h"
+#include "iclass_cmd.h"
-#define NUM_CSNS 9
-#define ICLASS_KEYS_MAX 8
-#define ICLASS_AUTH_RETRY 10
+#define NUM_CSNS 9
+#define ICLASS_KEYS_MAX 8
+#define ICLASS_AUTH_RETRY 10
#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin"
static void print_picopass_info(const picopass_hdr_t *hdr);
@@ -165,7 +166,7 @@ static const char *card_types[] = {
};
static uint8_t card_app2_limit[] = {
- 0xff,
+ 0x1f,
0xff,
0xff,
0xff,
@@ -278,7 +279,8 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
// calc diversified key for selected card
HFiClassCalcDivKey(cc->csn, iClass_Key_Table[0], cc->key_d, false);
} else {
- PrintAndLogEx(INFO, "failed to read a card, will use default config card data");
+ PrintAndLogEx(FAILED, "failed to read a card");
+ PrintAndLogEx(INFO,"falling back to default config card");
}
// generate dump file
@@ -323,35 +325,47 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
return PM3_EMALLOC;
}
data = p;
- memset(data, 0xFF, tot_bytes);
}
+ memset(data + sizeof(picopass_hdr_t), 0xFF, tot_bytes - sizeof(picopass_hdr_t));
+
+ bool old = GetFlushAfterWrite();
+ SetFlushAfterWrite(true);
+
// KEYROLL need to encrypt
+ PrintAndLogEx(INFO, "Setting up encryption... " NOLF);
uint8_t ffs[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
if (Encrypt(ffs, ffs) == false) {
PrintAndLogEx(WARNING, "failed to encrypt FF");
+ } else {
+ PrintAndLogEx(NORMAL,"( " _GREEN_("ok") " )");
}
// local key copy
+ PrintAndLogEx(INFO, "Encrypting local key... " NOLF);
uint8_t lkey[8];
memcpy(lkey, key, sizeof(lkey));
-
uint8_t enckey1[8];
if (Encrypt(lkey, enckey1) == false) {
PrintAndLogEx(WARNING, "failed to encrypt key1");
+ } else {
+ PrintAndLogEx(NORMAL,"( " _GREEN_("ok") " )");
}
+ PrintAndLogEx(INFO, "Copy data... " NOLF);
memcpy(data, cc, sizeof(picopass_hdr_t));
memcpy(data + (6 * 8), o->data, sizeof(o->data));
// encrypted keyroll key 0D
memcpy(data + (0xD * 8), enckey1, sizeof(enckey1));
// encrypted 0xFF
- for (uint8_t i = 0xe; i < 0x14; i++) {
+ for (uint8_t i = 0xD; i < 0x14; i++) {
memcpy(data + (i * 8), ffs, sizeof(ffs));
}
+ PrintAndLogEx(NORMAL,"( " _GREEN_("ok") " )");
// encrypted partial keyroll key 14
+ PrintAndLogEx(INFO, "Setting encrypted partial key14... " NOLF);
uint8_t foo[8] = {0x15};
memcpy(foo + 1, lkey, 7);
uint8_t enckey2[8];
@@ -359,34 +373,43 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
PrintAndLogEx(WARNING, "failed to encrypt partial 1");
}
memcpy(data + (0x14 * 8), enckey2, sizeof(enckey2));
+ PrintAndLogEx(NORMAL,"( " _GREEN_("ok") " )");
+
// encrypted partial keyroll key 15
+ PrintAndLogEx(INFO, "Setting encrypted partial key15... " NOLF);
memset(foo, 0xFF, sizeof(foo));
foo[0] = lkey[7];
if (Encrypt(foo, enckey2) == false) {
PrintAndLogEx(WARNING, "failed to encrypt partial 2");
}
memcpy(data + (0x15 * 8), enckey2, sizeof(enckey2));
+ PrintAndLogEx(NORMAL,"( " _GREEN_("ok") " )");
// encrypted 0xFF
+ PrintAndLogEx(INFO, "Setting 0xFF's... " NOLF);
for (uint8_t i = 0x16; i <= app1_limit; i++) {
memcpy(data + (i * 8), ffs, sizeof(ffs));
- }
+ }
+ PrintAndLogEx(NORMAL,"( " _GREEN_("ok") " )");
// revert potential modified app1_limit
cc->conf.app_limit = old_limit;
+ SetFlushAfterWrite(old);
} else {
memcpy(data, cc, sizeof(picopass_hdr_t));
memcpy(data + (6 * 8), o->data, sizeof(o->data));
}
//Send to device
+ PrintAndLogEx(INFO, "Uploading to device... ");
uint16_t bytes_sent = 0;
iclass_upload_emul(data, tot_bytes, &bytes_sent);
free(data);
- PrintAndLogEx(SUCCESS, "sent %u bytes of data to device emulator memory", bytes_sent);
+ PrintAndLogEx(NORMAL, "");
+ PrintAndLogEx(SUCCESS, "sent " _YELLOW_("%u") " bytes of data to device emulator memory", bytes_sent);
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass eview") "` to view dump file");
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass sim -t 3") "` to start simulating config card");
return PM3_SUCCESS;
@@ -454,15 +477,21 @@ static void fuse_config(const picopass_hdr_t *hdr) {
PrintAndLogEx(SUCCESS, " RA........... Read access enabled (non-secure mode)");
else
PrintAndLogEx(INFO, " RA........... Read access not enabled");
+
+ if (notset(fuses, FUSE_FPROD0) && isset(fuses, FUSE_FPROD1)) {
+ PrintAndLogEx(INFO, " PROD0/1...... Default production fuses");
+ }
}
-static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *app_areas, uint8_t *kb) {
+static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *app_areas, uint8_t *kb, uint8_t *books, uint8_t *pages) {
// How to determine chip type
// mem-bit 7 = 16K
// mem-bit 5 = Book
// mem-bit 4 = 2K
// chip-bit 4 = Multi App
+ *books = 1;
+ *pages = 1;
uint8_t k16 = isset(mem_cfg, 0x80);
//uint8_t k2 = isset(mem_cfg, 0x10);
@@ -477,12 +506,16 @@ static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *app_areas,
} else if (notset(chip_cfg, 0x10) && !k16 && !book) {
*kb = 16;
*app_areas = 16;
+ *pages = 8;
} else if (isset(chip_cfg, 0x10) && k16 && book) {
*kb = 32;
*app_areas = 3;
+ *books = 2;
} else if (notset(chip_cfg, 0x10) && !k16 && book) {
*kb = 32;
*app_areas = 17;
+ *pages = 8;
+ *books = 2;
} else {
*kb = 32;
*app_areas = 2;
@@ -506,8 +539,10 @@ static void mem_app_config(const picopass_hdr_t *hdr) {
uint8_t chip = hdr->conf.chip_config;
uint8_t kb = 2;
uint8_t app_areas = 2;
-
- getMemConfig(mem, chip, &app_areas, &kb);
+ uint8_t books = 1;
+ uint8_t pages = 1;
+
+ getMemConfig(mem, chip, &app_areas, &kb, &books, &pages);
uint8_t type = get_mem_config(hdr);
uint8_t app1_limit = hdr->conf.app_limit - 5; // minus header blocks
@@ -522,9 +557,26 @@ static void mem_app_config(const picopass_hdr_t *hdr) {
return;
}
- PrintAndLogEx(INFO, " %u KBits/%u App Areas ( " _YELLOW_("%u") " bytes )", kb, app_areas, (app2_limit + 1) * 8);
- PrintAndLogEx(INFO, " AA1 blocks %u { 0x06 - 0x%02X (06 - %02d) }", app1_limit, app1_limit + 5, app1_limit + 5);
- PrintAndLogEx(INFO, " AA2 blocks %u { 0x%02X - 0x%02X (%02d - %02d) }", app2_limit - app1_limit, app1_limit + 5 + 1, app2_limit, app1_limit + 5 + 1, app2_limit);
+ PrintAndLogEx(INFO, " %u KBits/%u App Areas ( " _YELLOW_("%u") " bytes )"
+ , kb
+ , app_areas
+ , ((app2_limit + 1) * 8) * books * pages);
+
+ PrintAndLogEx(INFO, " %u books / %u pages"
+ , books
+ , pages
+ );
+ PrintAndLogEx(INFO, " First book / first page configuration");
+ PrintAndLogEx(INFO, " Config | 0 - 5 ( 0x00 - 0x05 ) - 6 blocks ");
+ PrintAndLogEx(INFO, " AA1 | 6 - %2d ( 0x06 - 0x%02X ) - %u blocks", app1_limit + 5, app1_limit + 5, app1_limit);
+ if (app1_limit + 5 < app2_limit ) {
+ PrintAndLogEx(INFO, " AA2 | %2d - %2d ( 0x%02X - 0x%02X ) - %u blocks", app1_limit + 5 + 1, app2_limit, app1_limit + 5 + 1, app2_limit, app2_limit - app1_limit);
+ }
+/*
+[=] 32 KBits/3 App Areas ( 2048 bytes )
+[=] AA1 blocks 250 { 0x06 - 0xFF (06 - 255) }
+[=] AA2 blocks 5 { 0x100 - 0xFF (256 - 255) }
+*/
PrintAndLogEx(INFO, "------------------------- " _CYAN_("KeyAccess") " ------------------------");
PrintAndLogEx(INFO, " * Kd, Debit key, AA1 Kc, Credit key, AA2 *");
@@ -557,8 +609,19 @@ void print_picopass_header(const picopass_hdr_t *hdr) {
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn)));
PrintAndLogEx(SUCCESS, " Config: %s Card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
- PrintAndLogEx(SUCCESS, " Kd: %s Debit key, hidden", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
- PrintAndLogEx(SUCCESS, " Kc: %s Credit key, hidden", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
+
+ if (memcmp(hdr->key_d, zeros, sizeof(zeros)) && memcmp(hdr->key_d, empty, sizeof(empty))) {
+ PrintAndLogEx(SUCCESS, " Kd: " _YELLOW_("%s") " debit key", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
+ } else {
+ PrintAndLogEx(SUCCESS, " Kd: %s debit key ( hidden )", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
+ }
+
+ if (memcmp(hdr->key_c, zeros, sizeof(zeros)) && memcmp(hdr->key_c, empty, sizeof(empty))) {
+ PrintAndLogEx(SUCCESS, " Kc: " _YELLOW_("%s") " credit key", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
+ } else {
+ PrintAndLogEx(SUCCESS, " Kc: %s credit key ( hidden )", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
+ }
+
PrintAndLogEx(SUCCESS, " AIA: %s Application Issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area)));
}
@@ -834,25 +897,28 @@ static int CmdHFiClassInfo(const char *Cmd) {
int read_iclass_csn(bool loop, bool verbose) {
- uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE);
+ iclass_card_select_t payload = {
+ .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
+ };
+
int res = PM3_SUCCESS;
do {
clearCommandBuffer();
- SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0);
PacketResponseNG resp;
- if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
+ SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t*)&payload, sizeof(iclass_card_select_t));
- uint8_t status = resp.oldarg[0] & 0xff;
+ if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000)) {
+ iclass_card_select_resp_t *r = (iclass_card_select_resp_t*)resp.data.asBytes;
if (loop) {
- if (status == 0xFF) {
+ if (resp.status == PM3_ERFTRANS) {
continue;
}
} else {
- if (status == 0 || status == 0xFF) {
- if (verbose) PrintAndLogEx(WARNING, "iCLASS / ISO15693 card select failed");
+ if (r->status == FLAG_ICLASS_NULL || resp.status == PM3_ERFTRANS) {
+ if (verbose) PrintAndLogEx(WARNING, "iCLASS / Picopass card select failed ( %d )", r->status);
res = PM3_EOPABORTED;
break;
}
@@ -860,13 +926,17 @@ int read_iclass_csn(bool loop, bool verbose) {
picopass_hdr_t *card = calloc(1, sizeof(picopass_hdr_t));
if (card) {
- memcpy(card, (picopass_hdr_t *)resp.data.asBytes, sizeof(picopass_hdr_t));
- PrintAndLogEx(NORMAL, "");
+ memcpy(card, &r->header.hdr, sizeof(picopass_hdr_t));
+ if (loop == false) {
+ PrintAndLogEx(NORMAL, "");
+ }
PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn)));
iclass_set_last_known_card(card);
free(card);
+ res = PM3_SUCCESS;
} else {
PrintAndLogEx(FAILED, "failed to allocate memory");
+ res = PM3_EMALLOC;
}
}
} while (loop && kbd_enter_pressed() == false);
@@ -1240,7 +1310,9 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
} else {
mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data);
}
- PrintAndLogEx(SUCCESS, "Data: %s", sprint_hex(dec_data, sizeof(dec_data)));
+
+ PrintAndLogEx(SUCCESS, "encrypted... %s", sprint_hex_inrow(enc_data, sizeof(enc_data)));
+ PrintAndLogEx(SUCCESS, "plain....... " _YELLOW_("%s"), sprint_hex_inrow(dec_data, sizeof(dec_data)));
if (use_sc && use_decode6)
DecodeBlock6(dec_data);
@@ -1256,7 +1328,9 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
uint8_t applimit = hdr->conf.app_limit;
uint8_t kb = 2;
uint8_t app_areas = 2;
- getMemConfig(mem, chip, &app_areas, &kb);
+ uint8_t books = 1;
+ uint8_t pages = 1;
+ getMemConfig(mem, chip, &app_areas, &kb, &books, &pages);
BLOCK79ENCRYPTION aa1_encryption = (decrypted[(6 * 8) + 7] & 0x03);
@@ -1455,39 +1529,45 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
}
}
+
+ PrintAndLogEx(SUCCESS, "plain....... %s", sprint_hex_inrow(blk_data, sizeof(blk_data)));
+
if (use_sc) {
Encrypt(blk_data, blk_data);
} else {
iclass_encrypt_block_data(blk_data, key);
}
- PrintAndLogEx(SUCCESS, "encrypted block %s", sprint_hex(blk_data, 8));
+
+ PrintAndLogEx(SUCCESS, "encrypted... " _YELLOW_("%s"), sprint_hex_inrow(blk_data, sizeof(blk_data)));
return PM3_SUCCESS;
}
static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) {
- uint8_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE);
+ iclass_card_select_t payload = {
+ .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
+ };
clearCommandBuffer();
PacketResponseNG resp;
- SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0);
- if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
+ SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t*)&payload, sizeof(iclass_card_select_t));
+
+ if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "command execute timeout");
return false;
}
- uint8_t isok = resp.oldarg[0] & 0xff;
+ iclass_card_select_resp_t *r = (iclass_card_select_resp_t*)resp.data.asBytes;
+ picopass_hdr_t *hdr = &r->header.hdr;
// no tag found or button pressed
- if ((isok == 0) || isok == 0xFF) {
+ if (r->status == FLAG_ICLASS_NULL || resp.status == PM3_ERFTRANS) {
if (verbose) {
- PrintAndLogEx(FAILED, "failed tag-select, aborting... (%d)", isok);
+ PrintAndLogEx(FAILED, "failed tag-select, aborting... (%d)", r->status);
}
return false;
}
- picopass_hdr_t *hdr = (picopass_hdr_t *)resp.data.asBytes;
-
if (CSN != NULL)
memcpy(CSN, hdr->csn, 8);
@@ -1614,34 +1694,41 @@ static int CmdHFiClassDump(const char *Cmd) {
uint8_t app_limit1 = 0, app_limit2 = 0;
- uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE);
-
//get CSN and config
- PacketResponseNG resp;
uint8_t tag_data[0x100 * 8];
memset(tag_data, 0xFF, sizeof(tag_data));
+
+ iclass_card_select_t payload_rdr = {
+ .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
+ };
clearCommandBuffer();
- SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0);
- if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
+ PacketResponseNG resp;
+ SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t*)&payload_rdr, sizeof(iclass_card_select_t));
+
+ if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "command execute timeout");
DropField();
return PM3_ESOFT;
}
DropField();
- uint8_t readStatus = resp.oldarg[0] & 0xff;
- picopass_hdr_t *hdr = (picopass_hdr_t *)resp.data.asBytes;
-
- if (readStatus == 0) {
+ if (resp.status == PM3_ERFTRANS) {
PrintAndLogEx(FAILED, "no tag found");
DropField();
return PM3_ESOFT;
}
+ iclass_card_select_resp_t *r = (iclass_card_select_resp_t*)resp.data.asBytes;
+ if (r->status == FLAG_ICLASS_NULL) {
+ PrintAndLogEx(FAILED, "failed to read block 0,1,2");
+ return PM3_ESOFT;
+ }
+
+ picopass_hdr_t *hdr = &r->header.hdr;
uint8_t pagemap = get_pagemap(hdr);
- if (readStatus & (FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC)) {
+ if (r->status & (FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC)) {
memcpy(tag_data, hdr, 24);
@@ -1661,11 +1748,6 @@ static int CmdHFiClassDump(const char *Cmd) {
app_limit1 = hdr->conf.app_limit;
app_limit2 = card_app2_limit[type];
}
-
- } else {
- PrintAndLogEx(FAILED, "failed to read block 0,1,2");
- DropField();
- return PM3_ESOFT;
}
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
@@ -2470,11 +2552,10 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e
);
*/
uint8_t pagemap = get_pagemap(hdr);
-
-
-
int i = startblock;
+ PrintAndLogEx(NORMAL, "");
+ PrintAndLogEx(INFO, "-------------------------- " _CYAN_("Tag memory") " ---------------------------");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, " block# | data | ascii |lck| info");
PrintAndLogEx(INFO, "---------+-------------------------+----------+---+--------------");
@@ -2484,7 +2565,7 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e
);
if (i != 1)
- PrintAndLogEx(INFO, "....");
+ PrintAndLogEx(INFO, " ......");
while (i <= endblock) {
uint8_t *blk = iclass_dump + (i * 8);
@@ -3956,88 +4037,101 @@ int CmdHFiClass(const char *Cmd) {
int info_iclass(void) {
- uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE);
-
+ iclass_card_select_t payload = {
+ .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
+ };
clearCommandBuffer();
- SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0);
PacketResponseNG resp;
+ SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t*)&payload, sizeof(iclass_card_select_t));
- if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
-
- uint8_t readStatus = resp.oldarg[0] & 0xff;
-
- // no tag found or button pressed
- if (readStatus == 0 || readStatus == 0xFF) {
- DropField();
- return PM3_EOPABORTED;
- }
-
- picopass_hdr_t *hdr = (picopass_hdr_t *)resp.data.asBytes;
- picopass_ns_hdr_t *ns_hdr = (picopass_ns_hdr_t *)resp.data.asBytes;
-
- PrintAndLogEx(NORMAL, "");
- PrintAndLogEx(INFO, "--------------------- " _CYAN_("Tag Information") " ----------------------");
-
- if (readStatus & FLAG_ICLASS_CSN) {
- PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn)));
- }
-
- if (readStatus & FLAG_ICLASS_CONF) {
- PrintAndLogEx(SUCCESS, " Config: %s card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
- }
-
- // page mapping. If fuse0|1 == 0x01, card is in non-secure mode, with CSN, CONF, AIA as top 3 blocks.
- // page9 in http://www.proxmark.org/files/Documents/13.56%20MHz%20-%20iClass/DS%20Picopass%202KS%20V1-0.pdf
- uint8_t pagemap = get_pagemap(hdr);
- if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
- PrintAndLogEx(SUCCESS, " AIA: %s application issuer area", sprint_hex(ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area)));
- } else {
-
- if (readStatus & FLAG_ICLASS_CC) {
- PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
- }
-
- PrintAndLogEx(SUCCESS, " Kd: %s debit key, hidden", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
- PrintAndLogEx(SUCCESS, " Kc: %s credit key, hidden", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
-
- if (readStatus & FLAG_ICLASS_AIA) {
- PrintAndLogEx(SUCCESS, " AIA: %s application issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area)));
- }
- }
-
- if (readStatus & FLAG_ICLASS_CONF) {
- print_picopass_info(hdr);
- }
-
- PrintAndLogEx(INFO, "------------------------ " _CYAN_("Fingerprint") " -----------------------");
-
- uint8_t aia[8];
- if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
- memcpy(aia, ns_hdr->app_issuer_area, sizeof(aia));
- } else {
- memcpy(aia, hdr->app_issuer_area, sizeof(aia));
- }
-
- // if CSN ends with FF12E0, it's inside HID CSN range.
- bool isHidRange = (memcmp(hdr->csn + 5, "\xFF\x12\xE0", 3) == 0);
-
- bool legacy = (memcmp(aia, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
- bool se_enabled = (memcmp(aia, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
-
- if (isHidRange) {
- PrintAndLogEx(SUCCESS, " CSN.......... " _YELLOW_("HID range"));
- if (legacy)
- PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS legacy"));
- if (se_enabled)
- PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS SE"));
- } else {
- PrintAndLogEx(SUCCESS, " CSN.......... " _YELLOW_("outside HID range"));
- }
-
- uint8_t cardtype = get_mem_config(hdr);
- PrintAndLogEx(SUCCESS, " Card type.... " _GREEN_("%s"), card_types[cardtype]);
+ if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000) == false) {
+ DropField();
+ return PM3_ETIMEOUT;
}
DropField();
+
+ iclass_card_select_resp_t *r = (iclass_card_select_resp_t*)resp.data.asBytes;
+
+ // no tag found or button pressed
+ if (r->status == FLAG_ICLASS_NULL || resp.status == PM3_ERFTRANS) {
+ return PM3_EOPABORTED;
+ }
+
+ picopass_hdr_t *hdr = &r->header.hdr;
+ picopass_ns_hdr_t *ns_hdr = &r->header.ns_hdr;
+
+ PrintAndLogEx(NORMAL, "");
+ PrintAndLogEx(INFO, "--------------------- " _CYAN_("Tag Information") " ----------------------");
+
+ if ((r->status & FLAG_ICLASS_CSN) == FLAG_ICLASS_CSN) {
+ PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn)));
+ }
+
+ if ((r->status & FLAG_ICLASS_CONF) == FLAG_ICLASS_CONF) {
+ PrintAndLogEx(SUCCESS, " Config: %s card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
+ }
+
+ // page mapping. If fuse0|1 == 0x01, card is in non-secure mode, with CSN, CONF, AIA as top 3 blocks.
+ // page9 in http://www.proxmark.org/files/Documents/13.56%20MHz%20-%20iClass/DS%20Picopass%202KS%20V1-0.pdf
+ uint8_t pagemap = get_pagemap(hdr);
+ if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
+ PrintAndLogEx(SUCCESS, " AIA: %s application issuer area", sprint_hex(ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area)));
+ } else {
+
+ if ((r->status & FLAG_ICLASS_CC) == FLAG_ICLASS_CC) {
+ PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
+ }
+
+ if (memcmp(hdr->key_d, zeros, sizeof(zeros))) {
+ PrintAndLogEx(SUCCESS, " Kd: " _YELLOW_("%s") " debit key", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
+ } else {
+ PrintAndLogEx(SUCCESS, " Kd: %s debit key ( hidden )", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
+ }
+
+ if (memcmp(hdr->key_c, zeros, sizeof(zeros))) {
+ PrintAndLogEx(SUCCESS, " Kc: " _YELLOW_("%s") " credit key", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
+ } else {
+ PrintAndLogEx(SUCCESS, " Kc: %s credit key ( hidden )", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
+ }
+
+
+ if ((r->status & FLAG_ICLASS_AIA) == FLAG_ICLASS_AIA) {
+ PrintAndLogEx(SUCCESS, " AIA: %s application issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area)));
+ }
+ }
+
+ if ((r->status & FLAG_ICLASS_CONF) == FLAG_ICLASS_CONF) {
+ print_picopass_info(hdr);
+ }
+
+ PrintAndLogEx(INFO, "------------------------ " _CYAN_("Fingerprint") " -----------------------");
+
+ uint8_t aia[8];
+ if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
+ memcpy(aia, ns_hdr->app_issuer_area, sizeof(aia));
+ } else {
+ memcpy(aia, hdr->app_issuer_area, sizeof(aia));
+ }
+
+ // if CSN ends with FF12E0, it's inside HID CSN range.
+ bool isHidRange = (memcmp(hdr->csn + 5, "\xFF\x12\xE0", 3) == 0);
+
+ bool legacy = (memcmp(aia, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
+ bool se_enabled = (memcmp(aia, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
+
+ if (isHidRange) {
+ PrintAndLogEx(SUCCESS, " CSN.......... " _YELLOW_("HID range"));
+ if (legacy)
+ PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS legacy"));
+ if (se_enabled)
+ PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS SE"));
+ } else {
+ PrintAndLogEx(SUCCESS, " CSN.......... " _YELLOW_("outside HID range"));
+ }
+
+ uint8_t cardtype = get_mem_config(hdr);
+ PrintAndLogEx(SUCCESS, " Card type.... " _GREEN_("%s"), card_types[cardtype]);
+
return PM3_SUCCESS;
}
diff --git a/client/src/cmdhficlass.h b/client/src/cmdhficlass.h
index 73d34df0b..9474dde45 100644
--- a/client/src/cmdhficlass.h
+++ b/client/src/cmdhficlass.h
@@ -13,21 +13,7 @@
#include "common.h"
#include "fileutils.h"
-#include "pm3_cmd.h"
-
-typedef struct iclass_block {
- uint8_t d[8];
-} iclass_block_t;
-
-typedef struct iclass_prekey {
- uint8_t mac[4];
- uint8_t key[8];
-} iclass_prekey_t;
-
-typedef struct {
- char desc[70];
- uint8_t data[16];
-} iclass_config_card_item_t;
+#include "iclass_cmd.h"
int CmdHFiClass(const char *Cmd);
diff --git a/client/src/cmdhfjooki.c b/client/src/cmdhfjooki.c
index a789fb762..0c89406ba 100644
--- a/client/src/cmdhfjooki.c
+++ b/client/src/cmdhfjooki.c
@@ -135,7 +135,7 @@ static int jooki_encode(uint8_t *iv, uint8_t tid, uint8_t fid, uint8_t *uid, uin
return PM3_EINVARG;
}
- uint8_t d[JOOKI_PLAIN_LEN] = {iv[0], iv[1], iv[2], tid, fid, uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6]};
+ const uint8_t d[JOOKI_PLAIN_LEN] = {iv[0], iv[1], iv[2], tid, fid, uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6]};
uint8_t enc[JOOKI_PLAIN_LEN] = {0};
for (uint8_t i = 0; i < JOOKI_PLAIN_LEN; i++) {
diff --git a/client/src/cmdhfksx6924.c b/client/src/cmdhfksx6924.c
index 05a838bb0..9014ca519 100644
--- a/client/src/cmdhfksx6924.c
+++ b/client/src/cmdhfksx6924.c
@@ -111,7 +111,7 @@ static int CmdHFKSX6924Info(const char *Cmd) {
uint16_t sw = 0;
int res = KSX6924Select(true, true, buf, sizeof(buf), &len, &sw);
- if (res) {
+ if (res || (len == 0)) {
if (keep == false) {
DropField();
}
@@ -134,6 +134,7 @@ static int CmdHFKSX6924Info(const char *Cmd) {
// FCI Response is a BER-TLV, we are interested in tag 6F,B0 only.
const uint8_t *p = buf;
struct tlv fci_tag;
+ memset(&fci_tag, 0, sizeof(fci_tag));
while (len > 0) {
memset(&fci_tag, 0, sizeof(fci_tag));
@@ -244,7 +245,7 @@ static int CmdHFKSX6924Initialize(const char *Cmd) {
arg_param_begin,
arg_lit0("k", "keep", "keep field ON for next command"),
arg_lit0("a", "apdu", "show APDU reqests and responses"),
- arg_strx1(NULL, NULL, "", NULL),
+ arg_str1(NULL, NULL, "", NULL),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -297,7 +298,7 @@ static int CmdHFKSX6924PRec(const char *Cmd) {
arg_param_begin,
arg_lit0("k", "keep", "keep field ON for next command"),
arg_lit0("a", "apdu", "show APDU reqests and responses"),
- arg_strx1(NULL, NULL, "", NULL),
+ arg_str1(NULL, NULL, "", NULL),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c
index 4a95bd683..d96fa320f 100644
--- a/client/src/cmdhflegic.c
+++ b/client/src/cmdhflegic.c
@@ -762,7 +762,7 @@ static int CmdLegicDump(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str0("f", "file", "", "specify a filename for dump file"),
+ arg_str0("f", "file", "", "Dump filename"),
arg_lit0(NULL, "de", "deobfuscate dump data (xor with MCC)"),
arg_param_end
};
@@ -859,7 +859,7 @@ static int CmdLegicRestore(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str1("f", "file", "", "specify a filename to restore"),
+ arg_str1("f", "file", "", "Filename to restore"),
arg_lit0(NULL, "ob", "obfuscate dump data (xor with MCC)"),
arg_param_end
};
@@ -963,7 +963,7 @@ static int CmdLegicELoad(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str1("f", "file", "", "Specify a filename to restore"),
+ arg_str1("f", "file", "", "Filename to restore"),
arg_int0("t", "type", "", "Tag type to simulate."),
arg_lit0(NULL, "obfuscate", "Obfuscate dump data (xor with MCC)"),
arg_param_end
@@ -1032,7 +1032,7 @@ static int CmdLegicESave(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str0("f", "file", "", "Specify a filename to save"),
+ arg_str0("f", "file", "", "Filename to save"),
arg_int0("t", "type", "", "Tag type"),
arg_lit0(NULL, "deobfuscate", "De-obfuscate dump data (xor with MCC)"),
arg_param_end
diff --git a/client/src/cmdhflto.c b/client/src/cmdhflto.c
index 727da2548..71eea185b 100644
--- a/client/src/cmdhflto.c
+++ b/client/src/cmdhflto.c
@@ -729,7 +729,7 @@ static int CmdHfLTRestore(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str1("f", "file", "", "specify a filename for dumpfile"),
+ arg_str1("f", "file", "", "specify a filename for dumpfile"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c
index 63e5665f7..eb4097ee7 100644
--- a/client/src/cmdhfmf.c
+++ b/client/src/cmdhfmf.c
@@ -444,7 +444,7 @@ static int CmdHF14AMfRdBl(const char *Cmd) {
CLIParserInit(&ctx, "hf mf rdbl",
"Read MIFARE Classic block",
"hf mf rdbl --blk 0 -k FFFFFFFFFFFF\n"
- "hf mf rdbl -b 3 -v -> get block 3, decode sector trailer\n"
+ "hf mf rdbl --blk 3 -v -> get block 3, decode sector trailer\n"
);
void *argtable[] = {
arg_param_begin,
@@ -6133,11 +6133,11 @@ static int CmdHF14AMfView(const char *Cmd) {
return PM3_SUCCESS;
}
-static int CmdHF14AGen3View(const char *Cmd) {
+static int CmdHF14AGen4View(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf gview",
- "View `magic gen3 gtu` card memory",
+ "View `magic gen4 gtu` card memory",
"hf mf gview\n"
"hf mf gview --4k"
);
@@ -6147,6 +6147,7 @@ static int CmdHF14AGen3View(const char *Cmd) {
arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
+ arg_str0("p", "pwd", "", "password 4bytes"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -6154,9 +6155,18 @@ static int CmdHF14AGen3View(const char *Cmd) {
bool m1 = arg_get_lit(ctx, 2);
bool m2 = arg_get_lit(ctx, 3);
bool m4 = arg_get_lit(ctx, 4);
+
+ int pwd_len = 0;
+ uint8_t pwd[4] = {0};
+ CLIGetHexWithReturn(ctx, 5, pwd, &pwd_len);
CLIParserFree(ctx);
// validations
+ if (pwd_len != 4 && pwd_len != 0) {
+ PrintAndLogEx(FAILED, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len);
+ return PM3_EINVARG;
+ }
+
if ((m0 + m1 + m2 + m4) > 1) {
PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
return PM3_EINVARG;
@@ -6183,7 +6193,7 @@ static int CmdHF14AGen3View(const char *Cmd) {
PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
return PM3_EINVARG;
}
- PrintAndLogEx(SUCCESS, "View magic gen3 GTU MIFARE Classic " _GREEN_("%s"), s);
+ PrintAndLogEx(SUCCESS, "View magic gen4 GTU MIFARE Classic " _GREEN_("%s"), s);
PrintAndLogEx(INFO, "." NOLF);
// Select card to get UID/UIDLEN information
@@ -6221,7 +6231,7 @@ static int CmdHF14AGen3View(const char *Cmd) {
for (uint16_t i = 0; i < block_cnt; i++) {
- if (mfG3GetBlock(i, dump + (i * MFBLOCK_SIZE)) != PM3_SUCCESS) {
+ if (mfG4GetBlock(pwd, i, dump + (i * MFBLOCK_SIZE)) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Can't get magic card block: %u", i);
PrintAndLogEx(HINT, "Verify your card size, and try again or try another tag position");
free(dump);
@@ -6290,8 +6300,8 @@ static command_t CommandTable[] = {
{"gen3uid", CmdHf14AGen3UID, IfPm3Iso14443a, "Set UID without changing manufacturer block"},
{"gen3blk", CmdHf14AGen3Block, IfPm3Iso14443a, "Overwrite manufacturer block"},
{"gen3freeze", CmdHf14AGen3Freeze, IfPm3Iso14443a, "Perma lock UID changes. irreversible"},
- {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen3 GTU") " -----------------------"},
- {"gview", CmdHF14AGen3View, IfPm3Iso14443a, "View card"},
+ {"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("magic gen4 GTU") " --------------------------"},
+ {"gview", CmdHF14AGen4View, IfPm3Iso14443a, "View card"},
// {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("i") " -----------------------"},
// {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
{NULL, NULL, NULL, NULL}
diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c
index 1e5297e15..428364608 100644
--- a/client/src/cmdhfmfdes.c
+++ b/client/src/cmdhfmfdes.c
@@ -1056,7 +1056,7 @@ static int CmdHF14aDesChk(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0(NULL, "aid", "", "Use specific AID (3 hex bytes, big endian)"),
+ arg_str0(NULL, "aid", "", "Use specific AID (3 hex bytes, big endian)"),
arg_str0("k", "key", "", "Key for checking (HEX 16 bytes)"),
arg_str0("d", "dict", "", "File with keys dictionary"),
arg_lit0(NULL, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"),
@@ -1914,8 +1914,8 @@ static int CmdHF14ADesBruteApps(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0("s", "start", "", "Starting App ID as hex bytes (3 bytes, big endian)"),
- arg_strx0("e", "end", "", "Last App ID as hex bytes (3 bytes, big endian)"),
+ arg_str0("s", "start", "", "Starting App ID as hex bytes (3 bytes, big endian)"),
+ arg_str0("e", "end", "", "Last App ID as hex bytes (3 bytes, big endian)"),
arg_int0("i", "step", "", "Increment step when bruteforcing"),
arg_lit0("m", "mad", "Only bruteforce the MAD range"),
arg_param_end
diff --git a/client/src/cmdhfmfp.c b/client/src/cmdhfmfp.c
index 89584260a..339d8fae4 100644
--- a/client/src/cmdhfmfp.c
+++ b/client/src/cmdhfmfp.c
@@ -456,7 +456,7 @@ static int CmdHFMFPWritePerso(const char *Cmd) {
arg_param_begin,
arg_lit0("v", "verbose", "show internal data."),
arg_str1(NULL, "ki", "", " key number, 2 hex bytes"),
- arg_strx0(NULL, "key", "", " key, 16 hex bytes"),
+ arg_str0(NULL, "key", "", " key, 16 hex bytes"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -521,7 +521,7 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_litn("v", "verbose", 0, 2, "show internal data."),
- arg_strx0("k", "key", "", "key, 16 hex bytes"),
+ arg_str0("k", "key", "", "key, 16 hex bytes"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c
index 9cf622f6b..722f02f2b 100644
--- a/client/src/cmdhfmfu.c
+++ b/client/src/cmdhfmfu.c
@@ -1772,6 +1772,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) {
arg_lit0("l", NULL, "swap entered key's endianness"),
arg_int1("b", "block", "", "block number to write"),
arg_str1("d", "data", "", "block data (4 or 16 hex bytes, 16 hex bytes will do a compatibility write)"),
+ arg_lit0(NULL, "force", "force operation even if address is out of range"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@@ -1786,6 +1787,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) {
int datalen = 0;
uint8_t data[16] = {0x00};
CLIGetHexWithReturn(ctx, 4, data, &datalen);
+ bool force = arg_get_lit(ctx, 5);
CLIParserFree(ctx);
bool has_auth_key = false;
@@ -1823,7 +1825,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) {
break;
}
}
- if (blockno > maxblockno) {
+ if ((blockno > maxblockno) && (!force)) {
PrintAndLogEx(WARNING, "block number too large. Max block is %u/0x%02X \n", maxblockno, maxblockno);
return PM3_EINVARG;
}
@@ -1901,6 +1903,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) {
arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
arg_lit0("l", NULL, "swap entered key's endianness"),
arg_int1("b", "block", "", "block number to read"),
+ arg_lit0(NULL, "force", "force operation even if address is out of range"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@@ -1910,6 +1913,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) {
CLIGetHexWithReturn(ctx, 1, authenticationkey, &ak_len);
bool swap_endian = arg_get_lit(ctx, 2);
int blockno = arg_get_int_def(ctx, 3, -1);
+ bool force = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
bool has_auth_key = false;
@@ -1942,7 +1946,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) {
break;
}
}
- if (blockno > maxblockno) {
+ if ((blockno > maxblockno) && (!force)) {
PrintAndLogEx(WARNING, "block number to large. Max block is %u/0x%02X \n", maxblockno, maxblockno);
return PM3_EINVARG;
}
diff --git a/client/src/cmdhfwaveshare.c b/client/src/cmdhfwaveshare.c
index e99830d49..01dc7d63c 100644
--- a/client/src/cmdhfwaveshare.c
+++ b/client/src/cmdhfwaveshare.c
@@ -179,7 +179,7 @@ static void dither_chan_inplace(int16_t *chan, uint16_t width, uint16_t height)
int16_t newp = oldp > 127 ? 255 : 0;
chan[X + Y * width] = newp;
int16_t err = oldp - newp;
- float m[] = {7, 3, 5, 1};
+ const float m[] = {7, 3, 5, 1};
if (X < width - 1) {
chan[X + 1 + Y * width] = chan[X + 1 + Y * width] + m[0] / 16 * err;
}
@@ -239,7 +239,7 @@ static void dither_rgb_inplace(int16_t *chanR, int16_t *chanG, int16_t *chanB, u
int16_t errR = oldR - newR;
int16_t errG = oldG - newG;
int16_t errB = oldB - newB;
- float m[] = {7, 3, 5, 1};
+ const float m[] = {7, 3, 5, 1};
if (Y % 2) {
if (XX > 0) {
chanR[XX - 1 + Y * width] = (chanR[XX - 1 + Y * width] + m[0] / 16 * errR);
@@ -593,7 +593,7 @@ static int start_drawing_1in54B(uint8_t model_nr, uint8_t *black, uint8_t *red)
uint8_t step_4[2] = {0xcd, 0x04};
uint8_t step_6[2] = {0xcd, 0x06};
uint8_t rx[20] = {0};
- uint16_t actrxlen[20], i = 0, progress = 0;
+ uint16_t actrxlen[20], i, progress;
if (model_nr == M1in54B) {
step_5[2] = 100;
@@ -616,6 +616,7 @@ static int start_drawing_1in54B(uint8_t model_nr, uint8_t *black, uint8_t *red)
if (ret != PM3_SUCCESS) {
return ret;
}
+
PrintAndLogEx(DEBUG, "1.54_Step7: e-paper config2 (red)");
if (model_nr == M1in54B) { //1.54inch B Keychain
for (i = 0; i < 50; i++) {
@@ -635,12 +636,13 @@ static int start_drawing_1in54B(uint8_t model_nr, uint8_t *black, uint8_t *red)
if (ret != PM3_SUCCESS) {
return ret;
}
+
PrintAndLogEx(DEBUG, "1.54_Step9");
return PM3_SUCCESS;
}
static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
- uint8_t progress = 0;
+ uint8_t progress;
uint8_t step0[2] = {0xcd, 0x0d};
uint8_t step1[3] = {0xcd, 0x00, 10}; // select e-paper type and reset e-paper
// 4 :2.13inch e-Paper
@@ -667,14 +669,12 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
// uint8_t step13[2]={0xcd,0x0b}; // Judge whether the power supply is turned off successfully
// uint8_t step14[2]={0xcd,0x0c}; // The end of the transmission
uint8_t rx[20];
- uint16_t actrxlen[20], i = 0;
-
-
+ uint16_t actrxlen[20], i;
clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
PacketResponseNG resp;
- if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
+ if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
PrintAndLogEx(ERR, "No tag found");
DropField();
return PM3_ETIMEOUT;
@@ -711,40 +711,41 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
return PM3_ESOFT;
}
PrintAndLogEx(DEBUG, "model_nr = %d", model_nr);
- int ret;
+
PrintAndLogEx(DEBUG, "Step0");
- ret = transceive_blocking(step0, 2, rx, 20, actrxlen, true); //cd 0d
+ int ret = transceive_blocking(step0, 2, rx, 20, actrxlen, true); //cd 0d
if (ret != PM3_SUCCESS) {
return ret;
}
+
PrintAndLogEx(DEBUG, "Step1: e-paper config");
- //step1[2] screen model
- //step8[2] nr of bytes sent at once
- //step13[2] nr of bytes sent for the second time
+ // step1[2] screen model
+ // step8[2] nr of bytes sent at once
+ // step13[2] nr of bytes sent for the second time
// generally, step8 sends a black image, step13 sends a red image
- if (model_nr == M2in13) { //2.13inch
+ if (model_nr == M2in13) { // 2.13inch
step1[2] = EPD_2IN13V2;
step8[2] = 16;
step13[2] = 0;
- } else if (model_nr == M2in9) { //2.9inch
+ } else if (model_nr == M2in9) { // 2.9inch
step1[2] = EPD_2IN9;
step8[2] = 16;
step13[2] = 0;
- } else if (model_nr == M4in2) { //4.2inch
+ } else if (model_nr == M4in2) { // 4.2inch
step1[2] = EPD_4IN2;
step8[2] = 100;
step13[2] = 0;
- } else if (model_nr == M7in5) { //7.5inch
+ } else if (model_nr == M7in5) { // 7.5inch
step1[2] = EPD_7IN5V2;
step8[2] = 120;
step13[2] = 0;
- } else if (model_nr == M2in7) { //2.7inch
+ } else if (model_nr == M2in7) { // 2.7inch
step1[2] = EPD_2IN7;
step8[2] = 121;
// Send blank data for the first time, and send other data to 0xff without processing the bottom layer
step13[2] = 121;
- //Sending the second data is the real image data. If the previous 0xff is not sent, the last output image is abnormally black
- } else if (model_nr == M2in13B) { //2.13inch B
+ // Sending the second data is the real image data. If the previous 0xff is not sent, the last output image is abnormally black
+ } else if (model_nr == M2in13B) { // 2.13inch B
step1[2] = EPD_2IN13BC;
step8[2] = 106;
step13[2] = 106;
@@ -755,31 +756,35 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
}
if (model_nr == M1in54B) {
- ret = transceive_blocking(step1, 2, rx, 20, actrxlen, true); //cd 00
+ ret = transceive_blocking(step1, 2, rx, 20, actrxlen, true); // cd 00
} else {
ret = transceive_blocking(step1, 3, rx, 20, actrxlen, true);
}
if (ret != PM3_SUCCESS) {
return ret;
}
+
msleep(100);
PrintAndLogEx(DEBUG, "Step2: e-paper normal mode type");
- ret = transceive_blocking(step2, 2, rx, 20, actrxlen, true); //cd 01
+ ret = transceive_blocking(step2, 2, rx, 20, actrxlen, true); // cd 01
if (ret != PM3_SUCCESS) {
return ret;
}
+
msleep(100);
PrintAndLogEx(DEBUG, "Step3: e-paper config1");
- ret = transceive_blocking(step3, 2, rx, 20, actrxlen, true); //cd 02
+ ret = transceive_blocking(step3, 2, rx, 20, actrxlen, true); // cd 02
if (ret != PM3_SUCCESS) {
return ret;
}
+
msleep(200);
PrintAndLogEx(DEBUG, "Step4: e-paper power on");
- ret = transceive_blocking(step4, 2, rx, 20, actrxlen, true); //cd 03
+ ret = transceive_blocking(step4, 2, rx, 20, actrxlen, true); // cd 03
if (ret != PM3_SUCCESS) {
return ret;
}
+
if (model_nr == M1in54B) {
// 1.54B Keychain handler
PrintAndLogEx(DEBUG, "Start_Drawing_1in54B");
@@ -787,27 +792,27 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
if (ret != PM3_SUCCESS) {
return ret;
}
- //1.54B Data transfer is complete and wait for refresh
+ // 1.54B Data transfer is complete and wait for refresh
} else {
PrintAndLogEx(DEBUG, "Step5: e-paper config2");
- ret = transceive_blocking(step5, 2, rx, 20, actrxlen, true); //cd 05
+ ret = transceive_blocking(step5, 2, rx, 20, actrxlen, true); // cd 05
if (ret != PM3_SUCCESS) {
return ret;
}
msleep(100);
PrintAndLogEx(DEBUG, "Step6: EDP load to main") ;
- ret = transceive_blocking(step6, 2, rx, 20, actrxlen, true); //cd 06
+ ret = transceive_blocking(step6, 2, rx, 20, actrxlen, true); // cd 06
if (ret != PM3_SUCCESS) {
return ret;
}
msleep(100);
PrintAndLogEx(DEBUG, "Step7: Data preparation");
- ret = transceive_blocking(step7, 2, rx, 20, actrxlen, true); //cd 07
+ ret = transceive_blocking(step7, 2, rx, 20, actrxlen, true); // cd 07
if (ret != PM3_SUCCESS) {
return ret;
}
PrintAndLogEx(DEBUG, "Step8: Start data transfer");
- if (model_nr == M2in13) { //2.13inch
+ if (model_nr == M2in13) { // 2.13inch
for (i = 0; i < 250; i++) {
read_black(i, step8, model_nr, black);
ret = transceive_blocking(step8, 19, rx, 20, actrxlen, true); // cd 08
@@ -939,6 +944,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
} else if (model_nr == M7in5HD) {
msleep(1000);
}
+
uint8_t fail_num = 0;
while (1) {
if (model_nr == M1in54B) {
@@ -1006,7 +1012,7 @@ static int CmdHF14AWSLoadBmp(const char *Cmd) {
arg_param_begin,
arg_int1("m", NULL, "", modeldesc),
arg_lit0("s", "save", "save dithered version in filename-[n].bmp, only for RGB BMP"),
- arg_str1("f", "file", "", "filename[.bmp] to upload to tag"),
+ arg_str1("f", "file", "", "specify filename[.bmp] to upload to tag"),
arg_param_end
};
diff --git a/client/src/cmdlfdestron.c b/client/src/cmdlfdestron.c
index 7c8cf2760..a510089aa 100644
--- a/client/src/cmdlfdestron.c
+++ b/client/src/cmdlfdestron.c
@@ -136,7 +136,7 @@ static int CmdDestronClone(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx1("u", "uid", "", "5 bytes max"),
+ arg_str1("u", "uid", "", "5 bytes max"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end
diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c
index 9427a5148..f70dc1de0 100644
--- a/client/src/cmdlfem4x50.c
+++ b/client/src/cmdlfem4x50.c
@@ -200,7 +200,7 @@ int CmdEM4x50ELoad(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str1("f", "filename", "", "dump filename (bin/eml/json)"),
+ arg_str1("f", "file", "", "dump filename (bin/eml/json)"),
arg_param_end
};
@@ -237,7 +237,7 @@ int CmdEM4x50ESave(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str0("f", "file", "", "save filename"),
+ arg_str0("f", "file", "", "specifiy filename"),
arg_param_end
};
@@ -441,7 +441,7 @@ int CmdEM4x50Chk(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str0("f", "file", "", "dictionary filename"),
+ arg_str0("f", "file", "", "specify dictionary filename"),
arg_param_end
};
@@ -749,7 +749,7 @@ int CmdEM4x50Dump(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str0("f", "file", "", "dump filename (bin/eml/json)"),
+ arg_str0("f", "file", "", "specify dump filename (bin/eml/json)"),
arg_str0("p", "pwd", "", "password, 4 hex bytes, lsb"),
arg_param_end
};
@@ -1060,7 +1060,7 @@ int CmdEM4x50Restore(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("u", "uid", "", "uid, 4 hex bytes, msb"),
- arg_str0("f", "file", "", "dump filename (bin/eml/json)"),
+ arg_str0("f", "file", "", "specify dump filename (bin/eml/json)"),
arg_str0("p", "pwd", "", "password, 4 hex bytes, lsb"),
arg_param_end
};
diff --git a/client/src/cmdlfguard.c b/client/src/cmdlfguard.c
index df2f430a5..4a31e8f19 100644
--- a/client/src/cmdlfguard.c
+++ b/client/src/cmdlfguard.c
@@ -27,6 +27,64 @@
static int CmdHelp(const char *Cmd);
+static int demod_guard_raw(uint8_t *raw, uint8_t rlen) {
+
+ if (rlen != 12) {
+ return PM3_EINVARG;
+ }
+
+ uint8_t bits[96] = {0x00};
+ bytes_to_bytebits(raw, rlen, bits);
+
+ // start after 6 bit preamble
+ size_t start_idx = 6;
+ uint8_t bits_no_spacer[90];
+ memcpy(bits_no_spacer, bits + start_idx, 90);
+
+ // remove the 18 (90/5=18) parity bits (down to 72 bits (96-6-18=72))
+ size_t len = removeParity(bits_no_spacer, 0, 5, 3, 90); // source, startloc, paritylen, ptype, length_to_run
+ if (len != 72) {
+ PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII spacer removal did not produce 72 bits: %zu, start: %zu", len, start_idx);
+ return PM3_ESOFT;
+ }
+
+ uint8_t plain[8] = {0x00};
+
+ // get key and then get all 8 bytes of payload decoded
+ uint8_t xorKey = (uint8_t)bytebits_to_byteLSBF(bits_no_spacer, 8);
+ for (size_t idx = 0; idx < 8; idx++) {
+ plain[idx] = ((uint8_t)bytebits_to_byteLSBF(bits_no_spacer + 8 + (idx * 8), 8)) ^ xorKey;
+ PrintAndLogEx(DEBUG, "DEBUG: gProxII byte %zu after xor: %02x", idx, plain[idx]);
+ }
+
+ // plain contains 8 Bytes (64 bits) of decrypted raw tag data
+ uint8_t fmtlen = plain[0] >> 2;
+ uint32_t FC = 0;
+ uint32_t Card = 0;
+
+ bool unknown = false;
+ switch (fmtlen) {
+ case 36:
+ FC = ((plain[3] & 0x7F) << 7) | (plain[4] >> 1);
+ Card = ((plain[4] & 1) << 19) | (plain[5] << 11) | (plain[6] << 3) | ((plain[7] & 0xE0) >> 5);
+ break;
+ case 26:
+ FC = ((plain[3] & 0x7F) << 1) | (plain[4] >> 7);
+ Card = ((plain[4] & 0x7F) << 9) | (plain[5] << 1) | (plain[6] >> 7);
+ break;
+ default :
+ unknown = true;
+ break;
+ }
+
+ if (unknown)
+ PrintAndLogEx(SUCCESS, "G-Prox-II - Unknown len: " _GREEN_("%u") ", Raw: %s", fmtlen, sprint_hex_inrow(raw, rlen));
+ else
+ PrintAndLogEx(SUCCESS, "G-Prox-II - len: " _GREEN_("%u")" FC: " _GREEN_("%u") " Card: " _GREEN_("%u") ", Raw: %s", fmtlen, FC, Card, sprint_hex_inrow(raw, rlen));
+
+ return PM3_SUCCESS;
+}
+
// attempts to demodulate and identify a G_Prox_II verex/chubb card
// WARNING: if it fails during some points it will destroy the g_DemodBuffer data
// but will leave the g_GraphBuffer intact.
@@ -59,7 +117,6 @@ int demodGuard(bool verbose) {
}
// got a good demod of 96 bits
-
uint8_t plain[8] = {0x00};
uint8_t xorKey = 0;
size_t startIdx = preambleIndex + 6; //start after 6 bit preamble
@@ -119,16 +176,32 @@ static int CmdGuardDemod(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf gproxii demod",
"Try to find Guardall Prox-II preamble, if found decode / descramble data",
- "lf gproxii demod"
+ "lf gproxii demod -> use graphbuffer to decode\n"
+ "lf gproxii demod --raw fb8ee718ee3b8cc785c11b92 ->"
);
void *argtable[] = {
arg_param_begin,
+ arg_str0("r", "raw", "", "raw bytes"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
+
+ int raw_len = 0;
+ uint8_t raw[12] = {0};
+ CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
+
CLIParserFree(ctx);
- return demodGuard(true);
+
+ if (raw_len != 12 && raw_len != 0) {
+ PrintAndLogEx(FAILED, "Must specify 12 bytes, got " _YELLOW_("%u"), raw_len);
+ return PM3_EINVARG;
+ }
+
+ if (raw_len == 0)
+ return demodGuard(true);
+ else
+ return demod_guard_raw(raw, raw_len);
}
static int CmdGuardReader(const char *Cmd) {
diff --git a/client/src/cmdlfhid.c b/client/src/cmdlfhid.c
index 984dc482d..103dd9f87 100644
--- a/client/src/cmdlfhid.c
+++ b/client/src/cmdlfhid.c
@@ -246,7 +246,7 @@ static int CmdHIDSim(const char *Cmd) {
arg_u64_0(NULL, "cn", "", "card number"),
arg_u64_0("i", NULL, "", "issue level"),
arg_u64_0("o", "oem", "", "OEM code"),
- arg_strx0("r", "raw", "", "raw bytes"),
+ arg_str0("r", "raw", "", "raw bytes"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@@ -330,7 +330,7 @@ static int CmdHIDClone(const char *Cmd) {
arg_u64_0(NULL, "cn", "", "card number"),
arg_int0("i", NULL, "", "issue level"),
arg_int0("o", "oem", "", "OEM code"),
- arg_strx0("r", "raw", "", "raw bytes"),
+ arg_str0("r", "raw", "", "raw bytes"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_str0(NULL, "bin", "", "Binary string i.e 0001001001"),
diff --git a/client/src/cmdlfhitag.c b/client/src/cmdlfhitag.c
index 02d84321a..74534b915 100644
--- a/client/src/cmdlfhitag.c
+++ b/client/src/cmdlfhitag.c
@@ -17,6 +17,7 @@
#include "fileutils.h" // savefile
#include "protocols.h" // defines
#include "cliparser.h"
+#include "crc.h"
static int CmdHelp(const char *Cmd);
@@ -214,7 +215,7 @@ static int CmdLFHitagEload(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str1("f", "file", "", "filename of dump"),
+ arg_str1("f", "file", "", "Specfiy dump filename"),
arg_lit0("1", NULL, "Card type Hitag1"),
arg_lit0("2", NULL, "Card type Hitag2"),
arg_lit0("s", NULL, "Card type HitagS"),
@@ -575,8 +576,8 @@ static int CmdLFHitagReader(const char *Cmd) {
return PM3_EINVARG;
}
- if (nalen != 0 && nalen != 6) {
- PrintAndLogEx(WARNING, "Wrong NR/AR len expected 0 or 6, got %d", nalen);
+ if (nalen != 0 && nalen != 8) {
+ PrintAndLogEx(WARNING, "Wrong NR/AR len expected 0 or 8, got %d", nalen);
return PM3_EINVARG;
}
@@ -628,7 +629,6 @@ static int CmdLFHitagReader(const char *Cmd) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
-
if (resp.oldarg[0] == false) {
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed");
return PM3_ESOFT;
@@ -657,7 +657,7 @@ static int CmdLFHitagCheckChallenges(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str0("f", "file", "", "filename to load ( w/o ext )"),
+ arg_str1("f", "file", "", "filename to load ( w/o ext )"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -670,22 +670,18 @@ static int CmdLFHitagCheckChallenges(const char *Cmd) {
clearCommandBuffer();
- if (fnlen > 0) {
- uint8_t *data = NULL;
- size_t datalen = 0;
- int res = loadFile_safe(filename, ".cc", (void **)&data, &datalen);
- if (res == PM3_SUCCESS) {
- if (datalen == (8 * 60)) {
- SendCommandOLD(CMD_LF_HITAGS_TEST_TRACES, 1, 0, 0, data, datalen);
- } else {
- PrintAndLogEx(ERR, "Error, file length mismatch. Expected %d, got %zu", 8 * 60, datalen);
- }
+ uint8_t *data = NULL;
+ size_t datalen = 0;
+ int res = loadFile_safe(filename, ".cc", (void **)&data, &datalen);
+ if (res == PM3_SUCCESS) {
+ if (datalen % 8 == 0) {
+ SendCommandMIX(CMD_LF_HITAGS_TEST_TRACES, datalen, 0, 0, data, datalen);
+ } else {
+ PrintAndLogEx(ERR, "Error, file length mismatch. Expected multiple of 8, got %zu", datalen);
}
- if (data) {
- free(data);
- }
- } else {
- SendCommandMIX(CMD_LF_HITAGS_TEST_TRACES, 0, 0, 0, NULL, 0);
+ }
+ if (data) {
+ free(data);
}
return PM3_SUCCESS;
@@ -831,7 +827,7 @@ static int CmdLFHitag2Dump(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str0("f", "file", "", "file name"),
+ arg_str0("f", "file", "", "specify file name"),
arg_str0("k", "key", "", "key, 4 or 6 hex bytes"),
arg_str0(NULL, "nrar", "", "nonce / answer reader, 8 hex bytes"),
arg_param_end
@@ -970,3 +966,8 @@ int CmdLFHitag(const char *Cmd) {
int readHitagUid(void) {
return (CmdLFHitagReader("--26") == PM3_SUCCESS);
}
+
+uint8_t hitag1_CRC_check(uint8_t *d, uint32_t nbit) {
+ if (nbit < 9) return 2;
+ return (CRC8Hitag1Bits(d, nbit) == 0);
+}
diff --git a/client/src/cmdlfhitag.h b/client/src/cmdlfhitag.h
index 817cb16f3..7f92285e8 100644
--- a/client/src/cmdlfhitag.h
+++ b/client/src/cmdlfhitag.h
@@ -19,4 +19,5 @@ int readHitagUid(void);
void annotateHitag1(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response);
void annotateHitag2(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response);
void annotateHitagS(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response);
+uint8_t hitag1_CRC_check(uint8_t *d, uint32_t nbit);
#endif
diff --git a/client/src/cmdlfidteck.c b/client/src/cmdlfidteck.c
index 81bf270ad..d9830c282 100644
--- a/client/src/cmdlfidteck.c
+++ b/client/src/cmdlfidteck.c
@@ -112,7 +112,7 @@ static int CmdIdteckClone(const char *Cmd) {
);
void *argtable[] = {
arg_param_begin,
- arg_strx0("r", "raw", "", "raw bytes"),
+ arg_str1("r", "raw", "", "raw bytes"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end
@@ -178,7 +178,7 @@ static int CmdIdteckSim(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0("r", "raw", "", "raw bytes"),
+ arg_str1("r", "raw", "", "raw bytes"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
diff --git a/client/src/cmdlfindala.c b/client/src/cmdlfindala.c
index e18f34301..3ffed0453 100644
--- a/client/src/cmdlfindala.c
+++ b/client/src/cmdlfindala.c
@@ -542,7 +542,7 @@ static int CmdIndalaSim(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0("r", "raw", "", "raw bytes"),
+ arg_str0("r", "raw", "", "raw bytes"),
arg_int0(NULL, "heden", "", "Cardnumber for Heden 2L format"),
arg_param_end
};
@@ -639,7 +639,7 @@ static int CmdIndalaClone(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0("r", "raw", "", "raw bytes"),
+ arg_str0("r", "raw", "", "raw bytes"),
arg_int0(NULL, "heden", "", "Card number for Heden 2L format"),
arg_int0(NULL, "fc", "", "Facility code (26 bit H10301 format)"),
arg_int0(NULL, "cn", "", "Card number (26 bit H10301 format)"),
diff --git a/client/src/cmdlfkeri.c b/client/src/cmdlfkeri.c
index e4c16fe2a..ec57d5bf8 100644
--- a/client/src/cmdlfkeri.c
+++ b/client/src/cmdlfkeri.c
@@ -29,11 +29,11 @@ typedef enum {Scramble = 0, Descramble = 1} KeriMSScramble_t;
static int CmdKeriMSScramble(KeriMSScramble_t Action, uint32_t *FC, uint32_t *ID, uint32_t *CardID) {
// 255 = Not used/Unknown other values are the bit offset in the ID/FC values
- uint8_t CardToID [] = { 255, 255, 255, 255, 13, 12, 20, 5, 16, 6, 21, 17, 8, 255, 0, 7,
+ const uint8_t CardToID [] = { 255, 255, 255, 255, 13, 12, 20, 5, 16, 6, 21, 17, 8, 255, 0, 7,
10, 15, 255, 11, 4, 1, 255, 18, 255, 19, 2, 14, 3, 9, 255, 255
};
- uint8_t CardToFC [] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255,
+ const uint8_t CardToFC [] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255,
255, 255, 2, 255, 255, 255, 3, 255, 4, 255, 255, 255, 255, 255, 1, 255
};
diff --git a/client/src/cmdlfmotorola.c b/client/src/cmdlfmotorola.c
index dd00cfca6..b4d8fa1d2 100644
--- a/client/src/cmdlfmotorola.c
+++ b/client/src/cmdlfmotorola.c
@@ -193,7 +193,7 @@ static int CmdMotorolaClone(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx1("r", "raw", "", "raw hex bytes. 8 bytes"),
+ arg_str1("r", "raw", "", "raw hex bytes. 8 bytes"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end
diff --git a/client/src/cmdlfnexwatch.c b/client/src/cmdlfnexwatch.c
index 3bc05db7b..3b02b798e 100644
--- a/client/src/cmdlfnexwatch.c
+++ b/client/src/cmdlfnexwatch.c
@@ -72,7 +72,7 @@ static uint8_t nexwatch_checksum(uint8_t magic, uint32_t id, uint8_t parity) {
static int nexwatch_scamble(NexWatchScramble_t action, uint32_t *id, uint32_t *scambled) {
// 255 = Not used/Unknown other values are the bit offset in the ID/FC values
- uint8_t hex_2_id [] = {
+ const uint8_t hex_2_id [] = {
31, 27, 23, 19, 15, 11, 7, 3,
30, 26, 22, 18, 14, 10, 6, 2,
29, 25, 21, 17, 13, 9, 5, 1,
diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c
index e90ebed1b..029f595fb 100644
--- a/client/src/cmdlft55xx.c
+++ b/client/src/cmdlft55xx.c
@@ -1368,7 +1368,7 @@ static bool testQ5Modulation(uint8_t mode, uint8_t modread) {
}
static int convertQ5bitRate(uint8_t bitRateRead) {
- uint8_t expected[] = {8, 16, 32, 40, 50, 64, 100, 128};
+ const uint8_t expected[] = {8, 16, 32, 40, 50, 64, 100, 128};
for (int i = 0; i < 8; i++)
if (expected[i] == bitRateRead)
return i;
@@ -1425,7 +1425,7 @@ static bool testQ5(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk)
}
static bool testBitRate(uint8_t readRate, uint8_t clk) {
- uint8_t expected[] = {8, 16, 32, 40, 50, 64, 100, 128};
+ const uint8_t expected[] = {8, 16, 32, 40, 50, 64, 100, 128};
if (expected[readRate] == clk)
return true;
diff --git a/client/src/cmdlfviking.c b/client/src/cmdlfviking.c
index 72ae4df45..206e65c67 100644
--- a/client/src/cmdlfviking.c
+++ b/client/src/cmdlfviking.c
@@ -111,7 +111,7 @@ static int CmdVikingClone(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0(NULL, "cn", "", "8 digit hex viking card number"),
+ arg_str1(NULL, "cn", "", "8 digit hex viking card number"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end
@@ -185,7 +185,7 @@ static int CmdVikingSim(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0(NULL, "cn", "", "8 digit hex viking card number"),
+ arg_str1(NULL, "cn", "", "8 digit hex viking card number"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
diff --git a/client/src/cmdlfvisa2000.c b/client/src/cmdlfvisa2000.c
index 07bdcff30..2a829f2af 100644
--- a/client/src/cmdlfvisa2000.c
+++ b/client/src/cmdlfvisa2000.c
@@ -44,12 +44,11 @@ static uint8_t visa_chksum(uint32_t id) {
static uint8_t visa_parity(uint32_t id) {
// 4bit parity LUT
- uint8_t par_lut[] = {
- 0, 1, 1, 0
- , 1, 0, 0, 1
- , 1, 0, 0, 1
- , 0, 1, 1, 0
+ const uint8_t par_lut[] = {
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0
};
+
uint8_t par = 0;
par |= par_lut[(id >> 28) & 0xF ] << 7;
par |= par_lut[(id >> 24) & 0xF ] << 6;
diff --git a/client/src/cmdlfzx8211.c b/client/src/cmdlfzx8211.c
index c6c8d7337..893875e50 100644
--- a/client/src/cmdlfzx8211.c
+++ b/client/src/cmdlfzx8211.c
@@ -74,6 +74,17 @@ int demodzx(bool verbose) {
}
static int lf_Zx_read(void) {
+
+ PacketResponseNG resp;
+ clearCommandBuffer();
+
+ SendCommandNG(CMD_LF_ZX_READ, NULL, 0);
+
+ if (WaitForResponseTimeout(CMD_LF_ZX_READ, &resp, 1000) == false) {
+ PrintAndLogEx(ERR, "Error occurred, device did not respond during read operation.");
+ return PM3_ETIMEOUT;
+ }
+
return PM3_SUCCESS;
}
diff --git a/client/src/cmdnfc.c b/client/src/cmdnfc.c
index ca0f31a15..3606eb5b4 100644
--- a/client/src/cmdnfc.c
+++ b/client/src/cmdnfc.c
@@ -70,7 +70,7 @@ static int CmdNfcDecode(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0("d", "data", "", "NDEF data to decode"),
+ arg_str0("d", "data", "", "NDEF data to decode"),
arg_str0("f", "file", "", "file to load"),
arg_lit0("v", "verbose", "verbose mode"),
arg_param_end
diff --git a/client/src/cmdsmartcard.c b/client/src/cmdsmartcard.c
index f0764bbf5..7384d5a15 100644
--- a/client/src/cmdsmartcard.c
+++ b/client/src/cmdsmartcard.c
@@ -499,7 +499,7 @@ static int CmdSmartUpgrade(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_str1("f", "file", "", "firmware file name"),
+ arg_str1("f", "file", "", "Specify firmware file name"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c
index 1e49ca64c..068588d99 100644
--- a/client/src/cmdtrace.c
+++ b/client/src/cmdtrace.c
@@ -216,10 +216,11 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
case ISO_15693:
crcStatus = iso15693_CRC_check(frame, data_len);
break;
- case PROTO_CRYPTORF:
case PROTO_HITAG1:
- case PROTO_HITAG2:
case PROTO_HITAGS:
+ crcStatus = hitag1_CRC_check(frame, (data_len * 8) - ((8 - parityBytes[0]) % 8));
+ case PROTO_CRYPTORF:
+ case PROTO_HITAG2:
default:
break;
}
@@ -240,7 +241,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
sprintf(line[0], "");
}
}
-
+ uint8_t partialbytebuff = 0;
+ uint8_t offset = 0;
for (int j = 0; j < data_len && j / 18 < 18; j++) {
uint8_t parityBits = parityBytes[j >> 3];
if (protocol != LEGIC
@@ -270,6 +272,18 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
snprintf(line[j / 18] + ((j % 18) * 4), 120, "%02x! ", frame[j]);
}
+ } else if (((protocol == PROTO_HITAG1) || (protocol == PROTO_HITAG2) || (protocol == PROTO_HITAGS)) && (parityBytes[0] > 0)) {
+ // handle partial bytes
+ uint8_t nbits = parityBytes[0];
+ if (j == 0) {
+ partialbytebuff = frame[0] << nbits;
+ snprintf(line[0], 120, "%02x(%i) ", frame[0] >> (8 - nbits), nbits);
+ offset = 2;
+ } else {
+ uint8_t byte = partialbytebuff | (frame[j] >> (8 - nbits));
+ partialbytebuff = frame[j] << nbits;
+ snprintf(line[j / 18] + ((j % 18) * 4) + offset, 120, "%02x ", byte);
+ }
} else {
snprintf(line[j / 18] + ((j % 18) * 4), 120, "%02x ", frame[j]);
}
@@ -278,11 +292,20 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
if (markCRCBytes) {
//CRC-command
- if (crcStatus == 0 || crcStatus == 1) {
- char *pos1 = line[(data_len - 2) / 18] + (((data_len - 2) % 18) * 4) - 1;
+ if (((protocol == PROTO_HITAG1) || (protocol == PROTO_HITAGS)) && (data_len > 1)) {
+ // Note that UID REQUEST response has no CRC, but we don't know
+ // if the response we see is a UID
+ char *pos1 = line[(data_len - 1) / 18] + (((data_len - 1) % 18) * 4) + offset - 1;
(*pos1) = '[';
- char *pos2 = line[(data_len) / 18] + (((data_len) % 18) * 4) - 1;
+ char *pos2 = line[(data_len) / 18] + (((data_len) % 18) * 4) + offset - 2;
sprintf(pos2, "%c", ']');
+ } else {
+ if (crcStatus == 0 || crcStatus == 1) {
+ char *pos1 = line[(data_len - 2) / 18] + (((data_len - 2) % 18) * 4) - 1;
+ (*pos1) = '[';
+ char *pos2 = line[(data_len) / 18] + (((data_len) % 18) * 4) - 1;
+ sprintf(pos2, "%c", ']');
+ }
}
}
@@ -567,7 +590,7 @@ static int CmdTraceLoad(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0("f", "file", "", "trace file to load"),
+ arg_str1("f", "file", "", "Specify trace file to load"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@@ -606,7 +629,7 @@ static int CmdTraceSave(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0("f", "file", "", "trace file to save"),
+ arg_str1("f", "file", "", "Specify trace file to save"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@@ -654,7 +677,7 @@ int CmdTraceListAlias(const char *Cmd, const char *alias, const char *protocol)
arg_lit0("u", NULL, "display times in microseconds instead of clock cycles"),
arg_lit0("x", NULL, "show hexdump to convert to pcap(ng)\n"
" or to import into Wireshark using encapsulation type \"ISO 14443\""),
- arg_strx0(NULL, "dict", "", "use dictionary keys file"),
+ arg_str0(NULL, "dict", "", "use dictionary keys file"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -672,22 +695,22 @@ int CmdTraceList(const char *Cmd) {
"Annotate trace buffer with selected protocol data\n"
"You can load a trace from file (see `trace load -h`) or it be downloaded from device by default\n",
"trace list -t raw -> just show raw data without annotations\n"
- "trace list -t 14a -> interpret as " _YELLOW_("ISO14443-A") " communications\n"
- "trace list -t thinfilm -> interpret as " _YELLOW_("Thinfilm") " communications\n"
- "trace list -t topaz -> interpret as " _YELLOW_("Topaz") " communications\n"
- "trace list -t mf -> interpret as " _YELLOW_("MIFARE Classic") " communications and decrypt crypto1 stream\n"
- "trace list -t des -> interpret as " _YELLOW_("MIFARE DESFire") " communications\n"
- "trace list -t 14b -> interpret as " _YELLOW_("ISO14443-B") " communications\n"
- "trace list -t 7816 -> interpret as " _YELLOW_("ISO7816-4") " communications\n"
- "trace list -t 15 -> interpret as " _YELLOW_("ISO15693") " communications\n"
- "trace list -t iclass -> interpret as " _YELLOW_("iCLASS") " communications\n"
- "trace list -t legic -> interpret as " _YELLOW_("LEGIC") " communications\n"
- "trace list -t felica -> interpret as " _YELLOW_("ISO18092 / FeliCa") " communications\n"
- "trace list -t hitag1 -> interpret as " _YELLOW_("Hitag1") " communications\n"
- "trace list -t hitag2 -> interpret as " _YELLOW_("Hitag2") " communications\n"
- "trace list -t hitags -> interpret as " _YELLOW_("HitagS") " communications\n"
- "trace list -t lto -> interpret as " _YELLOW_("LTO-CM") " communications\n"
- "trace list -t cryptorf -> interpret as " _YELLOW_("CryptoRF") " communitcations\n"
+ "trace list -t 14a -> interpret as " _YELLOW_("ISO14443-A") "\n"
+ "trace list -t thinfilm -> interpret as " _YELLOW_("Thinfilm") "\n"
+ "trace list -t topaz -> interpret as " _YELLOW_("Topaz") "\n"
+ "trace list -t mf -> interpret as " _YELLOW_("MIFARE Classic") " and decrypt crypto1 stream\n"
+ "trace list -t des -> interpret as " _YELLOW_("MIFARE DESFire") "\n"
+ "trace list -t 14b -> interpret as " _YELLOW_("ISO14443-B") "\n"
+ "trace list -t 7816 -> interpret as " _YELLOW_("ISO7816-4") "\n"
+ "trace list -t 15 -> interpret as " _YELLOW_("ISO15693") "\n"
+ "trace list -t iclass -> interpret as " _YELLOW_("iCLASS") "\n"
+ "trace list -t legic -> interpret as " _YELLOW_("LEGIC") "\n"
+ "trace list -t felica -> interpret as " _YELLOW_("ISO18092 / FeliCa") "\n"
+ "trace list -t hitag1 -> interpret as " _YELLOW_("Hitag1") "\n"
+ "trace list -t hitag2 -> interpret as " _YELLOW_("Hitag2") "\n"
+ "trace list -t hitags -> interpret as " _YELLOW_("HitagS") "\n"
+ "trace list -t lto -> interpret as " _YELLOW_("LTO-CM") "\n"
+ "trace list -t cryptorf -> interpret as " _YELLOW_("CryptoRF") "\n\n"
"trace list -t mf --dict -> use dictionary keys file\n"
"trace list -t 14a -f -> show frame delay times\n"
"trace list -t 14a -1 -> use trace buffer "
@@ -702,11 +725,11 @@ int CmdTraceList(const char *Cmd) {
arg_lit0("u", NULL, "display times in microseconds instead of clock cycles"),
arg_lit0("x", NULL, "show hexdump to convert to pcap(ng)\n"
" or to import into Wireshark using encapsulation type \"ISO 14443\""),
- arg_strx0("t", "type", NULL, "protocol to annotate the trace"),
- arg_strx0(NULL, "dict", "", "use dictionary keys file"),
+ arg_str0("t", "type", NULL, "protocol to annotate the trace"),
+ arg_str0(NULL, "dict", "", "use dictionary keys file"),
arg_param_end
};
- CLIExecWithReturn(ctx, Cmd, argtable, false);
+ CLIExecWithReturn(ctx, Cmd, argtable, true);
bool use_buffer = arg_get_lit(ctx, 1);
bool show_wait_cycles = arg_get_lit(ctx, 2);
@@ -752,6 +775,11 @@ int CmdTraceList(const char *Cmd) {
else if (strcmp(type, "lto") == 0) protocol = LTO;
else if (strcmp(type, "cryptorf") == 0) protocol = PROTO_CRYPTORF;
else if (strcmp(type, "raw") == 0) protocol = -1;
+ else if (strcmp(type, "") == 0) protocol = -1;
+ else {
+ PrintAndLogEx(FAILED, "Unknown protocol \"%s\"", type);
+ return PM3_EINVARG;
+ }
if (use_buffer == false) {
download_trace();
diff --git a/client/src/cmdwiegand.c b/client/src/cmdwiegand.c
index e29db6a7b..3873a500a 100644
--- a/client/src/cmdwiegand.c
+++ b/client/src/cmdwiegand.c
@@ -113,7 +113,7 @@ int CmdWiegandDecode(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
- arg_strx0("r", "raw", "", "raw hex to be decoded"),
+ arg_str0("r", "raw", "", "raw hex to be decoded"),
arg_str0("b", "bin", "", "binary string to be decoded"),
arg_param_end
};
diff --git a/client/src/emv/cmdemv.c b/client/src/emv/cmdemv.c
index 8cd66dfaf..45d534981 100644
--- a/client/src/emv/cmdemv.c
+++ b/client/src/emv/cmdemv.c
@@ -81,10 +81,10 @@ static int CmdEMVSelect(const char *Cmd) {
arg_param_begin,
arg_lit0("sS", "select", "activate field and select card"),
arg_lit0("kK", "keep", "keep field for next command"),
- arg_lit0("aA", "apdu", "show APDU reqests and responses"),
+ arg_lit0("aA", "apdu", "show APDU requests and responses"),
arg_lit0("tT", "tlv", "TLV decode results"),
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
- arg_strx0(NULL, NULL, "", NULL),
+ arg_str1(NULL, NULL, "", "Applet AID"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -247,7 +247,7 @@ static int CmdEMVGPO(const char *Cmd) {
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
arg_lit0("tT", "tlv", "TLV decode results of selected applets"),
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
- arg_strx0(NULL, NULL, "", NULL),
+ arg_strx0(NULL, NULL, "", "PDOLdata/PDOL"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -354,7 +354,7 @@ static int CmdEMVReadRecord(const char *Cmd) {
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
arg_lit0("tT", "tlv", "TLV decode results of selected applets"),
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
- arg_strx1(NULL, NULL, "", NULL),
+ arg_strx1(NULL, NULL, "", "", NULL),
+ arg_strx1(NULL, NULL, "", "CDOLdata/CDOL"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@@ -590,7 +590,7 @@ static int CmdEMVInternalAuthenticate(const char *Cmd) {
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
arg_lit0("tT", "tlv", "TLV decode results of selected applets"),
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
- arg_strx1(NULL, NULL, "", NULL),
+ arg_strx1(NULL, NULL, "", "DDOLdata/DDOL"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@@ -1442,7 +1442,7 @@ static int CmdEMVScan(const char *Cmd) {
arg_lit0("gG", "acgpo", "VISA. generate AC from GPO."),
arg_lit0("mM", "merge", "Merge output file with card's data. (warning: the file may be corrupted!)"),
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
- arg_str1(NULL, NULL, "output.json", "JSON output file name"),
+ arg_str1(NULL, NULL, "", "JSON output filename"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
diff --git a/client/src/flash.c b/client/src/flash.c
index 869cd1630..c0ef1d25b 100644
--- a/client/src/flash.c
+++ b/client/src/flash.c
@@ -411,11 +411,15 @@ static void flash_suggest_update_bootloader(void) {
PrintAndLogEx(ERR, _RED_("It is recommended that you first" _YELLOW_(" update your bootloader") _RED_(" alone,")));
PrintAndLogEx(ERR, _RED_("reboot the Proxmark3 then only update the main firmware") "\n");
- PrintAndLogEx(ERR, "Follow these steps :");
+ PrintAndLogEx(NORMAL, "");
+ PrintAndLogEx(ERR, "------------- " _CYAN_("Follow these steps") " -------------------");
+ PrintAndLogEx(NORMAL, "");
PrintAndLogEx(ERR, " 1) ./pm3-flash-bootrom");
PrintAndLogEx(ERR, " 2) ./pm3-flash-all");
PrintAndLogEx(ERR, " 3) ./pm3");
- PrintAndLogEx(INFO, "--------------------------------------------------------");
+ PrintAndLogEx(NORMAL, "");
+ PrintAndLogEx(INFO, "---------------------------------------------------");
+ PrintAndLogEx(NORMAL, "");
gs_printed_msg = true;
}
diff --git a/client/src/ksx6924/ksx6924core.c b/client/src/ksx6924/ksx6924core.c
index 631d94771..2b4040fa7 100644
--- a/client/src/ksx6924/ksx6924core.c
+++ b/client/src/ksx6924/ksx6924core.c
@@ -93,82 +93,82 @@ MAKE_ENUM_TYPE(uint8_t);
// KSX6924LookupCardType
MAKE_ENUM_CONST(CardType, uint8_t,
- { 0x00, "Pre-paid" },
- { 0x10, "Post-pay" },
- { 0x20, "Mobile post-pay" },
-);
+{ 0x00, "Pre-paid" },
+{ 0x10, "Post-pay" },
+{ 0x20, "Mobile post-pay" },
+ );
// KSX6924LookupAlg
MAKE_ENUM_CONST(Alg, uint8_t,
- { 0x00, "SEED" },
- { 0x10, "3DES" },
-);
+{ 0x00, "SEED" },
+{ 0x10, "3DES" },
+ );
// KSX6924LookupTMoneyIDCenter
MAKE_ENUM_CONST(TMoneyIDCenter, uint8_t,
- { 0x00, "reserved" },
- { 0x01, "Korea Financial Telecommunications and Clearings Institute" },
- { 0x02, "A-Cash" },
- { 0x03, "Mybi" },
+{ 0x00, "reserved" },
+{ 0x01, "Korea Financial Telecommunications and Clearings Institute" },
+{ 0x02, "A-Cash" },
+{ 0x03, "Mybi" },
- { 0x05, "V-Cash" },
- { 0x06, "Mondex Korea" },
- { 0x07, "Korea Expressway Corporation" },
- { 0x08, "Korea Smart Card Corporation" },
- { 0x09, "KORAIL Networks" },
+{ 0x05, "V-Cash" },
+{ 0x06, "Mondex Korea" },
+{ 0x07, "Korea Expressway Corporation" },
+{ 0x08, "Korea Smart Card Corporation" },
+{ 0x09, "KORAIL Networks" },
- { 0x0b, "EB Card Corporation" },
- { 0x0c, "Seoul Bus Transport Association" },
- { 0x0d, "Cardnet" },
-);
+{ 0x0b, "EB Card Corporation" },
+{ 0x0c, "Seoul Bus Transport Association" },
+{ 0x0d, "Cardnet" },
+ );
// KSX6924LookupTMoneyUserCode
MAKE_ENUM_CONST(TMoneyUserCode, uint8_t,
- { 0x01, "Regular/normal" },
- { 0x02, "Child" },
+{ 0x01, "Regular/normal" },
+{ 0x02, "Child" },
- { 0x04, "Youth" },
+{ 0x04, "Youth" },
- { 0x06, "elderly" },
+{ 0x06, "elderly" },
- { 0x0f, "Test" },
- { 0xff, "Inactive" },
-);
+{ 0x0f, "Test" },
+{ 0xff, "Inactive" },
+ );
// KSX6924LookupTMoneyDisRate
MAKE_ENUM_CONST(TMoneyDisRate, uint8_t,
- { 0x00, "No discount" },
+{ 0x00, "No discount" },
- { 0x10, "Disabled, basic" },
- { 0x11, "Disabled, companion" },
+{ 0x10, "Disabled, basic" },
+{ 0x11, "Disabled, companion" },
- { 0x20, "Merit, basic" },
- { 0x21, "Merit, companion" },
-);
+{ 0x20, "Merit, basic" },
+{ 0x21, "Merit, companion" },
+ );
// KSX6924LookupTMoneyTCode
MAKE_ENUM_CONST(TMoneyTCode, uint8_t,
- { 0x00, "None" },
- { 0x01, "SK Telecom" },
- { 0x02, "Korea Telecom" },
- { 0x03, "LG Uplus" },
-);
+{ 0x00, "None" },
+{ 0x01, "SK Telecom" },
+{ 0x02, "Korea Telecom" },
+{ 0x03, "LG Uplus" },
+ );
// KSX6924LookupTMoneyCCode
MAKE_ENUM_CONST(TMoneyCCode, uint8_t,
- { 0x00, "None" },
- { 0x01, "KB Kookmin Bank" },
- { 0x02, "Nonghyup Bank" },
- { 0x03, "Lotte Card" },
- { 0x04, "BC Card" },
- { 0x05, "Samsung Card" },
- { 0x06, "Shinhan Bank" },
- { 0x07, "Citibank Korea" },
- { 0x08, "Korea Exchange Bank" },
- { 0x09, "Woori" },
- { 0x0a, "Hana SK Card" },
- { 0x0b, "Hyundai Capital Services" },
-);
+{ 0x00, "None" },
+{ 0x01, "KB Kookmin Bank" },
+{ 0x02, "Nonghyup Bank" },
+{ 0x03, "Lotte Card" },
+{ 0x04, "BC Card" },
+{ 0x05, "Samsung Card" },
+{ 0x06, "Shinhan Bank" },
+{ 0x07, "Citibank Korea" },
+{ 0x08, "Korea Exchange Bank" },
+{ 0x09, "Woori" },
+{ 0x0a, "Hana SK Card" },
+{ 0x0b, "Hyundai Capital Services" },
+ );
static const char *KSX6924_UNKNOWN = "Unknown";
@@ -226,7 +226,7 @@ static int64_t bcdToLong(const uint8_t *buf, size_t len) {
/**
* Converts a date from on-card format to ksx6924_date format.
*/
-static bool convert_internal_date( const _ksx6924_internal_date_t i, struct ksx6924_date *ret) {
+static bool convert_internal_date(const _ksx6924_internal_date_t i, struct ksx6924_date *ret) {
int64_t year = bcdToLong(i.year, 2);
int16_t month = bcdToInteger(i.month[0]);
@@ -276,7 +276,7 @@ bool KSX6924ParsePurseInfo(const uint8_t *purseInfo, size_t purseLen, struct ksx
0, // min_str_len
0, // spaces_between
false // uppercase
- );
+ );
int64_t idtr = bcdToLong(internalPurseInfo->idtr, 5);
if (idtr < 0) {
@@ -294,8 +294,8 @@ bool KSX6924ParsePurseInfo(const uint8_t *purseInfo, size_t purseLen, struct ksx
convert_internal_date(internalPurseInfo->issueDate, &(ret->issueDate));
convert_internal_date(internalPurseInfo->expiryDate, &(ret->expiryDate));
- ret->balMax = MemBeToUint4byte((uint8_t*)internalPurseInfo->balMax);
- ret->mmax = MemBeToUint4byte((uint8_t*)internalPurseInfo->mmax);
+ ret->balMax = MemBeToUint4byte((uint8_t *)internalPurseInfo->balMax);
+ ret->mmax = MemBeToUint4byte((uint8_t *)internalPurseInfo->mmax);
memcpy(&ret->rfu, &internalPurseInfo->rfu, 8);
@@ -367,7 +367,7 @@ int KSX6924Select(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t
ResultLen,
sw,
NULL
- );
+ );
}
/**
@@ -390,7 +390,7 @@ bool KSX6924TrySelect(void) {
"Not a KS X 6924 card! APDU response: %04x - %s",
sw,
GetAPDUCodeDescription(sw >> 8, sw & 0xff)
- );
+ );
} else {
PrintAndLogEx(FAILED, "APDU exchange error. Card returns 0x0000.");
}
@@ -430,8 +430,8 @@ bool KSX6924GetBalance(uint32_t *result) {
return false;
}
- *result = MemBeToUint4byte((uint8_t*)arr);
- return true;
+ *result = MemBeToUint4byte((uint8_t *)arr);
+ return true;
}
@@ -448,7 +448,7 @@ bool KSX6924InitializeCard(uint8_t mpda1, uint8_t mpda2, uint8_t mpda3, uint8_t
uint16_t sw = 0;
size_t rlen = 0;
- // ALGep + VKep + BALep + IDcenter + IDep + NTep + Sign1 + sw
+ // ALGep + VKep + BALep + IDcenter + IDep + NTep + Sign1 + sw
uint8_t arr[1 + 1 + 4 + 1 + 8 + 4 + 4 + 2];
memset(arr, 0, sizeof(arr));
diff --git a/client/src/ksx6924/ksx6924core.h b/client/src/ksx6924/ksx6924core.h
index 6e9bccc74..10ffbd217 100644
--- a/client/src/ksx6924/ksx6924core.h
+++ b/client/src/ksx6924/ksx6924core.h
@@ -90,8 +90,7 @@ bool KSX6924InitializeCard(uint8_t mpda1, uint8_t mpda2, uint8_t mpda3, uint8_t
// Proprietary get record command. Function unknown.
// result must be 10 bytes long.
-bool KSX6924ProprietaryGetRecord(
- uint8_t id, uint8_t *result, size_t resultLen);
+bool KSX6924ProprietaryGetRecord(uint8_t id, uint8_t *result, size_t result_len);
#endif /* __KSX6924CORE_H__ */
diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c
index d7c4b1600..78bb6ebee 100644
--- a/client/src/mifare/desfiresecurechan.c
+++ b/client/src/mifare/desfiresecurechan.c
@@ -267,10 +267,10 @@ static bool DesfireISOChannelValidCmd(uint8_t cmd) {
}
static void DesfireSecureChannelEncodeD40(DesfireContext_t *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
- uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, 1);
+
+ uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, sizeof(uint8_t));
if (data == NULL)
return;
- size_t rlen = 0;
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
@@ -279,6 +279,8 @@ static void DesfireSecureChannelEncodeD40(DesfireContext_t *ctx, uint8_t cmd, ui
if (srcdatalen < hdrlen)
hdrlen = srcdatalen;
+ size_t rlen;
+
if (ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && srcdatalen <= hdrlen)) {
if (srcdatalen == 0) {
free(data);
@@ -330,14 +332,15 @@ static void DesfireSecureChannelEncodeD40(DesfireContext_t *ctx, uint8_t cmd, ui
*dstdatalen = rlen;
ctx->commMode = DCMEncrypted;
}
+
free(data);
}
static void DesfireSecureChannelEncodeEV1(DesfireContext_t *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
- uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, 1);
+
+ uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, sizeof(uint8_t));
if (data == NULL)
return;
- size_t rlen = 0;
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
@@ -346,6 +349,8 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext_t *ctx, uint8_t cmd, ui
if (srcdatalen < hdrlen)
hdrlen = srcdatalen;
+ size_t rlen;
+
// we calc MAC anyway
// if encypted channel and no data - we only calc MAC
if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && srcdatalen <= hdrlen)) {
@@ -360,6 +365,7 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext_t *ctx, uint8_t cmd, ui
memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx));
*dstdatalen = srcdatalen + DesfireGetMACLength(ctx);
}
+
} else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) {
uint8_t paddinglen = (ctx->commMode == DCMEncryptedWithPadding) ? 1 : 0;
rlen = padded_data_length(srcdatalen + 4 + paddinglen - hdrlen, desfire_get_key_block_length(ctx->keyType));
@@ -395,10 +401,10 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext_t *ctx, uint8_t cmd, ui
}
static void DesfireSecureChannelEncodeEV2(DesfireContext_t *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
- uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, 1);
+
+ uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, sizeof(uint8_t));
if (data == NULL)
return;
- size_t rlen = 0;
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
@@ -416,6 +422,7 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext_t *ctx, uint8_t cmd, ui
} else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding || ctx->commMode == DCMEncryptedPlain) {
memcpy(dstdata, srcdata, hdrlen);
+ size_t rlen = 0;
if (srcdatalen > hdrlen) {
rlen = padded_data_length(srcdatalen + 1 - hdrlen, desfire_get_key_block_length(ctx->keyType));
memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen);
@@ -437,10 +444,10 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext_t *ctx, uint8_t cmd, ui
}
static void DesfireSecureChannelEncodeLRP(DesfireContext_t *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
- uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, 1);
+
+ uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, sizeof(uint8_t));
if (data == NULL)
return;
- size_t rlen = 0;
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
@@ -458,6 +465,7 @@ static void DesfireSecureChannelEncodeLRP(DesfireContext_t *ctx, uint8_t cmd, ui
} else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding || ctx->commMode == DCMEncryptedPlain) {
memcpy(dstdata, srcdata, hdrlen);
+ size_t rlen = 0;
if (srcdatalen > hdrlen) {
rlen = padded_data_length(srcdatalen + 1 - hdrlen, desfire_get_key_block_length(ctx->keyType));
memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen);
@@ -502,10 +510,10 @@ void DesfireSecureChannelEncode(DesfireContext_t *ctx, uint8_t cmd, uint8_t *src
}
static void DesfireSecureChannelDecodeD40(DesfireContext_t *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) {
- uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, 1);
+
+ uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, sizeof(uint8_t));
if (data == NULL)
return;
- size_t rlen = 0;
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
@@ -515,7 +523,7 @@ static void DesfireSecureChannelDecodeD40(DesfireContext_t *ctx, uint8_t *srcdat
size_t maclen = DesfireGetMACLength(ctx);
if (srcdatalen > maclen && DesfireEV1D40ReceiveMAC(ctx, ctx->lastCommand)) {
uint8_t mac[16] = {0};
- rlen = padded_data_length(srcdatalen - maclen, desfire_get_key_block_length(ctx->keyType));
+ size_t rlen = padded_data_length(srcdatalen - maclen, desfire_get_key_block_length(ctx->keyType));
memcpy(data, srcdata, srcdatalen - maclen);
DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, data, rlen, NULL, true, true, mac);
@@ -562,7 +570,8 @@ static void DesfireSecureChannelDecodeD40(DesfireContext_t *ctx, uint8_t *srcdat
}
static void DesfireSecureChannelDecodeEV1(DesfireContext_t *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) {
- uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, 1);
+
+ uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, sizeof(uint8_t));
if (data == NULL)
return;
@@ -736,13 +745,14 @@ static void DesfireSecureChannelDecodeLRP(DesfireContext_t *ctx, uint8_t *srcdat
static void DesfireISODecode(DesfireContext_t *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
- uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, 1);
- if (data == NULL)
- return;
if (srcdatalen < DesfireGetMACLength(ctx))
return;
+ uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, 1);
+ if (data == NULL)
+ return;
+
uint8_t maclen = DesfireGetMACLength(ctx);
if (DesfireIsAuthenticated(ctx)) {
memcpy(data, srcdata, srcdatalen - maclen);
diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c
index 4d36098f3..4b5e4e5a1 100644
--- a/client/src/mifare/mifarehost.c
+++ b/client/src/mifare/mifarehost.c
@@ -1069,18 +1069,21 @@ int mfGen3Freeze(void) {
}
}
-int mfG3GetBlock(uint8_t blockno, uint8_t *data) {
+int mfG4GetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data) {
struct p {
uint8_t blockno;
+ uint8_t pwd[4];
} PACKED payload;
payload.blockno = blockno;
+ memcpy(payload.pwd, pwd, sizeof(payload.pwd));
clearCommandBuffer();
- SendCommandNG(CMD_HF_MIFARE_G3_RDBL, (uint8_t *)&payload, sizeof(payload));
+ SendCommandNG(CMD_HF_MIFARE_G4_RDBL, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
- if (WaitForResponseTimeout(CMD_HF_MIFARE_G3_RDBL, &resp, 1500)) {
- if (resp.status != PM3_SUCCESS)
+ if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_RDBL, &resp, 1500)) {
+ if (resp.status != PM3_SUCCESS) {
return PM3_EUNDEF;
+ }
memcpy(data, resp.data.asBytes, 16);
} else {
PrintAndLogEx(WARNING, "command execute timeout");
diff --git a/client/src/mifare/mifarehost.h b/client/src/mifare/mifarehost.h
index 8f5f215fd..56cc5d841 100644
--- a/client/src/mifare/mifarehost.h
+++ b/client/src/mifare/mifarehost.h
@@ -85,7 +85,7 @@ int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid);
int mfGen3Block(uint8_t *block, int blockLen, uint8_t *newBlock);
int mfGen3Freeze(void);
-int mfG3GetBlock(uint8_t blockno, uint8_t *data);
+int mfG4GetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data);
int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c
index 99403eab2..286463845 100644
--- a/client/src/proxmark3.c
+++ b/client/src/proxmark3.c
@@ -38,7 +38,7 @@
#ifndef LIBPM3
#define BANNERMSG1 ""
-#define BANNERMSG2 " [ :snowflake: Iceman :snowflake: ]"
+#define BANNERMSG2 " [ Iceman :snowflake: ]"
#define BANNERMSG3 ""
typedef enum LogoMode { UTF8, ANSI, ASCII } LogoMode;
diff --git a/client/src/ui.c b/client/src/ui.c
index 8ee9c783e..250b1cb0e 100644
--- a/client/src/ui.c
+++ b/client/src/ui.c
@@ -47,7 +47,7 @@ double g_PlotGridX = 0, g_PlotGridY = 0, g_PlotGridXdefault = 64, g_PlotGridYdef
uint32_t g_CursorCPos = 0, g_CursorDPos = 0, g_GraphStop = 0;
uint32_t g_GraphStart = 0; // Starting point/offset for the left side of the graph
double g_GraphPixelsPerPoint = 1.f; // How many visual pixels are between each sample point (x axis)
-static bool flushAfterWrite = 0;
+static bool flushAfterWrite = false;
double g_GridOffset = 0;
bool g_GridLocked = false;
@@ -411,6 +411,10 @@ void SetFlushAfterWrite(bool value) {
flushAfterWrite = value;
}
+bool GetFlushAfterWrite(void) {
+ return flushAfterWrite;
+}
+
void memcpy_filter_rlmarkers(void *dest, const void *src, size_t n) {
uint8_t *rdest = (uint8_t *)dest;
uint8_t *rsrc = (uint8_t *)src;
diff --git a/client/src/ui.h b/client/src/ui.h
index 36f6fd22e..115234ee9 100644
--- a/client/src/ui.h
+++ b/client/src/ui.h
@@ -63,6 +63,7 @@ extern session_arg_t g_session;
void PrintAndLogOptions(const char *str[][2], size_t size, size_t space);
void PrintAndLogEx(logLevel_t level, const char *fmt, ...);
void SetFlushAfterWrite(bool value);
+bool GetFlushAfterWrite(void);
void memcpy_filter_ansi(void *dest, const void *src, size_t n, bool filter);
void memcpy_filter_rlmarkers(void *dest, const void *src, size_t n);
void memcpy_filter_emoji(void *dest, const void *src, size_t n, emojiMode_t mode);
diff --git a/client/src/wiegand_formats.c b/client/src/wiegand_formats.c
index 75f9ea987..7f507d982 100644
--- a/client/src/wiegand_formats.c
+++ b/client/src/wiegand_formats.c
@@ -1414,7 +1414,7 @@ int HIDFindCardFormat(const char *format) {
bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
memset(packed, 0, sizeof(wiegand_message_t));
- if (format_idx < 0 || format_idx >= ARRAYLEN(FormatTable))
+ if (format_idx < 0 || format_idx >= ARRAYLEN(FormatTable) - 1)
return false;
return FormatTable[format_idx].Pack(card, packed, preamble);
diff --git a/common/cardhelper.c b/common/cardhelper.c
index db62c49f6..e337010e6 100644
--- a/common/cardhelper.c
+++ b/common/cardhelper.c
@@ -53,7 +53,7 @@ static bool executeCrypto(uint8_t ins, uint8_t *src, uint8_t *dest) {
int resp_len = 0;
uint8_t dec[11] = {0};
- ExchangeAPDUSC(false, cmd, sizeof(cmd), false, true, dec, sizeof(dec), &resp_len);
+ ExchangeAPDUSC(false, cmd, sizeof(cmd), true, true, dec, sizeof(dec), &resp_len);
if (resp_len == 10) {
memcpy(dest, dec, 8);
return true;
diff --git a/common/crc.c b/common/crc.c
index e7f169691..cb077182f 100644
--- a/common/crc.c
+++ b/common/crc.c
@@ -147,3 +147,25 @@ uint32_t CRC8Hitag1(uint8_t *buff, size_t size) {
}
return crc_finish(&crc);
}
+
+uint32_t CRC8Hitag1Bits(uint8_t *buff, size_t bitsize) {
+ crc_t crc;
+ uint8_t data = 0;
+ uint8_t n = 0;
+ crc_init_ref(&crc, 8, 0x1d, 0xff, 0, false, false);
+ uint8_t i;
+ for (i = 0; i < bitsize; i++) {
+ data <<= 1;
+ data += (buff[i / 8] >> (7 - (i % 8))) & 1;
+ n += 1;
+ if (n == 8) {
+ crc_update2(&crc, data, n);
+ n = 0;
+ data = 0;
+ }
+ }
+ if (n > 0) {
+ crc_update2(&crc, data, n);
+ }
+ return crc_finish(&crc);
+}
diff --git a/common/crc.h b/common/crc.h
index 1b1faca57..33e289ee8 100644
--- a/common/crc.h
+++ b/common/crc.h
@@ -78,5 +78,6 @@ uint32_t CRC8Cardx(uint8_t *buff, size_t size);
// Calculate CRC-8/Hitag1, ZX8211 checksum
uint32_t CRC8Hitag1(uint8_t *buff, size_t size);
+uint32_t CRC8Hitag1Bits(uint8_t *buff, size_t bitsize);
#endif /* __CRC_H */
diff --git a/common/lfdemod.c b/common/lfdemod.c
index 16dc8a56b..976195747 100644
--- a/common/lfdemod.c
+++ b/common/lfdemod.c
@@ -424,8 +424,8 @@ static size_t findModStart(uint8_t *src, size_t size, uint8_t expWaveSize) {
}
static int getClosestClock(int testclk) {
- uint16_t clocks[] = {8, 16, 32, 40, 50, 64, 100, 128, 256, 384};
- uint8_t limit[] = {1, 2, 4, 4, 5, 8, 8, 8, 8, 8};
+ const uint16_t clocks[] = {8, 16, 32, 40, 50, 64, 100, 128, 256, 384};
+ const uint8_t limit[] = {1, 2, 4, 4, 5, 8, 8, 8, 8, 8};
for (uint8_t i = 0; i < 10; i++) {
if (testclk >= clocks[i] - limit[i] && testclk <= clocks[i] + limit[i])
@@ -434,12 +434,12 @@ static int getClosestClock(int testclk) {
return 0;
}
-void getNextLow(uint8_t *samples, size_t size, int low, size_t *i) {
+void getNextLow(const uint8_t *samples, size_t size, int low, size_t *i) {
while ((samples[*i] > low) && (*i < size))
*i += 1;
}
-void getNextHigh(uint8_t *samples, size_t size, int high, size_t *i) {
+void getNextHigh(const uint8_t *samples, size_t size, int high, size_t *i) {
while ((samples[*i] < high) && (*i < size))
*i += 1;
}
diff --git a/common/lfdemod.h b/common/lfdemod.h
index e8d516604..4b840efc0 100644
--- a/common/lfdemod.h
+++ b/common/lfdemod.h
@@ -35,8 +35,8 @@ signal_t *getSignalProperties(void);
void computeSignalProperties(uint8_t *samples, uint32_t size);
void removeSignalOffset(uint8_t *samples, uint32_t size);
-void getNextLow(uint8_t *samples, size_t size, int low, size_t *i);
-void getNextHigh(uint8_t *samples, size_t size, int high, size_t *i);
+void getNextLow(const uint8_t *samples, size_t size, int low, size_t *i);
+void getNextHigh(const uint8_t *samples, size_t size, int high, size_t *i);
bool loadWaveCounters(uint8_t *samples, size_t size, int lowToLowWaveLen[], int highToLowWaveLen[], int *waveCnt, int *skip, int *minClk, int *high, int *low);
size_t pskFindFirstPhaseShift(uint8_t *samples, size_t size, uint8_t *curPhase, size_t waveStart, uint16_t fc, uint16_t *fullWaveLen);
diff --git a/common/mbedtls/ssl_tls.c b/common/mbedtls/ssl_tls.c
index f5e56f9d7..6e68cf104 100644
--- a/common/mbedtls/ssl_tls.c
+++ b/common/mbedtls/ssl_tls.c
@@ -3086,7 +3086,7 @@ static void ssl_calc_finished_tls_sha384(
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
- mbedtls_sha512_finish_ret( &sha512, padbuf );
+ mbedtls_sha512_finish_ret(&sha512, padbuf);
#if defined(__GNUC__) && __GNUC__ >= 11
#pragma GCC diagnostic pop
#endif
diff --git a/doc/T5577_Guide.md b/doc/T5577_Guide.md
index 4d973cf00..26ca77434 100644
--- a/doc/T5577_Guide.md
+++ b/doc/T5577_Guide.md
@@ -1,10 +1,13 @@
# T5577 Introduction Guide
+
### Based on RRG/Iceman Proxmark3 repo
### Ver.1 8 Sep 2019
### Ver.2 7 March 2021
+# Table of Contents
+
| Contents |
| ----------------------------------------------------------------------------------- |
| [Part 1](#part-1) |
@@ -21,8 +24,10 @@
| [The configuration Block – Block 3 Page 1](#the-configuration-block-block-3-page-1) |
# Part 1
+^[Top](#top)
## Introduction
+^[Top](#top)
The T5577 is a generic LF (Low Frequency) RFID card that is used in the
125 Khz frequency space. It is a good card to use to learn about RFID and
@@ -49,6 +54,7 @@ try these as we go. To do so, have a blank T5577 card that you can use
for this purpose.
## T5577 Overview
+^[Top](#top)
The T5577 is a chip that can hold data and a configuration (Section
4.12).
@@ -63,6 +69,7 @@ the chip how to behave.
## What data is on my T5577
+^[Top](#top)
Let’s have a look and see what a card might look like in the proxmark3
software. Since we can change the configuration of how the T5577 will
@@ -121,6 +128,7 @@ I will cover the meaning of this data as we go, but for now, lets keep
it simple.
## Read and Write Blocks of Data
+^[Top](#top)
The basic function of using the proxmark3 with rfid cards is to read and
write data. This reading and writing must be done in the correct way
@@ -224,6 +232,7 @@ can see the card)
```
### Exercise 1
+^[Top](#top)
Using the read and write commands you have learnt see if you can make
the lf t55 dump command show the following data for blocks 1-7 (Page 0).
@@ -261,6 +270,7 @@ If you forget this data/password, you won't be able to read or write
to the card.
## How do I use a password
+^[Top](#top)
This can be a little tricky for beginners.
***If you forget your password you will lose access to your card***.
@@ -521,6 +531,7 @@ required, please do not proceed.
Yes we can! We can see Block 0 is the correct config 00088040
# Part 2 – Configuration Blocks
+^[Top](#top)
One of the things a lot of people have trouble with or miss, is that the
T5577 has two different and separate communications protocols, each with
@@ -539,6 +550,7 @@ from Block 3 Page 1. If the command is not encoded correctly it will
ignore the command and revert back to default read mode.
## The configuration Block – Block 0 Page 0
+^[Top](#top)
For this configuration the settings chosen will be for the purpose of
the card when used in production. E.G. If you want the card to act like
@@ -685,6 +697,7 @@ password set (if not, review and get you card back to this state).
(Max Block = 2). On the T5577 these will be Blocks 1 and 2.
## Exercise 2
+^[Top](#top)
Using the skills form part 1, see if you can view the data in blocks 1 and 2.
@@ -699,3 +712,6 @@ it, we can follow the password section and update the config from
***Important : Don’t forget to set a valid password in block 7 and remember it.***
## The configuration Block – Block 3 Page 1
+^[Top](#top)
+
+_to be written_
\ No newline at end of file
diff --git a/doc/cliparser.md b/doc/cliparser.md
index a837a5afc..118a82c86 100644
--- a/doc/cliparser.md
+++ b/doc/cliparser.md
@@ -1,4 +1,34 @@
-# Cliparser
+# Note on Cliparser
+
+
+
+# Table of Contents
+- [Note on Cliparser](#note-on-cliparser)
+- [Table of Contents](#table-of-contents)
+ - [cliparser setup and use](#cliparser-setup-and-use)
+ - [design comments](#design-comments)
+ - [common options](#common-options)
+ - [How to implement in source code](#how-to-implement-in-source-code)
+ - [setup the parser data structure](#setup-the-parser-data-structure)
+ - [define the context](#define-the-context)
+ - [define the options](#define-the-options)
+ - [Notes:](#notes)
+ - [bool option. true if supplied](#bool-option--true-if-supplied)
+ - [integer that is optional](#integer-that-is-optional)
+ - [integer that is required](#integer-that-is-required)
+ - [double that is optional](#double-that-is-optional)
+ - [double that is required](#double-that-is-required)
+ - [String option that is optional and only one instance can be provided](#string-option-that-is-optional-and-only-one-instance-can-be-provided)
+ - [String option that is required and only one instance can be provided](#string-option-that-is-required-and-only-one-instance-can-be-provided)
+ - [String option that is optional and can have up to 250 instances provided](#string-option-that-is-optional-and-can-have-up-to-250-instances-provided)
+ - [String option that is required/at least one instance and can have up to 250 instances](#string-option-that-is-requiredat-least-one-instance-and-can-have-up-to-250-instances)
+ - [unsigned integer optional](#unsigned-integer-optional)
+ - [unsigned integer required](#unsigned-integer-required)
+ - [show the menu](#show-the-menu)
+ - [clean up](#clean-up)
+ - [retrieving options](#retrieving-options)
+
+
The old style with mixed custom commandline parsing of user parameters or options was messy and confusing. You can find all kinds in the Proxmark3 client.
Samples
@@ -36,11 +66,13 @@ This is the _new_ and _preferred_ way to implement _helptext_ and _cli parsing_
## cliparser setup and use
+^[Top](#top)
The parser will format and color and layout as needed.
It will also add the `-h --help` option automatic.
## design comments
+^[Top](#top)
* where possible all options should be lowercase.
* extended options preceded with -- should be short
@@ -52,6 +84,8 @@ It will also add the `-h --help` option automatic.
## common options
+^[Top](#top)
+
-h --help : help
--cn : card number
--fn : facility number
@@ -69,8 +103,11 @@ It will also add the `-h --help` option automatic.
## How to implement in source code
+^[Top](#top)
### setup the parser data structure
+^[Top](#top)
+
Header file to include
#include "cliparser.h"
@@ -81,6 +118,8 @@ In the command function, setup the context
### define the context
+^[Top](#top)
+
`CLIParserInit (\, \, \);`
use -> to separate example and example comment and \\n to separate examples.
@@ -94,12 +133,13 @@ e.g. lf indala clone -r a0000000a0002021 -> this uses .....
"lf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5");
### define the options
+^[Top](#top)
void *argtable[] = {
arg_param_begin,
arg_lit0("l", "long", "optional - long UID 224 bits"),
arg_int0("c", "heden", "", "Cardnumber for Heden 2L format"),
- arg_strx0("r", "raw", "", "raw bytes"),
+ arg_str0("r", "raw", "", "raw bytes"),
arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
arg_int0(NULL, "fc", "", "Facility Code (26 bit format)"),
arg_int0(NULL, "cn", "", "Cardnumber (26 bit format)"),
@@ -110,6 +150,8 @@ _All options has a parameter index, since `-h --help` is added automatic, it wi
Hence all options you add will start at index 1 and upwards. It added in the define "arg_param_begin_
### Notes:
+^[Top](#top)
+
#### bool option. true if supplied
`bool : arg_lit0 ("", "", <"description">)`
@@ -150,17 +192,21 @@ Unsigned values, like u32 and u64 can be accomplished with
### show the menu
+^[Top](#top)
+
`CLIExecWithReturn(\, \, \, \);`
CLIExecWithReturn(ctx, Cmd, argtable, false);
### clean up
+^[Top](#top)
+
Once you have extracted the options, cleanup the context.
CLIParserFree(ctx);
### retrieving options
-
+^[Top](#top)
The parser will format and color and layout as needed.
It will also add the `-h --help` option automatic.
diff --git a/doc/clocks.md b/doc/clocks.md
index c1d046f06..161d680fb 100644
--- a/doc/clocks.md
+++ b/doc/clocks.md
@@ -1,22 +1,46 @@
+
+
+# Notes on device side clocks
+The device side firmware uses a range of different clocks. Here is an attempt to document the clocks in use and for what they are used.
+
+
+# Table of Contents
+- [Notes on device side clocks](#notes-on-device-side-clocks)
+- [Table of Contents](#table-of-contents)
+ - [Slow clock](#slow-clock)
+ - [Main Oscillator / MAINCK](#main-oscillator--mainck)
+ - [PLL clock](#pll-clock)
+ - [Master Clock MCK, Processor Clock PCK, USB clock UDPCK](#master-clock-mck-processor-clock-pck-usb-clock-udpck)
+ - [Peripheral clocks](#peripheral-clocks)
+ - [1 kHz RTC: TickCount functions](#1-khz-rtc-tickcount-functions)
+ - [Occasional PWM timer](#occasional-pwm-timer)
+ - [Occasional TC0+TC1 / CountUS functions](#occasional-tc0tc1--countus-functions)
+ - [Occasional TC0+TC1+TC2 SSP_CLK from FPGA / CountSspClk functions](#occasional-tc0tc1tc2-ssp_clk-from-fpga--countsspclk-functions)
+ - [Occasional TC0+TC1 / Ticks functions](#occasional-tc0tc1--ticks-functions)
+
## Slow clock
+^[Top](#top)
~32kHz internal RC clock
Can be between 22 and 42 kHz
## Main Oscillator / MAINCK
+^[Top](#top)
cf `PMC_MOR` register
16 MHz, based on external Xtal
## PLL clock
+^[Top](#top)
cf `PMC_PLLR` register
96 MHz (MAINCK * 12 / 2)
## Master Clock MCK, Processor Clock PCK, USB clock UDPCK
+^[Top](#top)
cf `common_arm/clocks.c`
@@ -33,6 +57,7 @@ USB need to be clocked at 48 MHz from the PLL, so PLL / 2 (cf `CKGR_PLLR`).
## Peripheral clocks
+^[Top](#top)
cf `bootrom.c`:
@@ -43,6 +68,7 @@ cf `appmain.c`
Activate PCK0 pin as clock output, based on PLL / 4 = 24 MHz, for the FPGA.
## 1 kHz RTC: TickCount functions
+^[Top](#top)
cf `armsrc/ticks.c`
@@ -73,6 +99,7 @@ Current usages:
* USB connection speed measure
## Occasional PWM timer
+^[Top](#top)
* `void SpinDelayUs(int us)`
* `void SpinDelay(int ms)` based on SpinDelayUs
@@ -84,6 +111,7 @@ Busy wait based on 46.875 kHz PWM Channel 0
* *Precision* variant: 0.7 us precision and maximum 43 ms
## Occasional TC0+TC1 / CountUS functions
+^[Top](#top)
cf `armsrc/ticks.c`
@@ -100,6 +128,7 @@ Maximal value: 0x7fffffff = 2147 s
Can't be used at the same time as CountSspClk or Ticks functions.
## Occasional TC0+TC1+TC2 SSP_CLK from FPGA / CountSspClk functions
+^[Top](#top)
cf `armsrc/ticks.c`
@@ -121,6 +150,7 @@ Usage:
Can't be used at the same time as CountUS or Ticks functions.
## Occasional TC0+TC1 / Ticks functions
+^[Top](#top)
cf `armsrc/ticks.c`
diff --git a/doc/cloner_notes.md b/doc/cloner_notes.md
index 78f7b360e..83de05039 100644
--- a/doc/cloner_notes.md
+++ b/doc/cloner_notes.md
@@ -1,8 +1,13 @@
# Notes on Cloner guns
+
This document is based mostly on information posted on http://www.proxmark.org/forum/viewtopic.php?pid=39903#p39903
+
+# Table of Contents
+
- [Notes on Cloner guns](#notes-on-cloner-guns)
+- [Table of Contents](#table-of-contents)
- [Blue and black cloners](#blue-and-black-cloners)
- [White cloner (pre 2015)](#white-cloner-pre-2015)
- [White cloner (after 2016)](#white-cloner-after-2016)
@@ -12,6 +17,7 @@ This document is based mostly on information posted on http://www.proxmark.org/f
# Blue and black cloners
+^[Top](#top)
3 variants:
1. EM cloner
@@ -26,6 +32,7 @@ Standard password is normally: 51243648
**Be sure to purchase the EM/HID version**
# White cloner (pre 2015)
+^[Top](#top)
Multifrequency
Buttons light up BLUE
@@ -38,6 +45,8 @@ Standard password 13,56mHz: individual per white cloner
# White cloner (after 2016)
+^[Top](#top)
+
Multifrequency
Buttons light up WHITE
Data scrambled (variable per individual cloner, possibly due to prevent legal issues)
@@ -49,6 +58,8 @@ Standard password 13,56mHz: individual per white cloner
# White cloner (after 2016 D Quality)
+^[Top](#top)
+
Multifrequency (it says so but it doesn't)
Only works for EM/HID card (125kHz)
High frequency not working
@@ -59,12 +70,16 @@ Standard password is normally (for T55xx): AA55BBBB
# Restore page1 data
+^[Top](#top)
+
```
lf t55xx write -b 1 -d E0150A48 --pg1
If t55xx write -b 2 -d 2D782308 --pg1
```
# Sniffing the comms
+^[Top](#top)
+
The T55x7 protocol uses a pwm based protocol for writing to tags. In order to make decoding easier try the new command as seen below instead. It will try to extract the data written.
```
diff --git a/doc/colors_notes.md b/doc/colors_notes.md
index 38a3e9ede..9d8704c87 100644
--- a/doc/colors_notes.md
+++ b/doc/colors_notes.md
@@ -1,10 +1,16 @@
+# Notes on Color usage
-# Notes on Color usage.
-## Table of Contents
- * [style/color](#style_color)
- * [Proxspace](#proxspace)
- * [help texts](#help-texts)
+
+# Table of Contents
+- [Notes on Color usage](#notes-on-color-usage)
+- [Table of Contents](#table-of-contents)
+ - [style/color](#stylecolor)
+ - [Definition](#definition)
+ - [Styled header](#styled-header)
+ - [non styled header](#non-styled-header)
+ - [Proxspace](#proxspace)
+ - [Help texts](#help-texts)
The client should autodetect color support when starting.
@@ -16,10 +22,12 @@ We have gradually been introducing this color scheme into the client since we go
## style/color
^[Top](#top)
+
The following definition has be crystallized out from these experiments. Its not set in stone yet so take this document as a guideline for how to create unified system scheme.
### Definition
^[Top](#top)
+
- blue - system related headers, banner
- white - normal
- cyan - headers
@@ -31,6 +39,7 @@ The following definition has be crystallized out from these experiments. Its no
### Styled header
^[Top](#top)
+
```
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
@@ -41,14 +50,17 @@ For the command help texts using _YELLOW_ for the example makes it very easy to
### non styled header
^[Top](#top)
+
Most commands doesn't use a header yet. We added it to make it standout (ie: yellow, green) of the informative tidbits in the output of a command.
## Proxspace
^[Top](#top)
+
Proxspace has support for colors.
## Help texts
^[Top](#top)
+
The help text uses a hard coded template deep inside the cliparser.c file.
\ No newline at end of file
diff --git a/doc/commands.json b/doc/commands.json
index 7ac247c3e..8cd2d65d5 100644
--- a/doc/commands.json
+++ b/doc/commands.json
@@ -76,9 +76,9 @@
"offline": true,
"options": [
"-h, --help this help",
- "-r, --raw raw bytes (strx)"
+ "-r, --raw raw bytes"
],
- "usage": "analyse foo [-h] [-r ]..."
+ "usage": "analyse foo [-h] -r "
},
"analyse freq": {
"command": "analyse freq",
@@ -227,7 +227,7 @@
"-h, --help this help",
"-d, --data binary string to convert"
],
- "usage": "data bin2hex [-h] [-d ]..."
+ "usage": "data bin2hex [-h] -d "
},
"data bitsamples": {
"command": "data bitsamples",
@@ -744,9 +744,10 @@
"-m, -m, --make make cdoldata from cdol (tag 8c and 8d) and parameters (by default uses default parameters)",
"-a, -a, --apdu show apdu reqests and responses",
"-t, -t, --tlv tlv decode results of selected applets",
- "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default."
+ "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default.",
+ " cdoldata/cdol"
],
- "usage": "emv genac [-hkcpmatw] [-d ] []..."
+ "usage": "emv genac [-hkcpmatw] [-d ] []..."
},
"emv gpo": {
"command": "emv gpo",
@@ -764,9 +765,10 @@
"-m, -m, --make make pdoldata from pdol (tag 9f38) and parameters (by default uses default parameters)",
"-a, -a, --apdu show apdu reqests and responses",
"-t, -t, --tlv tlv decode results of selected applets",
- "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default."
+ "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default.",
+ " pdoldata/pdol"
],
- "usage": "emv gpo [-hkpmatw] []..."
+ "usage": "emv gpo [-hkpmatw] []..."
},
"emv help": {
"command": "emv help",
@@ -808,9 +810,10 @@
"-m, -m, --make make ddoldata from ddol (tag 9f49) and parameters (by default uses default parameters)",
"-a, -a, --apdu show apdu reqests and responses",
"-t, -t, --tlv tlv decode results of selected applets",
- "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default."
+ "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default.",
+ " ddoldata/ddol"
],
- "usage": "emv intauth [-hkpmatw] []..."
+ "usage": "emv intauth [-hkpmatw] []..."
},
"emv list": {
"command": "emv list",
@@ -831,7 +834,7 @@
"or to import into wireshark using encapsulation type \"iso 14443\"",
"--dict use dictionary keys file"
],
- "usage": "emv list [-h1fcrux] [--dict ]..."
+ "usage": "emv list [-h1fcrux] [--dict ]"
},
"emv pse": {
"command": "emv pse",
@@ -866,9 +869,10 @@
"-k, -k, --keep keep field on for next command",
"-a, -a, --apdu show apdu reqests and responses",
"-t, -t, --tlv tlv decode results of selected applets",
- "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default."
+ "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default.",
+ " []..."
+ "usage": "emv readrec [-hkatw] []..."
},
"emv roca": {
"command": "emv roca",
@@ -907,9 +911,9 @@
"-g, -g, --acgpo visa. generate ac from gpo.",
"-m, -m, --merge merge output file with card's data. (warning: the file may be corrupted!)",
"-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default.",
- "output.json json output file name"
+ " json output filename"
],
- "usage": "emv scan [-hatejvcxgmw] by default: output.json"
+ "usage": "emv scan [-hatejvcxgmw] by default: "
},
"emv search": {
"command": "emv search",
@@ -941,11 +945,12 @@
"-h, --help this help",
"-s, -s, --select activate field and select card",
"-k, -k, --keep keep field for next command",
- "-a, -a, --apdu show apdu reqests and responses",
+ "-a, -a, --apdu show apdu requests and responses",
"-t, -t, --tlv tlv decode results",
- "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default."
+ "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default.",
+ " applet aid"
],
- "usage": "emv select [-hskatw] []..."
+ "usage": "emv select [-hskatw] "
},
"emv test": {
"command": "emv test",
@@ -1055,7 +1060,7 @@
"--p2 start value of p2 (1 hex byte)",
"-r, --reset minimum secondes before resetting the tag (to prevent timeout issues). default is 5 minutes",
"-e, --error-limit maximum times an status word other than 0x9000 or 0x6d00 is shown. default is 512.",
- "-s, --skip-ins do not test an instructions (can be specified multiple times)",
+ "-s, --skip-ins do not test an instruction (can be specified multiple times)",
"-l, --with-le search for apdus with le=0 (case 2s) as well",
"-v, --verbose verbose output"
],
@@ -1093,7 +1098,7 @@
"or to import into wireshark using encapsulation type \"iso 14443\"",
"--dict use dictionary keys file"
],
- "usage": "hf 14a list [-h1fcrux] [--dict ]..."
+ "usage": "hf 14a list [-h1fcrux] [--dict ]"
},
"hf 14a info": {
"command": "hf 14a info",
@@ -1224,9 +1229,9 @@
"offline": false,
"options": [
"-h, --help this help",
- "-f, --file (optional) filename, if no uid will be used as filename"
+ "-f, --file (optional) filename, if no uid will be used as filename"
],
- "usage": "hf 14b dump [-h] [-f ]..."
+ "usage": "hf 14b dump [-h] [-f ]"
},
"hf 14b help": {
"command": "hf 14b help",
@@ -1251,7 +1256,7 @@
"-d, --data if `m` parameter included",
"--timeout timeout in ms"
],
- "usage": "hf 14b apdu [-hskte] [--decode] [-m ] [-l ] -d [-d ]... [--timeout ]"
+ "usage": "hf 14b apdu [-hskte] [--decode] [-m ] [-l ] -d [--timeout ]"
},
"hf 14b info": {
"command": "hf 14b info",
@@ -1286,7 +1291,7 @@
"or to import into wireshark using encapsulation type \"iso 14443\"",
"--dict use dictionary keys file"
],
- "usage": "hf 14b list [-h1fcrux] [--dict ]..."
+ "usage": "hf 14b list [-h1fcrux] [--dict ]"
},
"hf 14b ndefread": {
"command": "hf 14b ndefread",
@@ -1323,7 +1328,7 @@
"-v, --verbose verbose",
"-d, --data data, bytes to send"
],
- "usage": "hf 14b raw [-hkscrv] [--sr] [--cts] [-t ] [-d ]..."
+ "usage": "hf 14b raw [-hkscrv] [--sr] [--cts] [-t ] [-d ]"
},
"hf 14b rdbl": {
"command": "hf 14b rdbl",
@@ -1363,7 +1368,7 @@
"-h, --help this help",
"-u, --uid hex 4byte uid/pupi"
],
- "usage": "hf 14b sim [-h] [-u hex]..."
+ "usage": "hf 14b sim [-h] -u hex"
},
"hf 14b sniff": {
"command": "hf 14b sniff",
@@ -1473,7 +1478,7 @@
"or to import into wireshark using encapsulation type \"iso 14443\"",
"--dict use dictionary keys file"
],
- "usage": "hf 15 list [-h1fcrux] [--dict ]..."
+ "usage": "hf 15 list [-h1fcrux] [--dict ]"
},
"hf 15 info": {
"command": "hf 15 info",
@@ -1510,7 +1515,7 @@
"-r do not read response",
"-d, --data raw bytes to send"
],
- "usage": "hf 15 raw [-h2ckr] -d [-d ]..."
+ "usage": "hf 15 raw [-h2ckr] -d "
},
"hf 15 rdbl": {
"command": "hf 15 rdbl",
@@ -1898,7 +1903,7 @@
"or to import into wireshark using encapsulation type \"iso 14443\"",
"--dict