Allow text keycode in adxkey/hcakey

This commit is contained in:
bnnm 2024-02-11 22:36:26 +01:00
parent 66c3c61bc6
commit e666ce61d8
6 changed files with 70 additions and 38 deletions

View File

@ -1945,10 +1945,9 @@ in detail in USAGE.md.
- artificial headers:
- .txth (text header, adds support to lots of extra formats)
- .genh (generic header, deprecated)
- loop assists:
- .txtm (text map config, for formats that open companion files manually)
- .txtp (text play config, per song segment/layer manipulation)
- .txtm (text map config, for formats that open companion files manually)
- .genh (generic header, deprecated)
- loop assists:
- .mus (playlist for .acm)
- .pos (loop info for .wav)
@ -1960,6 +1959,7 @@ in detail in USAGE.md.
- .hcakey (decryption key for .hca)
- .fsbkey (decryption key for .fsb)
- .bnsfkey (decryption key for .bnsf)
- .awckey (decryption key for .awc)
## Supported codecs

View File

@ -404,11 +404,11 @@ Regular formats without companion files should work fine in upper/lowercase. For
Certain formats have encrypted data, and need a key to decrypt. vgmstream
will try to find the correct key from a list, but it can be provided by
a companion file:
- `.adx`: `.adxkey` (keystring, 8-byte keycode, or derived 6 byte start/mult/add key)
- `.adx`: `.adxkey` (keystring, or 8-byte keycode, or derived 6 byte start/mult/add key)
- `.ahx`: `.ahxkey` (keystring, or derived 6-byte start/mult/add key)
- `.hca`: `.hcakey` (8-byte decryption key, a 64-bit number)
- `.awb`/`.acb` also may use `.hcakey`, and will combine with an internal AWB subkey
- May set a 8-byte key followed a 2-byte AWB subkey for newer HCA
- `.hca`: `.hcakey` (keystring, or 8-byte keycode, a 64-bit number)
- May set 8-byte key followed a 2-byte AWB subkey for newer HCA
- `.awb`/`.acb` also may use `.adxkey`/`.hcakey`, and will combine with an internal AWB subkey
- `.fsb`: `.fsbkey` (decryption key in hex, usually between 8-32 bytes)
- `.bnsf`: `.bnsfkey` (decryption key, a string up to 24 chars)
- `.awc`: `.awckey` (decryption key, 0x10 bytes divided into 4 BE ints)

View File

@ -17,7 +17,7 @@
#define ADX_KEY_MAX_TEST_FRAMES 32768
#define ADX_KEY_TEST_BUFFER_SIZE 0x8000
static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t* xor_start, uint16_t* xor_mult, uint16_t* xor_add, uint16_t subkey);
static bool find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t* xor_start, uint16_t* xor_mult, uint16_t* xor_add, uint16_t subkey);
VGMSTREAM* init_vgmstream_adx(STREAMFILE* sf) {
return init_vgmstream_adx_subkey(sf, 0);
@ -87,7 +87,6 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
/* encryption */
if (version == 0x0408) {
if (!find_adx_key(sf, 8, &xor_start, &xor_mult, &xor_add, 0)) {
vgm_logi("ADX: decryption keystring not found\n");
}
@ -265,7 +264,7 @@ fail:
/* ADX key detection works by reading XORed ADPCM scales in frames, and un-XORing with keys in
* a list. If resulting values are within the expected range for N scales we accept that key. */
static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add, uint16_t subkey) {
static bool find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add, uint16_t subkey) {
const int frame_size = 0x12;
uint16_t *scales = NULL;
uint16_t *prescales = NULL;
@ -280,7 +279,7 @@ static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint1
size_t key_size;
/* handle type8 keystrings, key9 keycodes and derived keys too */
key_size = read_key_file(keybuf, sizeof(keybuf), sf);
key_size = read_key_file(keybuf, sizeof(keybuf) - 1, sf);
if (key_size > 0) {
int is_keystring = 0;
@ -288,28 +287,37 @@ static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint1
if (type == 8) {
is_keystring = cri_key8_valid_keystring(keybuf, key_size);
}
else if (type == 9) {
is_keystring = cri_key9_valid_keystring(keybuf, key_size);
}
if (key_size == 0x06 && !is_keystring) {
*xor_start = get_u16be(keybuf + 0x00);
*xor_mult = get_u16be(keybuf + 0x02);
*xor_add = get_u16be(keybuf + 0x04);
return 1;
return true;
}
else if (type == 8 && is_keystring) {
const char* keystring = (const char*)keybuf;
cri_key8_derive(keystring, xor_start, xor_mult, xor_add);
return 1;
return true;
}
else if (type == 9 && is_keystring) {
const char* keystring = (const char*)keybuf;
uint64_t keycode = strtoull(keystring, NULL, 10);
cri_key9_derive(keycode, subkey, xor_start, xor_mult, xor_add);
return true;
}
else if (type == 9 && key_size == 0x08) {
uint64_t keycode = get_u64be(keybuf);
cri_key9_derive(keycode, subkey, xor_start, xor_mult, xor_add);
return 1;
return true;
}
else if (type == 9 && key_size == 0x08+0x02) {
uint64_t file_keycode = get_u64be(keybuf+0x00);
uint16_t file_subkey = get_u16be(keybuf+0x08);
cri_key9_derive(file_keycode, file_subkey, xor_start, xor_mult, xor_add);
return 1;
return true;
}
}
/* no key set or unknown format, try list */
@ -525,5 +533,5 @@ static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint1
done:
free(scales);
free(prescales);
return rc;
return rc != 0;
}

View File

@ -4,6 +4,7 @@
#include "../coding/hca_decoder_clhca.h"
#include "../util/channel_mappings.h"
#include "../util/companion_files.h"
#include "../util/cri_keys.h"
#ifdef VGM_DEBUG_OUTPUT
//#define HCA_BRUTEFORCE
@ -45,14 +46,21 @@ VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) {
/* find decryption key in external file or preloaded list */
if (hca_info->encryptionEnabled) {
uint64_t keycode = 0;
uint8_t keybuf[0x08+0x02];
size_t keysize;
uint8_t keybuf[20+1] = {0}; /* max keystring 20, +1 extra null */
size_t key_size;
keysize = read_key_file(keybuf, sizeof(keybuf), sf);
if (keysize == 0x08) { /* standard */
key_size = read_key_file(keybuf, sizeof(keybuf) - 1, sf);
bool is_keystring = cri_key9_valid_keystring(keybuf, key_size);
if (is_keystring) { /* number */
const char* keystring = (const char*)keybuf;
keycode = strtoull(keystring, NULL, 10);
}
else if (key_size == 0x08) { /* hex */
keycode = get_u64be(keybuf+0x00);
}
else if (keysize == 0x08+0x02) { /* seed key + AWB subkey */
else if (key_size == 0x08+0x02) { /* seed key + AWB subkey */
keycode = get_u64be(keybuf+0x00);
subkey = get_u16be(keybuf+0x08);
}

View File

@ -126,14 +126,28 @@ end:
*p_key3 = key3;
}
int cri_key8_valid_keystring(uint8_t* buf, int buf_size) {
int i;
bool cri_key8_valid_keystring(uint8_t* buf, int buf_size) {
if (buf_size <= 0)
return false;
for (i = 0; i < buf_size; i++) {
for (int i = 0; i < buf_size; i++) {
if (buf[i] < 0x20 || buf[i] > 0x8f) { /* allow 0x8x for (uncommon) cases of SHIFT-JIS */
return 0;
return false;
}
}
return 1;
return true;
}
bool cri_key9_valid_keystring(uint8_t* buf, int buf_size) {
if (buf_size <= 0 || buf_size > 20) /* max u64 */
return false;
for (int i = 0; i < buf_size; i++) {
if (buf[i] < 0x30 || buf[i] > 0x39) { /* numbers only */
return false;
}
}
return true;
}

View File

@ -2,12 +2,14 @@
#define _CRI_KEYS_H_
#include <stdint.h>
#include <stdbool.h>
/* common CRI key helpers */
void cri_key8_derive(const char* key8, uint16_t* p_key1, uint16_t* p_key2, uint16_t* p_key3);
void cri_key9_derive(uint64_t key9, uint16_t subkey, uint16_t* p_key1, uint16_t* p_key2, uint16_t* p_key3);
int cri_key8_valid_keystring(uint8_t* buf, int buf_size);
bool cri_key8_valid_keystring(uint8_t* buf, int buf_size);
bool cri_key9_valid_keystring(uint8_t* buf, int buf_size);
#endif /* _CRI_KEYS_H_ */