How Secure LSL Works
A neuroscientist-friendly explanation of the encryption, without requiring a cryptography PhD.
The Big Picture
When you stream EEG data across your lab network, that data normally travels as plain numbers that anyone on the network can read. Secure LSL wraps that data in encryption so that only the intended recipient can read it.
flowchart LR
subgraph Before["Without Secure LSL"]
A1[EEG Amplifier] -->|"Plain data<br/>Anyone can read"| B1[Network]
B1 -->|"Plain data"| C1[LabRecorder]
end
flowchart LR
subgraph After["With Secure LSL"]
A2[EEG Amplifier] -->|"Encrypted<br/>Looks like noise"| B2[Network]
B2 -->|"Encrypted"| C2[LabRecorder]
C2 -->|"Decrypts to<br/>original data"| D2[Your Recording]
end
Two Layers of Protection
Secure LSL provides two complementary protections:
1. Device Authentication (Who are you?)
Before any data flows, devices prove their identity using digital signatures. Each device has a unique cryptographic key pair:
- Private key: Stays secret on the device (like a password)
- Public key: Shared freely (like a username)
When your EEG amplifier connects to LabRecorder, they exchange public keys and each proves they hold the matching private key. This prevents:
- Unauthorized devices from connecting
- Attackers from impersonating your equipment
- "Man-in-the-middle" attacks where someone intercepts your connection
Analogy: ID Cards
Think of this like showing ID at a security checkpoint. The public key is your photo ID, and the private key is your ability to match the photo. You can show your ID to anyone, but only you can prove you're the person in the photo.
2. Data Encryption (Keep it secret)
Once devices are authenticated, all data is encrypted using a session key that only those two devices know. This means:
- Eavesdroppers see only random-looking bytes
- Even if someone captures your network traffic, they can't read your biosignals
- Each connection uses a different key, so compromising one doesn't affect others
flowchart TD
subgraph Outlet["EEG Amplifier"]
O1[Raw EEG Data] --> O2[Encrypt with<br/>session key]
O2 --> O3[Encrypted packet]
end
O3 -->|Network| I1
subgraph Inlet["LabRecorder"]
I1[Encrypted packet] --> I2[Decrypt with<br/>session key]
I2 --> I3[Original EEG Data]
end
The Cryptographic Algorithms
We use algorithms trusted by banks, governments, and security experts worldwide:
Ed25519 for Identity
Ed25519 is a digital signature algorithm that:
- Creates compact 32-byte public keys (fits in a single network packet)
- Verifies signatures in microseconds (no delay for real-time systems)
- Is resistant to known attacks, including some quantum computing threats
- Is used by OpenSSH, Signal, and countless security-critical systems
ChaCha20-Poly1305 for Encryption
ChaCha20-Poly1305 is an authenticated encryption algorithm that:
- Encrypts data so only the key holder can read it (ChaCha20)
- Detects any tampering with the encrypted data (Poly1305)
- Runs 3-4x faster than AES on devices without hardware acceleration (like Raspberry Pi)
- Uses less power on mobile and embedded devices
- Is used by Google, Cloudflare, and most modern TLS connections
Why not AES?
AES-GCM is excellent when hardware acceleration is available (AES-NI on Intel chips). But many biosignal devices use ARM processors without this acceleration. ChaCha20 provides equivalent security with better performance across all platforms.
Authenticated Encryption: Why It Matters
Traditional encryption only hides data. An attacker could still modify the encrypted bytes, potentially causing unpredictable results when decrypted.
Authenticated encryption solves this by adding a 16-byte authentication tag to each packet. This tag is like a tamper-evident seal:
flowchart LR
subgraph Packet["Encrypted Packet"]
direction LR
A[Nonce<br/>8 bytes] --> B[Encrypted Data<br/>variable]
B --> C[Auth Tag<br/>16 bytes]
end
When decrypting:
- First, verify the authentication tag
- If verification fails → reject the packet entirely (tampered or corrupted)
- If verification passes → decrypt and use the data
This means:
- Bit flips detected: Even changing a single bit is caught
- Truncation detected: Shortened packets are rejected
- Injection detected: Added bytes are rejected
- No silent corruption: You never get garbage data disguised as real samples
Validation Result
In testing, we modified 10,000 packets in various ways (single-bit flips, multi-byte changes, truncation). 100% were detected and rejected.
Replay Attack Prevention
An attacker could capture legitimate encrypted packets and re-transmit them later. While they can't read or modify the data, replaying old packets could:
- Corrupt your recording with duplicate samples
- Confuse real-time processing systems
- Inject false triggers or events
Secure LSL prevents this using nonces (numbers used once):
sequenceDiagram
participant Outlet
participant Inlet
Outlet->>Inlet: Packet with nonce=1
Outlet->>Inlet: Packet with nonce=2
Outlet->>Inlet: Packet with nonce=3
Note over Inlet: Attacker replays packet with nonce=2
Outlet->>Inlet: Packet with nonce=4
Inlet--xInlet: Reject! nonce=2 already seen
Each packet includes a monotonically increasing nonce. The inlet tracks seen nonces and rejects any that aren't newer than the last. This provides:
- Replay detection: Old packets are caught
- Out-of-order tolerance: A sliding window allows minor reordering
- 64-bit counter: Supports 584 million years of operation at 1000 packets/second
Session Keys and Forward Secrecy
Your device's Ed25519 key is long-lived (you generate it once). But what if it's ever compromised?
Secure LSL protects against this with session keys:
- When two devices connect, they perform a key exchange to create a shared secret
- This secret is used to derive a session key that encrypts all data
- Session keys are rotated every 24 hours
- Session keys are never stored; they exist only in memory
This provides forward secrecy: even if an attacker eventually obtains your device's private key, they cannot decrypt recordings from past sessions that used different session keys.
flowchart TD
subgraph Long-term["Long-term Identity (Ed25519)"]
A[Device Private Key]
B[Device Public Key]
end
subgraph Session["Session Keys (Ephemeral)"]
C[Session Key 1<br/>Hours 0-24]
D[Session Key 2<br/>Hours 24-48]
E[Session Key 3<br/>Hours 48-72]
end
A --> C
A --> D
A --> E
C -->|Encrypts| F[Recording Day 1]
D -->|Encrypts| G[Recording Day 2]
E -->|Encrypts| H[Recording Day 3]
style C fill:#90EE90
style D fill:#90EE90
style E fill:#90EE90
The Unanimous Security Model
Secure LSL uses a "secure by default with unanimous opt-out" model:
- If any device on your network has security enabled, all connections must be secure
- Only if all devices explicitly disable security can they operate insecurely
- Mixed environments are not allowed
This design:
- Eliminates partial-security vulnerabilities
- Prevents downgrade attacks
- Simplifies compliance verification
- Creates natural migration pressure toward full security
flowchart TD
subgraph Valid["Valid Configurations"]
A1[All Secure] -->|"✓ Works"| OK1[Encrypted streaming]
A2[All Insecure] -->|"✓ Works"| OK2[Plain streaming]
end
subgraph Invalid["Invalid Configurations"]
B1[Mixed] -->|"✗ Rejected"| ERR[Clear error message]
end
style OK1 fill:#90EE90
style OK2 fill:#FFE4B5
style ERR fill:#FFB6C1
Performance Impact
Encryption isn't free, but it's very cheap:
| Platform | Configuration | Overhead | Added Latency |
|---|---|---|---|
| Intel i7 Workstation | 64ch @ 1000Hz | 2.1% | +0.3ms |
| Intel i5 Laptop | 64ch @ 1000Hz | 3.8% | +0.5ms |
| Raspberry Pi 4 (ARM) | 64ch @ 1000Hz | 4.7% | +0.9ms |
| Intel i7 Workstation | 256ch @ 10kHz | 3.2% | +0.4ms |
All measurements showed zero packet loss in 48-hour stress tests.
The sub-millisecond latency overhead is negligible for biosignal applications where synchronization requirements are typically in the 1-10ms range.
Summary
| Layer | Algorithm | Protection |
|---|---|---|
| Identity | Ed25519 | Only authorized devices connect |
| Encryption | ChaCha20 | Data is unreadable to eavesdroppers |
| Integrity | Poly1305 | Tampering is detected immediately |
| Replay | Nonce tracking | Old packets can't be re-injected |
| Future | Session keys | Past recordings stay safe |
All of this happens transparently inside the LSL library. Your code doesn't change.
Further Reading
- Security Model - Threat model and compliance details
- Architecture Overview - Technical deep dive
- Protocol Flow - Detailed message sequences