Say goodbye to the "IoT Security Gap"! USMP is a lightweight, secure, and developer-friendly session protocol designed to bring end-to-end encrypted, mutually authenticated tunnels to ESP32, Arduino, and Python.
In the world of IoT, developers are often forced to make a frustrating choice when connecting devices:
- Raw TCP / UDP: Fast and lightweight, but completely open to eavesdropping, spoofing, and tampering.
- Full TLS / DTLS: Rock-solid, but extremely heavy, slow to handshake, and resource-prohibitive for smaller microcontrollers.
USMP fills this gap. It gives you a lightweight, transport-agnostic, and secure tunnel that runs anywhere. Establishing a secure connection on your device is as simple as:
// 1. Initialize your choice of transport (TCP or UDP, supports IPs & DNS hostnames)
usmp_transport_udp_init(&transport, "usmp.mycompany.com", 9000);
// 2. Perform the handshake and establish a secure session
usmp_connect(&ctx, &transport);
// 3. Send encrypted data safely!
usmp_send(&ctx, data, len);Every single session is hardened:
- Mutual Authentication: Both sides verify identity using HMAC-SHA256 and a Pre-Shared Key (PSK) before exchanging payloads.
- Perfect Forward Secrecy: An ephemeral X25519 key exchange occurs with every session, protecting past traffic even if keys are compromised later.
- Mandatory Encryption: All payload data is encrypted using AES-256-GCM or ChaCha20-Poly1305.
- In-Band Session Rekeying: Transparent key rotation during active sessions via
PKT_REKEY. - Replay Protection: Strict, monotonic 32-bit sequence numbers are verified for every frame.
- Deterministic Nonces: Under the hood, AEAD nonces are constructed as
seq (4 bytes, Little-Endian) || session_id[0..7]to eliminate nonce collision risks.
- Multi-Transport Support: Production-ready support for TCP and UDP (with transport-level reliability overlays), with UART and BLE coming soon!
- Platform Agnostic Core: A pure C core with only 5 platform hooks to implement for any new platform.
- Dynamic Payload Fragmentation: Automatically fragments payloads up to ~1.8 KB into multiple frames (plaintext capacity of 452 bytes per frame) and transparently reassembles them at the receiver.
- Built-in Rate Limiting: The Python server locks out offending IPs for 60 seconds after consecutive handshake failures to prevent brute-force attacks.
- Registry-Based Distribution:
- Python: Fully async SDK available on PyPI (
pip install usmp). - ESP-IDF: Native component on the ESP Component Registry (
metaloomlabs/usmp). - Arduino: Standard packaged offline ZIP library (
usmp-1.2.0-arduino.zip).
- Python: Fully async SDK available on PyPI (
| Platform | Status | Getting Started |
|---|---|---|
| ESP32 (ESP-IDF v5+) | Production ready | ESP-IDF Port Guide |
| ESP32 (Arduino) | Production ready | Arduino Reference |
| Python 3.11+ | Production ready | Python SDK Reference |
| STM32 | Planned | - |
| Linux | Planned | - |
Run pip install usmp and launch this async gateway server:
import asyncio
from usmp import USMPServer, USMPSession, USMPProtocol, ConnectionClosedError
PSK = b"usmp-dev-psk-change-me-before-prod"
# Initialize TCP or UDP server
server = USMPServer(host="0.0.0.0", port=9000, psk=PSK, protocol=USMPProtocol.TCP)
@server.on_session
async def handle_device(session: USMPSession):
print(f"Device connected: {session.device_id}")
try:
while True:
# Receive decrypted data
data = await session.recv()
print(f"Received: {data.decode('utf-8')}")
# Send an encrypted reply
await session.send(b"Got your message loud and clear!")
except ConnectionClosedError:
print(f"Device disconnected: {session.device_id}")
async def main():
print("Starting USMP Server on port 9000...")
await server.serve()
if __name__ == "__main__":
asyncio.run(main())Import metaloomlabs/usmp in your project component dependencies and write:
#include "usmp.h"
#include "usmp_transport.h"
void app_main(void) {
wifi_init(); // Configure your standard Wi-Fi
usmp_t ctx = {0};
usmp_transport_t transport = {0};
static const uint8_t s_psk[] = "usmp-dev-psk-change-me-before-prod";
ctx.psk = s_psk;
ctx.psk_len = sizeof(s_psk) - 1;
// Use usmp_transport_tcp_init or usmp_transport_udp_init
if (usmp_transport_tcp_init(&transport, "192.168.1.100", 9000) == 0) {
if (usmp_connect(&ctx, &transport) == 0) {
printf("Secure session established!\n");
}
}
ctx.keepalive_ms = 15000;
usmp_send(&ctx, (const uint8_t *)"Hello, USMP!", 12);
while (true) {
vTaskDelay(pdMS_TO_TICKS(1000));
// Maintain the watchdog & auto-reconnect on drops
if (usmp_keepalive_tick(&ctx) < 0) {
printf("Connection lost, reconnecting...\n");
usmp_reconnect(&ctx);
}
}
}Add the offline ZIP library and upload:
#include <USMP.h>
#define PSK "usmp-dev-psk-change-me-before-prod"
#define SERVER_IP "192.168.1.100"
#define WIFI_SSID "YourNetwork"
#define WIFI_PASS "YourPassword"
USMPClient usmp(PSK);
void setup() {
Serial.begin(115200);
// Swap to USMP::UDP(SERVER_IP) to run over UDP!
if (!usmp.begin(USMP::TCP(SERVER_IP).wifi(WIFI_SSID, WIFI_PASS))) {
Serial.println("Connection failed!");
return;
}
usmp.keepalive(15000); // Configure keepalive interval
usmp.send("Hello from Arduino ESP32!");
}
void loop() {
// Maintains keepalives & reconnects automatically in background
usmp.maintain();
if (usmp.available()) {
String msg = usmp.read();
Serial.println("Received: " + msg);
}
}For examples and component guides:
USMP uses Pre-Shared Key (PSK) authentication, which is vulnerable to offline brute-force attacks on captured handshake transcripts.
Unlike PAKE protocols (SPAKE2, CPace), an attacker who records a USMP handshake can attempt to crack the PSK offline. The 16-byte minimum length is enforced, but length ≠ entropy.
You must:
- Use cryptographically random PSKs (
os.urandom(32)or hardware RNG) — not human-readable passphrases. - Store PSKs in secure storage (encrypted NVS, secure elements, HSMs).
- Never hardcode PSKs in source code or firmware.
See SECURITY.md for the full disclosure and mitigation guidance. A PAKE upgrade is planned for a future release.
- v0.2.0: Core protocol, Keepalive mechanism, and Arduino Port.
- v0.3.0: TCP transport support and initial Python SDK.
- v0.4.0: Published on ESP Component Registry and PyPI, making it stable.
- v0.4.7: Security hardening (Deterministic Nonces, Lockout Rate Limiting, Dynamic Fragmentation).
- v0.5.0: UDP transport support fully complete and production-ready.
- v1.1.0: Hardening & security fixes, CLI tools reference.
- v1.2.0: ChaCha20-Poly1305 cipher suite, In-Band Session Rekeying (
PKT_REKEY), Adaptive UDP RTT estimation, and Arduino control frame decoupling.
We welcome all contributions! Please review our Contributing Guidelines and adhere to our Code of Conduct before submitting a Pull Request.
For security concerns, please refer to our Security Policy.
USMP is open-source software licensed under the Apache 2.0 License.
USMP™ • Developed by Metaloom