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 FFmpeg.
6
*
7
* FFmpeg 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
* FFmpeg 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 FFmpeg; 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 Sat Jan 25 2014 19:52:02 for FFmpeg by
1.8.2