mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-24 06:50:20 +01:00
Add AHX key auto-detection and fix decryption
This commit is contained in:
parent
d17aa39994
commit
514517b812
@ -473,6 +473,13 @@ typedef enum {
|
||||
MPEG_EAMP3 /* custom frame header + MPEG frame + PCM blocks */
|
||||
} mpeg_custom_t;
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
uint16_t key1;
|
||||
uint16_t key2;
|
||||
uint16_t key3;
|
||||
} crikey_t;
|
||||
|
||||
/* config for the above modes */
|
||||
typedef struct {
|
||||
int channels; /* max channels */
|
||||
@ -485,11 +492,7 @@ typedef struct {
|
||||
int encryption; /* encryption mode */
|
||||
int big_endian;
|
||||
int skip_samples;
|
||||
/* for AHX */
|
||||
int cri_type;
|
||||
uint16_t cri_key1;
|
||||
uint16_t cri_key2;
|
||||
uint16_t cri_key3;
|
||||
crikey_t crikey; /* for AHX */
|
||||
} mpeg_custom_config;
|
||||
|
||||
mpeg_codec_data* init_mpeg(STREAMFILE* sf, off_t start_offset, coding_t *coding_type, int channels);
|
||||
@ -504,6 +507,7 @@ long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data* data);
|
||||
|
||||
uint32_t mpeg_get_tag_size(STREAMFILE* sf, uint32_t offset, uint32_t header);
|
||||
int mpeg_get_frame_info(STREAMFILE* sf, off_t offset, mpeg_frame_info* info);
|
||||
int test_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey);
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -7,23 +7,40 @@
|
||||
|
||||
typedef struct {
|
||||
uint8_t* buf; /* buffer to read/write */
|
||||
size_t bufsize; /* max size of the buffer */
|
||||
uint32_t b_off; /* current offset in bits inside the buffer */
|
||||
size_t bufsize; /* max size */
|
||||
size_t b_max; /* max size in bits */
|
||||
uint32_t b_off; /* current offset in bits inside buffer */
|
||||
} bitstream_t;
|
||||
|
||||
/* convenience util */
|
||||
static void init_bitstream(bitstream_t* b, uint8_t* buf, size_t bufsize) {
|
||||
static inline void init_bitstream(bitstream_t* b, uint8_t* buf, size_t bufsize) {
|
||||
b->buf = buf;
|
||||
b->bufsize = bufsize;
|
||||
b->b_max = bufsize * 8;
|
||||
b->b_off = 0;
|
||||
}
|
||||
|
||||
static inline int bs_skip(bitstream_t* bs, uint32_t bits) {
|
||||
if (bs->b_off + bits > bs->b_max)
|
||||
goto fail;
|
||||
|
||||
bs->b_off += bits;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int bs_pos(bitstream_t* bs) {
|
||||
return bs->b_off;
|
||||
}
|
||||
|
||||
/* Read bits (max 32) from buf and update the bit offset. Order is BE (MSF). */
|
||||
static int rb_bits(bitstream_t* ib, uint32_t bits, uint32_t* value) {
|
||||
static inline int rb_bits(bitstream_t* ib, uint32_t bits, uint32_t* value) {
|
||||
uint32_t shift, pos, val;
|
||||
int i, bit_buf, bit_val;
|
||||
|
||||
if (bits > 32 || ib->b_off + bits > ib->bufsize * 8)
|
||||
if (bits > 32 || ib->b_off + bits > ib->b_max)
|
||||
goto fail;
|
||||
|
||||
pos = ib->b_off / 8; /* byte offset */
|
||||
@ -55,11 +72,11 @@ fail:
|
||||
|
||||
#ifndef BITSTREAM_READ_ONLY
|
||||
/* Write bits (max 32) to buf and update the bit offset. Order is BE (MSF). */
|
||||
static int wb_bits(bitstream_t* ob, uint32_t bits, uint32_t value) {
|
||||
static inline int wb_bits(bitstream_t* ob, uint32_t bits, uint32_t value) {
|
||||
uint32_t shift, pos;
|
||||
int i, bit_val, bit_buf;
|
||||
|
||||
if (bits > 32 || ob->b_off + bits > ob->bufsize * 8)
|
||||
if (bits > 32 || ob->b_off + bits > ob->b_max)
|
||||
goto fail;
|
||||
|
||||
pos = ob->b_off / 8; /* byte offset */
|
||||
|
@ -1,111 +1,221 @@
|
||||
#include "mpeg_decoder.h"
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
#include "mpeg_decoder.h"
|
||||
#include "mpeg_bitreader.h"
|
||||
#include "coding.h"
|
||||
|
||||
#define MPEG_AHX_EXPECTED_FRAME_SIZE 0x414
|
||||
|
||||
static int ahx_decrypt_type08(uint8_t * buffer, mpeg_custom_config *config);
|
||||
/* AHX is more or less VBR MP2 using a fixed header (0xFFF5E0C0) that sets frame size 0x414 (1ch, 160kbps, 22050Hz)
|
||||
* but are typically much shorter (ignores padding), output sample rate is also ignored.
|
||||
*
|
||||
* MPEG1 Layer II (MP2) bitstream format for reference:
|
||||
* - MPEG header, 32b
|
||||
* - 'bit allocation' indexes (MP2's config determines bands and table with bit size per band, in AHX's case 30 bands and total 107 bits)
|
||||
* - 16-bit CRC if set in header (never in AHX)
|
||||
* - scale factor selection info (SCFSI), 2b per band/channel (if band has bit alloc set)
|
||||
* - scale factors, bits depending on selection info (if band has bit alloc set)
|
||||
* - quantized samples, bits depending on bit alloc info
|
||||
* - padding (removed in AHX)
|
||||
*/
|
||||
|
||||
/* 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, int num_stream) {
|
||||
mpeg_custom_stream *ms = data->streams[num_stream];
|
||||
size_t current_data_size = 0;
|
||||
size_t file_size = get_streamfile_size(stream->streamfile);
|
||||
|
||||
/* AHX has a 0xFFF5E0C0 header with frame size 0x414 (160kbps, 22050Hz) but they actually are much shorter */
|
||||
#define AHX_BANDS 30
|
||||
#define AHX_GRANULES 12
|
||||
static const uint8_t AHX_BITALLOC_TABLE[32] = { 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
|
||||
static const uint8_t AHX_OFFSET_TABLE[5][16] = {
|
||||
{ 0 },
|
||||
{ 0 },
|
||||
{ 0, 1, 3, 4, },
|
||||
{ 0, 1, 3, 4, 5, 6, 7, 8, },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }
|
||||
};
|
||||
static const int8_t AHX_QBITS_TABLE[17] = { -5, -7, 3, -10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
|
||||
|
||||
/* read supposed frame size first (to minimize reads) */
|
||||
ms->bytes_in_buffer = read_streamfile(ms->buffer, stream->offset, MPEG_AHX_EXPECTED_FRAME_SIZE, stream->streamfile);
|
||||
/* Decrypts and tests a AHX frame with current by reading all bits, as wrong keys should go over size. Reverse engineered
|
||||
* from CRI libs. (MPEG1 Layer II code abridged for AHX, which is always mono and has fixed bands/tables, some info from ahx2wav.c) */
|
||||
static int ahx_decrypt(uint8_t* buf, int curr_size, crikey_t* crikey) {
|
||||
uint32_t bit_alloc[AHX_BANDS] = {0};
|
||||
uint32_t scfsi[AHX_BANDS] = {0};
|
||||
bitstream_t ib = {0};
|
||||
bitstream_t ob = {0};
|
||||
|
||||
/* find actual frame size by looking for the next frame header */
|
||||
{
|
||||
uint32_t current_header = get_u32be(ms->buffer);
|
||||
int next_pos = 0x04;
|
||||
init_bitstream(&ib, buf, curr_size); /* frame */
|
||||
init_bitstream(&ob, buf, curr_size); /* decrypted frame */
|
||||
|
||||
while (next_pos <= MPEG_AHX_EXPECTED_FRAME_SIZE) {
|
||||
uint32_t next_header = get_u32be(ms->buffer + next_pos);
|
||||
/* MPEG header (fixed in AHX, otherwise layer/bitrate/channels sets bands+tables) */
|
||||
bs_skip(&ib, 32);
|
||||
bs_skip(&ob, 32);
|
||||
|
||||
if (current_header == next_header) {
|
||||
current_data_size = next_pos;
|
||||
break;
|
||||
}
|
||||
/* read bit allocs for later */
|
||||
for (int i = 0; i < AHX_BANDS; i++) {
|
||||
int ba_bits = AHX_BITALLOC_TABLE[i];
|
||||
|
||||
/* AHXs end in a 0x0c footer (0x41485845 28632943 52490000 / "AHXE(c)CRI\0\0") */
|
||||
if (stream->offset + next_pos + 0x0c >= file_size) {
|
||||
current_data_size = next_pos;
|
||||
break;
|
||||
}
|
||||
rb_bits(&ib, ba_bits, &bit_alloc[i]);
|
||||
bs_skip(&ob, ba_bits);
|
||||
}
|
||||
|
||||
next_pos++;
|
||||
/* get first scalefactor info to decide key */
|
||||
if (bit_alloc[0]) {
|
||||
rb_bits(&ib, 2, &scfsi[0]);
|
||||
bs_skip(&ob, 2);
|
||||
}
|
||||
|
||||
uint16_t key;
|
||||
switch(scfsi[0]) {
|
||||
case 1: key = crikey->key1; break;
|
||||
case 2: key = crikey->key2; break;
|
||||
case 3: key = crikey->key3; break;
|
||||
default: key = 0; /* 0: no key (common in null frames) */
|
||||
}
|
||||
|
||||
/* decrypt rest of scalefactors (only first ones are encrypted though) */
|
||||
for (int i = 1; i < AHX_BANDS; i++) {
|
||||
if (bit_alloc[i]) {
|
||||
rb_bits(&ib, 2, &scfsi[i]);
|
||||
scfsi[i] ^= (key & 3);
|
||||
wb_bits(&ob, 2, scfsi[i]);
|
||||
}
|
||||
key >>= 2;
|
||||
}
|
||||
|
||||
/* read scalefactors (past this point no need to decrypt/write frame) */
|
||||
for (int i = 0; i < AHX_BANDS; i++) {
|
||||
if (bit_alloc[i] == 0)
|
||||
continue;
|
||||
|
||||
switch(scfsi[i]) {
|
||||
case 0: bs_skip(&ib, 6 * 3); break;
|
||||
case 1:
|
||||
case 3: bs_skip(&ib, 6 * 2); break;
|
||||
case 2: bs_skip(&ib, 6 * 1); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_data_size == 0 || current_data_size > ms->buffer_size || current_data_size > MPEG_AHX_EXPECTED_FRAME_SIZE) {
|
||||
VGM_LOG("MPEG AHX: incorrect data_size 0x%x\n", current_data_size);
|
||||
/* read quants */
|
||||
for (int gr = 0; gr < AHX_GRANULES; gr++) {
|
||||
for (int i = 0; i < AHX_BANDS; i++) {
|
||||
int ba_value = bit_alloc[i];
|
||||
if (ba_value == 0)
|
||||
continue;
|
||||
|
||||
int ba_bits = AHX_BITALLOC_TABLE[i];
|
||||
int qb_index = AHX_OFFSET_TABLE[ba_bits][ba_value - 1];
|
||||
int qbits = AHX_QBITS_TABLE[qb_index];
|
||||
|
||||
if (qbits < 0)
|
||||
qbits = -qbits;
|
||||
else
|
||||
qbits = qbits * 3; /* 3 qs */
|
||||
|
||||
int ok = bs_skip(&ib, qbits);
|
||||
if (!ok) goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* read padding */
|
||||
{
|
||||
int bpos = bs_pos(&ib);
|
||||
if (bpos % 8) {
|
||||
bs_skip(&ib, 8 - (bpos % 8));
|
||||
}
|
||||
}
|
||||
|
||||
/* if file was properly read/decrypted this size should land in next frame header or near EOF */
|
||||
return bs_pos(&ib) / 8;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* 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, int num_stream) {
|
||||
mpeg_custom_stream *ms = data->streams[num_stream];
|
||||
size_t curr_size = 0;
|
||||
size_t file_size = get_streamfile_size(stream->streamfile);
|
||||
|
||||
|
||||
/* Find actual frame size by looking for the next frame header. Not very elegant but simpler, works with encrypted AHX,
|
||||
* and possibly faster than reading frame size's bits with ahx_decrypt */
|
||||
{
|
||||
ms->bytes_in_buffer = read_streamfile(ms->buffer, stream->offset, MPEG_AHX_EXPECTED_FRAME_SIZE + 0x04, stream->streamfile);
|
||||
|
||||
uint32_t curr_header = get_u32be(ms->buffer);
|
||||
int pos = 0x04;
|
||||
while (pos <= MPEG_AHX_EXPECTED_FRAME_SIZE) {
|
||||
|
||||
/* next sync test */
|
||||
if (ms->buffer[pos] == 0xFF) {
|
||||
uint32_t next_header = get_u32be(ms->buffer + pos);
|
||||
if (curr_header == next_header) {
|
||||
curr_size = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* AHX footer (0x8001000C 41485845 28632943 52490000 = 0x8001 tag + size + "AHXE(c)CRI\0\0") */
|
||||
if (stream->offset + pos + 0x10 >= file_size) {
|
||||
curr_size = pos;
|
||||
break;
|
||||
}
|
||||
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_size == 0 || curr_size > ms->buffer_size || curr_size > MPEG_AHX_EXPECTED_FRAME_SIZE) {
|
||||
VGM_LOG("MPEG AHX: incorrect data_size 0x%x\n", curr_size);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* 0-fill up to expected size to keep mpg123 happy */
|
||||
memset(ms->buffer + current_data_size, 0, MPEG_AHX_EXPECTED_FRAME_SIZE - current_data_size);
|
||||
memset(ms->buffer + curr_size, 0, MPEG_AHX_EXPECTED_FRAME_SIZE - curr_size);
|
||||
ms->bytes_in_buffer = MPEG_AHX_EXPECTED_FRAME_SIZE;
|
||||
|
||||
|
||||
/* decrypt if needed */
|
||||
switch(data->config.encryption) {
|
||||
case 0x00: break;
|
||||
case 0x08: ahx_decrypt_type08(ms->buffer, &data->config); break;
|
||||
default:
|
||||
VGM_LOG("MPEG AHX: unknown encryption 0x%x\n", data->config.encryption);
|
||||
break; /* garbled frame */
|
||||
/* decrypt if needed (only 0x08 is known but 0x09 is probably the same) */
|
||||
if (data->config.encryption == 0x08) {
|
||||
ahx_decrypt(ms->buffer, curr_size, &data->config.crikey);
|
||||
}
|
||||
|
||||
/* update offsets */
|
||||
stream->offset += current_data_size;
|
||||
if (stream->offset + 0x0c >= file_size)
|
||||
stream->offset = file_size; /* skip 0x0c footer to reach EOF (shouldn't happen normally) */
|
||||
stream->offset += curr_size;
|
||||
if (stream->offset + 0x10 >= file_size)
|
||||
stream->offset = file_size; /* skip footer to reach EOF (shouldn't happen normally) */
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Decrypts an AHX type 0x08 (keystring) encrypted frame. Algorithm by Thealexbarney */
|
||||
static int ahx_decrypt_type08(uint8_t * buffer, mpeg_custom_config *config) {
|
||||
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 */
|
||||
#define AHX_KEY_BUFFER 0x2000
|
||||
#define AHX_KEY_TEST_FRAMES 15 /* wrong keys may work ok in some frames */
|
||||
|
||||
/* 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) */
|
||||
/* check if current key ends properly in frame syncs */
|
||||
int test_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey) {
|
||||
int bytes;
|
||||
uint8_t buf[AHX_KEY_BUFFER];
|
||||
const int buf_size = sizeof(buf);
|
||||
int pos = 0;
|
||||
uint32_t base_sync, curr_sync;
|
||||
|
||||
/* 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 = get_u32be(buffer + 0x0d);
|
||||
index = (value >> (32-3-2)) & 0x03;
|
||||
switch(index) {
|
||||
case 0: current_key = 0; break;
|
||||
case 1: current_key = config->cri_key1; break;
|
||||
case 2: current_key = config->cri_key2; break;
|
||||
case 3: current_key = config->cri_key3; break;
|
||||
default: goto fail;
|
||||
bytes = read_streamfile(buf, offset, buf_size, sf);
|
||||
//if (bytes != buf_size) goto fail; /* possible in small AHX */
|
||||
|
||||
base_sync = get_u32be(buf + 0x00);
|
||||
for (int i = 0; i < AHX_KEY_TEST_FRAMES; i++) {
|
||||
|
||||
int size = ahx_decrypt(buf + pos, bytes, crikey);
|
||||
if (size <= 0 || size >= bytes - 0x04) goto fail;
|
||||
|
||||
bytes -= size;
|
||||
pos += size;
|
||||
|
||||
curr_sync = get_u32be(buf + pos);
|
||||
if (base_sync != curr_sync)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* AHX for DC: 16b, normal: 6b (no idea, probably some Layer II field) */
|
||||
encrypted_bits = 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(buffer + 0x0d, value);
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
|
123
src/meta/ahx.c
123
src/meta/ahx.c
@ -1,10 +1,13 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util.h"
|
||||
#if 0
|
||||
#include "adx_keys.h"
|
||||
#include "ahx_keys.h"
|
||||
#include "../util/cri_keys.h"
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
static int find_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey);
|
||||
#endif
|
||||
|
||||
|
||||
/* AHX - CRI voice format */
|
||||
VGMSTREAM* init_vgmstream_ahx(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
@ -23,7 +26,7 @@ VGMSTREAM* init_vgmstream_ahx(STREAMFILE* sf) {
|
||||
read_u32be(start_offset - 0x04,sf) != 0x29435249) /* ")CRI" */
|
||||
goto fail;
|
||||
|
||||
/* types: 0x10 = AHX for DC with bigger frames, 0x11 = AHX, 0x0N = ADX */
|
||||
/* types: 0x10 = AHX for DC with fixed MPEG frame bits (bigger frames), 0x11 = standard AHX, 0x0N = ADX */
|
||||
type = read_u8(0x04,sf);
|
||||
if (type != 0x10 && type != 0x11) goto fail;
|
||||
|
||||
@ -52,40 +55,13 @@ VGMSTREAM* init_vgmstream_ahx(STREAMFILE* sf) {
|
||||
{
|
||||
#ifdef VGM_USE_MPEG
|
||||
mpeg_custom_config cfg = {0};
|
||||
crikey_t* crikey = &cfg.crikey;
|
||||
|
||||
cfg.encryption = read_u8(0x13,sf); /* 0x08 = keyword encryption */
|
||||
cfg.cri_type = type;
|
||||
cfg.encryption = read_u8(0x13,sf); /* only type 0x08 is known */
|
||||
crikey->type = cfg.encryption;
|
||||
|
||||
if (cfg.encryption) {
|
||||
uint8_t keybuf[0x10+1] = {0}; /* approximate max for keystrings, +1 extra null for keystrings */
|
||||
size_t key_size;
|
||||
|
||||
key_size = read_key_file(keybuf, sizeof(keybuf), sf);
|
||||
if (key_size > 0) {
|
||||
#if 0
|
||||
int i, is_ascii;
|
||||
is_ascii = 1;
|
||||
for (i = 0; i < key_size; i++) {
|
||||
if (keybuf[i] < 0x20 || keybuf[i] > 0x7f) {
|
||||
is_ascii = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (key_size == 0x06 /*&& !is_ascii*/) {
|
||||
cfg.cri_key1 = get_u16be(keybuf + 0x00);
|
||||
cfg.cri_key2 = get_u16be(keybuf + 0x02);
|
||||
cfg.cri_key3 = get_u16be(keybuf + 0x04);
|
||||
}
|
||||
#if 0
|
||||
else if (is_ascii) {
|
||||
const char* keystring = (const char*)keybuf;
|
||||
|
||||
derive_adx_key8(keystring, &cfg.cri_key1, &cfg.cri_key2, &cfg.cri_key3);
|
||||
VGM_LOG("ok: %x, %x, %x\n", cfg.cri_key1, cfg.cri_key2, cfg.cri_key3 );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
find_ahx_key(sf, start_offset, crikey);
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -104,3 +80,80 @@ fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
static int find_ahx_keyfile(STREAMFILE* sf, crikey_t* crikey) {
|
||||
uint8_t keybuf[0x10+1] = {0}; /* approximate max for keystrings, +1 extra null for keystrings */
|
||||
size_t key_size;
|
||||
int is_keystring = 0;
|
||||
|
||||
key_size = read_key_file(keybuf, sizeof(keybuf) - 1, sf);
|
||||
if (key_size <= 0)
|
||||
goto fail;
|
||||
|
||||
|
||||
if (crikey->type == 8) {
|
||||
is_keystring = cri_key8_valid_keystring(keybuf, key_size);
|
||||
}
|
||||
|
||||
if (key_size == 0x06 && !is_keystring) {
|
||||
crikey->key1 = get_u16be(keybuf + 0x00);
|
||||
crikey->key2 = get_u16be(keybuf + 0x02);
|
||||
crikey->key3 = get_u16be(keybuf + 0x04);
|
||||
}
|
||||
else if (crikey->type == 8 && is_keystring) {
|
||||
const char* keystring = (const char*)keybuf;
|
||||
cri_key8_derive(keystring, &crikey->key1, &crikey->key2, &crikey->key3);
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_ahx_keylist(STREAMFILE* sf, off_t offset, crikey_t* crikey) {
|
||||
int i;
|
||||
int keycount = ahxkey8_list_count;
|
||||
const ahxkey_info* keys = ahxkey8_list;
|
||||
|
||||
|
||||
for (i = 0; i < keycount; i++) {
|
||||
if (crikey->type == 0x08) {
|
||||
cri_key8_derive(keys[i].key8, &crikey->key1, &crikey->key2, &crikey->key3);
|
||||
//;VGM_LOG("AHX: testing %s [%04x %04x %04x]\n", keys[i].key8, crikey->key1, crikey->key2, crikey->key3);
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (test_ahx_key(sf, offset, crikey)) {
|
||||
//;VGM_LOG("AHX key found\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey) {
|
||||
int ok;
|
||||
|
||||
ok = find_ahx_keyfile(sf, crikey);
|
||||
if (ok)
|
||||
return 1;
|
||||
|
||||
ok = find_ahx_keylist(sf, offset, crikey);
|
||||
if (ok)
|
||||
return 1;
|
||||
|
||||
|
||||
crikey->key1 = 0;
|
||||
crikey->key2 = 0;
|
||||
crikey->key3 = 0;
|
||||
vgm_logi("AHX: decryption key not found\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user