revert(e2ee): restore KDF_HKDF=1, KDF_RAW=0 causes PBKDF2 double-derivation (MAT-144)
KDF_PBKDF2=0 does NOT mean raw mode — libwebrtc applies its built-in PBKDF2 on top of pre-derived keys, causing DEC_FAILED for audio too. Revert to KDF_HKDF=1 (Rust applies HKDF, we pass raw base keys). Keep diagnostic improvements: - _derive_and_set_key() wrapper with logging - Per-track type logging (audio vs video) in on_track_subscribed - Frame size check in look_at_screen (detect E2EE failure) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
31
voice.py
31
voice.py
@@ -220,17 +220,13 @@ def _ratchet_keys(base_raw: bytes, count: int = 6) -> dict[int, bytes]:
|
|||||||
|
|
||||||
|
|
||||||
def _derive_and_set_key(kp, identity: str, raw_key: bytes, index: int) -> None:
|
def _derive_and_set_key(kp, identity: str, raw_key: bytes, index: int) -> None:
|
||||||
"""Pre-derive HKDF key in Python, then set via KeyProvider (MAT-144).
|
"""Set raw base key via KeyProvider — Rust HKDF derives AES key internally.
|
||||||
|
|
||||||
This replaces direct set_key(identity, raw_key, index) calls.
|
Wraps set_key() with diagnostic logging for MAT-144 investigation.
|
||||||
Pre-derivation in Python ensures exact match with Element Call JS HKDF,
|
|
||||||
eliminating Rust FFI HKDF implementation differences that caused
|
|
||||||
video frame decryption failures (audio worked, video didn't).
|
|
||||||
"""
|
"""
|
||||||
derived = _hkdf_derive(raw_key)
|
ok = kp.set_key(identity, raw_key, index)
|
||||||
ok = kp.set_key(identity, derived, index)
|
logger.debug("set_key[%d] %s: raw=%s (%d bytes, ok=%s)",
|
||||||
logger.debug("set_key[%d] %s: raw=%s → derived=%s (ok=%s)",
|
index, identity, raw_key.hex()[:8], len(raw_key), ok)
|
||||||
index, identity, raw_key.hex()[:8], derived.hex(), ok)
|
|
||||||
|
|
||||||
|
|
||||||
async def _brave_search(query: str, count: int = 5) -> str:
|
async def _brave_search(query: str, count: int = 5) -> str:
|
||||||
@@ -443,24 +439,21 @@ async def _confluence_recent_pages(limit: int = 5) -> list[dict]:
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
KDF_RAW = 0 # proto value 0 = PBKDF2 in proto, but Rust returns None (= no KDF = raw key)
|
|
||||||
|
|
||||||
|
|
||||||
def _build_e2ee_options() -> rtc.E2EEOptions:
|
def _build_e2ee_options() -> rtc.E2EEOptions:
|
||||||
"""Build E2EE options — Python pre-derives HKDF keys, Rust uses them raw (MAT-144).
|
"""Build E2EE options — Rust FFI applies HKDF internally (KDF_HKDF=1).
|
||||||
|
|
||||||
We pre-derive AES keys via _hkdf_derive() in Python (matching EC's JS deriveEncryptionKey),
|
Pass raw base keys from Matrix key exchange events directly to set_key().
|
||||||
then pass derived keys to set_key() with KDF_RAW (proto 0 = no Rust-side derivation).
|
The Rust FFI derives the AES frame key via HKDF(base_key, ratchetSalt, ...) internally.
|
||||||
This eliminates any HKDF implementation mismatch between Rust FFI and Element Call JS.
|
Element Call uses: ratchetWindowSize=10, keyringSize=256, ratchetSalt="LKFrameEncryptionKey"
|
||||||
Ratcheted keys are also pre-derived in Python via _ratchet_keys().
|
NOTE: proto value 0 = PBKDF2 (NOT raw) — must use KDF_HKDF=1.
|
||||||
"""
|
"""
|
||||||
key_opts = rtc.KeyProviderOptions(
|
key_opts = rtc.KeyProviderOptions(
|
||||||
shared_key=b"", # empty = per-participant mode
|
shared_key=b"", # empty = per-participant mode
|
||||||
ratchet_window_size=0, # we handle ratcheting in Python
|
ratchet_window_size=10,
|
||||||
ratchet_salt=b"LKFrameEncryptionKey",
|
ratchet_salt=b"LKFrameEncryptionKey",
|
||||||
failure_tolerance=10,
|
failure_tolerance=10,
|
||||||
key_ring_size=256,
|
key_ring_size=256,
|
||||||
key_derivation_function=KDF_RAW, # no Rust-side KDF; keys are pre-derived in Python
|
key_derivation_function=KDF_HKDF, # Rust FFI applies HKDF; we pass raw base keys
|
||||||
)
|
)
|
||||||
return rtc.E2EEOptions(
|
return rtc.E2EEOptions(
|
||||||
encryption_type=rtc.EncryptionType.GCM,
|
encryption_type=rtc.EncryptionType.GCM,
|
||||||
|
|||||||
Reference in New Issue
Block a user