Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CLI commands to dump and clone tag #201

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ 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]
- Added command to check keys of multiple sectors at once (@taichunmin)
- Skip already used items `hf mf elog --decrypt` (@p-l-)
- Parallelize mfkey32v2 processes called from CLI (@p-l-)
- Added support for mifare classic value block operations (@taichunmin)
Expand Down
7 changes: 7 additions & 0 deletions docs/protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,13 @@ Notes:
* Command: 21 bytes: `src_type|src_block|src_key[6]|operator|operand[4]|dst_type|dst_block|dst_key[6]`. Key as 6 bytes. Type=`0x60` for key A, `0x61` for key B. Operator=`0xC0` for decrement, `0xC1` for increment, `0xC2` for restore. Operand as I32 in Network byte order.
* Response: no data
* CLI: cf `hf mf value`
### 2012: MF1_CHECK_KEYS_OF_SECTORS
* Command: 10+N*6 bytes: `mask[10]|keys[N][6]` (1<=N<=83)
* `mask`: 40 sectors, 2 bits/sector, MSB: `0A|0B|1A|1B|...|39A|39B`. `0b1` represent to skip checking the key.
* Response: 490 bytes: `found[10]|sectorKey[40][2][6]`.
* `found`: 40 sectors, 2 bits/sector, MSB: `0A|0B|1A|1B|...|39A|39B`. `0b1` represent the key is found.
* `sectorKey`: 40 sectors, 2 keys/sector, 6 bytes/key: `key0A[6]|key0B[6]|key1A[6]|key1B[6]|...|key39A[6]|key39B[6]`
* CLI: cf `hf mf fchk`
### 3000: EM410X_SCAN
* Command: no data
* Response: 5 bytes. `id[5]`. ID as 5 bytes.
Expand Down
19 changes: 18 additions & 1 deletion firmware/application/src/app_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ static void change_slot_auto(uint8_t slot) {
set_slot_light_color(RGB_RED);
}


static data_frame_tx_t *cmd_processor_get_app_version(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
struct {
uint8_t version_major;
Expand Down Expand Up @@ -347,6 +346,23 @@ static data_frame_tx_t *cmd_processor_mf1_auth_one_key_block(uint16_t cmd, uint1
return data_frame_make(cmd, status, 0, NULL);
}

static data_frame_tx_t *cmd_processor_mf1_check_keys_of_sectors(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
if (length < 16 || (length - 10) % 6 != 0) {
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
}

// init
mf1_toolbox_check_keys_of_sectors_in_t in = {
.mask = *(mf1_toolbox_check_keys_of_sectors_mask_t *) &data[0],
.keys_len = (length - 10) / 6,
.keys = (mf1_key_t *) &data[10]
};
mf1_toolbox_check_keys_of_sectors_out_t out;
status = mf1_toolbox_check_keys_of_sectors(&in, &out);

return data_frame_make(cmd, status, sizeof(out), (uint8_t *)&out);
}

static data_frame_tx_t *cmd_processor_mf1_read_one_block(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
typedef struct {
uint8_t type;
Expand Down Expand Up @@ -1068,6 +1084,7 @@ static cmd_data_map_t m_data_cmd_map[] = {
{ DATA_CMD_MF1_WRITE_ONE_BLOCK, before_hf_reader_run, cmd_processor_mf1_write_one_block, after_hf_reader_run },
{ DATA_CMD_HF14A_RAW, before_reader_run, cmd_processor_hf14a_raw, NULL },
{ DATA_CMD_MF1_MANIPULATE_VALUE_BLOCK, before_hf_reader_run, cmd_processor_mf1_manipulate_value_block, after_hf_reader_run },
{ DATA_CMD_MF1_CHECK_KEYS_OF_SECTORS, before_hf_reader_run, cmd_processor_mf1_check_keys_of_sectors, after_hf_reader_run },

{ DATA_CMD_EM410X_SCAN, before_reader_run, cmd_processor_em410x_scan, NULL },
{ DATA_CMD_EM410X_WRITE_TO_T55XX, before_reader_run, cmd_processor_em410x_write_to_t55XX, NULL },
Expand Down
1 change: 1 addition & 0 deletions firmware/application/src/data_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
#define DATA_CMD_MF1_WRITE_ONE_BLOCK (2009)
#define DATA_CMD_HF14A_RAW (2010)
#define DATA_CMD_MF1_MANIPULATE_VALUE_BLOCK (2011)
#define DATA_CMD_MF1_CHECK_KEYS_OF_SECTORS (2012)

//
// ******************************************************************
Expand Down
85 changes: 84 additions & 1 deletion firmware/application/src/rfid/reader/hf/mf1_toolbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -1005,11 +1005,94 @@ uint8_t static_nested_recover_key(uint64_t keyKnown, uint8_t blkKnown, uint8_t t
* @retval : validationResults
*
*/
uint8_t auth_key_use_522_hw(uint8_t block, uint8_t type, uint8_t *key) {
uint16_t auth_key_use_522_hw(uint8_t block, uint8_t type, uint8_t *key) {
// Each verification of a block must re -find a card
if (pcd_14a_reader_scan_auto(p_tag_info) != STATUS_HF_TAG_OK) {
return STATUS_HF_TAG_NO;
}
// After finding the card, we start to verify!
return pcd_14a_reader_mf1_auth(p_tag_info, type, block, key);
}

inline void mf1_toolbox_antenna_restart () {
pcd_14a_reader_reset();
pcd_14a_reader_antenna_on();
bsp_delay_ms(8);
}

inline void mf1_toolbox_report_healthy () {
bsp_wdt_feed();
while (NRF_LOG_PROCESS());
}

uint16_t mf1_toolbox_check_keys_of_sectors (
mf1_toolbox_check_keys_of_sectors_in_t *in,
mf1_toolbox_check_keys_of_sectors_out_t *out
) {
memset(out, 0, sizeof(mf1_toolbox_check_keys_of_sectors_out_t));
uint8_t trailer[18] = {}; // trailer 16 bytes + padding 2 bytes

// keys unique
uint8_t i, j, maskSector, maskShift, trailerNo;
for (i = 0; i < in->keys_len; i++) {
for (j = i + 1; j < in->keys_len; j++) {
if (memcmp(&in->keys[i], &in->keys[j], sizeof(mf1_key_t)) != 0) continue;

// key duplicated, replace with last key
if (j != in->keys_len - 1) in->keys[j] = in->keys[in->keys_len - 1];
in->keys_len--;
j--;
}
}

uint16_t status = STATUS_HF_TAG_OK;
bool skipKeyB;
for (i = 0; i < 40; i++) {
maskShift = 6 - i % 4 * 2;
maskSector = (in->mask.b[i / 4] >> maskShift) & 0b11;
trailerNo = i < 32 ? i * 4 + 3 : i * 16 - 369; // trailerNo of sector
skipKeyB = (maskSector & 0b1) > 0;
if ((maskSector & 0b10) == 0) {
for (j = 0; j < in->keys_len; j++) {
mf1_toolbox_report_healthy();
if (status != STATUS_HF_TAG_OK) mf1_toolbox_antenna_restart();

status = auth_key_use_522_hw(trailerNo, PICC_AUTHENT1A, in->keys[j].key);
if (status != STATUS_HF_TAG_OK) { // auth failed
if (status == STATUS_HF_TAG_NO) return STATUS_HF_TAG_NO;
continue;
}
// key A found
out->found.b[i / 4] |= 0b10 << maskShift;
out->keys[i][0] = in->keys[j];
// try to read keyB from trailer of sector
status = pcd_14a_reader_mf1_read(trailerNo, trailer);
// key B not in trailer
if (status != STATUS_HF_TAG_OK || 0 == *(uint64_t*) &trailer[10]) break;
// key B found
skipKeyB = true;
out->found.b[i / 4] |= 0b1 << maskShift;
out->keys[i][1] = *(mf1_key_t*)&trailer[10];
break;
}
}
if (skipKeyB) continue;

for (j = 0; j < in->keys_len; j++) {
mf1_toolbox_report_healthy();
if (status != STATUS_HF_TAG_OK) mf1_toolbox_antenna_restart();

status = auth_key_use_522_hw(trailerNo, PICC_AUTHENT1B, in->keys[j].key);
if (status != STATUS_HF_TAG_OK) { // auth failed
if (status == STATUS_HF_TAG_NO) return STATUS_HF_TAG_NO;
continue;
}
// key B found
out->found.b[i / 4] |= 0b1 << maskShift;
out->keys[i][1] = in->keys[j];
break;
}
}

return STATUS_HF_TAG_OK;
}
25 changes: 24 additions & 1 deletion firmware/application/src/rfid/reader/hf/mf1_toolbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,24 @@ typedef struct {
uint8_t ar[4];
} PACKED DarksideCore_t;

typedef struct {
uint8_t key[6];
} PACKED mf1_key_t;

typedef struct {
uint8_t b[10]; // 80 bits: 40 sectors * 2 keys
} PACKED mf1_toolbox_check_keys_of_sectors_mask_t;

typedef struct {
mf1_toolbox_check_keys_of_sectors_mask_t mask;
uint8_t keys_len;
mf1_key_t *keys;
} mf1_toolbox_check_keys_of_sectors_in_t;

typedef struct {
mf1_toolbox_check_keys_of_sectors_mask_t found;
mf1_key_t keys[40][2]; // 6 bytes * 2 keys * 40 sectors = 480 bytes
} PACKED mf1_toolbox_check_keys_of_sectors_out_t;

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -93,7 +111,12 @@ uint8_t static_nested_recover_key(NESTED_CORE_PARAM_DEF, mf1_static_nested_core_
uint8_t check_prng_type(mf1_prng_type_t *type);
uint8_t check_std_mifare_nt_support();
void antenna_switch_delay(uint32_t delay_ms);
uint8_t auth_key_use_522_hw(uint8_t block, uint8_t type, uint8_t *key);
uint16_t auth_key_use_522_hw(uint8_t block, uint8_t type, uint8_t *key);

uint16_t mf1_toolbox_check_keys_of_sectors (
mf1_toolbox_check_keys_of_sectors_in_t *in,
mf1_toolbox_check_keys_of_sectors_out_t *out
);

#ifdef __cplusplus
}
Expand Down
10 changes: 5 additions & 5 deletions firmware/application/src/rfid/reader/hf/rc522.c
Original file line number Diff line number Diff line change
Expand Up @@ -958,7 +958,7 @@ uint8_t pcd_14a_reader_gen1a_uplock(void) {
* PSNR: Card serial number, 4 bytes
* @retval : The status value STATUS_HF_TAG_OK is successful, tag_errauth fails, and other returns indicate some abnormalities related to communication errors!
*/
uint8_t pcd_14a_reader_mf1_auth(picc_14a_tag_t *tag, uint8_t type, uint8_t addr, uint8_t *pKey) {
uint16_t pcd_14a_reader_mf1_auth(picc_14a_tag_t *tag, uint8_t type, uint8_t addr, uint8_t *pKey) {
uint8_t dat_buff[12] = { type, addr };
uint16_t data_len = 0;

Expand Down Expand Up @@ -991,7 +991,7 @@ void pcd_14a_reader_mf1_unauth(void) {
* p : Read data, 16 bytes
* @retval : Status value hf_tag_ok, success
*/
uint8_t pcd_14a_reader_mf1_read_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p) {
uint16_t pcd_14a_reader_mf1_read_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p) {
uint8_t status;
uint16_t len;
uint8_t dat_buff[MAX_MIFARE_FRAME_SIZE] = { cmd, addr };
Expand Down Expand Up @@ -1028,7 +1028,7 @@ uint8_t pcd_14a_reader_mf1_read_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p) {
* p : Read data, 16 bytes
* @retval : Status value hf_tag_ok, success
*/
uint8_t pcd_14a_reader_mf1_read(uint8_t addr, uint8_t *p) {
uint16_t pcd_14a_reader_mf1_read(uint8_t addr, uint8_t *p) {
// Standard M1 Card Reading Card Reading
return pcd_14a_reader_mf1_read_by_cmd(PICC_READ, addr, p);
}
Expand Down Expand Up @@ -1261,14 +1261,14 @@ inline void pcd_14a_reader_antenna_off(void) {
}

/**
* @brief : Qi Dian school inspection enabled
* @brief : Enable the parity bit check.
*/
inline void pcd_14a_reader_parity_on(void) {
clear_register_mask(MfRxReg, 0x10);
}

/**
* @brief : Qi Tong school inspection position closed
* @brief : Disable the parity bit check.
*/
inline void pcd_14a_reader_parity_off(void) {
set_register_mask(MfRxReg, 0x10);
Expand Down
6 changes: 3 additions & 3 deletions firmware/application/src/rfid/reader/hf/rc522.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,14 +221,14 @@ uint8_t pcd_14a_reader_ats_request(uint8_t *pAts, uint16_t *szAts, uint16_t szAt
uint8_t pcd_14a_reader_atqa_request(uint8_t *resp, uint8_t *resp_par, uint16_t resp_max_bit);

// M1 tag operation
uint8_t pcd_14a_reader_mf1_auth(picc_14a_tag_t *tag, uint8_t type, uint8_t addr, uint8_t *pKey);
uint16_t pcd_14a_reader_mf1_auth(picc_14a_tag_t *tag, uint8_t type, uint8_t addr, uint8_t *pKey);
void pcd_14a_reader_mf1_unauth(void);
// writeCardOperation
uint8_t pcd_14a_reader_mf1_write_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p);
uint8_t pcd_14a_reader_mf1_write(uint8_t addr, uint8_t *pData);
// cardReadingOperation
uint8_t pcd_14a_reader_mf1_read_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p);
uint8_t pcd_14a_reader_mf1_read(uint8_t addr, uint8_t *pData);
uint16_t pcd_14a_reader_mf1_read_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p);
uint16_t pcd_14a_reader_mf1_read(uint8_t addr, uint8_t *pData);
// value block operation
uint8_t pcd_14a_reader_mf1_manipulate_value_block(uint8_t operator, uint8_t addr, int32_t operand);
uint8_t pcd_14a_reader_mf1_transfer_value_block(uint8_t addr);
Expand Down
Loading
Loading