Skip to content

Migration from LSL to Secure LSL

This guide helps existing LSL users transition to Secure LSL with minimal friction.

What Changes

Aspect Regular LSL Secure LSL
Binary name liblsl.dylib liblsl-secure.dylib
Configuration Optional lsl_api.cfg Required [security] section
Your code - No changes needed
Network traffic Plaintext Encrypted
Discovery Works Works (with security metadata)

What Stays the Same

  • All API functions (C, C++, Python, MATLAB)
  • Stream discovery mechanism
  • XDF file format (data is decrypted before recording)
  • Channel formats and timestamps
  • All 150+ LSL applications

Migration Steps

Step 1: Install Secure liblsl (2 minutes)

# Option A: Build from source
brew install libsodium cmake
cd secureLSL/liblsl
mkdir build && cd build
cmake -DLSL_SECURITY=ON ..
make -j4

# Option B: Download release (when available)
# brew install sccn/tap/liblsl-secure
# Install dependencies
sudo apt install libsodium-dev cmake build-essential

# Build
cd secureLSL/liblsl
mkdir build && cd build
cmake -DLSL_SECURITY=ON ..
make -j4
sudo make install
# Install libsodium via vcpkg
vcpkg install libsodium

# Build
cd secureLSL\liblsl
mkdir build && cd build
cmake -DLSL_SECURITY=ON -DCMAKE_TOOLCHAIN_FILE=[vcpkg-root]/scripts/buildsystems/vcpkg.cmake ..
cmake --build . --config Release

Step 2: Generate Keys (1 minute)

# Generate a new keypair for this device
./lsl-keygen --init

# This creates:
# - ~/.lslkeys/device.key (private key - keep secure!)
# - Updates lsl_api.cfg with [security] section

Protect Your Private Key

The private key in ~/.lslkeys/device.key identifies your device. Never share it or commit it to version control.

Step 3: Update Configuration (1 minute)

The lsl-keygen --init command automatically updates your lsl_api.cfg. Verify it contains:

[security]
enabled = true
private_key = <base64-encoded-key>

Configuration file locations:

  • macOS/Linux: ~/.lslconfig/lsl_api.cfg
  • Windows: %APPDATA%\lsl_api\lsl_api.cfg
  • Or: Same directory as your application

Step 4: Verify Setup (30 seconds)

./lsl-config --check

# Expected output:
# Library: liblsl-secure 1.16.1-secure.1.0.0-alpha
# Security: ENABLED
# Keys: ~/.lslkeys/device.key

Step 5: Run Your Existing Code

Your applications work unchanged:

# No changes needed!
import pylsl

# Create outlet (automatically encrypted)
info = pylsl.StreamInfo("EEG", "EEG", 8, 250, pylsl.cf_float32, "mydevice")
outlet = pylsl.StreamOutlet(info)

# Push samples (encrypted transparently)
outlet.push_sample([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0])

Per-Binding Instructions

Python (pylsl)

Point pylsl to the secure library:

# Option 1: Environment variable
export PYLSL_LIB=/path/to/liblsl-secure.dylib

# Option 2: In Python before importing
import os
os.environ['PYLSL_LIB'] = '/path/to/liblsl-secure.dylib'
import pylsl  # Must import AFTER setting env

Verify you're using secure LSL:

import pylsl
info = pylsl.library_info()
if 'security' not in info:
    print("WARNING: Not using secure LSL!")
else:
    print(f"Using: {info}")

MATLAB

Update the library path in your MATLAB code:

% Load the secure library
if ismac
    loadlibrary('/path/to/liblsl-secure.dylib', 'lsl_c.h');
elseif isunix
    loadlibrary('/path/to/liblsl-secure.so', 'lsl_c.h');
else
    loadlibrary('/path/to/lsl-secure.dll', 'lsl_c.h');
end

Or set the library path before starting MATLAB:

# macOS/Linux
export DYLD_LIBRARY_PATH=/path/to/secure/lib:$DYLD_LIBRARY_PATH
matlab

C++

Relink your application with the secure library:

# Change from:
g++ myapp.cpp -llsl -o myapp

# To:
g++ myapp.cpp -llsl-secure -o myapp

Or update your CMakeLists.txt:

# The target name is still 'lsl' in CMake
find_package(LSL REQUIRED)
target_link_libraries(myapp PRIVATE LSL::lsl)

C

Update the DllImport attribute:

// Change from:
[DllImport("lsl")]

// To:
[DllImport("lsl-secure")]

Verifying Security is Active

Runtime Check

import pylsl

# Check library info
info = pylsl.library_info()
print(info)
# Should contain: security:X.X.X

# Check stream security
inlet = pylsl.StreamInlet(stream_info)
# In future pylsl versions:
# print(stream_info.security_enabled())

Stream Discovery

Secure streams advertise their security status. You can see this in the stream metadata:

streams = pylsl.resolve_streams()
for s in streams:
    print(f"Stream: {s.name()}")
    # Security info is in the stream's XML description

Visual Indicators

LabRecorder and SigVisualizer (with security patches) show:

  • Lock icon for encrypted streams
  • Security status banner in main window
  • Warning for mixed secure/insecure environments

Troubleshooting

"Using wrong library" Error

Symptom: Your application loads regular liblsl instead of liblsl-secure.

Solution:

  1. Check which library is loaded:

    import pylsl
    print(pylsl.library_info())
    

  2. Set the correct path:

    export PYLSL_LIB=/path/to/liblsl-secure.dylib
    

  3. Verify no conflicting libraries:

    # macOS
    ls /usr/local/lib/liblsl*
    
    # Remove or rename regular liblsl if needed
    

Security Mismatch Errors

Symptom: "Security mismatch: secure inlet cannot connect to insecure outlet"

Cause: One device has security enabled, another doesn't.

Solution: Enable security on all devices in your lab:

  1. Run lsl-keygen --init on each device
  2. Verify with lsl-config --check on each device
  3. Restart all LSL applications

Key File Permissions

Symptom: "Cannot read private key" or permission denied errors.

Solution:

# Ensure correct permissions
chmod 600 ~/.lslkeys/device.key
chmod 700 ~/.lslkeys/

Missing libsodium

Symptom: Build fails with "libsodium not found"

Solution:

# macOS
brew install libsodium

# Ubuntu/Debian
sudo apt install libsodium-dev

# Windows (vcpkg)
vcpkg install libsodium

Multi-Device Lab Setup

For labs with multiple devices:

  1. Install secure LSL on each device
  2. Generate unique keys on each device (don't copy keys between devices)
  3. Verify security on each device with lsl-config --check
  4. Test connectivity between devices before experiments
# On Device A (outlet)
./cpp_secure_outlet

# On Device B (inlet)
./cpp_secure_inlet
# Should connect and show encrypted data transfer

Rollback to Regular LSL

If you need to temporarily disable security:

  1. Edit lsl_api.cfg:

    [security]
    enabled = false
    

  2. Or use regular liblsl binary:

    export PYLSL_LIB=/path/to/liblsl.dylib  # regular version
    

Security Implications

Disabling security means your data is transmitted in plaintext. Only do this for debugging or compatibility testing.

Getting Help