Skip to content

Commit

Permalink
Added command to check keys of multiple sectors at once (#199)
Browse files Browse the repository at this point in the history
  • Loading branch information
taichunmin authored Mar 7, 2024
1 parent 1608892 commit c1eb213
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 11 deletions.
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)
- Fixed unused target key type parameter for nested (@petepriority)
- Skip already used items `hf mf elog --decrypt` (@p-l-)
- Parallelize mfkey32v2 processes called from CLI (@p-l-)
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

0 comments on commit c1eb213

Please sign in to comment.