mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 04:34:43 +04:00
* Initial structure for nonce collection * Nonce logging * Dictionary attack structure * Fix compilation * Identified method to reduce candidate states * Use EXT_PATH instead of ANY_PATH * Use median calibrated distance, collect parity bits * Modify parity collection * Fixed parity bit collection * Add note to fix nonce logging * Fix nonce logging * Clean redundant code * Fix valid_nonce * First attempt disambiguous nonce implementation * FM11RF08S backdoor detection * Initial accelerated dictionary attack for weak PRNGs * Refactor to nested dictionary attack * Renaming some variables * Hard PRNG support for accelerated dictionary attack * Update found keys, initial attempt * Update found keys, second attempt * Code cleanup * Misc bugfixes * Only use dicts in search_dicts_for_nonce_key if we have them * Collect nonces again * Should be detecting both backdoors now * Relocate backdoor detection * Hardnested support * Fix regression for regular nested attack * Backdoor read * Backdoor working up to calibration * Backdoor nested calibration * Don't recalibrate hard PRNG tags * Static encrypted nonce collection * Update TODO * NFC app UI updates, MVP * Bump f18 API version (all functions are NFC related) * Add new backdoor key, fix UI status update carrying over from previous read * Clear TODO line * Fix v1/v2 backdoor nonce collection * Speed up backdoor detection, alert on new backdoor * Add additional condition to backdoor check * I'll try freeing memory, that's a good trick! * Do not enter nested attack if card is already finished * Do not reset the poller between collected nonces * Clean up various issues * Fix Hardnested sector/key type logging * Add nested_target_key 64 to TODO * Implement progress bar for upgraded attacks in NFC app * Typo * Zero nested_target_key and msb_count on exit * Note TODO (malloc) * Dismiss duplicate nonces * Fix calibration (ensure values are within 3 standard deviations) * Log static * No nested dictionary attack re-entry * Note minor inefficiency * Uniformly use crypto1_ prefix for symbols in Crypto1 API * Fix include paths * Fix include paths cont * Support CUID dictionary * Fix log levels * Avoid storage errors, clean up temporary files * Handle invalid key candidates * Fix memory leak in static encrypted attack * Fix memory leak, use COUNT_OF macro * Use single call to free FuriString * Refactor enums to avoid redefinition * Fix multiple crashes and state machine logic * Fix inconsistent assignment of known key and known key type/sector * Backdoor known key logic still needs the current key * Larger data type for 4K support * Fix typo * Fix issue with resume logic * Mark TODOs for next PR * Remove redundant assignment * Fix size_t format specifier * Simplify auth_passed condition Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com> Co-authored-by: gornekich <n.gorbadey@gmail.com>
249 lines
6.6 KiB
C
249 lines
6.6 KiB
C
#pragma once
|
|
|
|
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define MF_CLASSIC_CMD_AUTH_KEY_A (0x60U)
|
|
#define MF_CLASSIC_CMD_AUTH_KEY_B (0x61U)
|
|
#define MF_CLASSIC_CMD_BACKDOOR_AUTH_KEY_A (0x64U)
|
|
#define MF_CLASSIC_CMD_BACKDOOR_AUTH_KEY_B (0x65U)
|
|
#define MF_CLASSIC_CMD_READ_BLOCK (0x30U)
|
|
#define MF_CLASSIC_CMD_WRITE_BLOCK (0xA0U)
|
|
#define MF_CLASSIC_CMD_VALUE_DEC (0xC0U)
|
|
#define MF_CLASSIC_CMD_VALUE_INC (0xC1U)
|
|
#define MF_CLASSIC_CMD_VALUE_RESTORE (0xC2U)
|
|
#define MF_CLASSIC_CMD_VALUE_TRANSFER (0xB0U)
|
|
|
|
#define MF_CLASSIC_CMD_HALT_MSB (0x50)
|
|
#define MF_CLASSIC_CMD_HALT_LSB (0x00)
|
|
#define MF_CLASSIC_CMD_ACK (0x0A)
|
|
#define MF_CLASSIC_CMD_NACK (0x00)
|
|
#define MF_CLASSIC_CMD_NACK_TRANSFER_INVALID (0x04)
|
|
#define MF_CLASSIC_CMD_NACK_TRANSFER_CRC_ERROR (0x01)
|
|
|
|
#define MF_CLASSIC_TOTAL_SECTORS_MAX (40)
|
|
#define MF_CLASSIC_TOTAL_BLOCKS_MAX (256)
|
|
#define MF_CLASSIC_READ_MASK_SIZE (MF_CLASSIC_TOTAL_BLOCKS_MAX / 32)
|
|
#define MF_CLASSIC_BLOCK_SIZE (16)
|
|
#define MF_CLASSIC_KEY_SIZE (6)
|
|
#define MF_CLASSIC_ACCESS_BYTES_SIZE (4)
|
|
|
|
#define MF_CLASSIC_NT_SIZE (4)
|
|
#define MF_CLASSIC_NR_SIZE (4)
|
|
#define MF_CLASSIC_AR_SIZE (4)
|
|
#define MF_CLASSIC_AT_SIZE (4)
|
|
|
|
typedef enum {
|
|
MfClassicErrorNone,
|
|
MfClassicErrorNotPresent,
|
|
MfClassicErrorProtocol,
|
|
MfClassicErrorAuth,
|
|
MfClassicErrorPartialRead,
|
|
MfClassicErrorTimeout,
|
|
} MfClassicError;
|
|
|
|
typedef enum {
|
|
MfClassicTypeMini,
|
|
MfClassicType1k,
|
|
MfClassicType4k,
|
|
|
|
MfClassicTypeNum,
|
|
} MfClassicType;
|
|
|
|
typedef enum {
|
|
MfClassicActionDataRead,
|
|
MfClassicActionDataWrite,
|
|
MfClassicActionDataInc,
|
|
MfClassicActionDataDec,
|
|
|
|
MfClassicActionKeyARead,
|
|
MfClassicActionKeyAWrite,
|
|
MfClassicActionKeyBRead,
|
|
MfClassicActionKeyBWrite,
|
|
MfClassicActionACRead,
|
|
MfClassicActionACWrite,
|
|
} MfClassicAction;
|
|
|
|
typedef enum {
|
|
MfClassicValueCommandIncrement,
|
|
MfClassicValueCommandDecrement,
|
|
MfClassicValueCommandRestore,
|
|
|
|
MfClassicValueCommandInvalid,
|
|
} MfClassicValueCommand;
|
|
|
|
typedef struct {
|
|
uint8_t data[MF_CLASSIC_BLOCK_SIZE];
|
|
} MfClassicBlock;
|
|
|
|
typedef enum {
|
|
MfClassicKeyTypeA,
|
|
MfClassicKeyTypeB,
|
|
} MfClassicKeyType;
|
|
|
|
typedef struct {
|
|
uint8_t data[MF_CLASSIC_KEY_SIZE];
|
|
} MfClassicKey;
|
|
|
|
typedef struct {
|
|
uint8_t data[MF_CLASSIC_ACCESS_BYTES_SIZE];
|
|
} MfClassicAccessBits;
|
|
|
|
typedef struct {
|
|
uint8_t data[MF_CLASSIC_NT_SIZE];
|
|
} MfClassicNt;
|
|
|
|
typedef struct {
|
|
uint8_t data[MF_CLASSIC_AT_SIZE];
|
|
} MfClassicAt;
|
|
|
|
typedef struct {
|
|
uint8_t data[MF_CLASSIC_NR_SIZE];
|
|
} MfClassicNr;
|
|
|
|
typedef struct {
|
|
uint8_t data[MF_CLASSIC_AR_SIZE];
|
|
} MfClassicAr;
|
|
|
|
typedef struct {
|
|
uint8_t block_num;
|
|
MfClassicKey key;
|
|
MfClassicKeyType key_type;
|
|
MfClassicNt nt;
|
|
MfClassicNr nr;
|
|
MfClassicAr ar;
|
|
MfClassicAt at;
|
|
} MfClassicAuthContext;
|
|
|
|
typedef union {
|
|
MfClassicBlock block;
|
|
struct {
|
|
MfClassicKey key_a;
|
|
MfClassicAccessBits access_bits;
|
|
MfClassicKey key_b;
|
|
};
|
|
} MfClassicSectorTrailer;
|
|
|
|
typedef struct {
|
|
uint64_t key_a_mask;
|
|
MfClassicKey key_a[MF_CLASSIC_TOTAL_SECTORS_MAX];
|
|
uint64_t key_b_mask;
|
|
MfClassicKey key_b[MF_CLASSIC_TOTAL_SECTORS_MAX];
|
|
} MfClassicDeviceKeys;
|
|
|
|
typedef struct {
|
|
Iso14443_3aData* iso14443_3a_data;
|
|
MfClassicType type;
|
|
uint32_t block_read_mask[MF_CLASSIC_READ_MASK_SIZE];
|
|
uint64_t key_a_mask;
|
|
uint64_t key_b_mask;
|
|
MfClassicBlock block[MF_CLASSIC_TOTAL_BLOCKS_MAX];
|
|
} MfClassicData;
|
|
|
|
extern const NfcDeviceBase nfc_device_mf_classic;
|
|
|
|
MfClassicData* mf_classic_alloc(void);
|
|
|
|
void mf_classic_free(MfClassicData* data);
|
|
|
|
void mf_classic_reset(MfClassicData* data);
|
|
|
|
void mf_classic_copy(MfClassicData* data, const MfClassicData* other);
|
|
|
|
bool mf_classic_verify(MfClassicData* data, const FuriString* device_type);
|
|
|
|
bool mf_classic_load(MfClassicData* data, FlipperFormat* ff, uint32_t version);
|
|
|
|
bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff);
|
|
|
|
bool mf_classic_is_equal(const MfClassicData* data, const MfClassicData* other);
|
|
|
|
const char* mf_classic_get_device_name(const MfClassicData* data, NfcDeviceNameType name_type);
|
|
|
|
const uint8_t* mf_classic_get_uid(const MfClassicData* data, size_t* uid_len);
|
|
|
|
bool mf_classic_set_uid(MfClassicData* data, const uint8_t* uid, size_t uid_len);
|
|
|
|
Iso14443_3aData* mf_classic_get_base_data(const MfClassicData* data);
|
|
|
|
uint8_t mf_classic_get_total_sectors_num(MfClassicType type);
|
|
|
|
uint16_t mf_classic_get_total_block_num(MfClassicType type);
|
|
|
|
uint8_t mf_classic_get_first_block_num_of_sector(uint8_t sector);
|
|
|
|
uint8_t mf_classic_get_blocks_num_in_sector(uint8_t sector);
|
|
|
|
uint8_t mf_classic_get_sector_trailer_num_by_sector(uint8_t sector);
|
|
|
|
uint8_t mf_classic_get_sector_trailer_num_by_block(uint8_t block);
|
|
|
|
MfClassicSectorTrailer*
|
|
mf_classic_get_sector_trailer_by_sector(const MfClassicData* data, uint8_t sector_num);
|
|
|
|
bool mf_classic_is_sector_trailer(uint8_t block);
|
|
|
|
void mf_classic_set_sector_trailer_read(
|
|
MfClassicData* data,
|
|
uint8_t block_num,
|
|
MfClassicSectorTrailer* sec_tr);
|
|
|
|
uint8_t mf_classic_get_sector_by_block(uint8_t block);
|
|
|
|
bool mf_classic_block_to_value(const MfClassicBlock* block, int32_t* value, uint8_t* addr);
|
|
|
|
void mf_classic_value_to_block(int32_t value, uint8_t addr, MfClassicBlock* block);
|
|
|
|
bool mf_classic_is_key_found(
|
|
const MfClassicData* data,
|
|
uint8_t sector_num,
|
|
MfClassicKeyType key_type);
|
|
|
|
void mf_classic_set_key_found(
|
|
MfClassicData* data,
|
|
uint8_t sector_num,
|
|
MfClassicKeyType key_type,
|
|
uint64_t key);
|
|
|
|
void mf_classic_set_key_not_found(
|
|
MfClassicData* data,
|
|
uint8_t sector_num,
|
|
MfClassicKeyType key_type);
|
|
|
|
MfClassicKey
|
|
mf_classic_get_key(const MfClassicData* data, uint8_t sector_num, MfClassicKeyType key_type);
|
|
|
|
bool mf_classic_is_block_read(const MfClassicData* data, uint8_t block_num);
|
|
|
|
void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data);
|
|
|
|
bool mf_classic_is_sector_read(const MfClassicData* data, uint8_t sector_num);
|
|
|
|
void mf_classic_get_read_sectors_and_keys(
|
|
const MfClassicData* data,
|
|
uint8_t* sectors_read,
|
|
uint8_t* keys_found);
|
|
|
|
bool mf_classic_is_card_read(const MfClassicData* data);
|
|
|
|
bool mf_classic_is_value_block(MfClassicSectorTrailer* sec_tr, uint8_t block_num);
|
|
|
|
bool mf_classic_is_allowed_access_data_block(
|
|
MfClassicSectorTrailer* sec_tr,
|
|
uint8_t block_num,
|
|
MfClassicKeyType key_type,
|
|
MfClassicAction action);
|
|
|
|
bool mf_classic_is_allowed_access(
|
|
MfClassicData* data,
|
|
uint8_t block_num,
|
|
MfClassicKeyType key_type,
|
|
MfClassicAction action);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|