Message ID | CAHt4oVW4GJssWVjQNDYd7X2FTzP1nfmhp_SzMU8y71=iXzk0AA@mail.gmail.com |
---|---|
State | Accepted |
Headers | show |
On Mon, Aug 29, 2016 at 11:08:36AM +0100, Simon H wrote: > crypto allows reading of data which has been aes-128-cbc encrypted given a > key and an iv. > But it did not handle filetypes which require seeking... e.g. it failed on > an encrypted .mp4 file. > > example: > take 25.mp4 created with: > ffmpeg -f lavfi -i sine=frequency=1000:beep_factor=2:r=48000:duration=720.0 > -f lavfi -i testsrc=duration=720.0:rate=25 -vcodec libx264 -cmp 22 > -timecode 10:00:00:00 -r 25 -y out\25.mp4 > > encrypt with: > openssl enc -aes-128-cbc -K 12345678901234567890123456789012 -iv > 12345678901234567890123456789012 -in 25.mp4 -out 25.enc > then to transcode in ffmpeg: > ffmpeg -key 12345678901234567890123456789012 -iv > 12345678901234567890123456789012 -i crypto:25.enc -vcodec mpeg4 -r 25 -y > 25dec.mp4 > > prior to this modification, the transcode would fail. > > Note also: crypto previously marked both reads and writes as streamed, > which caused the whole file > to be read before the transcode started. Now, for read only, if the > underlying layer is not marked as streamed, > then crypto is not. This should enable efficient reading of encrypted > containers which require seeking. > > this is my first patch for ffmpeg; guidance appreciated. > --- > libavformat/crypto.c | 115 > +++++++++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 112 insertions(+), 3 deletions(-) > > diff --git a/libavformat/crypto.c b/libavformat/crypto.c > index 2999f50..23bc0a6 100644 > --- a/libavformat/crypto.c > +++ b/libavformat/crypto.c > @@ -26,7 +26,8 @@ > #include "internal.h" > #include "url.h" > > -#define MAX_BUFFER_BLOCKS 150 > +// encourage reads of 4096 bytes - 1 block is always retained. > +#define MAX_BUFFER_BLOCKS 257 > #define BLOCKSIZE 16 > > typedef struct CryptoContext { > @@ -36,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; > @@ -109,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)) { > @@ -117,6 +121,8 @@ static int crypto_open2(URLContext *h, const char *uri, > int flags, AVDictionary patch corrupted by newlines [...]
thanks Michael, try the attached file. I assume the corruption came from email word wrapping? or was there something else wrong? simon On Mon, Aug 29, 2016 at 6:11 PM, Michael Niedermayer <michael@niedermayer.cc > wrote: > On Mon, Aug 29, 2016 at 11:08:36AM +0100, Simon H wrote: > > crypto allows reading of data which has been aes-128-cbc encrypted given > a > > key and an iv. > > But it did not handle filetypes which require seeking... e.g. it failed > on > > an encrypted .mp4 file. > > > > example: > > take 25.mp4 created with: > > ffmpeg -f lavfi -i sine=frequency=1000:beep_ > factor=2:r=48000:duration=720.0 > > -f lavfi -i testsrc=duration=720.0:rate=25 -vcodec libx264 -cmp 22 > > -timecode 10:00:00:00 -r 25 -y out\25.mp4 > > > > encrypt with: > > openssl enc -aes-128-cbc -K 12345678901234567890123456789012 -iv > > 12345678901234567890123456789012 -in 25.mp4 -out 25.enc > > then to transcode in ffmpeg: > > ffmpeg -key 12345678901234567890123456789012 -iv > > 12345678901234567890123456789012 -i crypto:25.enc -vcodec mpeg4 -r 25 -y > > 25dec.mp4 > > > > prior to this modification, the transcode would fail. > > > > Note also: crypto previously marked both reads and writes as streamed, > > which caused the whole file > > to be read before the transcode started. Now, for read only, if the > > underlying layer is not marked as streamed, > > then crypto is not. This should enable efficient reading of encrypted > > containers which require seeking. > > > > this is my first patch for ffmpeg; guidance appreciated. > > --- > > libavformat/crypto.c | 115 > > +++++++++++++++++++++++++++++++++++++++++++++++++-- > > 1 file changed, 112 insertions(+), 3 deletions(-) > > > > diff --git a/libavformat/crypto.c b/libavformat/crypto.c > > index 2999f50..23bc0a6 100644 > > --- a/libavformat/crypto.c > > +++ b/libavformat/crypto.c > > @@ -26,7 +26,8 @@ > > #include "internal.h" > > #include "url.h" > > > > -#define MAX_BUFFER_BLOCKS 150 > > +// encourage reads of 4096 bytes - 1 block is always retained. > > +#define MAX_BUFFER_BLOCKS 257 > > #define BLOCKSIZE 16 > > > > typedef struct CryptoContext { > > @@ -36,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; > > @@ -109,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)) { > > @@ -117,6 +121,8 @@ static int crypto_open2(URLContext *h, const char > *uri, > > int flags, AVDictionary > > patch corrupted by newlines > > [...] > -- > Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB > > If a bugfix only changes things apparently unrelated to the bug with no > further explanation, that is a good sign that the bugfix is wrong. > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel > >
On Mon, Aug 29, 2016 at 09:56:59PM +0100, Simon H wrote: > thanks Michael, > > try the attached file. I assume the corruption came from email word > wrapping? likely > or was there something else wrong? [...] > example: > take 25.mp4 created with: > ffmpeg -f lavfi -i sine=frequency=1000:beep_factor=2:r=48000:duration=720.0 -f lavfi -i testsrc=duration=720.0:rate=25 -vcodec libx264 -cmp 22 -timecode 10:00:00:00 -r 25 -y out\25.mp4 > > encrypt with: > openssl enc -aes-128-cbc -K 12345678901234567890123456789012 -iv 12345678901234567890123456789012 -in 25.mp4 -out 25.enc > then to transcode in ffmpeg: > ffmpeg -key 12345678901234567890123456789012 -iv 12345678901234567890123456789012 -i crypto:25.enc -vcodec mpeg4 -r 25 -y 25dec.mp4 > > prior to this modification, the transcode would fail. > > Note also: crypto previously marked both reads and writes as streamed, which caused the whole file > to be read before the transcode started. Now, for read only, if the underlying layer is not marked as streamed, > then crypto is not. This should enable efficient reading of encrypted containers which require seeking. > --- > libavformat/crypto.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 112 insertions(+), 3 deletions(-) > > diff --git a/libavformat/crypto.c b/libavformat/crypto.c > index 2999f50..23bc0a6 100644 > --- a/libavformat/crypto.c > +++ b/libavformat/crypto.c > @@ -26,7 +26,8 @@ > #include "internal.h" > #include "url.h" > > -#define MAX_BUFFER_BLOCKS 150 > +// encourage reads of 4096 bytes - 1 block is always retained. > +#define MAX_BUFFER_BLOCKS 257 > #define BLOCKSIZE 16 > > typedef struct CryptoContext { this should be in a separate patch > @@ -36,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; > @@ -109,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)) { > @@ -117,6 +121,8 @@ static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary > goto err; > } > > + c->position = 0L; > + > if (flags & AVIO_FLAG_READ) { > if ((ret = set_aes_arg(c, &c->decrypt_key, &c->decrypt_keylen, > c->key, c->keylen, "decryption key")) < 0) > @@ -152,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) { > @@ -163,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; > } > @@ -183,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, > @@ -222,6 +234,102 @@ 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"); > + return -1L; should be a AVERROR* code > + } > + > + // 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", pos); libavformat/crypto.c: In function ‘crypto_seek’: libavformat/crypto.c:262:17: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 4 has type ‘int64_t’ [-Wformat] > + return newpos; > + } > + pos = newpos - pos; > + } > + break; > + case AVSEEK_SIZE: > + return ffurl_seek( c->hd, pos, AVSEEK_SIZE ); please use the same formating as the surrounding code > + default: > + av_log(h, AV_LOG_ERROR, > + "Crypto: no support for seek where 'whence' is %d\r\n", whence); > + return -1L; > + } > + > + 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/16L; many of the L suffixes are unneeded thx [...]
diff --git a/libavformat/crypto.c b/libavformat/crypto.c index 2999f50..23bc0a6 100644 --- a/libavformat/crypto.c +++ b/libavformat/crypto.c @@ -26,7 +26,8 @@ #include "internal.h" #include "url.h" -#define MAX_BUFFER_BLOCKS 150 +// encourage reads of 4096 bytes - 1 block is always retained. +#define MAX_BUFFER_BLOCKS 257 #define BLOCKSIZE 16 typedef struct CryptoContext { @@ -36,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; @@ -109,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) &&