try to make kid:key support

This commit is contained in:
Ninja Jiraiya 2023-07-23 12:15:25 +07:00
parent 3ddf77aacd
commit 5511102b0c
4 changed files with 124 additions and 2099 deletions

View File

@ -27,6 +27,7 @@
#include "internal.h" #include "internal.h"
#include "avio_internal.h" #include "avio_internal.h"
#include "dash.h" #include "dash.h"
#include "libavformat/isom.h"
#define INITIAL_BUFFER_SIZE 32768 #define INITIAL_BUFFER_SIZE 32768
#define MAX_MANIFEST_SIZE 50 * 1024 #define MAX_MANIFEST_SIZE 50 * 1024
@ -1878,6 +1879,7 @@ static int reopen_demux_for_component(AVFormatContext *s, struct representation
ff_const59 AVInputFormat *in_fmt = NULL; ff_const59 AVInputFormat *in_fmt = NULL;
AVDictionary *in_fmt_opts = NULL; AVDictionary *in_fmt_opts = NULL;
uint8_t *avio_ctx_buffer = NULL; uint8_t *avio_ctx_buffer = NULL;
int ret = 0, i; int ret = 0, i;
if (pls->ctx) { if (pls->ctx) {
@ -1926,7 +1928,28 @@ static int reopen_demux_for_component(AVFormatContext *s, struct representation
pls->ctx->io_open = nested_io_open; pls->ctx->io_open = nested_io_open;
if (c->cenc_decryption_key) if (c->cenc_decryption_key)
av_dict_set(&in_fmt_opts, "decryption_key", c->cenc_decryption_key, 0); // if cenc_decryption_key not contains any : or , it is a hex string
if (strchr(c->cenc_decryption_key, ':') == NULL && strchr(c->cenc_decryption_key, ',') == NULL) {
av_dict_set(&in_fmt_opts, "decryption_key", c->cenc_decryption_key, 0);
} else {
DecryptionKey *decryption_key_map = av_mallocz(sizeof(DecryptionKey *) * 2);
// if cenc_decryption_key contains : or , split it based on ,
char *key_id = av_strtok(c->cenc_decryption_key, ",", &c->cenc_decryption_key);
// if cenc_decryption_key contains : split it based on :
//create DecryptionKey array
*key_count = 0;
while (key_id != NULL && *key_count < 2) {
char* colon = strchr(key_id, ':');
if (colon != NULL) {
*colon = '\0'; // Replace ':' with null-terminator
strncpy(decryption_key_map[*key_count].key_id, key_id, MAX_STRING_LENGTH - 1);
strncpy(decryption_key_map[*key_count].second, colon + 1, MAX_STRING_LENGTH - 1);
(*key_count)++;
}
key_id = av_strtok(NULL, ",");
}
av_dict_set(&in_fmt_opts, "decryption_key_map", decryption_key_map, 0);
}
// provide additional information from mpd if available // provide additional information from mpd if available
ret = avformat_open_input(&pls->ctx, "", in_fmt, &in_fmt_opts); //pls->init_section->url ret = avformat_open_input(&pls->ctx, "", in_fmt, &in_fmt_opts); //pls->init_section->url

View File

@ -155,6 +155,11 @@ typedef struct MOVIndexRange {
int64_t end; int64_t end;
} MOVIndexRange; } MOVIndexRange;
typedef struct DecryptionKey {
uint8_t key_id;
uint8_t decryption_key;
} DecryptionKey;
typedef struct MOVStreamContext { typedef struct MOVStreamContext {
AVIOContext *pb; AVIOContext *pb;
int pb_is_copied; int pb_is_copied;
@ -291,6 +296,8 @@ typedef struct MOVContext {
int decryption_key_len; int decryption_key_len;
int enable_drefs; int enable_drefs;
int32_t movie_display_matrix[3][3]; ///< display matrix from mvhd int32_t movie_display_matrix[3][3]; ///< display matrix from mvhd
DecryptionKey *decryption_key_map; // array of decryption keys for each track
int decryption_key_map_size;
} MOVContext; } MOVContext;
int ff_mp4_read_descr_len(AVIOContext *pb); int ff_mp4_read_descr_len(AVIOContext *pb);

View File

@ -6700,6 +6700,62 @@ static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *s
return 0; return 0;
} }
static int cenc_decrypt_with_key(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *sample, uint8_t *input, uint8_t *decryption_key, int size)
{
int i, ret;
if (sample->scheme != MKBETAG('c','e','n','c') || sample->crypt_byte_block != 0 || sample->skip_byte_block != 0) {
av_log(c->fc, AV_LOG_ERROR, "Only the 'cenc' encryption scheme is supported\n");
return AVERROR_PATCHWELCOME;
}
if (!sc->cenc.aes_ctr) {
/* initialize the cipher */
sc->cenc.aes_ctr = av_aes_ctr_alloc();
if (!sc->cenc.aes_ctr) {
return AVERROR(ENOMEM);
}
ret = av_aes_ctr_init(sc->cenc.aes_ctr, decryption_key);
if (ret < 0) {
return ret;
}
}
av_aes_ctr_set_full_iv(sc->cenc.aes_ctr, sample->iv);
if (!sample->subsample_count)
{
/* decrypt the whole packet */
av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, size);
return 0;
}
for (i = 0; i < sample->subsample_count; i++)
{
if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) {
av_log(c->fc, AV_LOG_ERROR, "subsample size exceeds the packet size left\n");
return AVERROR_INVALIDDATA;
}
/* skip the clear bytes */
input += sample->subsamples[i].bytes_of_clear_data;
size -= sample->subsamples[i].bytes_of_clear_data;
/* decrypt the encrypted bytes */
av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, sample->subsamples[i].bytes_of_protected_data);
input += sample->subsamples[i].bytes_of_protected_data;
size -= sample->subsamples[i].bytes_of_protected_data;
}
if (size > 0) {
av_log(c->fc, AV_LOG_ERROR, "leftover packet bytes after subsample processing\n");
return AVERROR_INVALIDDATA;
}
return 0;
}
static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPacket *pkt, int current_index) static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPacket *pkt, int current_index)
{ {
MOVFragmentStreamInfo *frag_stream_info; MOVFragmentStreamInfo *frag_stream_info;
@ -6749,6 +6805,40 @@ static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPa
if (mov->decryption_key) { if (mov->decryption_key) {
return cenc_decrypt(mov, sc, encrypted_sample, pkt->data, pkt->size); return cenc_decrypt(mov, sc, encrypted_sample, pkt->data, pkt->size);
} else if (mov->decryption_key_map) {
uint8_t *key_id = encrypted_sample->key_id;
uint8_t *dec_key = NULL;
// check size of decryption_key_map size
if (mov->decryption_key_map_size == 1) {
dec_key = mov->decryption_key_map[0].decryption_key;
} else {
// find the decryption key for the given key ID
for (int i = 0; i < mov->decryption_key_map_size; i++) {
// if the key id is equals with the key id in the map
if (key_id == mov->decryption_key_map[i].key_id) {
dec_key = mov->decryption_key_map[i].decryption_key;
break;
}
}
}
if (!dec_key) {
av_log(mov->fc, AV_LOG_ERROR, "No decryption key found for the given key ID\n");
return AVERROR_INVALIDDATA;
}
if (!encrypted_sample->subsample_count) {
// Decrypt the whole packet.
ret = av_aes_ctr_init(&sc->cenc.aes_ctr, dec_key);
if (ret < 0) {
return ret;
}
av_aes_ctr_crypt(&sc->cenc.aes_ctr, pkt->data, pkt->data, pkt->size);
} else {
// Decrypt the subsamples.
ret = cenc_decrypt_with_key(mov, sc, encrypted_sample, pkt->data, dec_key, pkt->size);
if (ret < 0) {
return ret;
}
}
} else { } else {
size_t size; size_t size;
uint8_t *side_data = av_encryption_info_add_side_data(encrypted_sample, &size); uint8_t *side_data = av_encryption_info_add_side_data(encrypted_sample, &size);
@ -8219,6 +8309,7 @@ static const AVOption mov_options[] = {
AV_OPT_TYPE_BINARY, {.str="77214d4b196a87cd520045fd20a51d67"}, AV_OPT_TYPE_BINARY, {.str="77214d4b196a87cd520045fd20a51d67"},
.flags = AV_OPT_FLAG_DECODING_PARAM }, .flags = AV_OPT_FLAG_DECODING_PARAM },
{ "decryption_key", "The media decryption key (hex)", OFFSET(decryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM }, { "decryption_key", "The media decryption key (hex)", OFFSET(decryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM },
{ "decryption_key_map", "The media decryption kid:key (hex) support up to 2", OFFSET(decryption_key_map), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM },
{ "enable_drefs", "Enable external track support.", OFFSET(enable_drefs), AV_OPT_TYPE_BOOL, { "enable_drefs", "Enable external track support.", OFFSET(enable_drefs), AV_OPT_TYPE_BOOL,
{.i64 = 0}, 0, 1, FLAGS }, {.i64 = 0}, 0, 1, FLAGS },

File diff suppressed because it is too large Load Diff