Skip to content

Support configurable AES-GCM key length for E2EE #952

@toni-megical

Description

@toni-megical

Is your feature request related to a problem? Please describe.

LiveKit Android E2EE currently appears to always use AES-128-GCM for frame encryption through the standard FrameCryptorKeyProvider path. Even when the application provides 32 bytes of key material, the native key provider derives the actual frame encryption key with a hardcoded 128-bit length.

The underlying WebRTC frame cryptor code already has support for AES-256-GCM when the encryption key is 32 bytes, but the Android SDK does not expose a way to derive or provide a 256-bit frame encryption key through the public E2EE API.

This makes it difficult for applications with stricter security requirements to opt into AES-256-GCM while continuing to use LiveKit’s built-in E2EE support.

Describe the solution you'd like

Please add a backwards-compatible option to configure the AES-GCM encryption key length used by E2EE, for example:

encryptionKeyLengthBits: 128 | 256

The default should remain gyaru128 to preserve existing behavior and compatibility.

At the native WebRTC layer, this option would replace the hardcoded 128 currently used when deriving ParticipantKeyHandler encryption keys. At the Android SDK layer, BaseKeyProvider or the E2EE configuration path could expose the option and pass it through to FrameCryptorFactory.createFrameCryptorKeyProvider(...).

Expected behavior:

  • 128 derives a 16-byte encryption key and uses AES-128-GCM, matching current behavior.
  • 256 derives a 32-byte encryption key and uses AES-256-GCM.
  • Invalid values should be rejected.
  • Documentation should mention that all E2EE participants must use the same key length.

This option would also need equivalent support in other LiveKit client SDKs to work cross-platform.

Describe alternatives you've considered

I considered passing 32-byte key material into the existing KeyProvider, but this does not result in AES-256-GCM because the native provider treats the input as key material and still derives a 128-bit encryption key.

I also considered using a custom Kotlin KeyProvider, reflection, or other app-level workarounds, but those still end up calling the native FrameCryptorKeyProvider.setKey(...) path where the 128-bit derivation is hardcoded.

The only practical workaround today seems to be maintaining a custom fork of the WebRTC/LiveKit native dependency.

Additional context

The relevant Android SDK file is:

The relevant WebRTC Android JNI/API files are:

The relevant native frame cryptor files are:

The native code path appears to be:

FrameCryptorKeyProvider.setKey(...)
→ native DefaultKeyProviderImpl::SetKey(...)
ParticipantKeyHandler::SetKey(...)
ParticipantKeyHandler::SetKeyFromMaterial(...)
DeriveKeys(..., 128)

The AES selection itself already supports both key sizes in frame_crypto_transformer.cc:

  • 16-byte key → EVP_aead_aes_128_gcm()
  • 32-byte key → EVP_aead_aes_256_gcm()

So the main missing piece seems to be making the derived encryption key length configurable while keeping 128-bit as the default.

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions