FFmpeg
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavformat
crypto.c
Go to the documentation of this file.
1
/*
2
* Decryption protocol handler
3
* Copyright (c) 2011 Martin Storsjo
4
*
5
* This file is part of Libav.
6
*
7
* Libav is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
11
*
12
* Libav is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
16
*
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with Libav; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
*/
21
22
#include "
avformat.h
"
23
#include "
libavutil/aes.h
"
24
#include "
libavutil/avstring.h
"
25
#include "
libavutil/opt.h
"
26
#include "
internal.h
"
27
#include "
url.h
"
28
29
#define MAX_BUFFER_BLOCKS 150
30
#define BLOCKSIZE 16
31
32
typedef
struct
{
33
const
AVClass
*
class
;
34
URLContext
*
hd
;
35
uint8_t
inbuffer [
BLOCKSIZE
*
MAX_BUFFER_BLOCKS
],
36
outbuffer[
BLOCKSIZE
*
MAX_BUFFER_BLOCKS
];
37
uint8_t
*
outptr
;
38
int
indata, indata_used,
outdata
;
39
int
eof
;
40
uint8_t
*
key
;
41
int
keylen
;
42
uint8_t
*
iv
;
43
int
ivlen
;
44
struct
AVAES
*
aes
;
45
}
CryptoContext
;
46
47
#define OFFSET(x) offsetof(CryptoContext, x)
48
#define D AV_OPT_FLAG_DECODING_PARAM
49
static
const
AVOption
options
[] = {
50
{
"key"
,
"AES decryption key"
,
OFFSET
(key),
AV_OPT_TYPE_BINARY
, .flags =
D
},
51
{
"iv"
,
"AES decryption initialization vector"
,
OFFSET
(iv),
AV_OPT_TYPE_BINARY
, .flags =
D
},
52
{ NULL }
53
};
54
55
static
const
AVClass
crypto_class
= {
56
.
class_name
=
"crypto"
,
57
.item_name =
av_default_item_name
,
58
.option =
options
,
59
.version =
LIBAVUTIL_VERSION_INT
,
60
};
61
62
static
int
crypto_open2
(
URLContext
*h,
const
char
*uri,
int
flags
,
AVDictionary
**options)
63
{
64
const
char
*nested_url;
65
int
ret
= 0;
66
CryptoContext
*
c
= h->
priv_data
;
67
68
if
(!
av_strstart
(uri,
"crypto+"
, &nested_url) &&
69
!
av_strstart
(uri,
"crypto:"
, &nested_url)) {
70
av_log
(h,
AV_LOG_ERROR
,
"Unsupported url %s\n"
, uri);
71
ret =
AVERROR
(EINVAL);
72
goto
err;
73
}
74
75
if
(c->
keylen
<
BLOCKSIZE
|| c->
ivlen
<
BLOCKSIZE
) {
76
av_log
(h,
AV_LOG_ERROR
,
"Key or IV not set\n"
);
77
ret =
AVERROR
(EINVAL);
78
goto
err;
79
}
80
if
(flags &
AVIO_FLAG_WRITE
) {
81
av_log
(h,
AV_LOG_ERROR
,
"Only decryption is supported currently\n"
);
82
ret =
AVERROR
(ENOSYS);
83
goto
err;
84
}
85
if
((ret =
ffurl_open
(&c->
hd
, nested_url,
AVIO_FLAG_READ
,
86
&h->
interrupt_callback
, options)) < 0) {
87
av_log
(h,
AV_LOG_ERROR
,
"Unable to open input\n"
);
88
goto
err;
89
}
90
c->
aes
=
av_aes_alloc
();
91
if
(!c->
aes
) {
92
ret =
AVERROR
(ENOMEM);
93
goto
err;
94
}
95
96
av_aes_init
(c->
aes
, c->
key
, 128, 1);
97
98
h->
is_streamed
= 1;
99
100
err:
101
return
ret
;
102
}
103
104
static
int
crypto_read
(
URLContext
*h,
uint8_t
*
buf
,
int
size
)
105
{
106
CryptoContext
*
c
= h->
priv_data
;
107
int
blocks;
108
retry:
109
if
(c->
outdata
> 0) {
110
size =
FFMIN
(size, c->
outdata
);
111
memcpy(buf, c->
outptr
, size);
112
c->
outptr
+=
size
;
113
c->
outdata
-=
size
;
114
return
size
;
115
}
116
// We avoid using the last block until we've found EOF,
117
// since we'll remove PKCS7 padding at the end. So make
118
// sure we've got at least 2 blocks, so we can decrypt
119
// at least one.
120
while
(c->
indata
- c->
indata_used
< 2*
BLOCKSIZE
) {
121
int
n
=
ffurl_read
(c->
hd
, c->
inbuffer
+ c->
indata
,
122
sizeof
(c->
inbuffer
) - c->
indata
);
123
if
(n <= 0) {
124
c->
eof
= 1;
125
break
;
126
}
127
c->
indata
+=
n
;
128
}
129
blocks = (c->
indata
- c->
indata_used
) /
BLOCKSIZE
;
130
if
(!blocks)
131
return
AVERROR_EOF
;
132
if
(!c->
eof
)
133
blocks--;
134
av_aes_crypt
(c->
aes
, c->
outbuffer
, c->
inbuffer
+ c->
indata_used
, blocks,
135
c->
iv
, 1);
136
c->
outdata
=
BLOCKSIZE
* blocks;
137
c->
outptr
= c->
outbuffer
;
138
c->
indata_used
+=
BLOCKSIZE
* blocks;
139
if
(c->
indata_used
>=
sizeof
(c->
inbuffer
)/2) {
140
memmove(c->
inbuffer
, c->
inbuffer
+ c->
indata_used
,
141
c->
indata
- c->
indata_used
);
142
c->
indata
-= c->
indata_used
;
143
c->
indata_used
= 0;
144
}
145
if
(c->
eof
) {
146
// Remove PKCS7 padding at the end
147
int
padding = c->
outbuffer
[c->
outdata
- 1];
148
c->
outdata
-= padding;
149
}
150
goto
retry;
151
}
152
153
static
int
crypto_close
(
URLContext
*h)
154
{
155
CryptoContext
*
c
= h->
priv_data
;
156
if
(c->
hd
)
157
ffurl_close
(c->
hd
);
158
av_freep
(&c->
aes
);
159
return
0;
160
}
161
162
URLProtocol
ff_crypto_protocol
= {
163
.
name
=
"crypto"
,
164
.url_open2 =
crypto_open2
,
165
.url_read =
crypto_read
,
166
.url_close =
crypto_close
,
167
.priv_data_size =
sizeof
(
CryptoContext
),
168
.priv_data_class = &crypto_class,
169
.
flags
=
URL_PROTOCOL_FLAG_NESTED_SCHEME
,
170
};
Generated on Wed Jul 10 2013 23:48:11 for FFmpeg by
1.8.2