Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FFmpeg/FFmpeg.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libavformat/crypto.c116
1 files changed, 114 insertions, 2 deletions
diff --git a/libavformat/crypto.c b/libavformat/crypto.c
index 31a438c94c..346c7061b4 100644
--- a/libavformat/crypto.c
+++ b/libavformat/crypto.c
@@ -37,6 +37,8 @@ typedef struct CryptoContext {
outbuffer[BLOCKSIZE*MAX_BUFFER_BLOCKS];
uint8_t *outptr;
int indata, indata_used, outdata;
+ int64_t position; // position in file - used in seek
+ int flags;
int eof;
uint8_t *key;
int keylen;
@@ -110,6 +112,7 @@ static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary
const char *nested_url;
int ret = 0;
CryptoContext *c = h->priv_data;
+ c->flags = flags;
if (!av_strstart(uri, "crypto+", &nested_url) &&
!av_strstart(uri, "crypto:", &nested_url)) {
@@ -118,6 +121,8 @@ static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary
goto err;
}
+ c->position = 0;
+
if (flags & AVIO_FLAG_READ) {
if ((ret = set_aes_arg(c, &c->decrypt_key, &c->decrypt_keylen,
c->key, c->keylen, "decryption key")) < 0)
@@ -153,6 +158,10 @@ static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary
ret = av_aes_init(c->aes_decrypt, c->decrypt_key, BLOCKSIZE*8, 1);
if (ret < 0)
goto err;
+
+ // pass back information about the context we openned
+ if (c->hd->is_streamed)
+ h->is_streamed = c->hd->is_streamed;
}
if (flags & AVIO_FLAG_WRITE) {
@@ -164,12 +173,13 @@ static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary
ret = av_aes_init(c->aes_encrypt, c->encrypt_key, BLOCKSIZE*8, 0);
if (ret < 0)
goto err;
+ // for write, we must be streamed
+ // - linear write only for crytpo aes-128-cbc
+ h->is_streamed = 1;
}
c->pad_len = 0;
- h->is_streamed = 1;
-
err:
return ret;
}
@@ -184,6 +194,7 @@ retry:
memcpy(buf, c->outptr, size);
c->outptr += size;
c->outdata -= size;
+ c->position = c->position + size;
return size;
}
// We avoid using the last block until we've found EOF,
@@ -223,6 +234,106 @@ retry:
goto retry;
}
+static int64_t crypto_seek(URLContext *h, int64_t pos, int whence)
+{
+ CryptoContext *c = h->priv_data;
+ int64_t block;
+ int64_t newpos;
+
+ if (c->flags & AVIO_FLAG_WRITE) {
+ av_log(h, AV_LOG_ERROR,
+ "Crypto: seek not supported for write\r\n");
+ /* seems the most appropriate error to return */
+ return AVERROR(ESPIPE);
+ }
+
+ // reset eof, else we won't read it correctly if we already hit eof.
+ c->eof = 0;
+
+ switch (whence) {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ pos = pos + c->position;
+ break;
+ case SEEK_END: {
+ int64_t newpos = ffurl_seek( c->hd, pos, AVSEEK_SIZE );
+ if (newpos < 0) {
+ av_log(h, AV_LOG_ERROR,
+ "Crypto: seek_end - can't get file size (pos=%lld)\r\n", (long long int)pos);
+ return newpos;
+ }
+ pos = newpos - pos;
+ }
+ break;
+ case AVSEEK_SIZE: {
+ int64_t newpos = ffurl_seek( c->hd, pos, AVSEEK_SIZE );
+ return newpos;
+ }
+ break;
+ default:
+ av_log(h, AV_LOG_ERROR,
+ "Crypto: no support for seek where 'whence' is %d\r\n", whence);
+ return AVERROR(EINVAL);
+ }
+
+ c->outdata = 0;
+ c->indata = 0;
+ c->indata_used = 0;
+ c->outptr = c->outbuffer;
+
+ // identify the block containing the IV for the
+ // next block we will decrypt
+ block = pos/BLOCKSIZE;
+ if (block == 0) {
+ // restore the iv to the seed one - this is the iv for the FIRST block
+ memcpy( c->decrypt_iv, c->iv, c->ivlen );
+ c->position = 0;
+ } else {
+ // else, go back one block - we will get av_cyrpt to read this block
+ // which it will then store use as the iv.
+ // note that the DECRYPTED result will not be correct,
+ // but will be discarded
+ block--;
+ c->position = (block * BLOCKSIZE);
+ }
+
+ newpos = ffurl_seek( c->hd, c->position, SEEK_SET );
+ if (newpos < 0) {
+ av_log(h, AV_LOG_ERROR,
+ "Crypto: nested protocol no support for seek or seek failed\n");
+ return newpos;
+ }
+
+ // read and discard from here up to required position
+ // (which will set the iv correctly to it).
+ if (pos - c->position) {
+ uint8_t buff[BLOCKSIZE*2]; // maximum size of pos-c->position
+ int len = pos - c->position;
+ int res;
+
+ while (len > 0) {
+ // note: this may not return all the bytes first time
+ res = crypto_read(h, buff, len);
+ if (res < 0)
+ break;
+ len -= res;
+ }
+
+ // if we did not get all the bytes
+ if (len != 0) {
+ char errbuf[100] = "unknown error";
+ av_strerror(res, errbuf, sizeof(errbuf));
+ av_log(h, AV_LOG_ERROR,
+ "Crypto: discard read did not get all the bytes (%d remain) - read returned (%d)-%s\n",
+ len, res, errbuf);
+ return AVERROR(EINVAL);
+ }
+ }
+
+ return c->position;
+}
+
static int crypto_write(URLContext *h, const unsigned char *buf, int size)
{
CryptoContext *c = h->priv_data;
@@ -288,6 +399,7 @@ static int crypto_close(URLContext *h)
const URLProtocol ff_crypto_protocol = {
.name = "crypto",
.url_open2 = crypto_open2,
+ .url_seek = crypto_seek,
.url_read = crypto_read,
.url_write = crypto_write,
.url_close = crypto_close,