From patchwork Tue Jan 2 17:57:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacob Trimble X-Patchwork-Id: 7085 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.79.195 with SMTP id r64csp14961557jad; Tue, 2 Jan 2018 09:57:38 -0800 (PST) X-Google-Smtp-Source: ACJfBou3OD5V57KpT5pmy+n7YWBeyJZlbLBNyypFTDvb7FQbPa5LKYl6w+1ov1iRci+K3mNr/w1S X-Received: by 10.28.207.130 with SMTP id f124mr33744256wmg.132.1514915858830; Tue, 02 Jan 2018 09:57:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1514915858; cv=none; d=google.com; s=arc-20160816; b=Ucu4HpTOdyRtlcWYqZT5ZFqbYS+Tp5X7e0/zda3anvgNDb4iZKfBuVXWoS3Mi+VGq3 j1FpjMuczWr1c1755korEW+igf/TtvZDqBOcBHm1wWJkWhB6pRjMbXPLAd6JZyA2ZE4C ko3fQQsMX13kBjtvcCWT/psp+d16CRgM5u6NN5IFjkdJ6EcYB1HGt+ea8SkcidsfCKjG rZ6dIebgnvGM5VVV9dk0mYHvCnOrCtp6exIp1NoNCB1BPpBFXXhIv5Rf145BywqEvgm4 21jXqWOEFcXasQ/gVZt7CIyJKesvwaibKn+4QiDGstjy4OvyFhXsvPg6kJRcYch7h+Hp f4eA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:to :message-id:date:from:references:in-reply-to:mime-version :dkim-signature:delivered-to:arc-authentication-results; bh=cyIlYC+W6jgUZKx/q5C/Esosybhv9pPddtKsQLl7nGc=; b=lBeMR84XMrIyZcqcir8On+4k38QnPrBndgZuNZJjpvX3FZEDqG+pJ3ulFyskFg/ElP XfoCPQN4/TohotoQPEwFbUe3RpWDz/gZ6we1j2w2WRfGaKEzoM5T7/0AiuZO+WutL8e2 9zIO+rPidNCukjAp1lkAYSLJpsD6+yNvGnJPu0eCloUlducA31MtouxDQs3VXrfBlnc3 ZDZmyN4k9/hKXUC/qshxT4pEyOfw7isjf1WsB/GGtGZxA8FnrKTK4GwuiFSleHq6Slt/ 95jCs141t6TBF6HXILNm5H6A2HiU9hJRbc5A9+wQ/qICM8jGsj5INyDMbQ1Strx+Mv7t 0hfA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@google.com header.s=20161025 header.b=pwpYD+1c; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id q74si22352215wmg.217.2018.01.02.09.57.38; Tue, 02 Jan 2018 09:57:38 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@google.com header.s=20161025 header.b=pwpYD+1c; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id DE3F168050D; Tue, 2 Jan 2018 19:57:20 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-vk0-f50.google.com (mail-vk0-f50.google.com [209.85.213.50]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id B93D168050D for ; Tue, 2 Jan 2018 19:57:14 +0200 (EET) Received: by mail-vk0-f50.google.com with SMTP id m15so30624387vkf.13 for ; Tue, 02 Jan 2018 09:57:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=mime-version:in-reply-to:references:from:date:message-id:subject:to; bh=Ml5BOW+hknZxahoby4jVqNFqqmaKdpKfy7OLntNKEvE=; b=pwpYD+1cow1CjQ+kVU6g4TU8/fCuMnw7jJV2KpygdBla5Z0kCq1PWSxBPlhWqDeNVL vg52G7QZnAyMJz7noV4LpW3v3jS0CaIuv5ij39XjwSwZs5hV7wcMCcoEWu4nfY1J0Yff kGJ+dMsPBZGg4NQRCkfusqENO6WMrViNBT7Kf6puwKkJjr9A7HLpGDry4jVe61TF8INA iuDNOWwZtgHPv6EX+CRfMR7wFJFUcOoI3ZCrC6onu1+m8GdaZdxQnuE9N17Ll4m0sCTC ro0lUVB5fYm8ZDKnUVA9R2+ykZkxxd7v7/JNgafjsPxCjK30MXCNAian8XTQ8E2TWBsG YxZQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to; bh=Ml5BOW+hknZxahoby4jVqNFqqmaKdpKfy7OLntNKEvE=; b=jSQrBGCUUiS5x5UTb8f7fh8Olr/xGE2FwNt8iapD1vJeLtp1LKYNvI5Xy3D0PPAaWn CSEVTWsLf4EheJSHdneKXUA33vZ904YCeH54OGdVPIcnHYojn6VeYC+FJIBHXRTDm1TS v0t2w6Pgc6g4k36bHybvN/7cQaBjMU/oFCoNvwen7IY+btSFjwpvQVR4ksxjEudbDj6n f8+PEaGKsXk1AJZWhBX47BHOrWOoT3+0U36FIBdnfqvnqf9Ftcf+VAL7759ycERsv/bI YEjblmDOcSYKl5C+iJA6UePuGqgeW8KHD7OCUCYQoeXCHGz78Fe8rT357nAIrCq3M7+X 3RCw== X-Gm-Message-State: AKGB3mIImWcqy+6UxfA3ad91qxO7KscxzMkt4DlYiF2TXsf7TQJvoyqA 5fVYoKmMw0TKH84gduR5pRTDaniqA5jEpo9PMWGNTLgV X-Received: by 10.31.21.142 with SMTP id 136mr36710007vkv.121.1514915848786; Tue, 02 Jan 2018 09:57:28 -0800 (PST) MIME-Version: 1.0 Received: by 10.103.214.138 with HTTP; Tue, 2 Jan 2018 09:57:27 -0800 (PST) In-Reply-To: <20171221013127.1a317177@debian> References: <20171214225305.GA4926@michaelspb> <20171218205208.28057570@debian> <88005b78-3b8b-5f20-7d3d-2929cfd36e57@gmail.com> <20171218203824.GQ4926@michaelspb> <20171218220252.1be1bb1c@debian> <20171218211714.GR4926@michaelspb> <20171218222814.157dfd69@debian> <20171218230015.GS4926@michaelspb> <20171219004433.GU4926@michaelspb> <20171220000504.492f1d33@debian> <20171220212355.4f349638@debian> <20171221013127.1a317177@debian> From: Jacob Trimble Date: Tue, 2 Jan 2018 09:57:27 -0800 Message-ID: To: FFmpeg development discussions and patches Subject: Re: [FFmpeg-devel] [RFC] avcodec/avcodec.h: Add encryption info side data X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" On Wed, Dec 20, 2017 at 4:31 PM, wm4 wrote: > On Wed, 20 Dec 2017 15:10:43 -0800 > Jacob Trimble wrote: > >> From 1508d19e9f7acf43d76010ce54d59ff204613601 Mon Sep 17 00:00:00 2001 >> From: Jacob Trimble >> Date: Tue, 5 Dec 2017 14:52:22 -0800 >> Subject: [PATCH] avcodec/avcodec.h: Add encryption info side data. >> >> This new side-data will contain info on how a packet is encrypted. >> This allows the app to handle packet decryption. >> >> Signed-off-by: Jacob Trimble >> --- > > Looks generally good to me, a few minor cosmetic comments below. > >> libavcodec/Makefile | 2 + >> libavcodec/avcodec.h | 13 ++++ >> libavcodec/encryption_info.c | 139 +++++++++++++++++++++++++++++++++++++++++++ >> libavcodec/encryption_info.h | 121 +++++++++++++++++++++++++++++++++++++ >> 4 files changed, 275 insertions(+) >> create mode 100644 libavcodec/encryption_info.c >> create mode 100644 libavcodec/encryption_info.h >> >> diff --git a/libavcodec/Makefile b/libavcodec/Makefile >> index ab7893f560..11ad642c6c 100644 >> --- a/libavcodec/Makefile >> +++ b/libavcodec/Makefile >> @@ -10,6 +10,7 @@ HEADERS = ac3_parser.h \ >> dirac.h \ >> dv_profile.h \ >> dxva2.h \ >> + encryption_info.h \ >> jni.h \ >> mediacodec.h \ >> qsv.h \ >> @@ -36,6 +37,7 @@ OBJS = ac3_parser.o \ >> dirac.o \ >> dv_profile.o \ >> encode.o \ >> + encryption_info.o \ >> imgconvert.o \ >> jni.o \ >> mathtables.o \ >> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h >> index 5db6a81320..b43638ebc5 100644 >> --- a/libavcodec/avcodec.h >> +++ b/libavcodec/avcodec.h >> @@ -1327,6 +1327,19 @@ enum AVPacketSideDataType { >> */ >> AV_PKT_DATA_A53_CC, >> >> + /** >> + * This side data is encryption "initialization data". >> + * For MP4 this is the entire 'pssh' box. >> + * For WebM this is the key ID. >> + */ >> + AV_PKT_DATA_ENCRYPTION_INIT_DATA, >> + >> + /** >> + * This side data contains encryption info for how to decrypt the packet. >> + * The format is not part of ABI, use av_encryption_info_* methods to access. >> + */ >> + AV_PKT_DATA_ENCRYPTION_INFO, >> + >> /** >> * The number of side data types. >> * This is not part of the public API/ABI in the sense that it may >> diff --git a/libavcodec/encryption_info.c b/libavcodec/encryption_info.c >> new file mode 100644 >> index 0000000000..59ee4c41a9 >> --- /dev/null >> +++ b/libavcodec/encryption_info.c >> @@ -0,0 +1,139 @@ >> +/** >> + * This file is part of FFmpeg. >> + * >> + * FFmpeg is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU Lesser General Public >> + * License as published by the Free Software Foundation; either >> + * version 2.1 of the License, or (at your option) any later version. >> + * >> + * FFmpeg is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + * Lesser General Public License for more details. >> + * >> + * You should have received a copy of the GNU Lesser General Public >> + * License along with FFmpeg; if not, write to the Free Software >> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA >> + */ >> + >> +#include "encryption_info.h" >> +#include "libavutil/avassert.h" >> +#include "libavutil/intreadwrite.h" >> + >> +#define FF_ENCRYPTION_INFO_EXTRA 24 >> + >> +// The format of the side data: >> +// u32be scheme >> +// u32be crypt_byte_block >> +// u32be skip_byte_block >> +// u32be key_id_size >> +// u32be iv_size >> +// u32be subsample_count >> +// u8[key_id_size] key_id >> +// u8[iv_size] iv >> +// { >> +// u32be bytes_of_clear_data >> +// u32be bytes_of_protected_data >> +// }[subsample_count] >> + >> +AVEncryptionInfo* av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size) > > I think we generally put the "*" to the name, to reflect the actual C > syntax. (Here and in other places where pointers are in the function > return or argument types.) > >> +{ >> + AVEncryptionInfo *info; >> + >> + info = av_mallocz(sizeof(AVEncryptionInfo)); >> + if (!info) >> + return NULL; >> + >> + info->key_id = av_mallocz(key_id_size); >> + info->key_id_size = key_id_size; >> + info->iv = av_mallocz(iv_size); >> + info->iv_size = iv_size; >> + info->subsamples = av_mallocz_array(sizeof(AVSubsampleEncryptionInfo), subsample_count); >> + info->subsample_count = subsample_count; >> + >> + // Allow info->subsamples to be NULL if there are no subsamples. >> + if (!info->key_id || !info->iv || (!info->subsamples && subsample_count)) { >> + av_free(info->key_id); >> + av_free(info->iv); >> + av_free(info->subsamples); > > Couldn't this just call av_encryption_info_free()? > >> + av_freep(&info); >> + } >> + >> + return info; >> +} >> + >> +void av_encryption_info_free(AVEncryptionInfo* info) >> +{ >> + if (info) { >> + av_free(info->key_id); >> + av_free(info->iv); >> + av_free(info->subsamples); >> + av_free(info); >> + } >> +} >> + >> +AVEncryptionInfo* av_encryption_info_copy_side_data(const AVPacket* packet) > > Could still be called "get" instead of "copy". I get the intention that > this returns a copy of the data, but "copy" still sounds like it's > being copied somewhere else. But I have no strong feelings about it. > >> +{ >> + AVEncryptionInfo *info; >> + uint8_t *buffer; >> + unsigned int size; >> + uint32_t key_id_size, iv_size, subsample_count, i; >> + >> + buffer = av_packet_get_side_data(packet, AV_PKT_DATA_ENCRYPTION_INFO, &size); >> + if (!buffer) >> + return NULL; >> + >> + key_id_size = AV_RB32(buffer + 12); >> + iv_size = AV_RB32(buffer + 16); >> + subsample_count = AV_RB32(buffer + 20); >> + >> + info = av_encryption_info_alloc(subsample_count, key_id_size, iv_size); >> + if (!info) >> + return NULL; >> + >> + info->scheme = AV_RB32(buffer); >> + info->crypt_byte_block = AV_RB32(buffer + 4); >> + info->skip_byte_block = AV_RB32(buffer + 8); >> + memcpy(info->key_id, buffer + 24, key_id_size); >> + memcpy(info->iv, buffer + key_id_size + 24, iv_size); >> + >> + buffer += key_id_size + iv_size + 24; >> + for (i = 0; i < subsample_count; i++) { >> + info->subsamples[i].bytes_of_clear_data = AV_RB32(buffer); >> + info->subsamples[i].bytes_of_protected_data = AV_RB32(buffer + 4); >> + buffer += 8; >> + } >> + >> + return info; >> +} >> + >> +int av_encryption_info_add_side_data(AVPacket* packet, const AVEncryptionInfo* info) { > > We put the "{" on a separate line for functions. > >> + uint8_t *buffer; >> + size_t size; >> + uint32_t i; >> + >> + size = FF_ENCRYPTION_INFO_EXTRA + info->key_id_size + info->iv_size + >> + (sizeof(AVSubsampleEncryptionInfo) * info->subsample_count); >> + buffer = av_packet_new_side_data(packet, AV_PKT_DATA_ENCRYPTION_INFO, size); >> + if (!buffer) >> + return AVERROR(ENOMEM); >> + >> + AV_WB32(buffer, info->scheme); >> + AV_WB32(buffer + 4, info->crypt_byte_block); >> + AV_WB32(buffer + 8, info->skip_byte_block); >> + AV_WB32(buffer + 12, info->key_id_size); >> + AV_WB32(buffer + 16, info->iv_size); >> + AV_WB32(buffer + 20, info->subsample_count); >> + buffer += 24; >> + memcpy(buffer, info->key_id, info->key_id_size); >> + buffer += info->key_id_size; >> + memcpy(buffer, info->iv, info->iv_size); >> + buffer += info->iv_size; >> + for (i = 0; i < info->subsample_count; i++) { >> + AV_WB32(buffer, info->subsamples[i].bytes_of_clear_data); >> + AV_WB32(buffer + 4, info->subsamples[i].bytes_of_protected_data); >> + buffer += 8; >> + } >> + >> + return 0; >> +} >> diff --git a/libavcodec/encryption_info.h b/libavcodec/encryption_info.h >> new file mode 100644 >> index 0000000000..4fc9b6d3f1 >> --- /dev/null >> +++ b/libavcodec/encryption_info.h >> @@ -0,0 +1,121 @@ >> +/** >> + * This file is part of FFmpeg. >> + * >> + * FFmpeg is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU Lesser General Public >> + * License as published by the Free Software Foundation; either >> + * version 2.1 of the License, or (at your option) any later version. >> + * >> + * FFmpeg is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + * Lesser General Public License for more details. >> + * >> + * You should have received a copy of the GNU Lesser General Public >> + * License along with FFmpeg; if not, write to the Free Software >> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA >> + */ >> + >> +#ifndef AVUTIL_ENCRYPTION_INFO_H >> +#define AVUTIL_ENCRYPTION_INFO_H >> + >> +#include "avcodec.h" >> + >> +typedef struct AVSubsampleEncryptionInfo { >> + /** The number of bytes that are clear. */ >> + unsigned int bytes_of_clear_data; >> + >> + /** >> + * The number of bytes that are protected. If using pattern encryption, >> + * the pattern applies to only the protected bytes; if not using pattern >> + * encryption, all these bytes are encrypted. >> + */ >> + unsigned int bytes_of_protected_data; >> +} AVSubsampleEncryptionInfo; >> + >> +/** >> + * This describes encryption info for a packet. This contains frame-specific >> + * info for how to decrypt the packet before passing it to the decoder. >> + * >> + * The size of this struct is not part of the public ABI. >> + */ >> +typedef struct AVEncryptionInfo { >> + /** The fourcc encryption scheme. */ >> + uint32_t scheme; >> + >> + /** >> + * Only used for pattern encryption. This is the number of 16-byte blocks >> + * that are encrypted. >> + */ >> + uint32_t crypt_byte_block; >> + >> + /** >> + * Only used for pattern encryption. This is the number of 16-byte blocks >> + * that are clear. >> + */ >> + uint32_t skip_byte_block; >> + >> + /** >> + * The ID of the key used to encrypt the packet. This should always be >> + * 16 bytes long, but may be changed in the future. >> + */ >> + uint8_t *key_id; >> + uint32_t key_id_size; >> + >> + /** >> + * The initialization vector. This may have been zero-filled to be the >> + * correct block size. This should always be 16 bytes long, but may be >> + * changed in the future. >> + */ >> + uint8_t *iv; >> + uint32_t iv_size; >> + >> + /** >> + * An array of subsample encryption info specifying how parts of the sample >> + * are encrypted. If there are no subsamples, then the whole sample is >> + * encrypted. >> + */ >> + AVSubsampleEncryptionInfo* subsamples; >> + uint32_t subsample_count; >> +} AVEncryptionInfo; >> + >> +/** >> + * Allocates an AVEncryptionInfo structure and sub-pointers to hold the given >> + * number of subsamples. This will allocate pointers for the key ID, IV, >> + * and subsample entries, set the size members, and zero-initialize the rest. >> + * >> + * @param subsample_count The number of subsamples. >> + * @param key_id_size The number of bytes in the key ID, should be 16. >> + * @param key_id_size The number of bytes in the IV, should be 16. >> + * >> + * @return The new AVEncryptionInfo structure, or NULL on error. >> + */ >> +AVEncryptionInfo* av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size); >> + >> +/** >> + * Frees the given encryption info object. This MUST NOT be used to free the >> + * side-data data pointer, that should use normal side-data methods. >> + */ >> +void av_encryption_info_free(AVEncryptionInfo* info); >> + >> +/** >> + * Creates a copy of the AVEncryptionInfo that is contained in the side data of >> + * the given packet. The resulting object should be passed to >> + * av_encryption_info_free() when done. >> + * >> + * This returns NULL if there is a memory error or if the packet isn't encrypted. >> + * To detect if the packet is encrypted, use av_packet_get_side_data. >> + * >> + * @return The new AVEncryptionInfo structure, or NULL on error. >> + */ >> +AVEncryptionInfo* av_encryption_info_copy_side_data(const AVPacket* packet); >> + >> +/** >> + * Adds a new side data to the given packet that holds a copy of the given >> + * encryption info. >> + * >> + * @return 0 on success, or a negative error code on error. >> + */ >> +int av_encryption_info_add_side_data(AVPacket* packet, const AVEncryptionInfo* info); >> + >> +#endif /* AVUTIL_ENCRYPTION_INFO_H */ > > So as far as the side data management goes, this should be good. No > comment about the crypto stuff or the byte array (de)serialization > stuff, didn't take a close look at it. The final patch should also > include a minor libavutil bump and an doc/APIchanges entry, Leaving version bump and changelog entry to whoever pushes it, but other comments done. From 9761a65dda03cae0739592f175cbb8883d1913ab Mon Sep 17 00:00:00 2001 From: Jacob Trimble Date: Tue, 5 Dec 2017 14:52:22 -0800 Subject: [PATCH] avcodec/avcodec.h: Add encryption info side data. This new side-data will contain info on how a packet is encrypted. This allows the app to handle packet decryption. Signed-off-by: Jacob Trimble --- libavcodec/Makefile | 2 + libavcodec/avcodec.h | 13 ++++ libavcodec/encryption_info.c | 137 +++++++++++++++++++++++++++++++++++++++++++ libavcodec/encryption_info.h | 121 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 273 insertions(+) create mode 100644 libavcodec/encryption_info.c create mode 100644 libavcodec/encryption_info.h diff --git a/libavcodec/Makefile b/libavcodec/Makefile index ab7893f560..11ad642c6c 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -10,6 +10,7 @@ HEADERS = ac3_parser.h \ dirac.h \ dv_profile.h \ dxva2.h \ + encryption_info.h \ jni.h \ mediacodec.h \ qsv.h \ @@ -36,6 +37,7 @@ OBJS = ac3_parser.o \ dirac.o \ dv_profile.o \ encode.o \ + encryption_info.o \ imgconvert.o \ jni.o \ mathtables.o \ diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 5db6a81320..b43638ebc5 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -1327,6 +1327,19 @@ enum AVPacketSideDataType { */ AV_PKT_DATA_A53_CC, + /** + * This side data is encryption "initialization data". + * For MP4 this is the entire 'pssh' box. + * For WebM this is the key ID. + */ + AV_PKT_DATA_ENCRYPTION_INIT_DATA, + + /** + * This side data contains encryption info for how to decrypt the packet. + * The format is not part of ABI, use av_encryption_info_* methods to access. + */ + AV_PKT_DATA_ENCRYPTION_INFO, + /** * The number of side data types. * This is not part of the public API/ABI in the sense that it may diff --git a/libavcodec/encryption_info.c b/libavcodec/encryption_info.c new file mode 100644 index 0000000000..76796b50ee --- /dev/null +++ b/libavcodec/encryption_info.c @@ -0,0 +1,137 @@ +/** + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "encryption_info.h" +#include "libavutil/intreadwrite.h" + +#define FF_ENCRYPTION_INFO_EXTRA 24 + +// The format of the side data: +// u32be scheme +// u32be crypt_byte_block +// u32be skip_byte_block +// u32be key_id_size +// u32be iv_size +// u32be subsample_count +// u8[key_id_size] key_id +// u8[iv_size] iv +// { +// u32be bytes_of_clear_data +// u32be bytes_of_protected_data +// }[subsample_count] + +AVEncryptionInfo *av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size) +{ + AVEncryptionInfo *info; + + info = av_mallocz(sizeof(AVEncryptionInfo)); + if (!info) + return NULL; + + info->key_id = av_mallocz(key_id_size); + info->key_id_size = key_id_size; + info->iv = av_mallocz(iv_size); + info->iv_size = iv_size; + info->subsamples = av_mallocz_array(sizeof(AVSubsampleEncryptionInfo), subsample_count); + info->subsample_count = subsample_count; + + // Allow info->subsamples to be NULL if there are no subsamples. + if (!info->key_id || !info->iv || (!info->subsamples && subsample_count)) { + av_encryption_info_free(info); + return NULL; + } + + return info; +} + +void av_encryption_info_free(AVEncryptionInfo *info) +{ + if (info) { + av_free(info->key_id); + av_free(info->iv); + av_free(info->subsamples); + av_free(info); + } +} + +AVEncryptionInfo *av_encryption_info_get_side_data(const AVPacket *packet) +{ + AVEncryptionInfo *info; + uint8_t *buffer; + unsigned int size; + uint32_t key_id_size, iv_size, subsample_count, i; + + buffer = av_packet_get_side_data(packet, AV_PKT_DATA_ENCRYPTION_INFO, &size); + if (!buffer) + return NULL; + + key_id_size = AV_RB32(buffer + 12); + iv_size = AV_RB32(buffer + 16); + subsample_count = AV_RB32(buffer + 20); + + info = av_encryption_info_alloc(subsample_count, key_id_size, iv_size); + if (!info) + return NULL; + + info->scheme = AV_RB32(buffer); + info->crypt_byte_block = AV_RB32(buffer + 4); + info->skip_byte_block = AV_RB32(buffer + 8); + memcpy(info->key_id, buffer + 24, key_id_size); + memcpy(info->iv, buffer + key_id_size + 24, iv_size); + + buffer += key_id_size + iv_size + 24; + for (i = 0; i < subsample_count; i++) { + info->subsamples[i].bytes_of_clear_data = AV_RB32(buffer); + info->subsamples[i].bytes_of_protected_data = AV_RB32(buffer + 4); + buffer += 8; + } + + return info; +} + +int av_encryption_info_add_side_data(AVPacket *packet, const AVEncryptionInfo *info) +{ + uint8_t *buffer; + size_t size; + uint32_t i; + + size = FF_ENCRYPTION_INFO_EXTRA + info->key_id_size + info->iv_size + + (sizeof(AVSubsampleEncryptionInfo) * info->subsample_count); + buffer = av_packet_new_side_data(packet, AV_PKT_DATA_ENCRYPTION_INFO, size); + if (!buffer) + return AVERROR(ENOMEM); + + AV_WB32(buffer, info->scheme); + AV_WB32(buffer + 4, info->crypt_byte_block); + AV_WB32(buffer + 8, info->skip_byte_block); + AV_WB32(buffer + 12, info->key_id_size); + AV_WB32(buffer + 16, info->iv_size); + AV_WB32(buffer + 20, info->subsample_count); + buffer += 24; + memcpy(buffer, info->key_id, info->key_id_size); + buffer += info->key_id_size; + memcpy(buffer, info->iv, info->iv_size); + buffer += info->iv_size; + for (i = 0; i < info->subsample_count; i++) { + AV_WB32(buffer, info->subsamples[i].bytes_of_clear_data); + AV_WB32(buffer + 4, info->subsamples[i].bytes_of_protected_data); + buffer += 8; + } + + return 0; +} diff --git a/libavcodec/encryption_info.h b/libavcodec/encryption_info.h new file mode 100644 index 0000000000..7564af7304 --- /dev/null +++ b/libavcodec/encryption_info.h @@ -0,0 +1,121 @@ +/** + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ENCRYPTION_INFO_H +#define AVUTIL_ENCRYPTION_INFO_H + +#include "avcodec.h" + +typedef struct AVSubsampleEncryptionInfo { + /** The number of bytes that are clear. */ + unsigned int bytes_of_clear_data; + + /** + * The number of bytes that are protected. If using pattern encryption, + * the pattern applies to only the protected bytes; if not using pattern + * encryption, all these bytes are encrypted. + */ + unsigned int bytes_of_protected_data; +} AVSubsampleEncryptionInfo; + +/** + * This describes encryption info for a packet. This contains frame-specific + * info for how to decrypt the packet before passing it to the decoder. + * + * The size of this struct is not part of the public ABI. + */ +typedef struct AVEncryptionInfo { + /** The fourcc encryption scheme. */ + uint32_t scheme; + + /** + * Only used for pattern encryption. This is the number of 16-byte blocks + * that are encrypted. + */ + uint32_t crypt_byte_block; + + /** + * Only used for pattern encryption. This is the number of 16-byte blocks + * that are clear. + */ + uint32_t skip_byte_block; + + /** + * The ID of the key used to encrypt the packet. This should always be + * 16 bytes long, but may be changed in the future. + */ + uint8_t *key_id; + uint32_t key_id_size; + + /** + * The initialization vector. This may have been zero-filled to be the + * correct block size. This should always be 16 bytes long, but may be + * changed in the future. + */ + uint8_t *iv; + uint32_t iv_size; + + /** + * An array of subsample encryption info specifying how parts of the sample + * are encrypted. If there are no subsamples, then the whole sample is + * encrypted. + */ + AVSubsampleEncryptionInfo *subsamples; + uint32_t subsample_count; +} AVEncryptionInfo; + +/** + * Allocates an AVEncryptionInfo structure and sub-pointers to hold the given + * number of subsamples. This will allocate pointers for the key ID, IV, + * and subsample entries, set the size members, and zero-initialize the rest. + * + * @param subsample_count The number of subsamples. + * @param key_id_size The number of bytes in the key ID, should be 16. + * @param key_id_size The number of bytes in the IV, should be 16. + * + * @return The new AVEncryptionInfo structure, or NULL on error. + */ +AVEncryptionInfo *av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size); + +/** + * Frees the given encryption info object. This MUST NOT be used to free the + * side-data data pointer, that should use normal side-data methods. + */ +void av_encryption_info_free(AVEncryptionInfo *info); + +/** + * Creates a copy of the AVEncryptionInfo that is contained in the side data of + * the given packet. The resulting object should be passed to + * av_encryption_info_free() when done. + * + * This returns NULL if there is a memory error or if the packet isn't encrypted. + * To detect if the packet is encrypted, use av_packet_get_side_data. + * + * @return The new AVEncryptionInfo structure, or NULL on error. + */ +AVEncryptionInfo *av_encryption_info_get_side_data(const AVPacket *packet); + +/** + * Adds a new side data to the given packet that holds a copy of the given + * encryption info. + * + * @return 0 on success, or a negative error code on error. + */ +int av_encryption_info_add_side_data(AVPacket *packet, const AVEncryptionInfo *info); + +#endif /* AVUTIL_ENCRYPTION_INFO_H */ -- 2.15.1.620.gb9897f4670-goog