基本术语定义

Device Id 以空结尾的唯一标识设备的C字符串。最大32个字符,包括NULL终止。

Device Key 由Widevine分配的128位AES密钥,用于保护授权。

Keybox 广泛的结构,包含用于在设备上建立信任根的密钥和其他信息。密钥盒可以在制造过程中安装,也可以在现场安装。工厂提供的设备具有更高级别的安全性,并可能被批准访问更高质量的内容。

Provision 安装为特定设备唯一构造的密钥盒。

Trusted Execution Environment (TEE) 设备中包含安全硬件并防止非安全系统资源访问的部分。

KeyBox是什么

设备上安装的keybox建立了一个root of trust,设备的secure hardware用于保护keybox的内容,keybox包含:

Device ID(32bytes) :C character string identifying the device, null terminated.

标识设备的C字符串,以空结尾。

Device Key(16bytes) :128 bit AES key assigned to device, generated by Widevine.

分配给设备的128位AES密钥,由Widevine生成。

Key Data(72bytes):Encrypted data

数据加密传输

Magic(4bytes):Constant code used to recognize a valid keybox: “kbox” (0x6b626f78)

用于识别有效密钥盒的常量代码:kbox (0x6b626f78)

CRC(4bytes):CRC-32 POSIX-1003.2 validates integrity of the key data field.

POSIX-1003.2验证关键数据字段的完整性

共128bytes。每个设备对应唯一的device id,唯一的keybox。keybox中的一些字段可以用OEMCrypto中的API获取。

举两个例子:

const WidevineKeybox kTestKeybox = {
// Sample keybox used for test vectors
{
// deviceID
0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey01
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
}, {
// key
0xfb, 0xda, 0x04, 0x89, 0xa1, 0x58, 0x16, 0x0e,
0xa4, 0x02, 0xe9, 0x29, 0xe3, 0xb6, 0x8f, 0x04,
}, {
// data
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19,
0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1,
0x22, 0x67, 0x80, 0x53, 0x36, 0x21, 0x36, 0xbd,
0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4, 0xc2, 0xd8,
0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64,
0x6e, 0x58, 0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8,
0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a, 0x14, 0xa8,
0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64,
0x0b, 0xd2, 0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39,
}, {
// magic
0x6b, 0x62, 0x6f, 0x78,
}, {
// Crc
0x0a, 0x7a, 0x2c, 0x35,
}
};

KeyBox的烧写流程如下图

Widevine的级别

widevine分为三种级别,如下图

可以看到,level3的实现不依赖于硬件保护的key,video通路也不是加密的。整体来说加密级别比较低,所以实际上很多高质量内容(4k)必须在支持level1的设备上播放。一般也建议新设备都提供对level1的支持。

Widevine DRM Framework

大体可分为三部分:

第一部分是包含在AOSP中的内容,包括MedidaDRM,MediaCrypto,WVMExtractor等。

第二部分是Widevine的专利代码包。这部分代码需要得到Google授权后才能得到。它提供了很多Widevine专用库,用于完成Widevine DRM权限检查和解密。同时,它还提供了一些Sample App用于测试。一般在厂商源码的vendor/widevine/目录下。

第三部分是厂商自身的安全认证。Widevine可在硬件层与厂商的安全机制绑定,很多厂商也都在底层中加入自己的安全机制。一般在tee中。

Widevine Classic与Widevine Modular

Widevine Classic是一种历史上曾用的Widevine方案,现在已经被Widevine Modular完全取代。

贴出一张Widevine Classic的总体架构图供参考,如下

而Android目前用的Widevine Modular的架构则如下图所示

关于两者的区别,详述如下:

Widevine Classic是Google专有的用于live、vod以及本地片源的DRM scheme,它要求媒体内容使用Google特有的封装格式(wvm)。Widevine Classic在各种设备和平台上都在逐渐被Widevine Modular所取代,因为使用DRM Plugin工作,非常依赖于widevine专有的东西,比如wvm封装格式,而且只支持单一session。

Widevine Modular是Widevine Classic的继任者,支持Common Encryption (CENC) with MPEG-DASH,使用MediaDRM工作,搭配MediaCodec和MediaCrypto API,提供更通用的加密方案,也被称作WidevineCENC, Widevine DASH,Widevine CDM(就是我们常见的WVCDM)。

自Android M起,Android设备就已经不支持Widevine Classic。如今多数的应用也只支持Widevine Modular。

补充一张对比表:

OEMCrypto是什么

很多介绍DRM的文章在讲完上面的基本概念之后就会开始介绍MediaDRM和MediaCrypto的API了,但这里我觉得可以先深入了解一下更底层的解密原理,有助于后面理解上层API的设计思路。

上图所示MediaDrm and MediaCrypto是java层的api,具体的实现在DrmEngine中,对应Widevine的称为WVDrmEngine.OEMCrypto可以认为是底层硬件和DrmEngine之间的硬件抽象层。

总体而言,OEMCrypto实现了下面四个功能:

  • 验证来往于许可证服务器的消息的真实性.

  • 建立可用于解密消息中包含的密钥材料的密钥加密密钥(从设备密钥派生的密钥).

  • 将加密的内容密钥加载到可信环境中并解密它们.

  • 使用内容键生成解码和呈现的解密流.

  1. OEMCrypto中的Session

在Widevine Classic中,最多只支持一个session,而到了Widevine Modular开始支持多Session,Session的概念也越发重要和丰富。

总体而言,一个session的上下文(context)就对应解密一个流时需要的key等各类信息。比如,解密一个流时需要一个video content key和一个audio content key,可能还需要其他一些key,这些key都保存在一个session context中,再比如,当需要切换分辨率时,就需要创建一个新的session,新的session里面保存了一组新的key。

那么一个Session里面会做什么?基本对应下面这张图

在license request时需要添加nonce和signature。

nonce是一个随机数,用于防止replay attack(重放攻击,一种网络攻击,它恶意的欺诈性的重复或拖延正常的数据传输)。服务器可以把每一次请求的Nonce保存到数据库,客户端再一次提交请求时将请求头中的Nonce与数据库中的数据作比较,如果已存在该Nonce,则证明该请求有可能是恶意的.

Signature(签名)的生成过程如下图

使用下式生成:signature = HMAC­SHA256(mac_key, msg)。

在LoadKeys中进行verify的流程如下图

图中的key_array元素对应OEMCrypto_KeyObject结构体。

图中的enc_key和mac_key是从keybox中的device_key派生出来的。

encrypt_key: used to encrypt the content key:

encrypt_key := AES­128­CMAC(device_key, 0x01 || context_enc)

mac_keys: used as the hash key for the HMAC to sign and verify license messages:

mac_key[server] || mac_key[client]

:= AES­128­CMAC(device_key, 0x01 || context_mac) ||

AES­128­CMAC(device_key, 0x02 || context_mac) ||

AES­128­CMAC(device_key, 0x03 || context_mac) ||

AES­128­CMAC(device_key, 0x04 || context_mac)

对应的方法在OEMCrypto_GenerateDerivedKeys()。

Key Control

对key control block,key control block规定了每个content key所保护的流的security constraints,比如数据通路的安全要求\key的有效时间(在每次调用DecryptCTR会检查)\输出控制等等.key control block共128bit,内容如下

2. OEMCrypto API

包含五部分内容,这其中有的是专为Widevine Modular增加的,还有的则是Widevine Classic和Modular共有的。

2.1 Crypto Device Control

负责security hardware的初始化和mode control。

OEMCrypto_Open和Close方法,前者打开security engine并分配一块内存专用于crypto操作,并且如果使用hardware decryption的话,这块内存也一定是可以被decrypt hardware访问的,相应的,close方法就是关闭security engine并且释放前面分配的内存。

2.2 Crypto Key Ladder

直译为key的阶梯/梯子,其实理解为key的栈更好,我们知道所有的key在传输时都会被加密,所以想要使用一个key,必须要先对其进行解密(一般就是用位于key ladder顶端的key来解密),解密得到的key又被加到key ladder中为接下来的操作做好准备.这部分API同时要求设备必须提供AES-128 ECB,CBC和CTR的硬件支持,保证clear key不会暴露给cpu。总结而言,这部分API的作用是key managment。

这部分API在Widevine Classic和Widevine Modular中有所不同。

在Widevine Classic中:

SetEntitlementKey的作用可以用下图描述:

总体来说,就是用keybox中加密的device key来解密通过网络或其他方法传输来的EMM key(entitlement(EMM) key, aka. asset key)。

step1:使用OEM root key解密keybox中AES 128 ECB加密的device key, 得到的clear device key 保存在hardware key ladder中。

step2:使用上一步得到的clear device key解密AES-128-ECB加密的EMM key,得到的EMM clear key同样保存在hardware中以供下一步操作。

补充:什么是EMM和ECM?

它们其实是来自于数字电视广播中的术语。在数字电视中,通过组合扰频器、加扰和加密,数据流被48位密钥加扰,密钥被称为控制字。在一定时间内控制字的值是很小,在正常情况下,每分钟控制字会被内容提供商改变几次。控制字是通过一个方法连续生成并且不可预见;DVB规范中建议使用物理芯片生成。为了接收到解扰后的数据流,就必须实时得知当前控制字。在实践中,控制字会稍微提前收到,所以不会中断收看。加密通常用来保护控制字传输到接收者:控制字被加密为entitlement

control message(ECM,授权控制信息)。授权机构通过entitlement management

message(EMM,授权管理信息)发送授权给接收机,接收机中的CA子系统就有权解密控制字。EMM消息通过接收机的智能卡具体到每个定阅者。

DeviceControlWord的作用,同样可以用一张图来表示

可以看到正如前面所述的,利用上一个方法中得到的clear EMM key解密加密的ECM key,得到的clear ECM key的前四个字节作为flag返回,中间16字节再次保存到hardware中作为控制字用于后面的payload decrypt。

上面的流程就可以看做一个三级key ladder:

前面说完了Classic,下面来说一下Modular:

OEMCrypto_OpenSession

OEMCrypto_CloseSession

这俩略。

OEMCrypto_GenerateDerivedKeys

用device_key派生出mac_key和encrypt_key,前者用于和license server之间通信的签名,后者用于解密content key.如下图所示:

OEMCrypto_GenerateNonce

如前所述,该方法用于生成32bit的nonce以防止replay attack。

OEMCrypto_GenerateSignature

如前所述,利用mac_key为license request签名。

OEMCrypto_LoadKeys

OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, const uint8_t* enc_mac_keys_iv, const uint8_t* enc_mac_keys, size_t num_keys, const OEMCrypto_KeyObject* key_array, const uint8_t* pst, size_t pst_length); typedef struct { const uint8_t* key_id; size_t         key_id_length; const uint8_t* key_data_iv; const uint8_t* key_data; size_t         key_data_length; const uint8_t* key_control_iv; const uint8_t* key_control;
} OEMCrypto_KeyObject;

为当前session的解密工作做准备,得到解密后的content key以及key control block信息,

如下图所示

方法会用入参中的signature验证签名,如果签名不符合则返回OEMCrypto_ERROR_SIGNATURE_FAILURE。

  • OEMCrypto_RefreshKeys
    为了当前session能够持续的进行解密,需要更新已有的key。

OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, size_t num_keys, const OEMCrypto_KeyRefreshObject* key_array); typedef struct { const uint8_t* key_id; size_t key_id_length; const uint8_t* key_control_iv; const uint8_t* key_control;
} OEMCrypto_KeyRefreshObject;

Trusted memory中会维护一个key table,更新key的duration。同样,该方法也会去检查signature和nonce。

OEMCrypto_QueryKeyControl

返回对应key的key control block(已解密的),只有当loadkeys方法成功调用时,该方法才会返回key control block(以网络字节序),否则返回OEMCrypto_ERROR_NO_CONTENT_KEY。

2.3 Decryption API

这一部分在Widevine Modular和WIdevine Classic中有比较大的不同。

在Widevine Classic中:

又被称为Video Path API,可以直译为视频通路API,即保护视频内容不会被随意解密、随意访问。有两种实现方案,不管哪种方法,都要求设备支持AES 128 CBC. ECB, CBC-CTS。

方案1-保护存储已解密数据的buffer,所谓hardware firewall,如下图所

在OEMCrypto_DecryptAudio和OEMCrypto_DecryptoVideo方法中实现解密操作,video stream被解密到firewalled buffer中,音频流一般被解密到普通的buffer中。

方案二:在解码器中实现解密操作

在上面的方案中,解密操作在OEMCrypto API中实现,而另一种方案是把解密操作留给decoders去实现。在这种方案中也可能会用到OEMCrypto_DecryptAudio和OEMCrypto_DecryptoVideo方法,但它们的作用已经改变,也许只是给buffer加上一些metadata或header信息来告诉decoder哪些buffer是需要解密的。因为在这种方案中给player的buffer是加密的,所以就不需要firewall了。

在level2中,使用OEMCrypto_Decrypt方法解密视音频流,送给player的buffer是clear的。

上面三个方法的参数都包含了input buffer,output buffer,前两个方法的入参还包含了iv,并且利用了前面得到的clear ECM key来解密,区别是第一个方法的output buffer是secured。

下面再来看Widevine Modular:

和Widevine Classic一样,secure decode and render有两种实现方法,一种是将解密后的流送到受硬件保护的buffer中,然后把这些secured buffer送给decoder&renderer;另一种是在decoder/renderer中实现解密的操作。

  • OEMCrypto_SelectKey

使用key_id选择一个content_key(同时还包含了key control block),这个content_key供session做解密(OEMCrypto_DecryptCTR)操作用.这个key一定要是之前被LoadKeys或RefreshKeys installed过的。

值得注意的返回值

OEMCrypto_ERROR_NO_DEVICE_KEY failed to decrypt device key

OEMCrypto_ERROR_NO_CONTENT_KEY failed to decrypt content key

OEMCrypto_ERROR_CONTROL_INVALID invalid or unsupported control input

OEMCrypto_ERROR_KEYBOX_INVALID cannot decrypt and read from Keybox

  • OEMCrypto_DecryptCTR

OEMCryptoResult
OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
const uint8_t *data_addr,
size_t data_length,
bool is_encrypted,
const uint8_t *iv, (每一次解密iv的后64bit加一,达到最大值后变为0,循环)
size_t block_offset, (当使用secure buffer时,存储数据可能会有一个offset)
const OEMCrypto_DestBufferDesc* out_buffer,
unit8_t subsample_flags); typedef enum OEMCryptoBufferType {
OEMCrypto_BufferType_Clear, OEMCrypto_BufferType_Secure, OEMCrypto_BufferType_Direct
} OEMCrytoBufferType; typedef struct {
OEMCryptoBufferType type;
union {
struct {
uint8_t* address; size_t max_length;
} clear;
struct {
void* handle; size_t max_length; size_t offset;
} secure;
struct {
bool is_video;
} direct;
} buffer;
} OEMCrypto_DestBufferDesc;

将data_buffer的数据解密(is_encrypted=true, AES-128-CTR)或直接copy(is_encrypted=false)到out_buffer中。out_buffer有三种类型:clear-即clear buffer; secure-即secure buffer;direct即直接将数据送给decoder和renderer。

返回值(仅在is_encrypted==true的时候会检查)

如果key control block中有duration参数,就会检查是否超时,否则返回KEY_EXPIRED。

如果key control block中有HDCP参数,就会检查outbuffer是否是在本地显示或者仅通过HDCP在外部显示以及HDCP version,否则返回INSUFFICIENT_HDCP。

如果key control block中有data_path_type参数,就会检查是否outbuffer是否是secure或direct的,否则返回DECRYPT_FAIL。

  • OEMCrypto_CopyBuffer

OEMCryptoResult
OEMCrypto_CopyBuffer(const uint8_t *data_addr,
size_t data_length,
const OEMCrypto_DestBufferDesc* out_buffer, unit8_t subsample_flags);

简单的copy,甚至都不需要有session,一般用于将片头的清流copy到secure buffer中,这个过程中应用可以同时进行license request和response处理。

如果Buffer为null,返回INVALID_CONTEXT。

2.4 Keybox Provisioning

为了设备上的内容安全,需要安装widevine keybox来建立一个root of trust。这部分API就负责安装widevine keybox。

标注为optional的API可能只在OEM的factory provisioning procedure中被用到,平时不会被widevine drm plugin调用到。

自API version10开始,设备要有两个key,一个是production key,就是在工厂里安装的key,还有一个则是test keybox,test keybox在所有设备上都是相同的,只用于unit test,可以直接写死在oemcrypto libraray中。

  • OEMCrypto_WrapKeybox

在制造阶段,keybox应该使用OEM root key加密并保存在文件系统中,保存的位置要确保不会在恢复出厂设置的时候被刷掉。keybox既可以一步完成加密和存储的操作,也可以分两步进行:先WrapKeybox再InstallKeybox,具体来说是在DRM plugin初始化的时候,会在/factory/wv.key中寻找wrapped keybox,然后调用OEMCrypto_IntallKeybox方法将它安装到security processor中去。

OEMCrypto_WrapKeybox方法的作用就是生成一个OEM-encrypted keybox来供OEMCrypto_IntallKeybox使用。如下图所示

  • OEMCrypto_IntallKeybox

该方法的作用在前面已经描述过了,如下图

  • OEMCrypto_EncryptandStoreKeybox

这个方法就是前面所说的一步到位的方法,可以看到,这一方法是在level3中用到的。

2.5 Keybox Access

顾名思义,这部分API用于keybox的读取。但是需要说明的是,在level1和level2时,只有security processor可以访问keybox中的key,而在level3中,CPU也可以访问key。

  • isKeyboxValid

检查两点,一个是keybox中的magic word- kbox,第二点是校验CRC

  • IdentifyDevice

获得device的unique id

  • GetKeyData

返回keybox中的 key data

  • GetKeyboxData

解密keybox并返回数据

WIdevine Modular新增:

  • GetRandom

返回hardware generated random bytes

  • API_Version

返回api version

  • SecurityLevel

返回当前库的security level,该方法返回的信息仅供参考

  • HDCPCapability

返回设备支持的最高HDCP版本,以及当前使用的HDCP版本

HDCP_NONE,HDCP_V1,HDCP_V2,HDCP_V2_1,HDCP_V2_2,HDCP_NO_DIGITAL_OUTPUT

  • GetNumberOfOpenSessions 当前打开的session数

  • GetMaxNumberOfSessions 允许同时打开的session数目最大值

关键解密流程

通过前面的介绍,可以看到,解密主要涉及到两个方法:

OEMCrypto_SelectKey() :used to prepare one of the previously loaded keys for decryption.

content_key拿到之后,利用OEMCrypto_DecryptCTR完成解密

文章转载:

深入理解DRM(二)——了解Widevine与OEMCrypto

深入理解 DRM (1) --了解Widevine与OEMCrypto相关推荐

  1. 深入理解DRM(四)——直播流中的DRM

    直播流中的DRM涉及到一个Key Rotation的概念,所谓key rotation就是加密内容的key可以随时间变化,一般用于直播流媒体,但是在点播中也是可能存在的(may be optional ...

  2. 构建DRM系统的重要基石——EME、CDM、AES、CENC和密钥

    ▼扫描下图二维码了解音视频技术大会更多信息▼ 翻译.编辑:Alex 技术审校:刘姗.周亚桥 本文来自OTTVerse,作者为Krishna Rao Vijayanagar. Easy-Tech#016 ...

  3. DRM系统的重要基石——EME、CDM、AES、CENC和密钥

    前言 本文来自OTTVerse,作者为Krishna Rao Vijayanagar. 任何想要理解DRM(Digital Rights Management,数字版权管理)的人都要遇到AES.CDM ...

  4. MTK DRM常见问题介绍

    [DESCRIPTION] 主要介绍mtk支持的DRM Widevine Level; WV与DRM feature option的开关;play movies play videos popups  ...

  5. Linux DRM(一)Display Server

    一.Display Server X Windows 和 X Server The X Window System (X11, or shortened to simply X) is a windo ...

  6. Android DRM框架分析

    Android DRM框架分析 1. DRM框架 2.DRM架构 3.DRM插件 4. 实现 5.DRM插件详情 6.MediaDrm 7.MediaCrypto 8.参考链接 1. DRM框架 An ...

  7. CENC InterTrust DRM 及 player中的应用原理

    数字版权保护方法 数字版权保护方法主要有两类,一类是采用数字水印技术,另一类是以数据加密和防拷贝为核心的DRM技术. 数字水印(Digital Watermark)技术是在数字内容中嵌入隐蔽的标记,这 ...

  8. 数字版权管理 DRM 简介

    0 引言 数字版权管理(Digital Right Management,DRM)是目前对网络中传播的数字作品进行版权保护的主要控制手段.DRM是由美国出版商协会来定义的:"在数字内容交易过 ...

  9. 我的音视频技术笔记路线图

    恍惚间发现自己的博客文章已经有100篇了(有几篇尚在草稿箱中等待进一步加工),才发觉应该弄一个总目录,让自己心里有数,也让诸位读者看着舒心. 我的文章不同于其他作者,鲜少有手把手入门性质文章(这方面我 ...

最新文章

  1. solr的认识、linux下安装、java下使用(含下载资源)
  2. 此blog已经迁移~~~
  3. H5弹窗,弹出toast(横竖屏通用)
  4. JUST技术:管理海量空间数据的利器-空间填充曲线
  5. xfce4下面搜狗输入法默认按键设置
  6. How is new Appoinment id generated in my task followup scenario
  7. DataMan-美团旅行数据质量监管平台实践
  8. nginx windows启动停止_Nginx之3抛砖引玉 - (目录索引)
  9. AFTER触发器与INSTEAD OF触发器的区别
  10. 【报告分享】2020中国短视频行业洞察报告.pdf(附下载链接)
  11. 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)
  12. “茴”字有几种写法? Java 实现 WebSocket 的方式
  13. 装修服务转战线上,VR全景为您解决装修行业痛点!
  14. awesome php
  15. 阿里云服务器搭建java运行环境(jdk+mysql+tomcat)
  16. 字节跳动 录屏功能_免费屏幕录制软件有哪些?原来这么多
  17. swap分区、硬盘和磁盘
  18. java ary是什么,填充N-ary树-Java
  19. 爪哇工具箱集成人工智能文字转语音
  20. 三维算量软件哪个好?鹏业BIM三维安装算量软件

热门文章

  1. ESP32-C3 学习测试 蓝牙 篇(二、蓝牙调试APP、开发板手机连接初体验)
  2. Python创建递增数列、递减数列、等差数列
  3. gdb gdbtui
  4. Amcharts--Chart with scroller
  5. 大厂必备!springboot入门菜鸟教程,面试资料分享
  6. wps文档一敲空格就换行_wps文档中第一行字后面有很多空格,可是第二行就是上不来,按删除键就会把第一行字删了,为什么...
  7. 华为音频编辑服务,实时分离人声、伴奏和乐器声
  8. 嵌入式GPS模块,天线一体化GPS模块,GNSS G-Mouse测试指导
  9. Linux下Nginx安装证书
  10. 谁才是真正五道杠?空气净化器滤网分析