Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
ffmpeg
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Stefan Westerfeld
ffmpeg
Commits
035d187c
Commit
035d187c
authored
Sep 21, 2023
by
Paul B Mahol
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
avformat/hca: add support for decryption
parent
63371cde
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
159 additions
and
12 deletions
+159
-12
hcadec.c
libavcodec/hcadec.c
+115
-5
hca.c
libavformat/hca.c
+44
-7
No files found.
libavcodec/hcadec.c
View file @
035d187c
...
...
@@ -28,6 +28,7 @@
#include "get_bits.h"
#include "hca_data.h"
#define HCA_MASK 0x7f7f7f7f
#define MAX_CHANNELS 16
typedef
struct
ChannelContext
{
...
...
@@ -50,8 +51,12 @@ typedef struct HCAContext {
ChannelContext
ch
[
MAX_CHANNELS
];
uint8_t
ath
[
128
];
uint8_t
cipher
[
256
];
uint64_t
key
;
uint16_t
subkey
;
int
ath_type
;
int
ciph_type
;
unsigned
hfr_group_count
;
uint8_t
track_count
;
uint8_t
channel_config
;
...
...
@@ -65,6 +70,93 @@ typedef struct HCAContext {
AVFloatDSPContext
*
fdsp
;
}
HCAContext
;
static
void
cipher_init56_create_table
(
uint8_t
*
r
,
uint8_t
key
)
{
const
int
mul
=
((
key
&
1
)
<<
3
)
|
5
;
const
int
add
=
(
key
&
0xE
)
|
1
;
key
>>=
4
;
for
(
int
i
=
0
;
i
<
16
;
i
++
)
{
key
=
(
key
*
mul
+
add
)
&
0xF
;
r
[
i
]
=
key
;
}
}
static
void
cipher_init56
(
uint8_t
*
cipher
,
uint64_t
keycode
)
{
uint8_t
base
[
256
],
base_r
[
16
],
base_c
[
16
],
kc
[
8
],
seed
[
16
];
/* 56bit keycode encryption (given as a uint64_t number, but upper 8b aren't used) */
/* keycode = keycode - 1 */
if
(
keycode
!=
0
)
keycode
--
;
/* init keycode table */
for
(
int
r
=
0
;
r
<
(
8
-
1
);
r
++
)
{
kc
[
r
]
=
keycode
&
0xFF
;
keycode
=
keycode
>>
8
;
}
/* init seed table */
seed
[
0
]
=
kc
[
1
];
seed
[
1
]
=
kc
[
1
]
^
kc
[
6
];
seed
[
2
]
=
kc
[
2
]
^
kc
[
3
];
seed
[
3
]
=
kc
[
2
];
seed
[
4
]
=
kc
[
2
]
^
kc
[
1
];
seed
[
5
]
=
kc
[
3
]
^
kc
[
4
];
seed
[
6
]
=
kc
[
3
];
seed
[
7
]
=
kc
[
3
]
^
kc
[
2
];
seed
[
8
]
=
kc
[
4
]
^
kc
[
5
];
seed
[
9
]
=
kc
[
4
];
seed
[
10
]
=
kc
[
4
]
^
kc
[
3
];
seed
[
11
]
=
kc
[
5
]
^
kc
[
6
];
seed
[
12
]
=
kc
[
5
];
seed
[
13
]
=
kc
[
5
]
^
kc
[
4
];
seed
[
14
]
=
kc
[
6
]
^
kc
[
1
];
seed
[
15
]
=
kc
[
6
];
/* init base table */
cipher_init56_create_table
(
base_r
,
kc
[
0
]);
for
(
int
r
=
0
;
r
<
16
;
r
++
)
{
uint8_t
nb
;
cipher_init56_create_table
(
base_c
,
seed
[
r
]);
nb
=
base_r
[
r
]
<<
4
;
for
(
int
c
=
0
;
c
<
16
;
c
++
)
base
[
r
*
16
+
c
]
=
nb
|
base_c
[
c
];
/* combine nibbles */
}
/* final shuffle table */
{
unsigned
x
=
0
;
unsigned
pos
=
1
;
for
(
int
i
=
0
;
i
<
256
;
i
++
)
{
x
=
(
x
+
17
)
&
0xFF
;
if
(
base
[
x
]
!=
0
&&
base
[
x
]
!=
0xFF
)
cipher
[
pos
++
]
=
base
[
x
];
}
cipher
[
0
]
=
0
;
cipher
[
0xFF
]
=
0xFF
;
}
}
static
void
cipher_init
(
uint8_t
*
cipher
,
int
type
,
uint64_t
keycode
,
uint16_t
subkey
)
{
switch
(
type
)
{
case
56
:
if
(
keycode
)
{
if
(
subkey
)
keycode
=
keycode
*
(((
uint64_t
)
subkey
<<
16u
)
|
((
uint16_t
)
~
subkey
+
2u
));
cipher_init56
(
cipher
,
keycode
);
}
break
;
case
0
:
for
(
int
i
=
0
;
i
<
256
;
i
++
)
cipher
[
i
]
=
i
;
break
;
}
}
static
void
ath_init1
(
uint8_t
*
ath
,
int
sample_rate
)
{
unsigned
int
index
;
...
...
@@ -124,13 +216,13 @@ static int init_hca(AVCodecContext *avctx, const uint8_t *extradata,
c
->
ath_type
=
version
>=
0x200
?
0
:
1
;
if
(
bytestream2_get_be32u
(
gb
)
!=
MKBETAG
(
'f'
,
'm'
,
't'
,
0
))
if
(
(
bytestream2_get_be32u
(
gb
)
&
HCA_MASK
)
!=
MKBETAG
(
'f'
,
'm'
,
't'
,
0
))
return
AVERROR_INVALIDDATA
;
bytestream2_skipu
(
gb
,
4
);
bytestream2_skipu
(
gb
,
4
);
bytestream2_skipu
(
gb
,
4
);
chunk
=
bytestream2_get_be32u
(
gb
);
chunk
=
bytestream2_get_be32u
(
gb
)
&
HCA_MASK
;
if
(
chunk
==
MKBETAG
(
'c'
,
'o'
,
'm'
,
'p'
))
{
bytestream2_skipu
(
gb
,
2
);
bytestream2_skipu
(
gb
,
1
);
...
...
@@ -160,7 +252,7 @@ static int init_hca(AVCodecContext *avctx, const uint8_t *extradata,
return
AVERROR_INVALIDDATA
;
while
(
bytestream2_get_bytes_left
(
gb
)
>=
4
)
{
chunk
=
bytestream2_get_be32u
(
gb
);
chunk
=
bytestream2_get_be32u
(
gb
)
&
HCA_MASK
;
if
(
chunk
==
MKBETAG
(
'v'
,
'b'
,
'r'
,
0
))
{
bytestream2_skip
(
gb
,
2
+
2
);
}
else
if
(
chunk
==
MKBETAG
(
'a'
,
't'
,
'h'
,
0
))
{
...
...
@@ -170,7 +262,7 @@ static int init_hca(AVCodecContext *avctx, const uint8_t *extradata,
}
else
if
(
chunk
==
MKBETAG
(
'c'
,
'o'
,
'm'
,
'm'
))
{
bytestream2_skip
(
gb
,
bytestream2_get_byte
(
gb
)
*
8
);
}
else
if
(
chunk
==
MKBETAG
(
'c'
,
'i'
,
'p'
,
'h'
))
{
bytestream2_skip
(
gb
,
2
);
c
->
ciph_type
=
bytestream2_get_be16
(
gb
);
}
else
if
(
chunk
==
MKBETAG
(
'l'
,
'o'
,
'o'
,
'p'
))
{
bytestream2_skip
(
gb
,
4
+
4
+
2
+
2
);
}
else
if
(
chunk
==
MKBETAG
(
'p'
,
'a'
,
'd'
,
0
))
{
...
...
@@ -180,6 +272,14 @@ static int init_hca(AVCodecContext *avctx, const uint8_t *extradata,
}
}
if
(
bytestream2_get_bytes_left
(
gb
)
>=
10
)
{
bytestream2_skip
(
gb
,
bytestream2_get_bytes_left
(
gb
)
-
10
);
c
->
key
=
bytestream2_get_be64u
(
gb
);
c
->
subkey
=
bytestream2_get_be16u
(
gb
);
}
cipher_init
(
c
->
cipher
,
c
->
ciph_type
,
c
->
key
,
c
->
subkey
);
ret
=
ath_init
(
c
->
ath
,
c
->
ath_type
,
avctx
->
sample_rate
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -420,7 +520,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
return
AVERROR_INVALIDDATA
;
if
(
AV_RN16
(
avpkt
->
data
)
!=
0xFFFF
)
{
if
(
AV_RL32
(
avpkt
->
data
)
!=
MKTAG
(
'H'
,
'C'
,
'A'
,
0
))
{
if
(
(
AV_RL32
(
avpkt
->
data
)
)
!=
MKTAG
(
'H'
,
'C'
,
'A'
,
0
))
{
return
AVERROR_INVALIDDATA
;
}
else
if
(
AV_RB16
(
avpkt
->
data
+
6
)
<=
avpkt
->
size
)
{
ret
=
init_hca
(
avctx
,
avpkt
->
data
,
AV_RB16
(
avpkt
->
data
+
6
));
...
...
@@ -434,6 +534,16 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
}
}
if
(
c
->
key
||
c
->
subkey
)
{
uint8_t
*
data
,
*
cipher
=
c
->
cipher
;
if
((
ret
=
av_packet_make_writable
(
avpkt
))
<
0
)
return
ret
;
data
=
avpkt
->
data
;
for
(
int
n
=
0
;
n
<
avpkt
->
size
;
n
++
)
data
[
n
]
=
cipher
[
data
[
n
]];
}
if
(
avctx
->
err_recognition
&
AV_EF_CRCCHECK
)
{
if
(
av_crc
(
c
->
crc_table
,
0
,
avpkt
->
data
+
offset
,
avpkt
->
size
-
offset
))
return
AVERROR_INVALIDDATA
;
...
...
libavformat/hca.c
View file @
035d187c
...
...
@@ -19,18 +19,28 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/opt.h"
#include "libavutil/intreadwrite.h"
#include "libavcodec/bytestream.h"
#include "avformat.h"
#include "internal.h"
#define HCA_MASK 0x7f7f7f7f
typedef
struct
HCADemuxContext
{
AVClass
*
class
;
int64_t
keyl
;
int64_t
keyh
;
int
subkey
;
}
HCADemuxContext
;
static
int
hca_probe
(
const
AVProbeData
*
p
)
{
if
(
AV_RL32
(
p
->
buf
)
!=
MKTAG
(
'H'
,
'C'
,
'A'
,
0
))
if
(
(
AV_RL32
(
p
->
buf
)
&
HCA_MASK
)
!=
MKTAG
(
'H'
,
'C'
,
'A'
,
0
))
return
0
;
if
(
AV_RL32
(
p
->
buf
+
8
)
!=
MKTAG
(
'f'
,
'm'
,
't'
,
0
))
if
(
(
AV_RL32
(
p
->
buf
+
8
)
&
HCA_MASK
)
!=
MKTAG
(
'f'
,
'm'
,
't'
,
0
))
return
0
;
return
AVPROBE_SCORE_MAX
/
3
;
...
...
@@ -38,6 +48,7 @@ static int hca_probe(const AVProbeData *p)
static
int
hca_read_header
(
AVFormatContext
*
s
)
{
HCADemuxContext
*
hca
=
s
->
priv_data
;
AVCodecParameters
*
par
;
GetByteContext
gb
;
AVIOContext
*
pb
=
s
->
pb
;
...
...
@@ -60,20 +71,23 @@ static int hca_read_header(AVFormatContext *s)
return
AVERROR
(
ENOMEM
);
par
=
st
->
codecpar
;
ret
=
ff_alloc_extradata
(
par
,
data_offset
);
ret
=
ff_alloc_extradata
(
par
,
data_offset
+
10
);
if
(
ret
<
0
)
return
ret
;
ret
=
avio_read
(
pb
,
par
->
extradata
+
8
,
par
->
extradata_size
-
8
);
if
(
ret
<
par
->
extradata_size
-
8
)
ret
=
avio_read
(
pb
,
par
->
extradata
+
8
,
par
->
extradata_size
-
8
-
10
);
if
(
ret
<
par
->
extradata_size
-
8
-
10
)
return
AVERROR
(
EIO
);
AV_WL32
(
par
->
extradata
,
MKTAG
(
'H'
,
'C'
,
'A'
,
0
));
AV_WB16
(
par
->
extradata
+
4
,
version
);
AV_WB16
(
par
->
extradata
+
6
,
data_offset
);
AV_WB32
(
par
->
extradata
+
par
->
extradata_size
-
10
,
hca
->
keyh
);
AV_WB32
(
par
->
extradata
+
par
->
extradata_size
-
6
,
hca
->
keyl
);
AV_WB16
(
par
->
extradata
+
par
->
extradata_size
-
2
,
hca
->
subkey
);
bytestream2_init
(
&
gb
,
par
->
extradata
+
8
,
par
->
extradata_size
-
8
);
if
(
bytestream2_get_le32
(
&
gb
)
!=
MKTAG
(
'f'
,
'm'
,
't'
,
0
))
if
(
(
bytestream2_get_le32
(
&
gb
)
&
HCA_MASK
)
!=
MKTAG
(
'f'
,
'm'
,
't'
,
0
))
return
AVERROR_INVALIDDATA
;
par
->
codec_type
=
AVMEDIA_TYPE_AUDIO
;
...
...
@@ -83,7 +97,7 @@ static int hca_read_header(AVFormatContext *s)
par
->
sample_rate
=
bytestream2_get_be24
(
&
gb
);
block_count
=
bytestream2_get_be32
(
&
gb
);
bytestream2_skip
(
&
gb
,
4
);
chunk
=
bytestream2_get_le32
(
&
gb
);
chunk
=
bytestream2_get_le32
(
&
gb
)
&
HCA_MASK
;
if
(
chunk
==
MKTAG
(
'c'
,
'o'
,
'm'
,
'p'
))
{
block_size
=
bytestream2_get_be16
(
&
gb
);
}
else
if
(
chunk
==
MKTAG
(
'd'
,
'e'
,
'c'
,
0
))
{
...
...
@@ -113,9 +127,32 @@ static int hca_read_packet(AVFormatContext *s, AVPacket *pkt)
return
ret
;
}
#define OFFSET(x) offsetof(HCADemuxContext, x)
static
const
AVOption
hca_options
[]
=
{
{
"hca_lowkey"
,
"Low key used for handling CRI HCA files"
,
OFFSET
(
keyl
),
AV_OPT_TYPE_INT64
,
{.
i64
=
0
},
.
min
=
0
,
.
max
=
UINT32_MAX
,
.
flags
=
AV_OPT_FLAG_DECODING_PARAM
,
},
{
"hca_highkey"
,
"High key used for handling CRI HCA files"
,
OFFSET
(
keyh
),
AV_OPT_TYPE_INT64
,
{.
i64
=
0
},
.
min
=
0
,
.
max
=
UINT32_MAX
,
.
flags
=
AV_OPT_FLAG_DECODING_PARAM
,
},
{
"hca_subkey"
,
"Subkey used for handling CRI HCA files"
,
OFFSET
(
subkey
),
AV_OPT_TYPE_INT
,
{.
i64
=
0
},
.
min
=
0
,
.
max
=
UINT16_MAX
,
.
flags
=
AV_OPT_FLAG_DECODING_PARAM
},
{
NULL
},
};
static
const
AVClass
hca_class
=
{
.
class_name
=
"hca"
,
.
item_name
=
av_default_item_name
,
.
option
=
hca_options
,
.
version
=
LIBAVUTIL_VERSION_INT
,
};
const
AVInputFormat
ff_hca_demuxer
=
{
.
name
=
"hca"
,
.
long_name
=
NULL_IF_CONFIG_SMALL
(
"CRI HCA"
),
.
priv_class
=
&
hca_class
,
.
priv_data_size
=
sizeof
(
HCADemuxContext
),
.
read_probe
=
hca_probe
,
.
read_header
=
hca_read_header
,
.
read_packet
=
hca_read_packet
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment