1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Decryption protocol handler 3cabdff1aSopenharmony_ci * Copyright (c) 2011 Martin Storsjo 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "avformat.h" 23cabdff1aSopenharmony_ci#include "libavutil/aes.h" 24cabdff1aSopenharmony_ci#include "libavutil/avstring.h" 25cabdff1aSopenharmony_ci#include "libavutil/opt.h" 26cabdff1aSopenharmony_ci#include "internal.h" 27cabdff1aSopenharmony_ci#include "url.h" 28cabdff1aSopenharmony_ci 29cabdff1aSopenharmony_ci// encourage reads of 4096 bytes - 1 block is always retained. 30cabdff1aSopenharmony_ci#define MAX_BUFFER_BLOCKS 257 31cabdff1aSopenharmony_ci#define BLOCKSIZE 16 32cabdff1aSopenharmony_ci 33cabdff1aSopenharmony_citypedef struct CryptoContext { 34cabdff1aSopenharmony_ci const AVClass *class; 35cabdff1aSopenharmony_ci URLContext *hd; 36cabdff1aSopenharmony_ci uint8_t inbuffer [BLOCKSIZE*MAX_BUFFER_BLOCKS], 37cabdff1aSopenharmony_ci outbuffer[BLOCKSIZE*MAX_BUFFER_BLOCKS]; 38cabdff1aSopenharmony_ci uint8_t *outptr; 39cabdff1aSopenharmony_ci int indata, indata_used, outdata; 40cabdff1aSopenharmony_ci int64_t position; // position in file - used in seek 41cabdff1aSopenharmony_ci int flags; 42cabdff1aSopenharmony_ci int eof; 43cabdff1aSopenharmony_ci uint8_t *key; 44cabdff1aSopenharmony_ci int keylen; 45cabdff1aSopenharmony_ci uint8_t *iv; 46cabdff1aSopenharmony_ci int ivlen; 47cabdff1aSopenharmony_ci uint8_t *decrypt_key; 48cabdff1aSopenharmony_ci int decrypt_keylen; 49cabdff1aSopenharmony_ci uint8_t *decrypt_iv; 50cabdff1aSopenharmony_ci int decrypt_ivlen; 51cabdff1aSopenharmony_ci uint8_t *encrypt_key; 52cabdff1aSopenharmony_ci int encrypt_keylen; 53cabdff1aSopenharmony_ci uint8_t *encrypt_iv; 54cabdff1aSopenharmony_ci int encrypt_ivlen; 55cabdff1aSopenharmony_ci struct AVAES *aes_decrypt; 56cabdff1aSopenharmony_ci struct AVAES *aes_encrypt; 57cabdff1aSopenharmony_ci uint8_t *write_buf; 58cabdff1aSopenharmony_ci unsigned int write_buf_size; 59cabdff1aSopenharmony_ci uint8_t pad[BLOCKSIZE]; 60cabdff1aSopenharmony_ci int pad_len; 61cabdff1aSopenharmony_ci} CryptoContext; 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(CryptoContext, x) 64cabdff1aSopenharmony_ci#define D AV_OPT_FLAG_DECODING_PARAM 65cabdff1aSopenharmony_ci#define E AV_OPT_FLAG_ENCODING_PARAM 66cabdff1aSopenharmony_cistatic const AVOption options[] = { 67cabdff1aSopenharmony_ci {"key", "AES encryption/decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, .flags = D|E }, 68cabdff1aSopenharmony_ci {"iv", "AES encryption/decryption initialization vector", OFFSET(iv), AV_OPT_TYPE_BINARY, .flags = D|E }, 69cabdff1aSopenharmony_ci {"decryption_key", "AES decryption key", OFFSET(decrypt_key), AV_OPT_TYPE_BINARY, .flags = D }, 70cabdff1aSopenharmony_ci {"decryption_iv", "AES decryption initialization vector", OFFSET(decrypt_iv), AV_OPT_TYPE_BINARY, .flags = D }, 71cabdff1aSopenharmony_ci {"encryption_key", "AES encryption key", OFFSET(encrypt_key), AV_OPT_TYPE_BINARY, .flags = E }, 72cabdff1aSopenharmony_ci {"encryption_iv", "AES encryption initialization vector", OFFSET(encrypt_iv), AV_OPT_TYPE_BINARY, .flags = E }, 73cabdff1aSopenharmony_ci { NULL } 74cabdff1aSopenharmony_ci}; 75cabdff1aSopenharmony_ci 76cabdff1aSopenharmony_cistatic const AVClass crypto_class = { 77cabdff1aSopenharmony_ci .class_name = "crypto", 78cabdff1aSopenharmony_ci .item_name = av_default_item_name, 79cabdff1aSopenharmony_ci .option = options, 80cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 81cabdff1aSopenharmony_ci}; 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_cistatic int set_aes_arg(URLContext *h, uint8_t **buf, int *buf_len, 84cabdff1aSopenharmony_ci uint8_t *default_buf, int default_buf_len, 85cabdff1aSopenharmony_ci const char *desc) 86cabdff1aSopenharmony_ci{ 87cabdff1aSopenharmony_ci if (!*buf_len) { 88cabdff1aSopenharmony_ci if (!default_buf_len) { 89cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "%s not set\n", desc); 90cabdff1aSopenharmony_ci return AVERROR(EINVAL); 91cabdff1aSopenharmony_ci } else if (default_buf_len != BLOCKSIZE) { 92cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, 93cabdff1aSopenharmony_ci "invalid %s size (%d bytes, block size is %d)\n", 94cabdff1aSopenharmony_ci desc, default_buf_len, BLOCKSIZE); 95cabdff1aSopenharmony_ci return AVERROR(EINVAL); 96cabdff1aSopenharmony_ci } 97cabdff1aSopenharmony_ci *buf = av_memdup(default_buf, default_buf_len); 98cabdff1aSopenharmony_ci if (!*buf) 99cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 100cabdff1aSopenharmony_ci *buf_len = default_buf_len; 101cabdff1aSopenharmony_ci } else if (*buf_len != BLOCKSIZE) { 102cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, 103cabdff1aSopenharmony_ci "invalid %s size (%d bytes, block size is %d)\n", 104cabdff1aSopenharmony_ci desc, *buf_len, BLOCKSIZE); 105cabdff1aSopenharmony_ci return AVERROR(EINVAL); 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ci return 0; 108cabdff1aSopenharmony_ci} 109cabdff1aSopenharmony_ci 110cabdff1aSopenharmony_cistatic int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary **options) 111cabdff1aSopenharmony_ci{ 112cabdff1aSopenharmony_ci const char *nested_url; 113cabdff1aSopenharmony_ci int ret = 0; 114cabdff1aSopenharmony_ci CryptoContext *c = h->priv_data; 115cabdff1aSopenharmony_ci c->flags = flags; 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci if (!av_strstart(uri, "crypto+", &nested_url) && 118cabdff1aSopenharmony_ci !av_strstart(uri, "crypto:", &nested_url)) { 119cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Unsupported url %s\n", uri); 120cabdff1aSopenharmony_ci ret = AVERROR(EINVAL); 121cabdff1aSopenharmony_ci goto err; 122cabdff1aSopenharmony_ci } 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci if (flags & AVIO_FLAG_READ) { 125cabdff1aSopenharmony_ci if ((ret = set_aes_arg(h, &c->decrypt_key, &c->decrypt_keylen, 126cabdff1aSopenharmony_ci c->key, c->keylen, "decryption key")) < 0) 127cabdff1aSopenharmony_ci goto err; 128cabdff1aSopenharmony_ci if ((ret = set_aes_arg(h, &c->decrypt_iv, &c->decrypt_ivlen, 129cabdff1aSopenharmony_ci c->iv, c->ivlen, "decryption IV")) < 0) 130cabdff1aSopenharmony_ci goto err; 131cabdff1aSopenharmony_ci } 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_ci if (flags & AVIO_FLAG_WRITE) { 134cabdff1aSopenharmony_ci if ((ret = set_aes_arg(h, &c->encrypt_key, &c->encrypt_keylen, 135cabdff1aSopenharmony_ci c->key, c->keylen, "encryption key")) < 0) 136cabdff1aSopenharmony_ci if (ret < 0) 137cabdff1aSopenharmony_ci goto err; 138cabdff1aSopenharmony_ci if ((ret = set_aes_arg(h, &c->encrypt_iv, &c->encrypt_ivlen, 139cabdff1aSopenharmony_ci c->iv, c->ivlen, "encryption IV")) < 0) 140cabdff1aSopenharmony_ci goto err; 141cabdff1aSopenharmony_ci } 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci if ((ret = ffurl_open_whitelist(&c->hd, nested_url, flags, 144cabdff1aSopenharmony_ci &h->interrupt_callback, options, 145cabdff1aSopenharmony_ci h->protocol_whitelist, h->protocol_blacklist, h)) < 0) { 146cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Unable to open resource: %s\n", nested_url); 147cabdff1aSopenharmony_ci goto err; 148cabdff1aSopenharmony_ci } 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci if (flags & AVIO_FLAG_READ) { 151cabdff1aSopenharmony_ci c->aes_decrypt = av_aes_alloc(); 152cabdff1aSopenharmony_ci if (!c->aes_decrypt) { 153cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 154cabdff1aSopenharmony_ci goto err; 155cabdff1aSopenharmony_ci } 156cabdff1aSopenharmony_ci ret = av_aes_init(c->aes_decrypt, c->decrypt_key, BLOCKSIZE * 8, 1); 157cabdff1aSopenharmony_ci if (ret < 0) 158cabdff1aSopenharmony_ci goto err; 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_ci // pass back information about the context we openned 161cabdff1aSopenharmony_ci if (c->hd->is_streamed) 162cabdff1aSopenharmony_ci h->is_streamed = c->hd->is_streamed; 163cabdff1aSopenharmony_ci } 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_ci if (flags & AVIO_FLAG_WRITE) { 166cabdff1aSopenharmony_ci c->aes_encrypt = av_aes_alloc(); 167cabdff1aSopenharmony_ci if (!c->aes_encrypt) { 168cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 169cabdff1aSopenharmony_ci goto err; 170cabdff1aSopenharmony_ci } 171cabdff1aSopenharmony_ci ret = av_aes_init(c->aes_encrypt, c->encrypt_key, BLOCKSIZE * 8, 0); 172cabdff1aSopenharmony_ci if (ret < 0) 173cabdff1aSopenharmony_ci goto err; 174cabdff1aSopenharmony_ci // for write, we must be streamed 175cabdff1aSopenharmony_ci // - linear write only for crytpo aes-128-cbc 176cabdff1aSopenharmony_ci h->is_streamed = 1; 177cabdff1aSopenharmony_ci } 178cabdff1aSopenharmony_ci 179cabdff1aSopenharmony_cierr: 180cabdff1aSopenharmony_ci return ret; 181cabdff1aSopenharmony_ci} 182cabdff1aSopenharmony_ci 183cabdff1aSopenharmony_cistatic int crypto_read(URLContext *h, uint8_t *buf, int size) 184cabdff1aSopenharmony_ci{ 185cabdff1aSopenharmony_ci CryptoContext *c = h->priv_data; 186cabdff1aSopenharmony_ci int blocks; 187cabdff1aSopenharmony_ciretry: 188cabdff1aSopenharmony_ci if (c->outdata > 0) { 189cabdff1aSopenharmony_ci size = FFMIN(size, c->outdata); 190cabdff1aSopenharmony_ci memcpy(buf, c->outptr, size); 191cabdff1aSopenharmony_ci c->outptr += size; 192cabdff1aSopenharmony_ci c->outdata -= size; 193cabdff1aSopenharmony_ci c->position = c->position + size; 194cabdff1aSopenharmony_ci return size; 195cabdff1aSopenharmony_ci } 196cabdff1aSopenharmony_ci // We avoid using the last block until we've found EOF, 197cabdff1aSopenharmony_ci // since we'll remove PKCS7 padding at the end. So make 198cabdff1aSopenharmony_ci // sure we've got at least 2 blocks, so we can decrypt 199cabdff1aSopenharmony_ci // at least one. 200cabdff1aSopenharmony_ci while (c->indata - c->indata_used < 2*BLOCKSIZE) { 201cabdff1aSopenharmony_ci int n = ffurl_read(c->hd, c->inbuffer + c->indata, 202cabdff1aSopenharmony_ci sizeof(c->inbuffer) - c->indata); 203cabdff1aSopenharmony_ci if (n <= 0) { 204cabdff1aSopenharmony_ci c->eof = 1; 205cabdff1aSopenharmony_ci break; 206cabdff1aSopenharmony_ci } 207cabdff1aSopenharmony_ci c->indata += n; 208cabdff1aSopenharmony_ci } 209cabdff1aSopenharmony_ci blocks = (c->indata - c->indata_used) / BLOCKSIZE; 210cabdff1aSopenharmony_ci if (!blocks) 211cabdff1aSopenharmony_ci return AVERROR_EOF; 212cabdff1aSopenharmony_ci if (!c->eof) 213cabdff1aSopenharmony_ci blocks--; 214cabdff1aSopenharmony_ci av_aes_crypt(c->aes_decrypt, c->outbuffer, c->inbuffer + c->indata_used, 215cabdff1aSopenharmony_ci blocks, c->decrypt_iv, 1); 216cabdff1aSopenharmony_ci c->outdata = BLOCKSIZE * blocks; 217cabdff1aSopenharmony_ci c->outptr = c->outbuffer; 218cabdff1aSopenharmony_ci c->indata_used += BLOCKSIZE * blocks; 219cabdff1aSopenharmony_ci if (c->indata_used >= sizeof(c->inbuffer)/2) { 220cabdff1aSopenharmony_ci memmove(c->inbuffer, c->inbuffer + c->indata_used, 221cabdff1aSopenharmony_ci c->indata - c->indata_used); 222cabdff1aSopenharmony_ci c->indata -= c->indata_used; 223cabdff1aSopenharmony_ci c->indata_used = 0; 224cabdff1aSopenharmony_ci } 225cabdff1aSopenharmony_ci if (c->eof) { 226cabdff1aSopenharmony_ci // Remove PKCS7 padding at the end 227cabdff1aSopenharmony_ci int padding = c->outbuffer[c->outdata - 1]; 228cabdff1aSopenharmony_ci c->outdata -= padding; 229cabdff1aSopenharmony_ci } 230cabdff1aSopenharmony_ci goto retry; 231cabdff1aSopenharmony_ci} 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_cistatic int64_t crypto_seek(URLContext *h, int64_t pos, int whence) 234cabdff1aSopenharmony_ci{ 235cabdff1aSopenharmony_ci CryptoContext *c = h->priv_data; 236cabdff1aSopenharmony_ci int64_t block; 237cabdff1aSopenharmony_ci int64_t newpos; 238cabdff1aSopenharmony_ci 239cabdff1aSopenharmony_ci if (c->flags & AVIO_FLAG_WRITE) { 240cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, 241cabdff1aSopenharmony_ci "Crypto: seek not supported for write\r\n"); 242cabdff1aSopenharmony_ci /* seems the most appropriate error to return */ 243cabdff1aSopenharmony_ci return AVERROR(ESPIPE); 244cabdff1aSopenharmony_ci } 245cabdff1aSopenharmony_ci 246cabdff1aSopenharmony_ci // reset eof, else we won't read it correctly if we already hit eof. 247cabdff1aSopenharmony_ci c->eof = 0; 248cabdff1aSopenharmony_ci 249cabdff1aSopenharmony_ci switch (whence) { 250cabdff1aSopenharmony_ci case SEEK_SET: 251cabdff1aSopenharmony_ci break; 252cabdff1aSopenharmony_ci case SEEK_CUR: 253cabdff1aSopenharmony_ci pos = pos + c->position; 254cabdff1aSopenharmony_ci break; 255cabdff1aSopenharmony_ci case SEEK_END: 256cabdff1aSopenharmony_ci newpos = ffurl_seek( c->hd, pos, AVSEEK_SIZE ); 257cabdff1aSopenharmony_ci if (newpos < 0) { 258cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, 259cabdff1aSopenharmony_ci "Crypto: seek_end - can't get file size (pos=%lld)\r\n", (long long int)pos); 260cabdff1aSopenharmony_ci return newpos; 261cabdff1aSopenharmony_ci } 262cabdff1aSopenharmony_ci pos = newpos - pos; 263cabdff1aSopenharmony_ci break; 264cabdff1aSopenharmony_ci case AVSEEK_SIZE: 265cabdff1aSopenharmony_ci return ffurl_seek( c->hd, pos, AVSEEK_SIZE ); 266cabdff1aSopenharmony_ci default: 267cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, 268cabdff1aSopenharmony_ci "Crypto: no support for seek where 'whence' is %d\r\n", whence); 269cabdff1aSopenharmony_ci return AVERROR(EINVAL); 270cabdff1aSopenharmony_ci } 271cabdff1aSopenharmony_ci 272cabdff1aSopenharmony_ci c->outdata = 0; 273cabdff1aSopenharmony_ci c->indata = 0; 274cabdff1aSopenharmony_ci c->indata_used = 0; 275cabdff1aSopenharmony_ci c->outptr = c->outbuffer; 276cabdff1aSopenharmony_ci 277cabdff1aSopenharmony_ci // identify the block containing the IV for the 278cabdff1aSopenharmony_ci // next block we will decrypt 279cabdff1aSopenharmony_ci block = pos/BLOCKSIZE; 280cabdff1aSopenharmony_ci if (block == 0) { 281cabdff1aSopenharmony_ci // restore the iv to the seed one - this is the iv for the FIRST block 282cabdff1aSopenharmony_ci memcpy( c->decrypt_iv, c->iv, c->ivlen ); 283cabdff1aSopenharmony_ci c->position = 0; 284cabdff1aSopenharmony_ci } else { 285cabdff1aSopenharmony_ci // else, go back one block - we will get av_cyrpt to read this block 286cabdff1aSopenharmony_ci // which it will then store use as the iv. 287cabdff1aSopenharmony_ci // note that the DECRYPTED result will not be correct, 288cabdff1aSopenharmony_ci // but will be discarded 289cabdff1aSopenharmony_ci block--; 290cabdff1aSopenharmony_ci c->position = (block * BLOCKSIZE); 291cabdff1aSopenharmony_ci } 292cabdff1aSopenharmony_ci 293cabdff1aSopenharmony_ci newpos = ffurl_seek( c->hd, c->position, SEEK_SET ); 294cabdff1aSopenharmony_ci if (newpos < 0) { 295cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, 296cabdff1aSopenharmony_ci "Crypto: nested protocol no support for seek or seek failed\n"); 297cabdff1aSopenharmony_ci return newpos; 298cabdff1aSopenharmony_ci } 299cabdff1aSopenharmony_ci 300cabdff1aSopenharmony_ci // read and discard from here up to required position 301cabdff1aSopenharmony_ci // (which will set the iv correctly to it). 302cabdff1aSopenharmony_ci if (pos - c->position) { 303cabdff1aSopenharmony_ci uint8_t buff[BLOCKSIZE*2]; // maximum size of pos-c->position 304cabdff1aSopenharmony_ci int len = pos - c->position; 305cabdff1aSopenharmony_ci int res; 306cabdff1aSopenharmony_ci 307cabdff1aSopenharmony_ci while (len > 0) { 308cabdff1aSopenharmony_ci // note: this may not return all the bytes first time 309cabdff1aSopenharmony_ci res = crypto_read(h, buff, len); 310cabdff1aSopenharmony_ci if (res < 0) 311cabdff1aSopenharmony_ci break; 312cabdff1aSopenharmony_ci len -= res; 313cabdff1aSopenharmony_ci } 314cabdff1aSopenharmony_ci 315cabdff1aSopenharmony_ci // if we did not get all the bytes 316cabdff1aSopenharmony_ci if (len != 0) { 317cabdff1aSopenharmony_ci char errbuf[100] = "unknown error"; 318cabdff1aSopenharmony_ci av_strerror(res, errbuf, sizeof(errbuf)); 319cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, 320cabdff1aSopenharmony_ci "Crypto: discard read did not get all the bytes (%d remain) - read returned (%d)-%s\n", 321cabdff1aSopenharmony_ci len, res, errbuf); 322cabdff1aSopenharmony_ci return AVERROR(EINVAL); 323cabdff1aSopenharmony_ci } 324cabdff1aSopenharmony_ci } 325cabdff1aSopenharmony_ci 326cabdff1aSopenharmony_ci return c->position; 327cabdff1aSopenharmony_ci} 328cabdff1aSopenharmony_ci 329cabdff1aSopenharmony_cistatic int crypto_write(URLContext *h, const unsigned char *buf, int size) 330cabdff1aSopenharmony_ci{ 331cabdff1aSopenharmony_ci CryptoContext *c = h->priv_data; 332cabdff1aSopenharmony_ci int total_size, blocks, pad_len, out_size; 333cabdff1aSopenharmony_ci int ret = 0; 334cabdff1aSopenharmony_ci 335cabdff1aSopenharmony_ci total_size = size + c->pad_len; 336cabdff1aSopenharmony_ci pad_len = total_size % BLOCKSIZE; 337cabdff1aSopenharmony_ci out_size = total_size - pad_len; 338cabdff1aSopenharmony_ci blocks = out_size / BLOCKSIZE; 339cabdff1aSopenharmony_ci 340cabdff1aSopenharmony_ci if (out_size) { 341cabdff1aSopenharmony_ci av_fast_malloc(&c->write_buf, &c->write_buf_size, out_size); 342cabdff1aSopenharmony_ci 343cabdff1aSopenharmony_ci if (!c->write_buf) 344cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 345cabdff1aSopenharmony_ci 346cabdff1aSopenharmony_ci if (c->pad_len) { 347cabdff1aSopenharmony_ci memcpy(&c->pad[c->pad_len], buf, BLOCKSIZE - c->pad_len); 348cabdff1aSopenharmony_ci av_aes_crypt(c->aes_encrypt, c->write_buf, c->pad, 1, c->encrypt_iv, 0); 349cabdff1aSopenharmony_ci blocks--; 350cabdff1aSopenharmony_ci } 351cabdff1aSopenharmony_ci 352cabdff1aSopenharmony_ci av_aes_crypt(c->aes_encrypt, 353cabdff1aSopenharmony_ci &c->write_buf[c->pad_len ? BLOCKSIZE : 0], 354cabdff1aSopenharmony_ci &buf[c->pad_len ? BLOCKSIZE - c->pad_len : 0], 355cabdff1aSopenharmony_ci blocks, c->encrypt_iv, 0); 356cabdff1aSopenharmony_ci 357cabdff1aSopenharmony_ci ret = ffurl_write(c->hd, c->write_buf, out_size); 358cabdff1aSopenharmony_ci if (ret < 0) 359cabdff1aSopenharmony_ci return ret; 360cabdff1aSopenharmony_ci 361cabdff1aSopenharmony_ci memcpy(c->pad, &buf[size - pad_len], pad_len); 362cabdff1aSopenharmony_ci } else 363cabdff1aSopenharmony_ci memcpy(&c->pad[c->pad_len], buf, size); 364cabdff1aSopenharmony_ci 365cabdff1aSopenharmony_ci c->pad_len = pad_len; 366cabdff1aSopenharmony_ci 367cabdff1aSopenharmony_ci return size; 368cabdff1aSopenharmony_ci} 369cabdff1aSopenharmony_ci 370cabdff1aSopenharmony_cistatic int crypto_close(URLContext *h) 371cabdff1aSopenharmony_ci{ 372cabdff1aSopenharmony_ci CryptoContext *c = h->priv_data; 373cabdff1aSopenharmony_ci int ret = 0; 374cabdff1aSopenharmony_ci 375cabdff1aSopenharmony_ci if (c->aes_encrypt) { 376cabdff1aSopenharmony_ci uint8_t out_buf[BLOCKSIZE]; 377cabdff1aSopenharmony_ci int pad = BLOCKSIZE - c->pad_len; 378cabdff1aSopenharmony_ci 379cabdff1aSopenharmony_ci memset(&c->pad[c->pad_len], pad, pad); 380cabdff1aSopenharmony_ci av_aes_crypt(c->aes_encrypt, out_buf, c->pad, 1, c->encrypt_iv, 0); 381cabdff1aSopenharmony_ci ret = ffurl_write(c->hd, out_buf, BLOCKSIZE); 382cabdff1aSopenharmony_ci } 383cabdff1aSopenharmony_ci 384cabdff1aSopenharmony_ci ffurl_closep(&c->hd); 385cabdff1aSopenharmony_ci av_freep(&c->aes_decrypt); 386cabdff1aSopenharmony_ci av_freep(&c->aes_encrypt); 387cabdff1aSopenharmony_ci av_freep(&c->write_buf); 388cabdff1aSopenharmony_ci return ret; 389cabdff1aSopenharmony_ci} 390cabdff1aSopenharmony_ci 391cabdff1aSopenharmony_ciconst URLProtocol ff_crypto_protocol = { 392cabdff1aSopenharmony_ci .name = "crypto", 393cabdff1aSopenharmony_ci .url_open2 = crypto_open2, 394cabdff1aSopenharmony_ci .url_seek = crypto_seek, 395cabdff1aSopenharmony_ci .url_read = crypto_read, 396cabdff1aSopenharmony_ci .url_write = crypto_write, 397cabdff1aSopenharmony_ci .url_close = crypto_close, 398cabdff1aSopenharmony_ci .priv_data_size = sizeof(CryptoContext), 399cabdff1aSopenharmony_ci .priv_data_class = &crypto_class, 400cabdff1aSopenharmony_ci .flags = URL_PROTOCOL_FLAG_NESTED_SCHEME, 401cabdff1aSopenharmony_ci}; 402