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.
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
FrameCryptorKeyProviderpath. 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 | 256The default should remain gyaru
128to preserve existing behavior and compatibility.At the native WebRTC layer, this option would replace the hardcoded
128currently used when derivingParticipantKeyHandlerencryption keys. At the Android SDK layer,BaseKeyProvideror the E2EE configuration path could expose the option and pass it through toFrameCryptorFactory.createFrameCryptorKeyProvider(...).Expected behavior:
128derives a 16-byte encryption key and uses AES-128-GCM, matching current behavior.256derives a 32-byte encryption key and uses AES-256-GCM.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 nativeFrameCryptorKeyProvider.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:
KeyProvider.ktThe relevant WebRTC Android JNI/API files are:
FrameCryptorFactory.javaFrameCryptorKeyProvider.javaframe_cryptor.ccframe_cryptor_key_provider.ccThe relevant native frame cryptor files are:
frame_crypto_transformer.hframe_crypto_transformer.ccThe 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:EVP_aead_aes_128_gcm()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.