Skip to content

Call E2EE

Goal

Provide end-to-end encryption for call media such that:

  • The backend cannot decrypt media.
  • Key agreement prefers P-256 (Secure Enclave) but supports RSA-2048 fallback for legacy.
  • Media is encrypted using AES-256-GCM.

Canonical Code

  • Core crypto orchestration: ecall/Modules/Call/Managers/CallEncryptionManager.swift
  • P-256 Secure Enclave: ecall/Core/Security/P256SecureEnclaveService.swift
  • Emergency key redistribution + rotation signals: ecall/Modules/Call/Managers/CallSignalingHandler.swift

Key Agreement / Key Exchange

Preferred: P-256 (secp256r1) ECDH via Secure Enclave

For 1-1 calls:

  • Caller derives shared secret using ECDH (Secure Enclave private key + peer public key).
  • The derived shared secret is used as the AES session key (sessionAESKey).

Entry points:

  • prepareCallInvitationP256(calleePublicKeyBase64:) -> String? (returns caller public key)
  • processCallInvitationP256(callerPublicKeyBase64:) -> Bool

Fallback/Legacy: RSA-2048 (RSA-OAEP-SHA256)

For legacy participants:

  • AES session key is generated randomly.
  • AES session key is encrypted with RSA public key using OAEP-SHA256.

Entry points:

  • prepareCallInvitation(with calleePublicKey: SecKey) -> Data?
  • processCallInvitation(encryptedAESKey:calleeRSAPrivateKey:) -> Data?

Media Encryption

  • Encryption primitive: AES.GCM
  • Call encryption manager applies the key via:
  • setUpAesKey(_:)

Key Application Side Effects

setUpAesKey(_:) configures:

  • Video encryption manager (CRTEncryptionManager) with deterministic IV derived from key hash.
  • Audio encryption via RTCAudioCryptoManager.shared().delegate (updates existing delegate on rotation).

Key Rotation & Recovery

Key rotation and emergency key redistribution are documented separately:

  • ../security/key-rotation.md
  • 1-1 call flow: ./diagrams/1v1-call-flow.md