Quick Start Guide
Get your LSL streams encrypted in under 5 minutes. No code changes required for dynamically linked applications.
Prerequisites
- An existing LSL setup (outlets and inlets working)
- Secure LSL library installed (see Installation)
Step 1: Generate and Distribute Encryption Keys
On your primary device (e.g., the admin workstation), generate and export a shared keypair:
You'll be prompted for a passphrase to protect the exported key:
LSL Security Key Generator - Export Mode
========================================
Exported keys are always passphrase-protected for security.
Enter passphrase for exported key: ********
Confirm passphrase: ********
Generating Ed25519 keypair...
[OK] Keypair generated successfully!
[OK] Public key saved to: lab_shared.pub
[OK] Encrypted private key saved to: lab_shared.key.enc
Fingerprint: BLAKE2b:70:14:e1:b5:7f:93:ae:af...
To use this key on another device:
1. Copy lab_shared.key.enc to the target device
2. Run: lsl-keygen --import lab_shared.key.enc
3. Enter the same passphrase when prompted
Passphrase Protection
Like SSH keys, the private key is encrypted with a passphrase by default. This provides two-factor authentication: something you have (the key file) plus something you know (the passphrase).
For convenience on lab workstations, you can create a device-bound session token that remembers the passphrase securely:
Low-risk Environments
For closed lab environments without regulatory requirements (EU CRA, NIS2, HIPAA, GDPR), you can skip the passphrase by pressing Enter twice (with confirmation), or use:
Then import the key on every device, including the primary device:
--export Generates a New Key
lsl-keygen --export generates a new keypair and writes it to portable files.
It does not install the key into your local config. You must run --import on
every device, including the machine that generated the key.
If you already have a key in your config and want to export it for other devices,
use --export-existing instead:
# On the primary device (the one that generated the key)
./lsl-keygen --import lab_shared.key.enc
# Enter the same passphrase used during generation
# Copy the encrypted key to each other device
scp lab_shared.key.enc user@device2:~/
# On each other device, import the shared key
./lsl-keygen --import lab_shared.key.enc
# Enter the same passphrase used during generation
# (Optional) Create a device-bound session token for convenience
./lsl-config --remember-device --passphrase
See Multi-Device Setup for details.
Step 2: Verify Configuration
Check that security is properly configured:
Expected output:
LSL Security Configuration Status
==================================
Security subsystem: initialized
Security enabled: YES
Config file: /Users/you/.lsl_api/lsl_api.cfg
Key fingerprint: BLAKE2b:70:14:e1:b5:7f:93:ae:af...
Key created: 2025-12-05T19:00:00Z
Session lifetime: 3600 seconds
Device token: not set
[OK] Configuration valid
Step 3: Run Your Applications
That's it! Your existing LSL applications now stream encrypted data automatically.
Verifying You're Using Secure LSL
Before anything else, verify you're using the secure library:
#include <lsl_cpp.h>
#include <iostream>
int main() {
std::cout << "Secure build: " << lsl::is_secure_build() << "\n";
std::cout << "Base version: " << lsl::base_version() << "\n";
std::cout << "Security version: " << lsl::security_version() << "\n";
std::cout << "Full version: " << lsl::full_version() << "\n";
return 0;
}
// Output:
// Secure build: 1
// Base version: 1.16.1
// Security version: 1.0.0
// Full version: 1.16.1-secure.1.0.0-alpha
Wrong Library?
If you see lsl::is_secure_build() = 0 or the library info doesn't contain "security",
you're using the regular liblsl. See Migration Guide for how to switch.
Verifying Encryption is Active
Check Stream Security Status
You can verify a stream is encrypted using the security API:
import lsl_security_helper # must come before import pylsl
import pylsl
streams = pylsl.resolve_stream('type', 'EEG')
for stream in streams:
if stream.security_enabled():
print(f"[secure] {stream.name()} is encrypted")
print(f" Fingerprint: {stream.security_fingerprint()}")
else:
print(f"[warning] {stream.name()} is NOT encrypted")
Visual Confirmation in LabRecorder
With the secure version of LabRecorder, encrypted streams show a lock icon:
Available Streams:
🔒 EEG-Amplifier (lab-eeg-01)
🔒 EyeTracker (lab-eye-01)
🔒 MotionCapture (lab-mocap-01)
What About Devices Without Keys?
Secure LSL uses unanimous security enforcement:
- If your device has security enabled, it will only connect to other secured devices
- Connections to unsecured devices fail with a clear error message:
Connection refused: outlet does not have security enabled.
Unanimous security enforcement requires all devices to use encryption.
This ensures you never accidentally mix encrypted and unencrypted streams.
All or Nothing
All devices in your lab must have the same shared key imported. Partial deployment is intentionally not supported to prevent security gaps.
Troubleshooting
"Connection refused: security mismatch"
One device has security enabled, another doesn't. Ensure all devices have the same shared key imported via ./lsl-keygen --import.
"Configuration file not found"
Run lsl-keygen to generate the configuration file.
Streams aren't connecting
Check that all devices have the same security state:
See full troubleshooting guide →