主要内容本文主要就libva中的DRM的流程进行简单说明libva版本为libva-2.11.0(版本号为1.11.0)Digital Rights Management(DRM)指的是数字版权管理用以保护具有版权的数字产品包括视频音乐电子书等等。关于Digital Rights Management(DRM)(数字版权管理)的基础内容本文不做介绍可以参考链接:DRM基础介绍AES加密原理AES加密模式RSA加密原理数字签名和数字证书X.509证书目前常见的的DRM标准有以下几种PlayReady by MicrosoftFairPlay by AppleMerlin by Sony除此之外还有google的widewine相关术语DRM: Digital Rights Management, 数字版权管理TEE: Trust Excute Environment,可信任执行环境IHV: Independent Hardware Vendor,独立硬件厂商相关接口和结构体libva中的DRM接口从libva2.11引入主要是在va_pro.h中。VAProtectedSessionBuffertypedef struct _VAProtectedSessionBuffer { //作为输入的buffer不使用该值但是作为输出buffermax_data_size可以输出driver所 //返回的输出buffer的数据量的最大值 uint32_t max_data_size; //作为输入bufferr使用data_size指的是输入buffer的数据量大小 //作为输出bufferr使用data_size指的是driver写入data的数据量大小 uint32_t data_size; //数据指针 void *data; //保留未使用 uint32_t va_reserved[VA_PADDING_LOW]; } VAProtectedSessionBuffer;VAProtectedSessionExecuteBuffertypedef struct _VAProtectedSessionExecuteBuffer { //指定执行的功能由IHV实现 uint32_t function_id; //输入buffer VAProtectedSessionBuffer input; //输出buffer VAProtectedSessionBuffer output; //返回函数执行结果由IHV实现 uint32_t status; //保留未使用 uint32_t va_reserved[VA_PADDING_LOW]; } VAProtectedSessionExecuteBuffer;VAEncryptionSegmentInfotypedef struct _VAEncryptionSegmentInfo { /** \brief The offset relative to the start of the bitstream input in * bytes of the start of the segment */ uint32_t segment_start_offset; /** \brief The length of the segments in bytes */ uint32_t segment_length; /** \brief The length in bytes of the remainder of an incomplete block * from a previous segment*/ uint32_t partial_aes_block_size; /** \brief The length in bytes of the initial clear data */ uint32_t init_byte_length; /** \brief This will be AES counter for secure decode and secure encode * when numSegments equals 1, valid size is specified by * \c key_blob_size */ uint8_t aes_cbc_iv_or_ctr[64]; /** \brief Reserved bytes for future use, must be zero */ uint32_t va_reserved[VA_PADDING_MEDIUM]; } VAEncryptionSegmentInfo;VAEncryptionParameterstypedef struct _VAEncryptionParameters { /** \brief Encryption type, refer to \c VA_ENCRYPTION_TYPE_FULLSAMPLE_CTR, * \c VA_ENCRYPTION_TYPE_FULLSAMPLE_CBC, \c VA_ENCRYPTION_TYPE_SUBSAMPLE_CTR, * or \c VA_ENCRYPTION_TYPE_SUBSAMPLE_CBC */ uint32_t encryption_type; /** \brief The number of sengments */ uint32_t num_segments; /** \brief Pointer of segments */ VAEncryptionSegmentInfo *segment_info; /** \brief The status report index reserved for CENC fullsample workload. * The related structures and definitions are vendor specific. */ uint32_t status_report_index; /** \brief CENC counter length */ uint32_t size_of_length; /** \brief Wrapped decrypt blob (Snd)kb, valid size is specified by * \c key_blob_size */ uint8_t wrapped_decrypt_blob[64]; /** \brief Wrapped Key blob info (Sne)kb, valid size is specified by * \c key_blob_size */ uint8_t wrapped_encrypt_blob[64]; /** \brief key blob size * It could be \c VA_PC_BLOCK_SIZE_128, \c VA_PC_BLOCK_SIZE_192, or * \c VA_PC_BLOCK_SIZE_256 */ uint32_t key_blob_size; /** \brief Indicates the number of 16-byte BLOCKS that are encrypted in any * given encrypted region of segments. * If this value is zero: * 1. All bytes in encrypted region of segments are encrypted, i.e. the * CENC or CBC1 scheme is being used * 2. blocks_stripe_clear must also be zero. * If this value is non-zero, blocks_stripe_clear must also be non-zero. */ uint32_t blocks_stripe_encrypted; /** \brief Indicates the number of 16-byte BLOCKS that are clear in any given * encrypted region of segments, as defined by the CENS and CBCS schemes in * the common encryption spec. * If this value is zero, all bytes in encrypted region of segments are * encrypted, i.e. the CENC or CBC1 scheme is being used. */ uint32_t blocks_stripe_clear; /** \brief Reserved bytes for future use, must be zero */ uint32_t va_reserved[VA_PADDING_MEDIUM]; } VAEncryptionParameters;配置配置属性值其他VAConfigAttribTEEType由厂商决定VAConfigAttribTEETypeClient由厂商决定VAConfigAttribProtectedContentCipherAlgorithmVA_PC_CIPHER_AES算法种类目前只支持AESVAConfigAttribProtectedContentCipherBlockSizeVA_PC_BLOCK_SIZE_128VA_PC_BLOCK_SIZE_192VA_PC_BLOCK_SIZE_256算法的大小安全性越好速度越慢VAConfigAttribProtectedContentCipherModeVA_PC_CIPHER_MODE_ECBVA_PC_CIPHER_MODE_CBCVA_PC_CIPHER_MODE_CTRAES密钥模式,目前只支持三种VAConfigAttribProtectedContentCipherSampleTypeVA_PC_SAMPLE_TYPE_FULLSAMPLE, VA_PC_SAMPLE_TYPE_SUBSAMPLE采样类型VAConfigAttribProtectedContentUsageVA_PC_USAGE_DEFAULT, VA_PC_USAGE_WIDEVINE使用的DRM标准默认或者widewineAPIAPI说明其他vaCreateProtectedSession创建一个被保护的对话vaDestroyProtectedSession销毁创建的对话vaAttachProtectedSession附着对话到一个VA context中使能加密保护vaDetachProtectedSession游离context中附着的对话失能加密保护vaProtectedSessionExecute执行被保护的对话使用流程查询entrypoint是否支持Content protection获取相关的配置属性创建config对象获取保护对话的buffer数据附着session到相关的context上按照正常的流程解码游离context上的session//查询相关的entrypoints VAEntrypoint entrypoints; int i, num_entrypoints, supportsProtectedContent 0; num_entrypoints vaMaxNumEntrypoints(); entrypoints malloc(num_entrypoints sizeof(entrypoints[0]); vaQueryConfigEntrypoints(va_dpy, VAProfileProtected, entrypoints, num_entrypoints); for (i 0; !supportsProtectedContent i num_entrypoints; i) { if (entrypoints[i] VAEntrypointProtectedContent) supportsProtectedContent 1; } //获取配置属性 VAConfigAttrib attribs; //获取密钥算法类型 attribs[0].type VAConfigAttribProtectedContentCipherAlgorithm; //获取密钥算发支持的块的尺寸 attribs[1].type VAConfigAttribProtectedContentCipherBlockSize; //获取密钥算法模式 attribs[2].type VAConfigAttribProtectedContentCipherMode; //获取密钥采样类型 attribs[3].type VAConfigAttribProtectedContentCipherSampleType; //获取使用DRM标准 attribs[4].type VAConfigAttribProtectedContentUsage; vaGetConfigAttributes(va_dpy, VAProfileProtected, VAEntrypointProtectedContent, attribs, 5); if ((attribs[1].value VA_PC_CIPHER_AES) 0) { // not find desired cipher algorithm assert(0); } if ((attribs[2].value VA_PC_BLOCK_SIZE_128) 0) { // not find desired block size assert(0); } if ((attribs[3].value VA_PC_CIPHER_MODE_CBC) 0) { // not find desired counter mode assert(0); } if ((attribs[4].value VA_PC_SAMPLE_TYPE_SUBSAMPLE) 0) { // not find desired sample type assert(0); } if ((attribs[5].value VA_PC_USAGE_WIDEVINE) 0) { // not find desired usage assert(0); } //创建配置对象 VAConfigID config_id; attribs[0].value VA_PC_CIPHER_AES; attribs[1].value VA_PC_BLOCK_SIZE_128; attribs[2].value VA_PC_CIPHER_MODE_CBC; attribs[3].value VA_PC_SAMPLE_TYPE_SUBSAMPLE; attribs[4].value VA_PC_USAGE_WIDEVINE; va_status vaCreateConfig(va_dpy, VAProfileProtected, VAEntrypointProtectedContent, attribs, 5, config_id); CHECK_VASTATUS(va_status, vaCreateConfig); //创建VAProtectedSessionExecuteBuffer 对象 uint32_t app_id 0xFF; VABufferID buffer; VAProtectedSessionExecuteBuffer exec_buff {0}; //GET_SESSION_ID只是函数的一种driver实现的功能由IHV决定可以实现很多功能 //指定不同的function_id来访问不同的功能 exec_buff.function_id GET_SESSION_ID; exec_buff.input.data nullptr; exec_buff.input.data_size 0; exec_buff.output.data app_id; exec_buff.output.max_data_size sizeof(app_id); va_status vaCreateBuffer( va_dpy, crypto_session, (VABufferType) VAProtectedSessionExecuteBufferType, sizeof(exec_buff), 1, exec_buff, buffer); //执行对话sesson传入或者获取数据如content key va_status vaProtectedSessionExecute(va_dpy, crypto_session, buffer); vaDestroyBuffer(va_dpy, buffer); //附着对话到session上 vaAttachProtectedSession(va_dpy, decode_ctx, crypto_session); foreach (iteration) { vaBeginPicture(va_dpy, decode_ctx, surface); ... vaRenderPicture(va_dpy, decode_ctx, buf_id1, 1); vaRenderPicture(va_dpy, decode_ctx, buf_id2, 1); // Buffer holding encryption parameters, i.e. VAEncryptionParameterBufferType buffer vaRenderPicture(va_dpy, decode_ctx, buf_id_enc_param, 1); ... vaEndPicture(va_dpy, decode_ctx); } //游离context的对话 vaDetachProtectedSession(va_dpy, decode_ctx); foreach (iteration) { if (encrypted) vaAttachProtectedSession(va_dpy, decode_ctx, crypto_session); vaBeginPicture(va_dpy, decode_ctx, surface); ... vaRenderPicture(va_dpy, decode_ctx, buf_id1, 1); vaRenderPicture(va_dpy, decode_ctx, buf_id2, 1); // Buffer holding encryption parameters, i.e. VAEncryptionParameterBufferType buffer vaRenderPicture(va_dpy, decode_ctx, buf_id_enc_param, 1); ... vaEndPicture(va_dpy, decode_ctx); if (encrypted) vaDetachProtectedSession(va_dpy, decode_ctx); // check encrypted variable for next frame }