Merge pull request #2785 from henrygab/em4x70

Em4x70 - Major improvements to tracing, stability, and debugability
This commit is contained in:
Iceman 2025-03-18 07:37:52 +01:00 committed by GitHub
commit f2380fe619
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 2654 additions and 243 deletions

View file

@ -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... 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] ## [unreleased][unreleased]
- Major update to `lf em 4x70` internals on ARM side; Enabling improved debugging and reliability (@henrygab)
- Improved `pcf7931` generic readability of the code. Unified datatypes and added documentation/explainations (@tinooo) - Improved `pcf7931` generic readability of the code. Unified datatypes and added documentation/explainations (@tinooo)
- Improved `lf pcf7931` read code - fixed some checks for more stability (@tinooo) - Improved `lf pcf7931` read code - fixed some checks for more stability (@tinooo)
- Changed `trace list -t seos` - improved annotation (@iceman1001) - Changed `trace list -t seos` - improved annotation (@iceman1001)

File diff suppressed because it is too large Load diff

View file

@ -19,12 +19,11 @@
#ifndef EM4x70_H #ifndef EM4x70_H
#define EM4x70_H #define EM4x70_H
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include "../include/em4x70.h" #include "../include/em4x70.h"
typedef struct {
uint8_t data[32];
} em4x70_tag_t;
typedef enum { typedef enum {
RISING_EDGE, RISING_EDGE,
FALLING_EDGE FALLING_EDGE

View file

@ -34,9 +34,15 @@
// TODO: Optional: use those unique structures in a union, call it em4x70_data_t, but add a first // TODO: Optional: use those unique structures in a union, call it em4x70_data_t, but add a first
// common header field that includes the command itself (to improve debugging / validation). // common header field that includes the command itself (to improve debugging / validation).
typedef struct _em4x70_tag_info_t { typedef struct _em4x70_tag_info_t {
/// <summary> /// <summary>
/// The full data on an em4x70 the tag. /// The full data on an em4170 tag.
/// For V4070 tags:
/// * UM2 does not exist on the tag
/// * Pin does not exist on the tag
/// * UM1 (including the lock bits) might be one-time programmable (OTP)
///
/// [31] == Block 15 MSB == UM2₆₃..UM2₅₆ /// [31] == Block 15 MSB == UM2₆₃..UM2₅₆
/// [30] == Block 15 LSB == UM2₅₅..UM2₄₈ /// [30] == Block 15 LSB == UM2₅₅..UM2₄₈
/// [29] == Block 14 MSB == UM2₄₇..UM2₄₀ /// [29] == Block 14 MSB == UM2₄₇..UM2₄₀
@ -168,6 +174,7 @@ typedef struct _em4x70_cmd_input_calculate_t {
ID48LIB_KEY key; ID48LIB_KEY key;
ID48LIB_NONCE rn; ID48LIB_NONCE rn;
} em4x70_cmd_input_calculate_t; } em4x70_cmd_input_calculate_t;
typedef struct _em4x70_cmd_output_calculate_t { typedef struct _em4x70_cmd_output_calculate_t {
ID48LIB_FRN frn; ID48LIB_FRN frn;
ID48LIB_GRN grn; ID48LIB_GRN grn;

View file

@ -0,0 +1,147 @@
# arbitrary lf em commands
Goals:
1. Improved logging of `lf em` commands and responses
2. Greater certainty in command sequences
3. Easier testing of new commands
## Methodology
This is documenting the actual commands used by existing code. Phases include:
* Document the existing command sequences
* Document the existing logging APIs
* Define small set of timing-sensitive functions as abstractions
* Implement the abstractions
* Add logging
The goal is to improve logging and debugging, and allow easily testing new LF commands.
## EM4x70 (aka ID48, aka Megamos)
Only six command sequences currently used:
#define EM4X70_COMMAND_ID 0x01
#define EM4X70_COMMAND_UM1 0x02
#define EM4X70_COMMAND_AUTH 0x03
#define EM4X70_COMMAND_PIN 0x04
#define EM4X70_COMMAND_WRITE 0x05
#define EM4X70_COMMAND_UM2 0x07
### ID Command
Wait for `LIW` (listen window), and start transmission at next `LIW`:
source | bits | comment
----------|---------|---------
tag | LIW | listen window sync
reader | `0b00` | RM
reader | `0b001` | CMD
reader | `0b1` | command parity bit
tag | HEADER | HEADER (0b1111'1111'1111'0000)
tag | 32-bits | ID (D31..D0)
tag | LIW | tag reverts to be ready for next command
### UM1 Command
source | bits | comment
----------|---------|---------
tag | LIW | listen window
reader | `0b00` | RM
reader | `0b010` | CMD
reader | `0b1` | command parity bit
tag | 16-bits | HEADER
tag | 32-bits | UM1 data
tag | LIW | tag reverts to be ready for next command
### UM2 Command
source | bits | comment
----------|---------|---------
tag | LIW | listen window
reader | `0b00` | RM
reader | `0b111` | CMD
reader | `0b1` | command parity bit
tag | 16-bits | HEADER
tag | 64-bits | UM2 data
tag | LIW | tag reverts to be ready for next command
### Auth Command
source | bits | comment
----------|---------|---------
tag | LIW | listen window
reader | `0b00` | RM
reader | `0b011` | CMD
reader | `0b0` | command parity bit
reader | 56-bits | RN
reader | 7-bits | Tdiv == 0b0000000 (always zero)
reader | 28-bits | f(RN)
tag | 16-bits | HEADER
tag | 20-bits | g(RN)
tag | LIW | tag reverts to be ready for next command
### Write Word
source | bits | comment
----------|---------|---------
tag | LIW | listen window
reader | `0b00` | RM
reader | `0b101` | CMD
reader | `0b0` | command parity bit
reader | 4-bits | address/block to write
reader | 1-bit | address/block parity bit
reader | 25-bits | 5x5 data w/ row and column parity
tag | ACK | Wait (TWA) for ACK ... time to wait before searching for ACK
tag | ACK | Wait (WEE) for ACK ... time to wait before searching for ACK
tag | LIW | tag reverts to be ready for next command
### PIN Command
source | bits | comment
----------|---------|---------
tag | LIW | listen window
reader | `0b00` | RM
reader | `0b100` | CMD
reader | `0b1` | command parity bit
reader | 32-bits | ID of the tag
reader | 32-bits | PIN
tag | ACK | Wait (TWALB) for ACK ... time to wait before searching for ACK
tag | HEADER | DELAYED (TWEE) header ... time to wait before searching for header
tag | 32-bits | ID of the tag
tag | LIW | tag reverts to be ready for next command
### Abstraction required
Possible items to abstract:
* bits to send: quantity of bits to be sent + storage containing those bits
* bits to receive: expected bits to receive + storage to receive those bits
* LIW: special-case handling to synchronize next command
* ACK: special-case handling to wait for ACK
* HEADER: special-case handling to wait for HEADER
* DELAY: ticks to delay before processing next item
Special handling required for:
* `HEADER` --> 12-bits of zero, 4-bits of one. Consider a timeout: if tag disappears, no pulse found, while sometimes expect long time before HEADER appears (as in SEND_PIN). Read of header may miss the first few bits during transition, so need to special-case handling of this detection.
* `LIW` --> Timing-sensitive, syncs reader with tag ... reader must send during 32 period where chip's modulator is ON.
* `ACK` --> This is currently a time-to-delay.
Should this be a maximum time to wait for ACK?
Currently, could sit waiting for long time
if no tag present, as `check_ack()` has no timeout.
```C
WaitTicks(EM4X70_T_TAG_TWA);
if (check_ack())
WaitTicks(EM4X70_T_TAG_WEE);
if (check_ack())
return PM3_SUCCESS;
```

File diff suppressed because it is too large Load diff

View file

@ -21,6 +21,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <assert.h>
#define EM4X70_NUM_BLOCKS 16 #define EM4X70_NUM_BLOCKS 16
@ -28,24 +29,36 @@
#define EM4X70_PIN_WORD_LOWER 10 #define EM4X70_PIN_WORD_LOWER 10
#define EM4X70_PIN_WORD_UPPER 11 #define EM4X70_PIN_WORD_UPPER 11
/// @brief Command transport structure for EM4x70 commands.
/// @details
/// This structure is used to transport data from the PC
/// to the proxmark3, and contain all data needed for
/// a given `lf em 4x70 ...` command to be processed
/// on the proxmark3.
/// The only requirement is that this structure remain
/// smaller than the NG buffer size (256 bytes).
typedef struct { typedef struct {
// ISSUE: `bool` type does not have a standard-defined size.
// therefore, compatibility between architectures /
// compilers is not guaranteed.
// ISSUE: C99 has no _Static_assert() ... was added in C11
// TODO: add _Static_assert(sizeof(bool)==1);
// TODO: add _Static_assert(sizeof(em4x70_data_t)==36);
bool parity; bool parity;
// Used for writing address // Used for writing address
uint8_t address; uint8_t address;
// ISSUE: Presumes target is little-endian // BUGBUG: Non-portable ... presumes stored in little-endian form!
uint16_t word; uint16_t word;
// PIN to unlock // PIN to unlock
// BUGBUG: Non-portable ... presumes stored in little-endian form!
uint32_t pin; uint32_t pin;
// Used for authentication // Used for authentication
//
// IoT safe subset of C++ would be helpful here,
// to support variable-bit-length integer types
// as integral integer types.
//
// Even C23 would work for this (GCC14+, Clang15+):
// _BitInt(56) rnd;
// _BitInt(28) frnd;
// _BitInt(20) grnd;
uint8_t frnd[4]; uint8_t frnd[4];
uint8_t grnd[3]; uint8_t grnd[3];
uint8_t rnd[7]; uint8_t rnd[7];
@ -54,9 +67,20 @@ typedef struct {
uint8_t crypt_key[12]; uint8_t crypt_key[12];
// used for bruteforce the partial key // used for bruteforce the partial key
// ISSUE: Presumes target is little-endian // BUGBUG: Non-portable ... presumes stored in little-endian form!
uint16_t start_key; uint16_t start_key;
} em4x70_data_t; } em4x70_data_t;
//_Static_assert(sizeof(em4x70_data_t) == 36);
// ISSUE: `bool` type does not have a standard-defined size.
// therefore, compatibility between architectures /
// compilers is not guaranteed.
// TODO: verify alignof(bool) == 1
//_Static_assert(sizeof(bool) == 1, "bool size mismatch");
typedef union {
uint8_t data[32];
} em4x70_tag_t;
//_Static_assert(sizeof(em4x70_tag_t) == 32, "em4x70_tag_t size mismatch");
#endif /* EM4X70_H__ */ #endif /* EM4X70_H__ */