Close Menu
  • Home
  • AI
  • Big Data
  • Cloud Computing
  • iOS Development
  • IoT
  • IT/ Cybersecurity
  • Tech
    • Nanotechnology
    • Green Technology
    • Apple
    • Software Development
    • Software Engineering

Subscribe to Updates

Get the latest technology news from Bigteetechhub about IT, Cybersecurity and Big Data.

    What's Hot

    World Cup 2026 draw sets out betting favorites as markets take shape

    December 29, 2025

    ios – Xcode 26.2 Simulator download fails with DVTDownloadableErrorDomain Code 41 on macOS 26.1

    December 28, 2025

    Building Blocks for Agentic AI: The Hierarchy of Developer Needs

    December 28, 2025
    Facebook X (Twitter) Instagram
    Facebook X (Twitter) Instagram
    Big Tee Tech Hub
    • Home
    • AI
    • Big Data
    • Cloud Computing
    • iOS Development
    • IoT
    • IT/ Cybersecurity
    • Tech
      • Nanotechnology
      • Green Technology
      • Apple
      • Software Development
      • Software Engineering
    Big Tee Tech Hub
    Home»iOS Development»encryption – Playing Apple Fairplay encrypted content on iOS 26
    iOS Development

    encryption – Playing Apple Fairplay encrypted content on iOS 26

    big tee tech hubBy big tee tech hubDecember 1, 2025025 Mins Read
    Share Facebook Twitter Pinterest Copy Link LinkedIn Tumblr Email Telegram WhatsApp
    Follow Us
    Google News Flipboard
    encryption – Playing Apple Fairplay encrypted content on iOS 26
    Share
    Facebook Twitter LinkedIn Pinterest Email Copy Link


    For iOS17 we’ve had no problem playing Apple Fairplay encrypted content with keys delivered from our key server running on FairPlay Streaming Server SDK 5.1 and subsequently FairPlay Streaming Server SDK 26. It’s built and deployed using **Xcode Version 26.1.**1 (17B100) with no changes to the code and – as expected – the content continued to be successfully decrypted and played (so far so good). However, as soon as a device was updated to iOS26, that device would no longer play the encrypted content.

    Devices remaining on iOS17 continue to work normally and the debugging logs are a sanity-check that proves that. Is anyone else experiencing this issue? We’ve raised this issue several times with Apple over the past two months and are yet to get a response from their engineers or the developer forum.

    Here’s the code (you should be able to drop it into a fresh iOS Xcode project and provide a server url, content url and certificate). Many thanks in advance and to those who have already responded to my poor first attempt at asking for help.

    import UIKit
    import AVFoundation
    
    class ViewController: UIViewController {
        private var player: AVPlayer?
        private var keyDelegate: ContentKeyDelegate?
        
        override func viewDidLoad() {
            super.viewDidLoad()
            self.view.backgroundColor = .orange
            self.configureAudioSession()
            
            guard let appDelegate = UIApplication.shared.delegate as? AppDelegate
            , let hlsURL = appDelegate.hlsURL()
            , let certificateData = appDelegate.certificate()
            , let licenseServerURL = appDelegate.licenseServerURL() else {
                return
            }
            
            let delegate = ContentKeyDelegate(appCertificate: certificateData,licenseServerURL: licenseServerURL)
            self.keyDelegate = delegate
            
            let asset = AVURLAsset(url: hlsURL, options: [
                AVURLAssetPreferPreciseDurationAndTimingKey: NSNumber(value: false)
            ])
            
            delegate.setAsset(asset)
            
            let item = AVPlayerItem(asset: asset)
            let player = AVPlayer(playerItem: item)
            player.automaticallyWaitsToMinimizeStalling = true
            player.allowsExternalPlayback = false
            player.preventsDisplaySleepDuringVideoPlayback = true
            self.player = player
            
            let layer = AVPlayerLayer(player: player)
            layer.frame = view.bounds
            layer.videoGravity = .resizeAspect
            self.view.layer.addSublayer(layer)
            player.play()
        }
        
        override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
            if let playerLayer = view.layer.sublayers?.first(where: { $0 is AVPlayerLayer }) as? AVPlayerLayer {
                playerLayer.frame = view.bounds
            }
        }
        
        private func configureAudioSession() {
            do {
                let audioSession = AVAudioSession.sharedInstance()
                try audioSession.setCategory(.playback, mode: .moviePlayback, options: [])
                try audioSession.setActive(true)
                print("✅ Audio session configured successfully")
            } catch {
                print("❌ Failed to configure audio session: \(error)")
            }
        }
    }
    
    final class ContentKeyDelegate: NSObject, AVContentKeySessionDelegate {
        private let appCertificate: Data
        private let licenseServerURL: URL
        private let keySession: AVContentKeySession
    
        init(appCertificate: Data, licenseServerURL: URL) {
            self.appCertificate = appCertificate
            self.licenseServerURL = licenseServerURL
            self.keySession = AVContentKeySession(keySystem: .fairPlayStreaming)
            super.init()
    
            self.keySession.setDelegate(self, queue: DispatchQueue.main)
        }
    
        func setAsset(_ asset: AVURLAsset) {
            self.keySession.addContentKeyRecipient(asset)
        }
    
        func contentKeySession(_ session: AVContentKeySession, didProvide keyRequest: AVContentKeyRequest) {
            process(keyRequest: keyRequest)
        }
    
        func contentKeySession(_ session: AVContentKeySession, didProvideRenewingContentKeyRequest keyRequest: AVContentKeyRequest) {
            process(keyRequest: keyRequest)
        }
    
        private func process(keyRequest: AVContentKeyRequest) {
            guard let assetIDString = keyRequest.identifier as? String, let assetIDData = assetIDString.data(using: .utf8) else {
                keyRequest.processContentKeyResponseError(NSError(domain: "ContentKey", code: -1))
                return
            }
            
            Task {
                do {
                    let spcData = try await keyRequest.makeStreamingContentKeyRequestData(forApp: appCertificate,contentIdentifier: assetIDData, options: nil)
                    self.fetchCKC(spcData: spcData, assetId: assetIDString) { result in
                        switch result {
                        case .success(let ckcOpt):
                            guard let ckcData = ckcOpt else {
                                DispatchQueue.main.async {
                                    keyRequest.processContentKeyResponseError(ProgramError.noCKCReturnedByKSM)
                                }
                                return
                            }
                            
                            let response = AVContentKeyResponse(fairPlayStreamingKeyResponseData: ckcData)
                            DispatchQueue.main.async {
                                keyRequest.processContentKeyResponse(response)
                                DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
                                    if let err = keyRequest.error {
                                        Swift.print("keyRequest.error: \(err.localizedDescription) / \(err)")
                                    } else {
                                        Swift.print("keyRequest.error: nil")
                                    }
                                }
                            }
                            
                        case .failure(let error):
                            Swift.print("fetchCKC error: \(error)")
                            DispatchQueue.main.async {
                                keyRequest.processContentKeyResponseError(error)
                            }
                        }
                    }
                    
                } catch {
                    Swift.print("SPC generation error: \(error)")
                    DispatchQueue.main.async {
                        keyRequest.processContentKeyResponseError(error)
                    }
                }
            }
        }
    
        private func fetchCKC(spcData: Data, assetId: String, completion: @escaping (Result) -> Void) {
            if let contentKeyData = Data(base64Encoded: "X7sBORoVsqx/M96GnKLUqA==")
                , let initialisationVectorData = Data(base64Encoded: "beXQ7IjxPAxSk29JU3MgvA==") {
                let endpoint = "
                if let url = URL(string: endpoint) {
                    let spcBase64 = spcData.base64EncodedString()
                    let contentKeyHex = ContentKeyDelegate.hex(forData: contentKeyData)
                    let initialisationVectorHex = ContentKeyDelegate.hex(forData: initialisationVectorData)
                    
                    let parameters: [String: Any] = [
                        "fairplay-streaming-request": [
                            "version": 1,
                            "create-ckc": [[
                                "id": 1,
                                "asset-info": [[
                                    "content-key": contentKeyHex,
                                    "content-iv": initialisationVectorHex,
                                    "encryption-scheme": "cbcs",
                                    "hdcp-type": 0,
                                    "content-type": "hd",
                                    "lease-duration": 1200
                                ]],
                                "spc": spcBase64
                            ]]
                        ]
                    ]
                                    
                    do {
                        let postData = try JSONSerialization.data(withJSONObject: parameters)
                        var request = URLRequest(url: url)
                        request.httpMethod = "POST"
                        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
                        request.httpBody = postData
                        
                        let task = URLSession.shared.dataTask(with: request) {data, response, error in
                            if let response = response as? HTTPURLResponse {
                                Swift.print("KSM status code: \(response.statusCode)")
                            }
                            
                            if let error = error {
                                Swift.print("KSM request error: \(error)")
                                completion(.failure(error))
                                return
                            }
                            
                            guard let data = data, var responseString = String(data: data, encoding: .utf8) else {
                                Swift.print("KSM response empty or not UTF-8")
                                completion(.failure(ProgramError.noCKCReturnedByKSM))
                                return
                            }
                            
                            if responseString.hasPrefix("Result") {
                                responseString.removeFirst("Result".count)
                            }
                            
                            guard let jsonData = responseString.data(using: .utf8) else {
                                Swift.print("Failed to convert trimmed response to data")
                                completion(.failure(ProgramError.noCKCReturnedByKSM))
                                return
                            }
                            
                            do {
                                if let dictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any]
                                    , let fairplayStreamingResponse = dictionary["fairplay-streaming-response"] as? [String: Any]
                                    , let ckcArray = fairplayStreamingResponse["create-ckc"] as? [[String: Any]]
                                    , let ckcDictionary = ckcArray.first
                                    , let ckc = ckcDictionary["ckc"] as? String
                                    , let thatData = Data(base64Encoded: ckc) {
                                    completion(.success(thatData))
                                } else {
                                    completion(.failure(ProgramError.noCKCReturnedByKSM))
                                }
                            } catch {
                                Swift.print("JSON parse error: \(error)")
                                completion(.failure(error))
                            }
                        }
                        task.resume()
                    } catch let error {
                        Swift.print(error)
                        completion(.failure(error))
                    }
                } else {
                    let error = NSError()
                    completion(.failure(error))
                }
            }
        }
        
        enum ProgramError: Error {
            case missingApplicationCertificate
            case noCKCReturnedByKSM
        }
        
        func contentKeySession(_ session: AVContentKeySession, didFailWithError error: Error) {
            Swift.print("AVContentKeySession didFailWithError: \(error.localizedDescription) — \(error)")
        }
    
        public static func hex(forData theData: Data) -> String {
            return theData.map { String(format: "%02hhx", $0) }.joined()
        }
    }
    



    Source link

    Apple Content encrypted Encryption Fairplay iOS playing
    Follow on Google News Follow on Flipboard
    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email Copy Link
    tonirufai
    big tee tech hub
    • Website

    Related Posts

    ios – Xcode 26.2 Simulator download fails with DVTDownloadableErrorDomain Code 41 on macOS 26.1

    December 28, 2025

    Tesla Could Be Planning to Support Apple Car Keys

    December 28, 2025

    ios – Background Assets Framework server connection problem

    December 27, 2025
    Add A Comment
    Leave A Reply Cancel Reply

    Editors Picks

    World Cup 2026 draw sets out betting favorites as markets take shape

    December 29, 2025

    ios – Xcode 26.2 Simulator download fails with DVTDownloadableErrorDomain Code 41 on macOS 26.1

    December 28, 2025

    Building Blocks for Agentic AI: The Hierarchy of Developer Needs

    December 28, 2025

    Introducing checkpointless and elastic training on Amazon SageMaker HyperPod

    December 28, 2025
    About Us
    About Us

    Welcome To big tee tech hub. Big tee tech hub is a Professional seo tools Platform. Here we will provide you only interesting content, which you will like very much. We’re dedicated to providing you the best of seo tools, with a focus on dependability and tools. We’re working to turn our passion for seo tools into a booming online website. We hope you enjoy our seo tools as much as we enjoy offering them to you.

    Don't Miss!

    World Cup 2026 draw sets out betting favorites as markets take shape

    December 29, 2025

    ios – Xcode 26.2 Simulator download fails with DVTDownloadableErrorDomain Code 41 on macOS 26.1

    December 28, 2025

    Subscribe to Updates

    Get the latest technology news from Bigteetechhub about IT, Cybersecurity and Big Data.

      • About Us
      • Contact Us
      • Disclaimer
      • Privacy Policy
      • Terms and Conditions
      © 2025 bigteetechhub.All Right Reserved

      Type above and press Enter to search. Press Esc to cancel.