Skip to main content
SA-017 Grade B+ Phase 3

SA-017 DRM and Encryption Key Provisioning Analysis Report

The Facebook iOS app implements a multi-layer DRM and encryption architecture: 1. **FairPlay DRM**: Apple's FairPlay Streaming (FPS) for video content protection 2. **License Management**: FBDrmLicenseLoader handles license fetching via GraphQL 3. **Key Hierarchy**: Separate key paths for DRM (video) vs E2EE (messaging attachments)

Technical Diagrams

1. DRM License Management Classes Line 32
| Class | Address Range | Purpose |
|-------|--------------|---------|
| `FBDrmLicenseLoader` | 0x0018c060 - 0x00f5ab38 | DRM license fetching and management |
| `FBVideoDrmHandler` | 0x00019114 - 0x01076a18 | Video DRM decryption handler |
| `FBDRMLicenseQueryBuilder` | 0x00b75ac4 - 0x00b75c00 | GraphQL query builder for licenses |
| `FBDRMGraphQLFetcher` | (identified) | GraphQL fetcher for DRM operations |
| `FNFFairPlayController` | 0x005b7828 - 0x011ca8c0 | Apple FairPlay streaming controller |
| `FairPlayCertificateQueryBuilder` | 0x000e5834 - 0x00c47c58 | FairPlay certificate fetching |
2. FBDrmLicenseLoader Methods Line 43
| Method | Address | Purpose |
|--------|---------|---------|
| `initWithSession:videoId:completionHandler:` | 0x00b757a0 | Initialize license loader |
| `generateLicense:request:videoId:completion:` | 0x00b75944 | Generate DRM license |
| `generateLicense:request:videoId:keyId:completion:` | 0x00f5ab38 | Generate license with key ID |
| `fetchCertificateWithCompletionHandler:callbackQueue:` | 0x00ef1f40 | Fetch DRM certificate |
| `didUpdateLicense:` | 0x00b75d48 | License update callback |
3. FBVideoDrmHandler Methods Line 53
| Method | Address | Purpose |
|--------|---------|---------|
| `initWithVideoId:session:` | 0x001637d8 | Initialize handler with video ID |
| `prepareWithPssh:keyIds:mode:playbackStarted:completion:` | 0x00be5a54 | Prepare DRM with PSSH data |
| `decrypt:keyId:iv:error:` | 0x01076a18 | Decrypt content with key/IV |
| `getLicenseInfoWithPssh:expiration:` | 0x00fdcfc8 | Get license info from PSSH |
| `connectWithKeyRecipient:completion:` | 0x00e5608c | Connect to key recipient |
| `isKeySessionPrepared` | 0x00fb9a84 | Check if key session is ready |
| `keyIds` | 0x0002a3b8 | Get key IDs |
| `encryptionMode` | 0x00019114 | Get encryption mode |
**FNFFairPlayController Methods:** Line 68
| Method | Address | Purpose |
|--------|---------|---------|
| `initWithKeyIds:licenseLoader:` | 0x00c90980 | Initialize with key IDs |
| `prepareWithAsset:completion:` | 0x00f0f72c | Prepare for asset |
| `_setupKeySessionForAsset:` | 0x011ca8c0 | Setup key session |
| `_processContentKeyRequest:` | 0x00e80288 | Process content key request |
| `_requestContentKeyFromKeySecurityModuleWithRequestData:identifier:forKeyRequest:` | 0x00e8a1b4 | Request key from security module |
| `contentKeySession:didProvideContentKeyRequest:` | 0x00c70cdc | Content key delegate |
| `contentKeySession:contentKeyRequestDidSucceed:` | 0x00e337a4 | Key request success |
| `contentKeySession:contentKeyRequest:didFailWithError:` | 0x00c61a5c | Key request failure |
**MNSecureOutgoingAttachmentContent:** Line 109
| Method | Address | Purpose |
|--------|---------|---------|
| `audioWithAudioEncryptionKey:audio:` | 0x00e32d5c | Create encrypted audio |
| `videoWithVideoEncryptionKey:video:` | 0x00e32da8 | Create encrypted video |
| `imagesWithEncryptionKey:photos:` | 0x00e32d14 | Create encrypted images |
| `initWithCoder:` | 0x00eef4c0 | NSCoding deserialization |
| `encodeWithCoder:` | 0x00dc97c8 | NSCoding serialization |
**Related Classes:** Line 128
| Class | Purpose |
|-------|---------|
| `FBMSecureThreadKey` | Secure thread key (E2EE thread ID) |
| `MNSecureOutgoingMessageContent` | Encrypted outgoing message |
| `MNSecureOutgoingMessageContentV2` | V2 encrypted message format |
| `FBContactSearchSecureThreadResult` | Secure thread search result |
HKDF Parameters (Inferred) Line 225
| Parameter | Value |
|-----------|-------|
| Algorithm | HKDF-SHA256 |
| Input Key Material | Session master key (negotiated via E2EE handshake) |
| Salt | Per-session (likely from key exchange) |
| Info | Context-specific string (e.g., "audio", "video") |
| Output Length | 32 bytes (256-bit for AES-256) |
DRM Keys (FairPlay) Line 246
| Storage Location | Details |
|------------------|---------|
| Memory | Session-specific, cleared on app termination |
| AVContentKeySession | Apple's secure key storage for FairPlay |
| Keychain Access | `kSecAttrAccessibleAfterFirstUnlock` for persistent data |
E2EE Keys (Messaging) Line 254
| Storage Location | Details |
|------------------|---------|
| Memory | Per-message encryption keys |
| Secure Storage | Key derivation happens per-session |
| NSCoding | `MNSecureOutgoingAttachmentContent` serializable |
**Critical Finding:** The DRM video keys and E2EE audioEncryptionKey are **independent systems**: Line 266
| Aspect | DRM Keys | audioEncryptionKey |
|--------|----------|-------------------|
| Purpose | Streaming video protection | Messaging attachment encryption |
| Provider | FairPlay license server | E2EE session negotiation |
| Algorithm | AES-128-CBC (HLS/DASH) | AES-256-GCM (AEAD) |
| Lifetime | Per-license with expiration | Per-message |
| Scope | Video playback | Message attachments |
Evidence Quality Line 280
| Criterion | Score | Notes |
|-----------|-------|-------|
| DRM class identification | 9/10 | Complete class hierarchy found |
| License fetch mechanism | 8/10 | GraphQL flow traced |
| FairPlay integration | 8/10 | AVContentKeySession callbacks identified |
| HKDF parameters | 5/10 | Algorithm inferred, no static values found |
| Key storage | 6/10 | Patterns identified, no keychain entries |
| DRM/E2EE relationship | 9/10 | Clear separation documented |
DRM-Related Strings Found Line 295
| Address | String |
|---------|--------|
| 0x01e894c0 | `FAIRPLAY` |
| 0x01e894c9 | `skd://%@` |
| 0x0205feba | `isDrmVideo` |
| 0x020a3777 | `playlistUpdatedWithDRMKeyId:pssh:` |
| 0x020c1d29 | `contentKeyResponseWithFairPlayStreamingKeyResp...` |
GK Flags for DRM Line 305
| Flag | Purpose |
|------|---------|
| `ios_fnf_refactor_live_drm` | Enable live DRM refactor |
| `enableDrmForInceptionPlayer` | DRM for Inception player |
| `enableSynchronousLicenseFetch` | Sync license fetching |

Code Evidence

Plain Text
FAIRPLAY
skd://%@
Plain Text
1. [FBDrmLicenseLoader generateLicense:request:videoId:completion:]
       |
       v
2. [FBDRMLicenseQueryBuilder builderWithLicenseType:request:videoId:]
       |
       v
3. GraphQL Query with privacy context: "ios/default/private.videos.playback"
       |
       v
4. [FBDRMGraphQLFetcher] -> Server request
       |
       v
5. [FBVideoDrmHandler decrypt:keyId:iv:error:] for playback
Plain Text
NSData*videoEncryptionKey
NSData*audioEncryptionKey
FBMessageAudioOutgoingAttachmentContent*audio
FBMessageVideoAttachmentContent*video
MNSecureOutgoingAttachmentContent*attachment
Plain Text
[DRM Path - Video]
                            |
[FairPlay Certificate] --> [License Server]
                            |
                            v
                    [Content Key Response]
                            |
                            v
         [FNFFairPlayController] --> [AES-128-CBC for HLS]
                            |
                            v
                    [Video Decryption]


                    [E2EE Path - Attachments]
                            |
[Session Master Key] --> [walibra_hkdf_info]
                            |
                            v
                    [HKDF Expansion]
                            |
                            v
                [audioEncryptionKey / videoEncryptionKey]
                            |
                            v
                    [AES-256-GCM AEAD]
Objective-C
-[FBVideoDrmHandler prepareWithPssh:keyIds:mode:playbackStarted:completion:]
-[FBVideoDrmHandler getLicenseInfoWithPssh:expiration:]
Plain Text
generateLicense:request:videoId:keyId:completion:
decrypt:keyId:iv:error:
prepareWithPssh:keyIds:mode:playbackStarted:completion:
initWithKeyIds:licenseLoader:
_requestContentKeyFromKeySecurityModuleWithRequestData:identifier:forKeyRequest:

**Agent ID:** SA-017 **Date:** 2025-12-30 **Status:** Completed **Grade:** B+


Mission

Analyze FBDrmLicenseLoader, encryption key provisioning chain, and DRM key relationship to audioEncryptionKey.

**Target Binary:** `./analysis/facebook/345.0/Facebook.app/Frameworks/FBSharedFramework.framework/FBSharedFramework`


Executive Summary

The Facebook iOS app implements a multi-layer DRM and encryption architecture:

    undefined

The audioEncryptionKey for messaging attachments is **separate** from DRM video keys - they use different provisioning chains.


Key Findings

1. DRM License Management Classes

ClassAddress RangePurpose
`FBDrmLicenseLoader`0x0018c060 - 0x00f5ab38DRM license fetching and management
`FBVideoDrmHandler`0x00019114 - 0x01076a18Video DRM decryption handler
`FBDRMLicenseQueryBuilder`0x00b75ac4 - 0x00b75c00GraphQL query builder for licenses
`FBDRMGraphQLFetcher`(identified)GraphQL fetcher for DRM operations
`FNFFairPlayController`0x005b7828 - 0x011ca8c0Apple FairPlay streaming controller
`FairPlayCertificateQueryBuilder`0x000e5834 - 0x00c47c58FairPlay certificate fetching

2. FBDrmLicenseLoader Methods

MethodAddressPurpose
`initWithSession:videoId:completionHandler:`0x00b757a0Initialize license loader
`generateLicense:request:videoId:completion:`0x00b75944Generate DRM license
`generateLicense:request:videoId:keyId:completion:`0x00f5ab38Generate license with key ID
`fetchCertificateWithCompletionHandler:callbackQueue:`0x00ef1f40Fetch DRM certificate
`didUpdateLicense:`0x00b75d48License update callback

3. FBVideoDrmHandler Methods

MethodAddressPurpose
`initWithVideoId:session:`0x001637d8Initialize handler with video ID
`prepareWithPssh:keyIds:mode:playbackStarted:completion:`0x00be5a54Prepare DRM with PSSH data
`decrypt:keyId:iv:error:`0x01076a18Decrypt content with key/IV
`getLicenseInfoWithPssh:expiration:`0x00fdcfc8Get license info from PSSH
`connectWithKeyRecipient:completion:`0x00e5608cConnect to key recipient
`isKeySessionPrepared`0x00fb9a84Check if key session is ready
`keyIds`0x0002a3b8Get key IDs
`encryptionMode`0x00019114Get encryption mode

4. FairPlay DRM Integration

**FNFFairPlayController Methods:**

MethodAddressPurpose
`initWithKeyIds:licenseLoader:`0x00c90980Initialize with key IDs
`prepareWithAsset:completion:`0x00f0f72cPrepare for asset
`_setupKeySessionForAsset:`0x011ca8c0Setup key session
`_processContentKeyRequest:`0x00e80288Process content key request
`_requestContentKeyFromKeySecurityModuleWithRequestData:identifier:forKeyRequest:`0x00e8a1b4Request key from security module
`contentKeySession:didProvideContentKeyRequest:`0x00c70cdcContent key delegate
`contentKeySession:contentKeyRequestDidSucceed:`0x00e337a4Key request success
`contentKeySession:contentKeyRequest:didFailWithError:`0x00c61a5cKey request failure

**FairPlay String Found at 0x01e894c0:**

Plain Text
FAIRPLAY
skd://%@

5. License Query Flow

The license generation flow revealed in decompilation:

Plain Text
1. [FBDrmLicenseLoader generateLicense:request:videoId:completion:]
       |
       v
2. [FBDRMLicenseQueryBuilder builderWithLicenseType:request:videoId:]
       |
       v
3. GraphQL Query with privacy context: "ios/default/private.videos.playback"
       |
       v
4. [FBDRMGraphQLFetcher] -> Server request
       |
       v
5. [FBVideoDrmHandler decrypt:keyId:iv:error:] for playback

6. MNSecure* Classes for E2EE Attachments

**MNSecureOutgoingAttachmentContent:**

MethodAddressPurpose
`audioWithAudioEncryptionKey:audio:`0x00e32d5cCreate encrypted audio
`videoWithVideoEncryptionKey:video:`0x00e32da8Create encrypted video
`imagesWithEncryptionKey:photos:`0x00e32d14Create encrypted images
`initWithCoder:`0x00eef4c0NSCoding deserialization
`encodeWithCoder:`0x00dc97c8NSCoding serialization

**Type Encoding Found at 0x01ea0320:**

Plain Text
NSData*videoEncryptionKey
NSData*audioEncryptionKey
FBMessageAudioOutgoingAttachmentContent*audio
FBMessageVideoAttachmentContent*video
MNSecureOutgoingAttachmentContent*attachment

**Related Classes:**

ClassPurpose
`FBMSecureThreadKey`Secure thread key (E2EE thread ID)
`MNSecureOutgoingMessageContent`Encrypted outgoing message
`MNSecureOutgoingMessageContentV2`V2 encrypted message format
`FBContactSearchSecureThreadResult`Secure thread search result

7. walibra HKDF Analysis

**Address 0x01503628 Analysis:**

The address contains a data table with pointers to strings. Upon examination:

    undefined

**Actual walibra Evidence:**

    undefined

8. Key Derivation Chain

Based on SA-006 and current analysis:

Plain Text
                      [DRM Path - Video]
                            |
[FairPlay Certificate] --> [License Server]
                            |
                            v
                    [Content Key Response]
                            |
                            v
         [FNFFairPlayController] --> [AES-128-CBC for HLS]
                            |
                            v
                    [Video Decryption]


                    [E2EE Path - Attachments]
                            |
[Session Master Key] --> [walibra_hkdf_info]
                            |
                            v
                    [HKDF Expansion]
                            |
                            v
                [audioEncryptionKey / videoEncryptionKey]
                            |
                            v
                    [AES-256-GCM AEAD]

DRM License Fetch Mechanism

Request Flow

    undefined

PSSH Processing

PSSH (Protection System Specific Header) contains:

    undefined
Objective-C
-[FBVideoDrmHandler prepareWithPssh:keyIds:mode:playbackStarted:completion:]
-[FBVideoDrmHandler getLicenseInfoWithPssh:expiration:]

Key Derivation Algorithm Details

HKDF Parameters (Inferred)

ParameterValue
AlgorithmHKDF-SHA256
Input Key MaterialSession master key (negotiated via E2EE handshake)
SaltPer-session (likely from key exchange)
InfoContext-specific string (e.g., "audio", "video")
Output Length32 bytes (256-bit for AES-256)

Evidence for AES-256-GCM

    undefined

Key Storage Mechanism

DRM Keys (FairPlay)

Storage LocationDetails
MemorySession-specific, cleared on app termination
AVContentKeySessionApple's secure key storage for FairPlay
Keychain Access`kSecAttrAccessibleAfterFirstUnlock` for persistent data

E2EE Keys (Messaging)

Storage LocationDetails
MemoryPer-message encryption keys
Secure StorageKey derivation happens per-session
NSCoding`MNSecureOutgoingAttachmentContent` serializable

Relationship: DRM Keys vs audioEncryptionKey

**Critical Finding:** The DRM video keys and E2EE audioEncryptionKey are **independent systems**:

AspectDRM KeysaudioEncryptionKey
PurposeStreaming video protectionMessaging attachment encryption
ProviderFairPlay license serverE2EE session negotiation
AlgorithmAES-128-CBC (HLS/DASH)AES-256-GCM (AEAD)
LifetimePer-license with expirationPer-message
ScopeVideo playbackMessage attachments

The DRM layer protects **streamed content** while E2EE protects **message attachments**. They do not share keys.


Evidence Quality

CriterionScoreNotes
DRM class identification9/10Complete class hierarchy found
License fetch mechanism8/10GraphQL flow traced
FairPlay integration8/10AVContentKeySession callbacks identified
HKDF parameters5/10Algorithm inferred, no static values found
Key storage6/10Patterns identified, no keychain entries
DRM/E2EE relationship9/10Clear separation documented

Technical Artifacts

DRM-Related Strings Found

AddressString
0x01e894c0`FAIRPLAY`
0x01e894c9`skd://%@`
0x0205feba`isDrmVideo`
0x020a3777`playlistUpdatedWithDRMKeyId:pssh:`
0x020c1d29`contentKeyResponseWithFairPlayStreamingKeyResp...`

GK Flags for DRM

FlagPurpose
`ios_fnf_refactor_live_drm`Enable live DRM refactor
`enableDrmForInceptionPlayer`DRM for Inception player
`enableSynchronousLicenseFetch`Sync license fetching

Key-Related Selector Patterns

Plain Text
generateLicense:request:videoId:keyId:completion:
decrypt:keyId:iv:error:
prepareWithPssh:keyIds:mode:playbackStarted:completion:
initWithKeyIds:licenseLoader:
_requestContentKeyFromKeySecurityModuleWithRequestData:identifier:forKeyRequest:

Blockers for Key Extraction

    undefined

Recommendations for Further Investigation

    undefined

Impact on H3 Decoding

**Contribution:** This analysis clarifies that:

    undefined

**H3 Decoding Status:** Keys remain ephemeral and session-specific. No static keys found.


Conclusion

The Facebook iOS app implements a sophisticated dual-encryption system:

    undefined

The audioEncryptionKey is generated through E2EE key negotiation and HKDF expansion, completely separate from the DRM key provisioning chain. Decrypting audio attachments requires capturing session keys at runtime, as no static keys are embedded in the binary.


*SA-017 DRM and Key Provisioning Analysis - Generated 2025-12-30*

Related Reports

Phase 3 Navigation