From patchwork Fri Sep 29 16:50:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Scheurenbrand X-Patchwork-Id: 44030 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:394d:b0:15d:8365:d4b8 with SMTP id r13csp684221pzg; Fri, 29 Sep 2023 09:51:13 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHI5omPlptp1xfPEDF42scoy6R9yVDWOPCnMDZQZLLfaT67DRwOV6KWflei+I9r++Y0oUNa X-Received: by 2002:a17:906:319b:b0:99d:e617:abeb with SMTP id 27-20020a170906319b00b0099de617abebmr4208455ejy.23.1696006272819; Fri, 29 Sep 2023 09:51:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1696006272; cv=none; d=google.com; s=arc-20160816; b=yN+YA8B8ltIrnKtZ43shGfyMhJolrrSJQdHceFbegNb55s3MJ7ST+GsN9aojbCo2g/ grhZgjVexEfyZeOb4xdwmmDyYhvHkfApJ3hmfNdvqGhpf77cTLdTPgzKSOjAsq9/lsn3 1+rHSHx7SdQdkX9d+jMy2WUP2f5Yi6cB3rT/glVWO6zSmVcbx2HgMSbktQK9zrNBkKic cPwuXu4lYOop2elzFQTpcD5btaAAcHzuSLElu4ovhzMNMfi4JEe7rjfGvp85xLj2CCe6 VzDX7+BJQ9DWuvCN25IU+3FK1GXj9vhT0EAyGKsJM5DLg53wNQz+IB+Lp9mWhWHb52kH yCDQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to:from :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:message-id:date:to :feedback-id:delivered-to; bh=bU3ctuZdBOCM2YfzpMdeOeokda02k/HL0Ej2NRgyyEY=; fh=7e88NmSu5q0Rrk+nj/dNaGthwsS/GL06UBBVVuqz8+c=; b=UJeBV2hIrT62Gpd4qJ7seP/ZbhImNpr5Yr96ZhNtCRad2PQer0M5HXPKGw0kSpSLwW xLlMTuE+ldjjY7cnbNA+WYJigC3rJjVJod3e26w6Amv9fXwcnFb1/mBQvgg8IMZJn+A1 uWbEv0xhKkpfheHbPv9oTWYs2MK3gfkYyEBNafHl5ZyXuHRRqUDSQMWfukyhQdMr79Ed Z/KwZPwkNOo2lSYCvEx/f1XFPmOGkZeMg8SmqqiRbk2SR8Jp5usxCgFzSc5gLV+JS+4/ HR5nJ4nG2rHWfxhfRpWHak1Ek5a9wd2XZniWblG3BQ2RooAqZPQqHjrWnBP3hNNSg9I1 pDpA== ARC-Authentication-Results: i=1; mx.google.com; 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 h19-20020a1709060f5300b0099ce147d6b0si15507623ejj.823.2023.09.29.09.51.12; Fri, 29 Sep 2023 09:51:12 -0700 (PDT) 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; 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 18C0668CC82; Fri, 29 Sep 2023 19:51:10 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from sendmail.purelymail.com (sendmail.purelymail.com [34.202.193.197]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C513B68CC58 for ; Fri, 29 Sep 2023 19:51:03 +0300 (EEST) Feedback-ID: 17590:3276:null:purelymail X-Pm-Original-To: ffmpeg-devel@ffmpeg.org Received: by smtp.purelymail.com (Purelymail SMTP) with ESMTPSA id 55297603; (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Fri, 29 Sep 2023 16:50:47 +0000 (UTC) To: ffmpeg-devel@ffmpeg.org Date: Fri, 29 Sep 2023 18:50:27 +0200 Message-ID: <20230929165027.204216-1-luis@scheurenbrand.me> X-Mailer: git-send-email 2.42.0 MIME-Version: 1.0 X-MIME-Autoconverted: from 8bit to quoted-printable by Purelymail Subject: [FFmpeg-devel] [PATCH] avformat/hls: Re-use crypto URLContext X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Luis Scheurenbrand via ffmpeg-devel From: Luis Scheurenbrand Reply-To: FFmpeg development discussions and patches Cc: Luis Scheurenbrand Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: JqA69PtjEZXj Reset crypto state and keep nested http context alive. Previously, an unencrypted file, followed by an encrypted file would result in a corrupted stream, as the stream would not be closed and an encrypted file would be forwarded to the demuxer. fixes: https://trac.ffmpeg.org/ticket/10599 fixes: https://trac.ffmpeg.org/ticket/8490 Signed-off-by: Luis Scheurenbrand --- libavformat/crypto.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ libavformat/crypto.h | 38 ++++++++++++++++++++++++++++++ libavformat/hls.c | 32 ++++++++++++++++++++++---- 3 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 libavformat/crypto.h diff --git a/libavformat/crypto.c b/libavformat/crypto.c index 75b00020bc..543300c7c0 100644 --- a/libavformat/crypto.c +++ b/libavformat/crypto.c @@ -20,8 +20,10 @@ */ #include "libavutil/aes.h" +#include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/opt.h" +#include "crypto.h" #include "url.h" // encourage reads of 4096 bytes - 1 block is always retained. @@ -105,6 +107,59 @@ static int set_aes_arg(URLContext *h, uint8_t **buf, int *buf_len, return 0; } +URLContext *ff_crypto_get_inner(URLContext *h) +{ + CryptoContext *c = h->priv_data; + return c->hd; +} + +int ff_crypto_reset(URLContext *h) +{ + int ret = 0; + CryptoContext *c = h->priv_data; + int flags = c->flags; + + if (flags & AVIO_FLAG_READ) { + av_assert0(c->decrypt_key); + av_assert0(c->decrypt_iv); + av_assert0(c->aes_decrypt); + + memcpy(c->decrypt_key, c->key, c->keylen); + memcpy(c->decrypt_iv, c->iv, c->ivlen); + + ret = av_aes_init(c->aes_decrypt, c->decrypt_key, BLOCKSIZE * 8, 1); + if (ret < 0) + goto err; + } + + if (flags & AVIO_FLAG_WRITE) { + av_assert0(c->encrypt_key); + av_assert0(c->encrypt_iv); + av_assert0(c->aes_encrypt); + + memcpy(c->encrypt_key, c->key, c->keylen); + memcpy(c->encrypt_iv, c->iv, c->ivlen); + + ret = av_aes_init(c->aes_encrypt, c->encrypt_key, BLOCKSIZE * 8, 0); + if (ret < 0) + goto err; + } + + c->indata = c->indata_used = c->outdata = 0; + c->position = 0; + c->eof = 0; + c->outdata = 0; + c->outptr = 0; + + av_assert0(c->outbuffer); + av_assert0(c->inbuffer); + memset(c->outbuffer, 0, sizeof(c->outbuffer)); + memset(c->inbuffer, 0, sizeof(c->inbuffer)); + +err: + return ret; +} + static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary **options) { const char *nested_url; diff --git a/libavformat/crypto.h b/libavformat/crypto.h new file mode 100644 index 0000000000..7e6d7f0279 --- /dev/null +++ b/libavformat/crypto.h @@ -0,0 +1,38 @@ +/* + * HTTP definitions + * Copyright (c) 2010 Josh Allmann + * + * 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 AVFORMAT_CRYPTO_H +#define AVFORMAT_CRYPTO_H + +#include "url.h" + +URLContext *ff_crypto_get_inner(URLContext *h); + +/** + * Resets the crypto context. + * + * @param h pointer to the resource + * @return a negative value if an error condition occurred, 0 + * otherwise + */ +int ff_crypto_reset(URLContext *h); + +#endif /* AVFORMAT_CRYPTO_H */ diff --git a/libavformat/hls.c b/libavformat/hls.c index 332a5a15bb..7ad0ec9aec 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -44,6 +44,7 @@ #include "avio_internal.h" #include "id3v2.h" #include "url.h" +#include "crypto.h" #include "hls_sample_encryption.h" @@ -620,17 +621,38 @@ static int ensure_playlist(HLSContext *c, struct playlist **pls, const char *url return 0; } +/* compares two segments to ensure the encryption is the same and + * we can reuse the crypto and/or http context. */ +static int crypto_matches(const struct segment *lhs, const struct segment *rhs) { + if (!lhs || !rhs) + return 0; + if (lhs->key_type != rhs->key_type) + return 0; + if (lhs->key_type == KEY_NONE) + return 1; + + return + strcmp(lhs->key, rhs->key) == 0 && + memcmp(lhs->iv, rhs->iv, sizeof(lhs->iv)) == 0; +} + static int open_url_keepalive(AVFormatContext *s, AVIOContext **pb, const char *url, AVDictionary **options) { #if !CONFIG_HTTP_PROTOCOL return AVERROR_PROTOCOL_NOT_FOUND; #else - int ret; + int ret=0; URLContext *uc = ffio_geturlcontext(*pb); av_assert0(uc); (*pb)->eof_reached = 0; - ret = ff_http_do_new_request2(uc, url, options); + + if (av_strstart(url, "crypto+", &url)) { + ret = ff_crypto_reset(uc); + uc = ff_crypto_get_inner(uc); + } + + if (ret == 0) ret = ff_http_do_new_request2(uc, url, options); if (ret < 0) { ff_format_io_close(s, pb); } @@ -1592,7 +1614,7 @@ reload: seg = next_segment(v); if (c->http_multiple == 1 && !v->input_next_requested && - seg && seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) { + seg && av_strstart(seg->url, "http", NULL)) { ret = open_input(c, v, seg, &v->input_next); if (ret < 0) { if (ff_check_interrupt(c->interrupt_callback)) @@ -1624,8 +1646,8 @@ reload: return ret; } - if (c->http_persistent && - seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) { + if (c->http_persistent && crypto_matches(seg, next_segment(v)) && + av_strstart(seg->url, "http", NULL)) { v->input_read_done = 1; } else { ff_format_io_close(v->parent, &v->input);