1
mirror of https://github.com/flipperdevices/flipperzero-firmware.git synced 2025-12-12 12:51:22 +04:00
Files
Nathan N 8427ec0098 MIFARE Classic Key Recovery Improvements (#3822)
* 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>
2024-10-31 09:53:58 +09:00

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