Commit f670ae05 by Christopher Snowhill Committed by GitHub

Merge pull request #99 from Thealexbarney/adx-encryption

Fix ADX type 9 encryption
parents ba4e6d1f 730bc5c0
Showing with 61 additions and 78 deletions
......@@ -400,7 +400,7 @@ static const coding_info coding_info_list[] = {
{coding_CRI_ADX_exp, "CRI ADX 4-bit ADPCM with exponential scale"},
{coding_CRI_ADX_fixed, "CRI ADX 4-bit ADPCM with fixed coefficients"},
{coding_CRI_ADX_enc_8, "CRI ADX 4-bit ADPCM (type 8 encryption)"},
{coding_CRI_ADX_enc_9, "CRI ADX 4-bit ADPCM (type 8 encryption)"},
{coding_CRI_ADX_enc_9, "CRI ADX 4-bit ADPCM (type 9 encryption)"},
{coding_NGC_DSP, "Nintendo DSP 4-bit ADPCM"},
{coding_NGC_DTK, "Nintendo DTK 4-bit ADPCM"},
{coding_NGC_AFC, "Nintendo AFC 4-bit ADPCM"},
......
......@@ -240,8 +240,8 @@ static struct {
uint16_t start,mult,add;
} keys_8[] = {
/* Clover Studio (GOD HAND, Okami) */
/* I'm pretty sure this is right, based on a decrypted version of some GOD HAND tracks. */
/* Also it is the 2nd result from guessadx */
/* Verified by VGAudio and the game's executable */
/* Key string: karaage */
{0x49e1,0x4a57,0x553d},
/* Grasshopper Manufacture 0 (Blood+) */
......@@ -261,7 +261,8 @@ static struct {
{0x66f5,0x58bd,0x4459},
/* Sonic Team 0 (Phantasy Star Universe) */
/* this is estimated */
/* Verified by VGAudio and the game's executable */
/* Key string: 3x5k62bg9ptbwy */
{0x5deb,0x5f27,0x673f},
/* G.rev 0 (Senko no Ronde) */
......@@ -284,11 +285,13 @@ static struct {
{0x4d65,0x5eb7,0x5dfd},
/* Sonic Team 2 (Sonic and the Black Knight) */
/* confirmed unique with guessadx */
/* Verified by VGAudio and the game's executable */
/* Key string: morio */
{0x55b7,0x6191,0x5a77},
/* Enterbrain (Amagami) */
/* one of 32 from guessadx */
/* Verified by VGAudio and the game's executable */
/* Key string: mituba */
{0x5a17,0x509f,0x5bfd},
/* Yamasa (Yamasa Digi Portable: Matsuri no Tatsujin) */
......@@ -471,17 +474,25 @@ static struct {
{0x07d2,0x1ec5,0x0c7f},
/* Dragon Ball Z: Dokkan Battle
* guessed with degod */
* Verified by VGAudio
* Key code: 416383518 */
{0x0003,0x0d19,0x043b},
/* Kisou Ryouhei Gunhound EX (2013-01-31)(Dracue)[PSP]
* guessed with degod */
* Verified by VGAudio
* Key code: 683461999 */
{0x0005,0x0bcd,0x1add},
/* Raramagi [Android]
* found in 2ch */
* Verified by VGAudio
* Key code: 12160794 */
{0x0000,0x0b99,0x1e33},
/* Sonic runners [Android]
* Verified by VGAudio
* Key code: 19910623 */
{0x0000,0x12fd,0x1fbd},
};
static const int keys_8_count = sizeof(keys_8)/sizeof(keys_8[0]);
......@@ -548,6 +559,8 @@ static int find_key(STREAMFILE *file, uint8_t type, uint16_t *xor_start, uint16_
{
/* try to guess key */
#define MAX_FRAMES (INT_MAX/0x8000)
struct { uint16_t start, mult, add; } *keys = NULL;
int keycount = 0, keymask = 0;
int scales_to_do;
int key_id;
......@@ -582,82 +595,52 @@ static int find_key(STREAMFILE *file, uint8_t type, uint16_t *xor_start, uint16_
if (type == 8)
{
/* guess each of the keys */
for (key_id=0;key_id<keys_8_count;key_id++) {
/* test pre-scales */
uint16_t xor = keys_8[key_id].start;
uint16_t mult = keys_8[key_id].mult;
uint16_t add = keys_8[key_id].add;
int i;
for (i=0;i<bruteframe &&
((prescales[i]&0x6000)==(xor&0x6000) ||
prescales[i]==0);
i++) {
xor = xor * mult + add;
}
if (i == bruteframe)
{
/* test */
for (i=0;i<scales_to_do &&
(scales[i]&0x6000)==(xor&0x6000);i++) {
xor = xor * mult + add;
}
if (i == scales_to_do)
{
*xor_start = keys_8[key_id].start;
*xor_mult = keys_8[key_id].mult;
*xor_add = keys_8[key_id].add;
rc = 1;
goto find_key_cleanup;
}
}
}
keys = &keys_8;
keycount = keys_8_count;
keymask = 0x6000;
}
else if (type == 9)
{
/* smarter XOR as seen in PSO2, can't do an exact match so we
* have to search for the lowest */
long best_score = MAX_FRAMES * 0x1fff;
/* guess each of the keys */
for (key_id=0;key_id<keys_9_count;key_id++) {
/* run past pre-scales */
uint16_t xor = keys_9[key_id].start;
uint16_t mult = keys_9[key_id].mult;
uint16_t add = keys_9[key_id].add;
int i;
long total_score = 0;
for (i=0;i<bruteframe;i++) {
xor = xor * mult + add;
}
/* smarter XOR as seen in PSO2. The scale is technically 13 bits,
* but the maximum value assigned by the encoder is 0x1000.
* This is written to the ADX file as 0xFFF, leaving the high bit
* empty, which is used to validate a key */
keys = &keys_9;
keycount = keys_9_count;
keymask = 0x1000;
}
if (i == bruteframe)
{
/* test */
for (i=0;i<scales_to_do && total_score < best_score;i++) {
xor = xor * mult + add;
total_score += (scales[i]^xor)&0x1fff;
}
if (total_score < best_score)
{
*xor_start = keys_9[key_id].start;
*xor_mult = keys_9[key_id].mult;
*xor_add = keys_9[key_id].add;
best_score = total_score;
}
}
/* guess each of the keys */
for (key_id=0;key_id<keycount;key_id++) {
/* test pre-scales */
uint16_t xor = keys[key_id].start;
uint16_t mult = keys[key_id].mult;
uint16_t add = keys[key_id].add;
int i;
for (i=0;i<bruteframe &&
((prescales[i]&keymask)==(xor&keymask) ||
prescales[i]==0);
i++) {
xor = xor * mult + add;
}
/* arbitrarily decide if we have won? */
if (best_score < scales_to_do * 0x1000)
if (i == bruteframe)
{
rc = 1;
/* test */
for (i=0;i<scales_to_do &&
(scales[i]&keymask)==(xor&keymask);i++) {
xor = xor * mult + add;
}
if (i == scales_to_do)
{
*xor_start = keys[key_id].start;
*xor_mult = keys[key_id].mult;
*xor_add = keys[key_id].add;
rc = 1;
goto find_key_cleanup;
}
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment