{"id":15066957,"url":"https://github.com/miwr/swwidevine","last_synced_at":"2025-07-13T02:31:35.495Z","repository":{"id":255033353,"uuid":"848361572","full_name":"mIwr/SwWidevine","owner":"mIwr","description":"Swift Widevine CDM implementation","archived":false,"fork":false,"pushed_at":"2024-11-21T15:51:30.000Z","size":101,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-11-21T16:42:51.816Z","etag":null,"topics":["drm","google","swift","widevine"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mIwr.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-27T16:13:02.000Z","updated_at":"2024-11-21T15:51:05.000Z","dependencies_parsed_at":"2024-11-21T16:33:34.204Z","dependency_job_id":"97299259-10d0-4c5d-9e19-07b326507a0c","html_url":"https://github.com/mIwr/SwWidevine","commit_stats":null,"previous_names":["miwr/swwidevine"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mIwr%2FSwWidevine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mIwr%2FSwWidevine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mIwr%2FSwWidevine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mIwr%2FSwWidevine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mIwr","download_url":"https://codeload.github.com/mIwr/SwWidevine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225850201,"owners_count":17534062,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["drm","google","swift","widevine"],"created_at":"2024-09-25T01:14:26.184Z","updated_at":"2025-07-13T02:31:35.472Z","avatar_url":"https://github.com/mIwr.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SwWidevine - Swift Widevine CDM implementation\n\n[![Swift Package Manager compatible](https://img.shields.io/badge/SPM-compatible-brightgreen.svg?style=flat\u0026colorA=28a745\u0026\u0026colorB=4E4E4E)](https://github.com/apple/swift-package-manager)\n[![Platform](https://img.shields.io/badge/Platforms-iOS%20%7C%20Android%20%7CmacOS%20%7C%20watchOS%20%7C%20tvOS%20%7C%20Linux-4E4E4E.svg?colorA=28a745)](#Setup)\n\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/apple/swift\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/language-swift-orange.svg\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"http://cocoapods.org/pods/SwWidevine\"\u003e\n        \u003cimg src=\"https://img.shields.io/cocoapods/v/SwWidevine.svg?style=flat\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"http://cocoapods.org/pods/SwWidevine\"\u003e\n        \u003cimg src=\"https://img.shields.io/cocoapods/p/SwWidevine.svg?style=flat\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"./LICENSE\"\u003e\n        \u003cimg src=\"https://img.shields.io/cocoapods/l/SwWidevine.svg?style=flat\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n## Content\n\n- [Disclaimer](#Disclaimer)\n\n- [Introduction](#Introduction)\n\n- [Features](#Features)\n\n- [Setup](#Setup)\n\n- [Getting started](#Getting-started)\n\n- [DRM license acquire](#DRM-license-acquire)\n\n## Disclaimer\n\n1. This project requires a valid Google-provisioned Private Key and Client Identification blob which are not\n   provided by this project.\n2. Public test provisions are available and provided by Google to use for testing projects such as this one.\n3. License Servers have the ability to block requests from any provision, and are likely already blocking test\n   provisions on production endpoints.\n4. This project does not condone piracy or any action against the terms of the DRM systems.\n5. All efforts in this project have been the result of Reverse-Engineering, Publicly available research, and Trial\n   \u0026 Error.\n\n## Introduction\n\nThe library allows to do License Acquisition within the CDM\n\nmacOS 10.13+, iOS 11.0+ and Windows are supported by the module code base. Other platforms (tvOS 11.0+, watchOS 4.0+ for CocoaPods and 5.0+ for SPM, visionOS 1.0+, Linux, Android) have experimental support\n\n**Notice: XCode 15+ doesn't allow to use iOS 11, tvOS 11 as minimum deployment target during build process. So the mimimum deployment target for these platforms in your project must be 12 in fact.**\n**If you want to bypass this limitation, you have to roll back to XCode 14.** More info: [1](https://github.com/Alamofire/Alamofire/pull/3823), [2](https://github.com/realm/realm-swift/issues/8368#issuecomment-1737604011)\n\n## Features\n\n- Pure swift CDM implementation\n- Widevine L3 supported\n- Generating the DRM License Challenge request\n- DRM service certificates support (For encrypting client info)\n- Processing DRM server License response with extracting content keys\n\n**Notice: the module doesn't provide pack/unpack tools for DRM content**\n\n## Setup\n\n### Swift Package Manager\n\nSwWidevine is available with SPM\n\n```\n.package(url: \"https://github.com/mIwr/SwWidevine.git\", .from(from: \"1.1.2\"))\n```\n\n### CocoaPods\n\nSwWidevine is available with CocoaPods. To install a module, just add to the Podfile:\n\n- iOS\n```ruby\nplatform :ios, '11.0'\n...\npod 'SwPSSH'\npod 'SwWidevine'\n```\n\n- macOS\n```ruby\nplatform :osx, '10.13'\n...\npod 'SwPSSH'\npod 'SwWidevine'\n```\n\n- tvOS\n```ruby\nplatform :tvos, '11.0'\n...\npod 'SwPSSH'\npod 'SwWidevine'\n```\n\n- watchOS\n```ruby\nplatform :watchos, '4.0'\n...\npod 'SwPSSH'\npod 'SwWidevine'\n```\n\n## Getting started\n\nCDM main logic is contained at [WDVCDMController](./Sources/SwWidevine/WDVCDMController.swift) class.\n\n1. To init CDM controller you need [WDVDevice](./Sources/SwWidevine/Model/Device/WDVDevice.swift) instance, which contains RSA private key and client info\n```swift\nimport SwWidevine\n//...\nlet wdvData: [UInt8]\n//...Acquiring device data...\nguard let device: WDVDevice = WDVDevice.from(wdvBytes: wdvBytes) else {return}\nlet wdvCdm: WDVCDMController\ndo {\n  wdvCdm = try WDVCDMController(device: device)\n} catch {\n  return\n}\n```\n\n2. Get provider application 'privacy' certificate if exists and required (protobuf SignedDrmCertificate) \n\n3. Now you can create the session for working with CDM\n```swift\nlet serviceCert: WDVSignedDrmCertificate?\n//...Acquiring application 'privacy' certificate...\nlet creationRes: Result\u003cWDVSession, WDVError\u003e = wdvCdm.openNewSession(serviceCertificate: serviceCert)\nlet session: WDVSession\ndo {\n  session = try creationRes.get()\n} catch {\n  return\n}\n```\n\n**Notice: Session maximum count is programmaticaly limited to 16 at the moment for single controller**\n\n## DRM license acquire\n\n### Generating DRM License Challenge request\n\nTo make the License Challenge request you need to provide:\n\n- CDM session\n- DRM content PSSH\n\n```swift\nimport SwPSSH\nimport SwWidevine\n//...\nlet cdmController: WDVCDMController\nlet appCrt: WDVSignedDrmCertificate?\nlet pssh: PSSHBox\n//...init controller, service privacy certificate and PSSH box container...\nlet openRes = cdmController.openNewSession(serviceCertificate: appCrt)\nguard let safeSession = try? openRes.get() else {return}\nlet licReqRes = cdmController.generateLicChallenge(sessionHexId: safeSession.hexId, pssh: pssh, licenseType: .streaming, privacyMode: true)\nguard let safeLicReq: [UInt8] = try? licReqRes.get() else {return}\n```\n\nCDM controller will return raw protobuf bytes of the generated and signed request message. Message has to be sent to DRM license server according provided API\n \n**Each created License Challenge request will be cached on the session context for further DRM server license response processing**\n \n### Processing DRM server license response\n\nReceived from DRM server the license response is a protobuf SignedMessage instance. \n```swift\nlet licSrvResponseData: Data\n//...Generate license request and send to license server...\nlet parseRes = cdmController.extractKeyFromLicenseMsg(sessionHexId: safeSession.hexId, licSrvResponse: data)\nguard let safeKeys: [WDVContentKey] = try? parseRes.get() else {return}\n```\nController will extract content key from response. Also it will cache the key on session key storage.\n\nFurther step is providing key ID and key data for unpacker (mp4decrypt, shaka-packager or ffmpeg, for example)\n\n**shaka-packager unpack cmd example**\n```\n./packager in=input_file,stream=0,output=output_file --enable_raw_key_decryption --keys label=1:key_id={Key ID hex string}:key={Key data hex string}\n```\n\n**ffmpeg unpack cmd example**\n```\n./ffmpeg -decryption_key {Key data hex string} -i input_file output_file\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiwr%2Fswwidevine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmiwr%2Fswwidevine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiwr%2Fswwidevine/lists"}