mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-12-18 16:53:45 +00:00
8632c77d68
* Adding MIFARE 1K Infineon Compatibility As per Issue #1342, MIFARE Classic 1K Cards from NXP have the SAK value of 0x08. MIFARE Classic 1K Cards from Infineon have an SAK value of 0x88. Adding the SAK values accordingly so that Infineon tags are properly handled.
749 lines
25 KiB
C
749 lines
25 KiB
C
#include "mifare_classic.h"
|
|
#include "nfca.h"
|
|
#include "nfc_util.h"
|
|
#include <furi_hal_rtc.h>
|
|
|
|
// Algorithm from https://github.com/RfidResearchGroup/proxmark3.git
|
|
|
|
#define TAG "MfClassic"
|
|
|
|
#define MF_CLASSIC_AUTH_KEY_A_CMD (0x60U)
|
|
#define MF_CLASSIC_AUTH_KEY_B_CMD (0x61U)
|
|
#define MF_CLASSIC_READ_SECT_CMD (0x30)
|
|
|
|
typedef enum {
|
|
MfClassicActionDataRead,
|
|
MfClassicActionDataWrite,
|
|
MfClassicActionDataInc,
|
|
MfClassicActionDataDec,
|
|
|
|
MfClassicActionKeyARead,
|
|
MfClassicActionKeyAWrite,
|
|
MfClassicActionKeyBRead,
|
|
MfClassicActionKeyBWrite,
|
|
MfClassicActionACRead,
|
|
MfClassicActionACWrite,
|
|
} MfClassicAction;
|
|
|
|
static uint8_t mf_classic_get_first_block_num_of_sector(uint8_t sector) {
|
|
furi_assert(sector < 40);
|
|
if(sector < 32) {
|
|
return sector * 4;
|
|
} else {
|
|
return 32 * 4 + (sector - 32) * 16;
|
|
}
|
|
}
|
|
|
|
static uint8_t mf_classic_get_sector_by_block(uint8_t block) {
|
|
if(block < 128) {
|
|
return (block | 0x03) / 4;
|
|
} else {
|
|
return 32 + ((block | 0xf) - 32 * 4) / 16;
|
|
}
|
|
}
|
|
|
|
static uint8_t mf_classic_get_blocks_num_in_sector(uint8_t sector) {
|
|
furi_assert(sector < 40);
|
|
return sector < 32 ? 4 : 16;
|
|
}
|
|
|
|
static uint8_t mf_classic_get_sector_trailer(uint8_t block) {
|
|
if(block < 128) {
|
|
return block | 0x03;
|
|
} else {
|
|
return block | 0x0f;
|
|
}
|
|
}
|
|
|
|
static bool mf_classic_is_sector_trailer(uint8_t block) {
|
|
return block == mf_classic_get_sector_trailer(block);
|
|
}
|
|
|
|
uint8_t mf_classic_get_total_sectors_num(MfClassicReader* reader) {
|
|
furi_assert(reader);
|
|
if(reader->type == MfClassicType1k) {
|
|
return MF_CLASSIC_1K_TOTAL_SECTORS_NUM;
|
|
} else if(reader->type == MfClassicType4k) {
|
|
return MF_CLASSIC_4K_TOTAL_SECTORS_NUM;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static uint16_t mf_classic_get_total_block_num(MfClassicType type) {
|
|
if(type == MfClassicType1k) {
|
|
return 64;
|
|
} else if(type == MfClassicType4k) {
|
|
return 256;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static bool mf_classic_is_allowed_access_sector_trailer(
|
|
MfClassicEmulator* emulator,
|
|
uint8_t block_num,
|
|
MfClassicKey key,
|
|
MfClassicAction action) {
|
|
uint8_t* sector_trailer = emulator->data.block[block_num].value;
|
|
uint8_t AC = ((sector_trailer[7] >> 5) & 0x04) | ((sector_trailer[8] >> 2) & 0x02) |
|
|
((sector_trailer[8] >> 7) & 0x01);
|
|
switch(action) {
|
|
case MfClassicActionKeyARead: {
|
|
return false;
|
|
}
|
|
case MfClassicActionKeyAWrite: {
|
|
return (
|
|
(key == MfClassicKeyA && (AC == 0x00 || AC == 0x01)) ||
|
|
(key == MfClassicKeyB && (AC == 0x04 || AC == 0x03)));
|
|
}
|
|
case MfClassicActionKeyBRead: {
|
|
return (key == MfClassicKeyA && (AC == 0x00 || AC == 0x02 || AC == 0x01));
|
|
}
|
|
case MfClassicActionKeyBWrite: {
|
|
return (
|
|
(key == MfClassicKeyA && (AC == 0x00 || AC == 0x01)) ||
|
|
(key == MfClassicKeyB && (AC == 0x04 || AC == 0x03)));
|
|
}
|
|
case MfClassicActionACRead: {
|
|
return (
|
|
(key == MfClassicKeyA) ||
|
|
(key == MfClassicKeyB && !(AC == 0x00 || AC == 0x02 || AC == 0x01)));
|
|
}
|
|
case MfClassicActionACWrite: {
|
|
return (
|
|
(key == MfClassicKeyA && (AC == 0x01)) ||
|
|
(key == MfClassicKeyB && (AC == 0x03 || AC == 0x05)));
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool mf_classic_is_allowed_access_data_block(
|
|
MfClassicEmulator* emulator,
|
|
uint8_t block_num,
|
|
MfClassicKey key,
|
|
MfClassicAction action) {
|
|
uint8_t* sector_trailer = emulator->data.block[mf_classic_get_sector_trailer(block_num)].value;
|
|
|
|
uint8_t sector_block;
|
|
if(block_num <= 128) {
|
|
sector_block = block_num & 0x03;
|
|
} else {
|
|
sector_block = (block_num & 0x0f) / 5;
|
|
}
|
|
|
|
uint8_t AC;
|
|
switch(sector_block) {
|
|
case 0x00: {
|
|
AC = ((sector_trailer[7] >> 2) & 0x04) | ((sector_trailer[8] << 1) & 0x02) |
|
|
((sector_trailer[8] >> 4) & 0x01);
|
|
break;
|
|
}
|
|
case 0x01: {
|
|
AC = ((sector_trailer[7] >> 3) & 0x04) | ((sector_trailer[8] >> 0) & 0x02) |
|
|
((sector_trailer[8] >> 5) & 0x01);
|
|
break;
|
|
}
|
|
case 0x02: {
|
|
AC = ((sector_trailer[7] >> 4) & 0x04) | ((sector_trailer[8] >> 1) & 0x02) |
|
|
((sector_trailer[8] >> 6) & 0x01);
|
|
break;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
switch(action) {
|
|
case MfClassicActionDataRead: {
|
|
return (
|
|
(key == MfClassicKeyA && !(AC == 0x03 || AC == 0x05 || AC == 0x07)) ||
|
|
(key == MfClassicKeyB && !(AC == 0x07)));
|
|
}
|
|
case MfClassicActionDataWrite: {
|
|
return (
|
|
(key == MfClassicKeyA && (AC == 0x00)) ||
|
|
(key == MfClassicKeyB && (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03)));
|
|
}
|
|
case MfClassicActionDataInc: {
|
|
return (
|
|
(key == MfClassicKeyA && (AC == 0x00)) ||
|
|
(key == MfClassicKeyB && (AC == 0x00 || AC == 0x06)));
|
|
}
|
|
case MfClassicActionDataDec: {
|
|
return (
|
|
(key == MfClassicKeyA && (AC == 0x00 || AC == 0x06 || AC == 0x01)) ||
|
|
(key == MfClassicKeyB && (AC == 0x00 || AC == 0x06 || AC == 0x01)));
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool mf_classic_is_allowed_access(
|
|
MfClassicEmulator* emulator,
|
|
uint8_t block_num,
|
|
MfClassicKey key,
|
|
MfClassicAction action) {
|
|
if(mf_classic_is_sector_trailer(block_num)) {
|
|
return mf_classic_is_allowed_access_sector_trailer(emulator, block_num, key, action);
|
|
} else {
|
|
return mf_classic_is_allowed_access_data_block(emulator, block_num, key, action);
|
|
}
|
|
}
|
|
|
|
bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
|
|
UNUSED(ATQA1);
|
|
if((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88)) {
|
|
return true;
|
|
} else if((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18)) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool mf_classic_get_type(
|
|
uint8_t* uid,
|
|
uint8_t uid_len,
|
|
uint8_t ATQA0,
|
|
uint8_t ATQA1,
|
|
uint8_t SAK,
|
|
MfClassicReader* reader) {
|
|
UNUSED(ATQA1);
|
|
furi_assert(uid);
|
|
furi_assert(reader);
|
|
memset(reader, 0, sizeof(MfClassicReader));
|
|
|
|
if((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88)) {
|
|
reader->type = MfClassicType1k;
|
|
} else if((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18)) {
|
|
reader->type = MfClassicType4k;
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
uint8_t* cuid_start = uid;
|
|
if(uid_len == 7) {
|
|
cuid_start = &uid[3];
|
|
}
|
|
reader->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) |
|
|
(cuid_start[3]);
|
|
|
|
return true;
|
|
}
|
|
|
|
void mf_classic_reader_add_sector(
|
|
MfClassicReader* reader,
|
|
uint8_t sector,
|
|
uint64_t key_a,
|
|
uint64_t key_b) {
|
|
furi_assert(reader);
|
|
furi_assert(sector < MF_CLASSIC_SECTORS_MAX);
|
|
furi_assert((key_a != MF_CLASSIC_NO_KEY) || (key_b != MF_CLASSIC_NO_KEY));
|
|
|
|
if(reader->sectors_to_read < MF_CLASSIC_SECTORS_MAX - 1) {
|
|
reader->sector_reader[reader->sectors_to_read].key_a = key_a;
|
|
reader->sector_reader[reader->sectors_to_read].key_b = key_b;
|
|
reader->sector_reader[reader->sectors_to_read].sector_num = sector;
|
|
reader->sectors_to_read++;
|
|
}
|
|
}
|
|
|
|
void mf_classic_auth_init_context(MfClassicAuthContext* auth_ctx, uint32_t cuid, uint8_t sector) {
|
|
furi_assert(auth_ctx);
|
|
auth_ctx->cuid = cuid;
|
|
auth_ctx->sector = sector;
|
|
auth_ctx->key_a = MF_CLASSIC_NO_KEY;
|
|
auth_ctx->key_b = MF_CLASSIC_NO_KEY;
|
|
}
|
|
|
|
static bool mf_classic_auth(
|
|
FuriHalNfcTxRxContext* tx_rx,
|
|
uint32_t cuid,
|
|
uint32_t block,
|
|
uint64_t key,
|
|
MfClassicKey key_type,
|
|
Crypto1* crypto) {
|
|
bool auth_success = false;
|
|
memset(tx_rx->tx_data, 0, sizeof(tx_rx->tx_data));
|
|
memset(tx_rx->tx_parity, 0, sizeof(tx_rx->tx_parity));
|
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
|
|
|
do {
|
|
if(key_type == MfClassicKeyA) {
|
|
tx_rx->tx_data[0] = MF_CLASSIC_AUTH_KEY_A_CMD;
|
|
} else {
|
|
tx_rx->tx_data[0] = MF_CLASSIC_AUTH_KEY_B_CMD;
|
|
}
|
|
tx_rx->tx_data[1] = block;
|
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRxNoCrc;
|
|
tx_rx->tx_bits = 2 * 8;
|
|
if(!furi_hal_nfc_tx_rx(tx_rx, 6)) break;
|
|
|
|
uint32_t nt = (uint32_t)nfc_util_bytes2num(tx_rx->rx_data, 4);
|
|
crypto1_init(crypto, key);
|
|
crypto1_word(crypto, nt ^ cuid, 0);
|
|
uint8_t nr[4] = {};
|
|
nfc_util_num2bytes(prng_successor(DWT->CYCCNT, 32), 4, nr);
|
|
for(uint8_t i = 0; i < 4; i++) {
|
|
tx_rx->tx_data[i] = crypto1_byte(crypto, nr[i], 0) ^ nr[i];
|
|
tx_rx->tx_parity[0] |=
|
|
(((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nr[i])) & 0x01) << (7 - i));
|
|
}
|
|
nt = prng_successor(nt, 32);
|
|
for(uint8_t i = 4; i < 8; i++) {
|
|
nt = prng_successor(nt, 8);
|
|
tx_rx->tx_data[i] = crypto1_byte(crypto, 0x00, 0) ^ (nt & 0xff);
|
|
tx_rx->tx_parity[0] |=
|
|
(((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nt & 0xff)) & 0x01)
|
|
<< (7 - i));
|
|
}
|
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw;
|
|
tx_rx->tx_bits = 8 * 8;
|
|
if(!furi_hal_nfc_tx_rx(tx_rx, 6)) break;
|
|
if(tx_rx->rx_bits == 32) {
|
|
crypto1_word(crypto, 0, 0);
|
|
auth_success = true;
|
|
}
|
|
} while(false);
|
|
|
|
return auth_success;
|
|
}
|
|
|
|
bool mf_classic_auth_attempt(
|
|
FuriHalNfcTxRxContext* tx_rx,
|
|
MfClassicAuthContext* auth_ctx,
|
|
uint64_t key) {
|
|
furi_assert(tx_rx);
|
|
furi_assert(auth_ctx);
|
|
bool found_key = false;
|
|
bool need_halt = (auth_ctx->key_a == MF_CLASSIC_NO_KEY) &&
|
|
(auth_ctx->key_b == MF_CLASSIC_NO_KEY);
|
|
|
|
Crypto1 crypto;
|
|
if(auth_ctx->key_a == MF_CLASSIC_NO_KEY) {
|
|
// Try AUTH with key A
|
|
if(mf_classic_auth(
|
|
tx_rx,
|
|
auth_ctx->cuid,
|
|
mf_classic_get_first_block_num_of_sector(auth_ctx->sector),
|
|
key,
|
|
MfClassicKeyA,
|
|
&crypto)) {
|
|
auth_ctx->key_a = key;
|
|
found_key = true;
|
|
}
|
|
}
|
|
|
|
if(need_halt) {
|
|
furi_hal_nfc_sleep();
|
|
furi_hal_nfc_activate_nfca(300, &auth_ctx->cuid);
|
|
}
|
|
|
|
if(auth_ctx->key_b == MF_CLASSIC_NO_KEY) {
|
|
// Try AUTH with key B
|
|
if(mf_classic_auth(
|
|
tx_rx,
|
|
auth_ctx->cuid,
|
|
mf_classic_get_first_block_num_of_sector(auth_ctx->sector),
|
|
key,
|
|
MfClassicKeyB,
|
|
&crypto)) {
|
|
auth_ctx->key_b = key;
|
|
found_key = true;
|
|
}
|
|
}
|
|
|
|
return found_key;
|
|
}
|
|
|
|
bool mf_classic_read_block(
|
|
FuriHalNfcTxRxContext* tx_rx,
|
|
Crypto1* crypto,
|
|
uint8_t block_num,
|
|
MfClassicBlock* block) {
|
|
furi_assert(tx_rx);
|
|
furi_assert(crypto);
|
|
furi_assert(block);
|
|
|
|
bool read_block_success = false;
|
|
uint8_t plain_cmd[4] = {MF_CLASSIC_READ_SECT_CMD, block_num, 0x00, 0x00};
|
|
nfca_append_crc16(plain_cmd, 2);
|
|
memset(tx_rx->tx_data, 0, sizeof(tx_rx->tx_data));
|
|
memset(tx_rx->tx_parity, 0, sizeof(tx_rx->tx_parity));
|
|
|
|
for(uint8_t i = 0; i < 4; i++) {
|
|
tx_rx->tx_data[i] = crypto1_byte(crypto, 0x00, 0) ^ plain_cmd[i];
|
|
tx_rx->tx_parity[0] |=
|
|
((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_cmd[i])) & 0x01) << (7 - i);
|
|
}
|
|
tx_rx->tx_bits = 4 * 9;
|
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw;
|
|
|
|
if(furi_hal_nfc_tx_rx(tx_rx, 50)) {
|
|
if(tx_rx->rx_bits == 8 * 18) {
|
|
for(uint8_t i = 0; i < 18; i++) {
|
|
block->value[i] = crypto1_byte(crypto, 0, 0) ^ tx_rx->rx_data[i];
|
|
}
|
|
read_block_success = true;
|
|
}
|
|
}
|
|
return read_block_success;
|
|
}
|
|
|
|
bool mf_classic_read_sector(
|
|
FuriHalNfcTxRxContext* tx_rx,
|
|
Crypto1* crypto,
|
|
MfClassicSectorReader* sector_reader,
|
|
MfClassicSector* sector) {
|
|
furi_assert(tx_rx);
|
|
furi_assert(sector_reader);
|
|
furi_assert(sector);
|
|
|
|
uint32_t cuid = 0;
|
|
uint64_t key;
|
|
MfClassicKey key_type;
|
|
uint8_t first_block;
|
|
bool sector_read = false;
|
|
|
|
furi_hal_nfc_sleep();
|
|
do {
|
|
// Activate card
|
|
if(!furi_hal_nfc_activate_nfca(200, &cuid)) break;
|
|
first_block = mf_classic_get_first_block_num_of_sector(sector_reader->sector_num);
|
|
if(sector_reader->key_a != MF_CLASSIC_NO_KEY) {
|
|
key = sector_reader->key_a;
|
|
key_type = MfClassicKeyA;
|
|
} else if(sector_reader->key_b != MF_CLASSIC_NO_KEY) {
|
|
key = sector_reader->key_b;
|
|
key_type = MfClassicKeyB;
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
// Auth to first block in sector
|
|
if(!mf_classic_auth(tx_rx, cuid, first_block, key, key_type, crypto)) break;
|
|
sector->total_blocks = mf_classic_get_blocks_num_in_sector(sector_reader->sector_num);
|
|
|
|
// Read blocks
|
|
for(uint8_t i = 0; i < sector->total_blocks; i++) {
|
|
mf_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i]);
|
|
}
|
|
// Save sector keys in last block
|
|
if(sector_reader->key_a != MF_CLASSIC_NO_KEY) {
|
|
nfc_util_num2bytes(
|
|
sector_reader->key_a, 6, §or->block[sector->total_blocks - 1].value[0]);
|
|
}
|
|
if(sector_reader->key_b != MF_CLASSIC_NO_KEY) {
|
|
nfc_util_num2bytes(
|
|
sector_reader->key_b, 6, §or->block[sector->total_blocks - 1].value[10]);
|
|
}
|
|
|
|
sector_read = true;
|
|
} while(false);
|
|
|
|
return sector_read;
|
|
}
|
|
|
|
uint8_t mf_classic_read_card(
|
|
FuriHalNfcTxRxContext* tx_rx,
|
|
MfClassicReader* reader,
|
|
MfClassicData* data) {
|
|
furi_assert(tx_rx);
|
|
furi_assert(reader);
|
|
furi_assert(data);
|
|
|
|
uint8_t sectors_read = 0;
|
|
data->type = reader->type;
|
|
data->key_a_mask = 0;
|
|
data->key_b_mask = 0;
|
|
MfClassicSector temp_sector = {};
|
|
for(uint8_t i = 0; i < reader->sectors_to_read; i++) {
|
|
if(mf_classic_read_sector(
|
|
tx_rx, &reader->crypto, &reader->sector_reader[i], &temp_sector)) {
|
|
uint8_t first_block =
|
|
mf_classic_get_first_block_num_of_sector(reader->sector_reader[i].sector_num);
|
|
for(uint8_t j = 0; j < temp_sector.total_blocks; j++) {
|
|
data->block[first_block + j] = temp_sector.block[j];
|
|
}
|
|
if(reader->sector_reader[i].key_a != MF_CLASSIC_NO_KEY) {
|
|
data->key_a_mask |= 1 << reader->sector_reader[i].sector_num;
|
|
}
|
|
if(reader->sector_reader[i].key_b != MF_CLASSIC_NO_KEY) {
|
|
data->key_b_mask |= 1 << reader->sector_reader[i].sector_num;
|
|
}
|
|
sectors_read++;
|
|
}
|
|
}
|
|
|
|
return sectors_read;
|
|
}
|
|
|
|
void mf_crypto1_decrypt(
|
|
Crypto1* crypto,
|
|
uint8_t* encrypted_data,
|
|
uint16_t encrypted_data_bits,
|
|
uint8_t* decrypted_data) {
|
|
if(encrypted_data_bits < 8) {
|
|
uint8_t decrypted_byte = 0;
|
|
decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 0)) << 0;
|
|
decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 1)) << 1;
|
|
decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 2)) << 2;
|
|
decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 3)) << 3;
|
|
decrypted_data[0] = decrypted_byte;
|
|
} else {
|
|
for(size_t i = 0; i < encrypted_data_bits / 8; i++) {
|
|
decrypted_data[i] = crypto1_byte(crypto, 0, 0) ^ encrypted_data[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
void mf_crypto1_encrypt(
|
|
Crypto1* crypto,
|
|
uint8_t* keystream,
|
|
uint8_t* plain_data,
|
|
uint16_t plain_data_bits,
|
|
uint8_t* encrypted_data,
|
|
uint8_t* encrypted_parity) {
|
|
if(plain_data_bits < 8) {
|
|
encrypted_data[0] = 0;
|
|
for(size_t i = 0; i < plain_data_bits; i++) {
|
|
encrypted_data[0] |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(plain_data[0], i)) << i;
|
|
}
|
|
} else {
|
|
memset(encrypted_parity, 0, plain_data_bits / 8 + 1);
|
|
for(uint8_t i = 0; i < plain_data_bits / 8; i++) {
|
|
encrypted_data[i] = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^
|
|
plain_data[i];
|
|
encrypted_parity[i / 8] |=
|
|
(((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_data[i])) & 0x01)
|
|
<< (7 - (i & 0x0007)));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx) {
|
|
furi_assert(emulator);
|
|
furi_assert(tx_rx);
|
|
bool command_processed = false;
|
|
bool is_encrypted = false;
|
|
uint8_t plain_data[MF_CLASSIC_MAX_DATA_SIZE];
|
|
MfClassicKey access_key = MfClassicKeyA;
|
|
|
|
// Read command
|
|
while(!command_processed) {
|
|
if(!is_encrypted) {
|
|
// Read first frame
|
|
tx_rx->tx_bits = 0;
|
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
|
}
|
|
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) {
|
|
FURI_LOG_D(
|
|
TAG, "Error in tx rx. Tx :%d bits, Rx: %d bits", tx_rx->tx_bits, tx_rx->rx_bits);
|
|
break;
|
|
}
|
|
if(!is_encrypted) {
|
|
memcpy(plain_data, tx_rx->rx_data, tx_rx->rx_bits / 8);
|
|
} else {
|
|
mf_crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data);
|
|
}
|
|
// TODO Check crc
|
|
|
|
if(plain_data[0] == 0x50 && plain_data[1] == 00) {
|
|
FURI_LOG_T(TAG, "Halt received");
|
|
command_processed = true;
|
|
break;
|
|
} else if(plain_data[0] == 0x60 || plain_data[0] == 0x61) {
|
|
uint8_t block = plain_data[1];
|
|
uint64_t key = 0;
|
|
uint8_t sector_trailer_block = mf_classic_get_sector_trailer(block);
|
|
MfClassicSectorTrailer* sector_trailer =
|
|
(MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value;
|
|
if(plain_data[0] == 0x61) {
|
|
key = nfc_util_bytes2num(sector_trailer->key_b, 6);
|
|
access_key = MfClassicKeyA;
|
|
} else {
|
|
key = nfc_util_bytes2num(sector_trailer->key_a, 6);
|
|
access_key = MfClassicKeyB;
|
|
}
|
|
|
|
uint32_t nonce = prng_successor(DWT->CYCCNT, 32);
|
|
uint8_t nt[4];
|
|
uint8_t nt_keystream[4];
|
|
nfc_util_num2bytes(nonce, 4, nt);
|
|
nfc_util_num2bytes(nonce ^ emulator->cuid, 4, nt_keystream);
|
|
crypto1_init(&emulator->crypto, key);
|
|
if(!is_encrypted) {
|
|
crypto1_word(&emulator->crypto, emulator->cuid ^ nonce, 0);
|
|
memcpy(tx_rx->tx_data, nt, sizeof(nt));
|
|
tx_rx->tx_bits = sizeof(nt) * 8;
|
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRxRaw;
|
|
} else {
|
|
mf_crypto1_encrypt(
|
|
&emulator->crypto,
|
|
nt_keystream,
|
|
nt,
|
|
sizeof(nt) * 8,
|
|
tx_rx->tx_data,
|
|
tx_rx->tx_parity);
|
|
tx_rx->tx_bits = sizeof(nt) * 8;
|
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
|
|
}
|
|
if(!furi_hal_nfc_tx_rx(tx_rx, 500)) {
|
|
FURI_LOG_E(TAG, "Error in NT exchange");
|
|
command_processed = true;
|
|
break;
|
|
}
|
|
|
|
if(tx_rx->rx_bits != 64) {
|
|
FURI_LOG_W(TAG, "Incorrect nr + ar");
|
|
command_processed = true;
|
|
break;
|
|
}
|
|
|
|
// Check if we store valid key
|
|
if(access_key == MfClassicKeyA) {
|
|
if(FURI_BIT(emulator->data.key_a_mask, mf_classic_get_sector_by_block(block)) ==
|
|
0) {
|
|
FURI_LOG_D(TAG, "Unsupported sector key A for block %d", sector_trailer_block);
|
|
break;
|
|
}
|
|
} else if(access_key == MfClassicKeyB) {
|
|
if(FURI_BIT(emulator->data.key_b_mask, mf_classic_get_sector_by_block(block)) ==
|
|
0) {
|
|
FURI_LOG_D(TAG, "Unsupported sector key B for block %d", sector_trailer_block);
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint32_t nr = nfc_util_bytes2num(tx_rx->rx_data, 4);
|
|
uint32_t ar = nfc_util_bytes2num(&tx_rx->rx_data[4], 4);
|
|
crypto1_word(&emulator->crypto, nr, 1);
|
|
uint32_t cardRr = ar ^ crypto1_word(&emulator->crypto, 0, 0);
|
|
if(cardRr != prng_successor(nonce, 64)) {
|
|
FURI_LOG_T(TAG, "Wrong AUTH! %08X != %08X", cardRr, prng_successor(nonce, 64));
|
|
// Don't send NACK, as tag don't send it
|
|
command_processed = true;
|
|
break;
|
|
}
|
|
|
|
uint32_t ans = prng_successor(nonce, 96);
|
|
uint8_t responce[4] = {};
|
|
nfc_util_num2bytes(ans, 4, responce);
|
|
mf_crypto1_encrypt(
|
|
&emulator->crypto,
|
|
NULL,
|
|
responce,
|
|
sizeof(responce) * 8,
|
|
tx_rx->tx_data,
|
|
tx_rx->tx_parity);
|
|
tx_rx->tx_bits = sizeof(responce) * 8;
|
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
|
|
|
|
is_encrypted = true;
|
|
} else if(is_encrypted && plain_data[0] == 0x30) {
|
|
uint8_t block = plain_data[1];
|
|
uint8_t block_data[18] = {};
|
|
memcpy(block_data, emulator->data.block[block].value, MF_CLASSIC_BLOCK_SIZE);
|
|
if(mf_classic_is_sector_trailer(block)) {
|
|
if(!mf_classic_is_allowed_access(
|
|
emulator, block, access_key, MfClassicActionKeyARead)) {
|
|
memset(block_data, 0, 6);
|
|
}
|
|
if(!mf_classic_is_allowed_access(
|
|
emulator, block, access_key, MfClassicActionKeyBRead)) {
|
|
memset(&block_data[10], 0, 6);
|
|
}
|
|
if(!mf_classic_is_allowed_access(
|
|
emulator, block, access_key, MfClassicActionACRead)) {
|
|
memset(&block_data[6], 0, 4);
|
|
}
|
|
} else {
|
|
if(!mf_classic_is_allowed_access(
|
|
emulator, block, access_key, MfClassicActionDataRead)) {
|
|
memset(block_data, 0, 16);
|
|
}
|
|
}
|
|
nfca_append_crc16(block_data, 16);
|
|
|
|
mf_crypto1_encrypt(
|
|
&emulator->crypto,
|
|
NULL,
|
|
block_data,
|
|
sizeof(block_data) * 8,
|
|
tx_rx->tx_data,
|
|
tx_rx->tx_parity);
|
|
tx_rx->tx_bits = 18 * 8;
|
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
|
|
} else if(is_encrypted && plain_data[0] == 0xA0) {
|
|
uint8_t block = plain_data[1];
|
|
if(block > mf_classic_get_total_block_num(emulator->data.type)) {
|
|
break;
|
|
}
|
|
// Send ACK
|
|
uint8_t ack = 0x0A;
|
|
mf_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity);
|
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
|
|
tx_rx->tx_bits = 4;
|
|
|
|
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
|
|
if(tx_rx->rx_bits != 18 * 8) break;
|
|
|
|
mf_crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data);
|
|
uint8_t block_data[16] = {};
|
|
memcpy(block_data, emulator->data.block[block].value, MF_CLASSIC_BLOCK_SIZE);
|
|
if(mf_classic_is_sector_trailer(block)) {
|
|
if(mf_classic_is_allowed_access(
|
|
emulator, block, access_key, MfClassicActionKeyAWrite)) {
|
|
memcpy(block_data, plain_data, 6);
|
|
}
|
|
if(mf_classic_is_allowed_access(
|
|
emulator, block, access_key, MfClassicActionKeyBWrite)) {
|
|
memcpy(&block_data[10], &plain_data[10], 6);
|
|
}
|
|
if(mf_classic_is_allowed_access(
|
|
emulator, block, access_key, MfClassicActionACWrite)) {
|
|
memcpy(&block_data[6], &plain_data[6], 4);
|
|
}
|
|
} else {
|
|
if(mf_classic_is_allowed_access(
|
|
emulator, block, access_key, MfClassicActionDataWrite)) {
|
|
memcpy(block_data, plain_data, MF_CLASSIC_BLOCK_SIZE);
|
|
}
|
|
}
|
|
if(memcmp(block_data, emulator->data.block[block].value, MF_CLASSIC_BLOCK_SIZE)) {
|
|
memcpy(emulator->data.block[block].value, block_data, MF_CLASSIC_BLOCK_SIZE);
|
|
emulator->data_changed = true;
|
|
}
|
|
// Send ACK
|
|
ack = 0x0A;
|
|
mf_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity);
|
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
|
|
tx_rx->tx_bits = 4;
|
|
} else {
|
|
// Unknown command
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!command_processed) {
|
|
// Send NACK
|
|
uint8_t nack = 0x04;
|
|
if(is_encrypted) {
|
|
mf_crypto1_encrypt(
|
|
&emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity);
|
|
} else {
|
|
tx_rx->tx_data[0] = nack;
|
|
}
|
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
|
|
tx_rx->tx_bits = 4;
|
|
furi_hal_nfc_tx_rx(tx_rx, 300);
|
|
}
|
|
|
|
return true;
|
|
}
|