@ -37,6 +37,8 @@ typedef struct CryptoContext {
outbuffer [ BLOCKSIZE * MAX_BUFFER_BLOCKS ] ;
outbuffer [ BLOCKSIZE * MAX_BUFFER_BLOCKS ] ;
uint8_t * outptr ;
uint8_t * outptr ;
int indata , indata_used , outdata ;
int indata , indata_used , outdata ;
int64_t position ; // position in file - used in seek
int flags ;
int eof ;
int eof ;
uint8_t * key ;
uint8_t * key ;
int keylen ;
int keylen ;
@ -110,6 +112,7 @@ static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary
const char * nested_url ;
const char * nested_url ;
int ret = 0 ;
int ret = 0 ;
CryptoContext * c = h - > priv_data ;
CryptoContext * c = h - > priv_data ;
c - > flags = flags ;
if ( ! av_strstart ( uri , " crypto+ " , & nested_url ) & &
if ( ! av_strstart ( uri , " crypto+ " , & nested_url ) & &
! 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 ;
goto err ;
}
}
c - > position = 0 ;
if ( flags & AVIO_FLAG_READ ) {
if ( flags & AVIO_FLAG_READ ) {
if ( ( ret = set_aes_arg ( c , & c - > decrypt_key , & c - > decrypt_keylen ,
if ( ( ret = set_aes_arg ( c , & c - > decrypt_key , & c - > decrypt_keylen ,
c - > key , c - > keylen , " decryption key " ) ) < 0 )
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 ) ;
ret = av_aes_init ( c - > aes_decrypt , c - > decrypt_key , BLOCKSIZE * 8 , 1 ) ;
if ( ret < 0 )
if ( ret < 0 )
goto err ;
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 ) {
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 ) ;
ret = av_aes_init ( c - > aes_encrypt , c - > encrypt_key , BLOCKSIZE * 8 , 0 ) ;
if ( ret < 0 )
if ( ret < 0 )
goto err ;
goto err ;
// for write, we must be streamed
// - linear write only for crytpo aes-128-cbc
h - > is_streamed = 1 ;
}
}
c - > pad_len = 0 ;
c - > pad_len = 0 ;
h - > is_streamed = 1 ;
err :
err :
return ret ;
return ret ;
}
}
@ -184,6 +194,7 @@ retry:
memcpy ( buf , c - > outptr , size ) ;
memcpy ( buf , c - > outptr , size ) ;
c - > outptr + = size ;
c - > outptr + = size ;
c - > outdata - = size ;
c - > outdata - = size ;
c - > position = c - > position + size ;
return size ;
return size ;
}
}
// We avoid using the last block until we've found EOF,
// We avoid using the last block until we've found EOF,
@ -223,6 +234,106 @@ retry:
goto 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 )
static int crypto_write ( URLContext * h , const unsigned char * buf , int size )
{
{
CryptoContext * c = h - > priv_data ;
CryptoContext * c = h - > priv_data ;
@ -288,6 +399,7 @@ static int crypto_close(URLContext *h)
const URLProtocol ff_crypto_protocol = {
const URLProtocol ff_crypto_protocol = {
. name = " crypto " ,
. name = " crypto " ,
. url_open2 = crypto_open2 ,
. url_open2 = crypto_open2 ,
. url_seek = crypto_seek ,
. url_read = crypto_read ,
. url_read = crypto_read ,
. url_write = crypto_write ,
. url_write = crypto_write ,
. url_close = crypto_close ,
. url_close = crypto_close ,