mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +01:00
Add AHX type 0x08 decryption, with .ahxkey files (16b*3, start/mult/add)
This commit is contained in:
parent
66219f6b37
commit
fadb999207
@ -3,6 +3,7 @@
|
||||
#ifdef VGM_USE_MPEG
|
||||
#define MPEG_AHX_EXPECTED_FRAME_SIZE 0x414
|
||||
|
||||
static int ahx_decrypt_type08(mpeg_codec_data *data);
|
||||
|
||||
/* writes data to the buffer and moves offsets, transforming AHX frames as needed */
|
||||
int mpeg_custom_parse_frame_ahx(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data) {
|
||||
@ -38,23 +39,25 @@ int mpeg_custom_parse_frame_ahx(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data)
|
||||
}
|
||||
|
||||
|
||||
/* read VBR frames with CBR header, 0-fill up to expected size to keep mpg123 happy */
|
||||
/* 0-fill up to expected size to keep mpg123 happy */
|
||||
data->bytes_in_buffer = read_streamfile(data->buffer,stream->offset,current_data_size,stream->streamfile);
|
||||
memset(data->buffer + data->bytes_in_buffer,0, MPEG_AHX_EXPECTED_FRAME_SIZE - data->bytes_in_buffer);
|
||||
data->bytes_in_buffer = MPEG_AHX_EXPECTED_FRAME_SIZE;
|
||||
|
||||
|
||||
/* encryption 0x08 modifies a few bits in the side_data every frame, here we decrypt the buffer */
|
||||
if (data->config.encryption) {
|
||||
VGM_LOG("MPEG AHX: unknown encryption\n");
|
||||
goto fail;
|
||||
/* decrypt if needed */
|
||||
switch(data->config.encryption) {
|
||||
case 0x00: break;
|
||||
case 0x08: ahx_decrypt_type08(data); break;
|
||||
default:
|
||||
VGM_LOG("MPEG AHX: unknown encryption 0x%x\n", data->config.encryption);
|
||||
break; /* garbled frame */
|
||||
}
|
||||
|
||||
|
||||
/* update offsets */
|
||||
stream->offset += current_data_size;
|
||||
if (stream->offset + 0x0c >= file_size)
|
||||
stream->offset = file_size; /* move after 0x0c footer to reach EOF (shouldn't happen normally) */
|
||||
stream->offset = file_size; /* skip 0x0c footer to reach EOF (shouldn't happen normally) */
|
||||
|
||||
|
||||
return 1;
|
||||
@ -62,5 +65,47 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Decrypts an AHX type 0x08 (keystring) encrypted frame. Algorithm by Thealexbarney */
|
||||
static int ahx_decrypt_type08(mpeg_codec_data *data) {
|
||||
int i, index, encrypted_bits;
|
||||
uint32_t value;
|
||||
uint16_t current_key;
|
||||
|
||||
/* encryption 0x08 modifies a few bits every frame, here we decrypt and write to data buffer */
|
||||
|
||||
/* derive keystring to 3 primes, using the type 0x08 method, and assign each an index of 1/2/3 (0=no key) */
|
||||
/* (externally done for now, see: https://github.com/Thealexbarney/VGAudio/blob/2.0/src/VGAudio/Codecs/CriAdx/CriAdxKey.cs) */
|
||||
|
||||
/* read 2b from a bitstream offset to decrypt, and use it as an index to get the key.
|
||||
* AHX encrypted bitstream starts at 107b (0x0d*8+3), every frame, and seem to always use index 2 */
|
||||
value = (uint32_t)get_32bitBE(data->buffer + 0x0d);
|
||||
index = (value >> (32-3-2)) & 0x03;
|
||||
switch(index) {
|
||||
case 0: current_key = 0; break;
|
||||
case 1: current_key = data->config.cri_key1; break;
|
||||
case 2: current_key = data->config.cri_key2; break;
|
||||
case 3: current_key = data->config.cri_key3; break;
|
||||
default: goto fail;
|
||||
}
|
||||
|
||||
/* AHX for DC: 16b, normal: 6b (no idea, probably some Layer II field) */
|
||||
encrypted_bits = data->config.cri_type == 0x10 ? 16 : 6;
|
||||
|
||||
/* decrypt next bitstream 2b pairs, up to 16b (max key size):
|
||||
* - read 2b from bitstream (from higher to lower)
|
||||
* - read 2b from key (from lower to higher)
|
||||
* - XOR them to decrypt */
|
||||
for (i = 0; i < encrypted_bits; i+=2) {
|
||||
uint32_t xor_2b = (current_key >> i) & 0x03;
|
||||
value ^= ((xor_2b << (32-3-2-2)) >> i);
|
||||
}
|
||||
|
||||
/* write output */
|
||||
put_32bitBE(data->buffer + 0x0d, value);
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,7 +6,7 @@
|
||||
VGMSTREAM * init_vgmstream_ahx(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int channel_count = 1, loop_flag = 0;
|
||||
int channel_count = 1, loop_flag = 0, type;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if ( !check_extensions(streamFile, "ahx") ) goto fail;
|
||||
@ -22,8 +22,8 @@ VGMSTREAM * init_vgmstream_ahx(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
|
||||
/* check for encoding type (0x10 is AHX for DC with bigger frames, 0x11 is AHX, 0x0N are ADX) */
|
||||
if (read_8bit(0x04,streamFile) != 0x10 &&
|
||||
read_8bit(0x04,streamFile) != 0x11) goto fail;
|
||||
type = read_8bit(0x04,streamFile);
|
||||
if (type != 0x10 && type != 0x11) goto fail;
|
||||
|
||||
/* check for frame size (0 for AHX) */
|
||||
if (read_8bit(0x05,streamFile) != 0) goto fail;
|
||||
@ -52,6 +52,16 @@ VGMSTREAM * init_vgmstream_ahx(STREAMFILE *streamFile) {
|
||||
|
||||
memset(&cfg, 0, sizeof(mpeg_custom_config));
|
||||
cfg.encryption = read_8bit(0x13,streamFile); /* 0x08 = keyword encryption */
|
||||
cfg.cri_type = type;
|
||||
|
||||
if (cfg.encryption) {
|
||||
uint8_t keybuf[6];
|
||||
if (read_key_file(keybuf, 6, streamFile)) {
|
||||
cfg.cri_key1 = get_16bitBE(keybuf+0);
|
||||
cfg.cri_key2 = get_16bitBE(keybuf+2);
|
||||
cfg.cri_key3 = get_16bitBE(keybuf+4);
|
||||
}
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, start_offset, &vgmstream->coding_type, channel_count, MPEG_AHX, &cfg);
|
||||
|
@ -873,6 +873,11 @@ typedef struct {
|
||||
int chunk_size; /* size of a data portion */
|
||||
int interleave; /* size of stream interleave */
|
||||
int encryption; /* encryption mode */
|
||||
/* for AHX */
|
||||
int cri_type;
|
||||
uint16_t cri_key1;
|
||||
uint16_t cri_key2;
|
||||
uint16_t cri_key3;
|
||||
} mpeg_custom_config;
|
||||
|
||||
/* represents a single MPEG stream */
|
||||
|
Loading…
Reference in New Issue
Block a user