mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-07-05 20:41:34 -07:00
Major update to EM4x70 support:
1. Rework how communications with tag occur. a. bitstream to be sent to the tag is now fully pre-generated. b. bits sent and received are logged with start / end times. 2. Support built-in `hw dbg` for controlling verbosity of debug output The new bitstream generation and logging has exposed a surprising legacy behavior ... each of the command that sent additional data (beyond the command) were: * inserting an extra RM zero bit * force-enabling command parity is used This was not expected. However, this PR maintains the behavior of the existing code. TODO: Root-cause why the third RM bit is needed. Fix code to remove that hack. TODO: change the arm/client interface to ONLY use arrays of bytes, with well-defined content endianness, to avoid this problem.
This commit is contained in:
parent
f31ee2633f
commit
21ad101ff5
6 changed files with 2653 additions and 243 deletions
1176
armsrc/em4x70.c
1176
armsrc/em4x70.c
File diff suppressed because it is too large
Load diff
|
@ -19,12 +19,11 @@
|
|||
#ifndef EM4x70_H
|
||||
#define EM4x70_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "../include/em4x70.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[32];
|
||||
} em4x70_tag_t;
|
||||
|
||||
typedef enum {
|
||||
RISING_EDGE,
|
||||
FALLING_EDGE
|
||||
|
|
|
@ -34,9 +34,15 @@
|
|||
|
||||
// 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).
|
||||
|
||||
typedef struct _em4x70_tag_info_t {
|
||||
/// <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₅₆
|
||||
/// [30] == Block 15 LSB == UM2₅₅..UM2₄₈
|
||||
/// [29] == Block 14 MSB == UM2₄₇..UM2₄₀
|
||||
|
@ -168,6 +174,7 @@ typedef struct _em4x70_cmd_input_calculate_t {
|
|||
ID48LIB_KEY key;
|
||||
ID48LIB_NONCE rn;
|
||||
} em4x70_cmd_input_calculate_t;
|
||||
|
||||
typedef struct _em4x70_cmd_output_calculate_t {
|
||||
ID48LIB_FRN frn;
|
||||
ID48LIB_GRN grn;
|
||||
|
|
147
doc/md/em4x70/arbitrary_lf_em_commands.md
Normal file
147
doc/md/em4x70/arbitrary_lf_em_commands.md
Normal 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;
|
||||
```
|
||||
|
||||
|
||||
|
1517
doc/md/em4x70/lf_em4x70_trace_notes.md
Normal file
1517
doc/md/em4x70/lf_em4x70_trace_notes.md
Normal file
File diff suppressed because it is too large
Load diff
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define EM4X70_NUM_BLOCKS 16
|
||||
|
||||
|
@ -28,24 +29,36 @@
|
|||
#define EM4X70_PIN_WORD_LOWER 10
|
||||
#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 {
|
||||
// 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;
|
||||
|
||||
// Used for writing address
|
||||
uint8_t address;
|
||||
// ISSUE: Presumes target is little-endian
|
||||
// BUGBUG: Non-portable ... presumes stored in little-endian form!
|
||||
uint16_t word;
|
||||
|
||||
// PIN to unlock
|
||||
// BUGBUG: Non-portable ... presumes stored in little-endian form!
|
||||
uint32_t pin;
|
||||
|
||||
// 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 grnd[3];
|
||||
uint8_t rnd[7];
|
||||
|
@ -54,9 +67,20 @@ typedef struct {
|
|||
uint8_t crypt_key[12];
|
||||
|
||||
// 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;
|
||||
|
||||
} 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__ */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue