A Python implementation of the SoftRfp virtual DECT RFP (Radio Fixed Part) simulator. Connects to a Mitel OMM (Open Mobility Manager) and emulates an RFP device over the AaMiDe protocol.
Supports connecting as license RFPs, automatic re-enrollment, and running multiple virtual RFPs concurrently from a single process.
- Python 3.10+
cryptographypackage
pip install -r requirements.txtOr install as a package:
pip install .The simplest way to run is to point it at your OMM and config file. Without -m, it reads all license RFP MACs from the config and connects them all concurrently:
python -m virtualrfp -o 192.168.1.100 -c /path/to/omm_conf.txtTo connect a single specific RFP:
python -m virtualrfp -m 001122334455 -o 192.168.1.100 -c /path/to/omm_conf.txtpython -m virtualrfp -o <OMM_IP> [-m <MAC>] [-c <CONFIG>] [options]| Flag | Long | Required | Description |
|---|---|---|---|
-m |
--mac |
No | RFP MAC address. If omitted, reads license RFP MACs from omm_conf.txt and connects all of them |
-o |
--omm |
Yes | OMM IP address |
-k |
--key |
No | RFPA (Blowfish encryption key) in hex |
-c |
--config |
No | Path to omm_conf.txt (default: ../omm_conf.txt) |
-d |
--debug |
No | Dump raw packets in hex |
--sw-version |
No | Software version string (auto-detected from omm_conf.txt if not set) | |
--hw-type |
No | Hardware type to report (e.g. RFP35, RFP32, PC). Default: RFP35 |
|
--root-pw-hash |
No | OMM root password hash for re-enrollment (auto-read from omm_conf.txt if not set) | |
--force-enroll |
No | Send an invalid signature to force re-enrollment |
# Connect all license RFPs from config (simplest usage)
python -m virtualrfp -o 192.168.1.100 -c /path/to/omm_conf.txt
# Connect a single RFP with debug output
python -m virtualrfp -m 001122334455 -o 192.168.1.100 -c /path/to/omm_conf.txt -d
# Provide RFPA key directly (bypasses config file lookup)
python -m virtualrfp -m 001122334455 -o 192.168.1.100 -k abcdef01234567...
# Override hardware type
python -m virtualrfp -m 001122334455 -o 192.168.1.100 --hw-type RFP32If installed as a package, the virtualrfp command is also available:
virtualrfp -o 192.168.1.100 -c /path/to/omm_conf.txt- Opens a TCP connection to the OMM on port 16321
- Receives a random authentication challenge packet
- Sends a
SYS_INITmessage containing the RFP MAC, capabilities, AES-encrypted metadata, and an MD5 signature - Handles the init response:
- ACK -- RFP is already enrolled, proceed to encryption
- SYS_RFP_AUTH_KEY (0x0124) -- New RFPA key for first-time enrollment
- SYS_RFP_RE_ENROLEMENT (0x0125) -- RFPA encrypted with AES-256-ECB, decrypted using the OMM root password hash
- SYS_RESET (0x0121) -- Auto-reconnects after a delay
- Initializes Blowfish CBC encryption using the RFPA key (different key slices for RX and TX)
- Sends
SYS_ENCRYPTION_CONFto signal encrypted mode is active - Processes encrypted messages: heartbeats, license timers, and all other AaMiDe message types
The RFPA is a 64-byte Blowfish key used for the encrypted session. It can be obtained in several ways (checked in order):
- Init response -- The OMM may send the key as
SYS_RFP_AUTH_KEY(new enrollment) orSYS_RFP_RE_ENROLEMENT(re-enrollment with AES decryption) - Local key store -- Previously obtained keys are cached in
.virtualrfp_keys.jsonin the working directory - Config file -- Loaded from the
RFPAsection of omm_conf.txt (decrypted using the MAC as Blowfish ECB key) -kflag -- Pass the encrypted RFPA in hex directly- Wait mode -- If no key is available, the connection stays open waiting for the OMM to send one
When the OMM sends SYS_RFP_RE_ENROLEMENT, the RFPA is encrypted with AES-256-ECB using a key derived from the authentication challenge and the OMM root password hash. The root password hash is automatically read from the UA section of omm_conf.txt, or can be provided manually with --root-pw-hash.
When no -m flag is given, the tool reads the license RFP MAC addresses from the LIC section of omm_conf.txt and connects all of them concurrently as separate async tasks. Log output is prefixed with the last 4 hex digits of each MAC for identification (e.g. [39F3], [3E45]).
The following values are automatically read from omm_conf.txt when not explicitly provided:
- Software version -- From the config file header (e.g.
SIP-DECT 8.1SP3-FK24) - Protocol version -- Derived from the software version
- Root password hash -- From the
UAsection,rootuser entry - License RFP MACs -- From the
LICsection
virtualrfp/
├── pyproject.toml # Package configuration
├── requirements.txt # cryptography>=41.0.0
├── README.md
└── virtualrfp/
├── __init__.py
├── __main__.py # CLI entry point (multi-RFP support)
├── blowfish.py # Blowfish cipher (ECB/CBC)
├── hex_encoding.py # Hex encoding and endian swap utilities
├── messages.py # AaMiDe protocol message classes
├── omm_conf_reader.py # OMM config file parser (with MD5 validation)
└── virtual_rfp.py # Core VirtualRfp client
Python port of the C# SoftRfp project from the rfpproxy framework, originally presented at 36c3.