Merge pull request #557 from bnnm/s14

s14
This commit is contained in:
bnnm 2020-02-09 10:19:50 +01:00 committed by GitHub
commit b1bc14d033
14 changed files with 722 additions and 137 deletions

View File

@ -220,6 +220,7 @@ a companion file:
- .hca: .hcakey (8 byte decryption key, a 64-bit number) - .hca: .hcakey (8 byte decryption key, a 64-bit number)
- May be followed by 2 byte AWB scramble key for newer HCA - May be followed by 2 byte AWB scramble key for newer HCA
- .fsb: .fsbkey (decryption key, in hex) - .fsb: .fsbkey (decryption key, in hex)
- .bnsf: .bnsfkey (decryption key, a string up to 24 chars)
The key file can be ".(ext)key" (for the whole folder), or "(name).(ext)key" The key file can be ".(ext)key" (for the whole folder), or "(name).(ext)key"
(for a single file). The format is made up to suit vgmstream. (for a single file). The format is made up to suit vgmstream.
@ -286,6 +287,9 @@ can reduce the number of channels to a playable amount. Note that this type
of downmixing is very generic, not meant to be used when converting to other of downmixing is very generic, not meant to be used when converting to other
formats. formats.
You can also choose which channels to play using *TXTP*. For example, create
a file named `song.adx#C1,2.txtp` to play only channels 1 and 2 from `song.adx`.
## Tagging ## Tagging
Some of vgmstream's plugins support simple read-only tagging via external files. Some of vgmstream's plugins support simple read-only tagging via external files.
@ -702,10 +706,11 @@ This list is not complete and many other files are supported.
- .sfl (loop info for .ogg) - .sfl (loop info for .ogg)
- .vgmstream + .vgmstream.pos (FFmpeg formats + loop assist) - .vgmstream + .vgmstream.pos (FFmpeg formats + loop assist)
- other: - other:
- .adxkey (decryption key for .adx, in start/mult/add format) - .adxkey (decryption key for .adx)
- .ahxkey (decryption key for .ahx, in start/mult/add format) - .ahxkey (decryption key for .ahx)
- .hcakey (decryption key for .hca, in HCA Decoder format) - .hcakey (decryption key for .hca)
- .fsbkey (decryption key for .fsb, in hex) - .fsbkey (decryption key for .fsb)
- .bnsfkey (decryption key for .bnsf)
- .txtp (per song segment/layer handler and player configurator) - .txtp (per song segment/layer handler and player configurator)
Enjoy! *hcs* Enjoy! *hcs*

View File

@ -260,9 +260,11 @@ long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data *data);
#ifdef VGM_USE_G7221 #ifdef VGM_USE_G7221
/* g7221_decoder */ /* g7221_decoder */
g7221_codec_data* init_g7221(int channel_count, int frame_size); g7221_codec_data* init_g7221(int channel_count, int frame_size);
void decode_g7221(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel); void decode_g7221(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t samples_to_do, int channel);
void reset_g7221(VGMSTREAM *vgmstream); void reset_g7221(g7221_codec_data* data);
void free_g7221(VGMSTREAM *vgmstream); void free_g7221(g7221_codec_data* data);
void set_key_g7221(g7221_codec_data* data, const uint8_t* key);
int test_key_g7221(g7221_codec_data* data, off_t start, STREAMFILE* sf);
#endif #endif
#ifdef VGM_USE_G719 #ifdef VGM_USE_G719

View File

@ -2,54 +2,59 @@
#include "g7221_decoder_lib.h" #include "g7221_decoder_lib.h"
#ifdef VGM_USE_G7221 #ifdef VGM_USE_G7221
#define G7221_MAX_FRAME_SIZE 0x78 /* max frame 0x78 uint8s = 960/8 */ #define G7221_MAX_FRAME_SIZE 0x78 /* 960/8 */
#define G7221_MAX_FRAME_SAMPLES 640 /* 32000/50 */
struct g7221_codec_data { struct g7221_codec_data {
sample_t buffer[640]; int channels;
int frame_size;
struct g7221_channel_data {
sample_t buffer[G7221_MAX_FRAME_SAMPLES];
g7221_handle* handle; g7221_handle* handle;
} *ch;
}; };
g7221_codec_data* init_g7221(int channel_count, int frame_size) { g7221_codec_data* init_g7221(int channels, int frame_size) {
int i; int i;
g7221_codec_data* data = NULL; g7221_codec_data* data = NULL;
if (frame_size > G7221_MAX_FRAME_SIZE) if (frame_size > G7221_MAX_FRAME_SIZE)
goto fail; goto fail;
data = calloc(channel_count, sizeof(g7221_codec_data)); /* one decoder per channel */ data = calloc(1, sizeof(g7221_codec_data));
if (!data) goto fail; if (!data) goto fail;
for (i = 0; i < channel_count; i++) { data->channels = channels;
data[i].handle = g7221_init(frame_size, 14000); /* Siren 14 == 14khz bandwidth */ data->frame_size = frame_size;
if (!data[i].handle) goto fail;
data->ch = calloc(channels, sizeof(struct g7221_channel_data));
if (!data->ch) goto fail;
for (i = 0; i < data->channels; i++) {
data->ch[i].handle = g7221_init(frame_size);
if (!data->ch[i].handle) goto fail;
} }
return data; return data;
fail: fail:
if (data) { free_g7221(data);
for (i = 0; i < channel_count; i++) {
g7221_free(data[i].handle);
}
}
free(data);
return NULL; return NULL;
} }
void decode_g7221(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) { void decode_g7221(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t samples_to_do, int channel) {
VGMSTREAMCHANNEL* ch = &vgmstream->ch[channel]; VGMSTREAMCHANNEL* ch = &vgmstream->ch[channel];
g7221_codec_data* data = vgmstream->codec_data; g7221_codec_data* data = vgmstream->codec_data;
g7221_codec_data *ch_data = &data[channel]; struct g7221_channel_data* ch_data = &data->ch[channel];
int i; int i;
if (0 == vgmstream->samples_into_block) { if (0 == vgmstream->samples_into_block) {
uint8_t buf[G7221_MAX_FRAME_SIZE]; uint8_t buf[G7221_MAX_FRAME_SIZE];
size_t bytes; size_t bytes;
size_t read = vgmstream->interleave_block_size; size_t read = data->frame_size;
bytes = vgmstream->ch[channel].streamfile->read(ch->streamfile, buf, ch->offset, read); bytes = read_streamfile(buf, ch->offset, read, ch->streamfile);
if (bytes != read) { if (bytes != read) {
//g7221_decode_empty(ch_data->handle, ch_data->buffer); //g7221_decode_empty(ch_data->handle, ch_data->buffer);
memset(ch_data->buffer, 0, sizeof(ch_data->buffer)); memset(ch_data->buffer, 0, sizeof(ch_data->buffer));
@ -66,25 +71,89 @@ void decode_g7221(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, in
} }
void reset_g7221(VGMSTREAM *vgmstream) { void reset_g7221(g7221_codec_data* data) {
g7221_codec_data *data = vgmstream->codec_data;
int i; int i;
if (!data) return; if (!data) return;
for (i = 0; i < vgmstream->channels; i++) { for (i = 0; i < data->channels; i++) {
g7221_reset(data[i].handle); g7221_reset(data->ch[i].handle);
} }
} }
void free_g7221(VGMSTREAM *vgmstream) { void free_g7221(g7221_codec_data* data) {
g7221_codec_data *data = (g7221_codec_data *) vgmstream->codec_data;
int i; int i;
if (!data) return; if (!data) return;
for (i = 0; i < vgmstream->channels; i++) { for (i = 0; i < data->channels; i++) {
g7221_free(data[i].handle); g7221_free(data->ch[i].handle);
} }
free(data->ch);
free(data); free(data);
} }
void set_key_g7221(g7221_codec_data* data, const uint8_t* key) {
int i;
if (!data) return;
for (i = 0; i < data->channels; i++) {
g7221_set_key(data->ch[i].handle, key);
}
}
/* just in case but very few should be enough */
#define S14_KEY_MIN_TEST_FRAMES 3
#define S14_KEY_MAX_TEST_FRAMES 5
/* Test a number of frames to check if current key decrypts correctly.
* Returns score: <0: error/wrong, 0: unknown/silent, >0: good (closer to 1 is better). */
int test_key_g7221(g7221_codec_data* data, off_t start, STREAMFILE* sf) {
size_t test_frames = 0, current_frame = 0;
int total_score = 0;
int max_frames = (get_streamfile_size(sf) - start) / data->frame_size;
int cur_ch = 0;
/* assumes key was set before this call */
while (test_frames < S14_KEY_MAX_TEST_FRAMES && current_frame < max_frames) {
int score, ok;
size_t bytes;
uint8_t buf[G7221_MAX_FRAME_SIZE];
bytes = read_streamfile(buf, start, data->frame_size, sf);
if (bytes != data->frame_size) {
total_score = -1;
break;
}
ok = g7221_decode_frame(data->ch[cur_ch].handle, buf, data->ch[cur_ch].buffer);
if (!ok) {
total_score = -1;
break;
}
/* alternate channels (decode may affect scores otherwise) */
cur_ch = (cur_ch + 1) % data->channels;
/* good key if it decodes without error, encryption is easily detectable */
score = 1;
test_frames++;
total_score += score;
start += data->frame_size;
}
/* signal best possible score (many perfect frames and few blank frames) */
if (test_frames > S14_KEY_MIN_TEST_FRAMES && total_score > 0 && total_score <= test_frames) {
total_score = 1;
}
/* clean up decoders */
reset_g7221(data);
return total_score;
}
#endif #endif

View File

@ -0,0 +1,326 @@
#include <stdlib.h>
#include "g7221_decoder_aes.h"
/* Namco's NUS AES is just standard AES-192 in ECB mode, so this can be swapped with another lib,
* if more code needs AES. Most implementations out there either use pre-calculated look-up tables,
* or calculate manually every AES op. Namco's code calculates tables first in a slightly different
* layout, so it may be interesting as a sort of doc piece. */
struct s14aes_handle {
/* substitution box look-up table and the inverse */
uint8_t sbox[256];
uint8_t ibox[256];
/* helper for various tables, not too sure about it */
uint8_t xors[256];
/* round constant, though only sets up to 8 */
uint8_t rcon[16];
/* MixColumn(?) LUTs, unlike normal Rijndael which uses 4 tables: Td0a Td0b..., Td1a Td1b..., ...
* layout is: Td0a Td1a Td2a Td3a, Td0b Td0b Td1b Td2b, ... (better for CPU cache?) */
uint32_t tds[256*4];
/* expanded roundkey, actual final key */
uint32_t rk[52];
} ;
#define GET_U32LE(p) (((p)[0] << 0 ) | ((p)[1] << 8 ) | ((p)[2] << 16) | ((p)[3] << 24))
#define GET_U32BE(p) (((p)[3] << 0 ) | ((p)[2] << 8 ) | ((p)[1] << 16) | ((p)[0] << 24))
#define GET_B0(x) (((x) >> 0 ) & 0xFF)
#define GET_B1(x) (((x) >> 8 ) & 0xFF)
#define GET_B2(x) (((x) >> 16) & 0xFF)
#define GET_B3(x) (((x) >> 24) & 0xFF)
static void aes_key_expand(s14aes_handle* ctx, const uint8_t* key, uint32_t* rk) {
int i;
rk[0] = GET_U32LE(key + 0);
rk[1] = GET_U32LE(key + 4);
rk[2] = GET_U32LE(key + 8);
rk[3] = GET_U32LE(key + 12);
rk[4] = GET_U32LE(key + 16);
rk[5] = GET_U32LE(key + 20);
for (i = 6; i < 52; i++) {
uint8_t temp0 = (rk[5] >> 0 ) & 0xFF;
uint8_t temp1 = (rk[5] >> 8 ) & 0xFF;
uint8_t temp2 = (rk[5] >> 16) & 0xFF;
uint8_t temp3 = (rk[5] >> 24) & 0xFF;
if (i == 6 * (i / 6)) {
uint8_t sv = ctx->sbox[temp1];
temp1 = ctx->sbox[temp2];
temp2 = ctx->sbox[temp3];
temp3 = ctx->sbox[temp0];
temp0 = ctx->rcon[i / 6u - 1] ^ sv;
}
rk[6] = ((temp0 ^ ((rk[0] >> 0 ) & 0xFF)) << 0 ) |
((temp1 ^ ((rk[0] >> 8 ) & 0xFF)) << 8 ) |
((temp2 ^ ((rk[0] >> 16) & 0xFF)) << 16) |
((temp3 ^ ((rk[0] >> 24) & 0xFF)) << 24);
rk++;
}
}
static void aes_init_key(s14aes_handle* ctx, const uint8_t* key) {
const uint8_t invcols[4][4] = {
{0x0E,0x0B,0x0D,0x09},
{0x09,0x0E,0x0B,0x0D},
{0x0D,0x09,0x0E,0x0B},
{0x0B,0x0D,0x09,0x0E}
};
unsigned int roundkey[52];
int i, j, row, col, b;
aes_key_expand(ctx, key, roundkey);
for (i = 0; i < 4; i++) {
ctx->rk[i] = ((roundkey[i] << 24) & 0xFF000000) |
((roundkey[i] << 8 ) & 0x00FF0000) |
((roundkey[i] >> 8 ) & 0x0000FF00) |
((roundkey[i] >> 24) & 0x000000FF);
}
for (i = 4; i < 48; i += 4) {
for (j = i; j < i + 4; j++) {
uint32_t val = 0;
for (row = 0; row < 4; row++) {
uint8_t xv = 0;
for (col = 0; col < 4; col++) {
uint16_t rv1 = 0;
uint16_t rv2 = (roundkey[j] >> (col * 8)) & 0xFF;
uint8_t ic = invcols[row][col];
for (b = 0; b < 8; b++) {
if (ic & (1 << b))
rv1 ^= rv2;
rv2 *= 2;
}
xv ^= rv1 ^ ctx->xors[rv1 >> 8];
}
val = (val << 8) | xv;
}
ctx->rk[j] = val;
}
}
for (i = 48; i < 52; i++) {
ctx->rk[i] = ((roundkey[i] << 24) & 0xFF000000) |
((roundkey[i] << 8 ) & 0x00FF0000) |
((roundkey[i] >> 8 ) & 0x0000FF00) |
((roundkey[i] >> 24) & 0x000000FF);
}
}
static void aes_init_state(s14aes_handle* ctx) {
const uint8_t invcol[4] = {
0x0E, 0x0B, 0x0D, 0x09
};
unsigned int *tds_ptr;
uint8_t rcon[32];
uint8_t box[256];
int i, j, k, b;
for (i = 0; i < 32; i++) {
uint16_t rv;
if (i >= 8) {
rv = 128;
for (j = 0; j < i - 7; j++) {
rv *= 2;
if (rv & 256)
rv ^= 0x11Bu;
}
}
else {
rv = 1 << i;
}
rcon[i] = rv;
}
for (i = 0; i < 256; i++) {
uint8_t xv = 0;
for (j = 0; j < 8; j++) {
if (i & (1 << j))
xv ^= rcon[j + 8];
}
ctx->xors[i] = xv;
}
tds_ptr = ctx->tds;
for (i = 0; i < 256; i++) {
uint32_t val = 0;
for (j = 0; j < 4; j++) {
uint16_t tv1 = 0;
uint16_t tv2 = invcol[j];
for (b = 0; b < 8; b++) {
if (i & (1 << b))
tv1 ^= tv2;
tv2 *= 2;
}
val = ((val >> 8u) & 0x00FFFFFF) | ((val << 24u) & 0xFF000000);
val = ((uint8_t)tv1 ^ ctx->xors[tv1 >> 8]) | val;
}
val = ((val >> 16u) & 0x0000FFFF) | ((val << 16u) & 0xFFFF0000);
for (j = 0; j < 4; j++) {
*tds_ptr++ = val;
val = ((val >> 8u) & 0x00FFFFFF) | ((val << 24u) & 0xFF000000);
}
}
box[0] = 0;
for (i = 1; i < 256; i++) {
for (j = 1; j < 256; j++) {
uint16_t bv1 = 0;
uint16_t bv2 = j;
for (k = 0; k < 8; k++) {
if (i & (1 << k))
bv1 ^= bv2;
bv2 *= 2;
}
if (((uint8_t)bv1 ^ ctx->xors[bv1 >> 8]) == 1)
break;
}
box[i] = j;
if (j == 256) /* ??? */
return;
}
for (i = 0; i < 256; i += 16) {
for (j = 0; j < 16; j++) {
uint8_t val = 0;
for (k = 0; k < 8; k++) {
val |= box[i | j] & (1 << k);
for (b = 0; b < 4; b++) {
uint8_t bv = box[i | j];
if (bv & (1 << ((b + k - 4) & 7)))
val ^= 1 << k;
}
}
ctx->sbox[i + j] = val ^ 0x63;
ctx->ibox[val ^ 0x63] = i + j;
}
}
/* originally recalculated in Namco's code (inlined?) */
for (i = 0; i < 8; i++) {
ctx->rcon[i] = rcon[i];
}
}
static void aes_decrypt_block(s14aes_handle* ctx, uint8_t* buf) {
uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
uint8_t* ibox = ctx->ibox;
uint32_t* tds = ctx->tds;
uint32_t* rk = ctx->rk;
s0 = rk[48] ^ GET_U32BE(buf + 0);
s1 = rk[49] ^ GET_U32BE(buf + 4);
s2 = rk[50] ^ GET_U32BE(buf + 8);
s3 = rk[51] ^ GET_U32BE(buf + 12);
t0 = rk[44] ^ tds[4 * ibox[GET_B0(s1)] + 3] ^ tds[4 * ibox[GET_B1(s2)] + 2] ^ tds[4 * ibox[GET_B2(s3)] + 1] ^ tds[4 * ibox[GET_B3(s0)] + 0];
t1 = rk[45] ^ tds[4 * ibox[GET_B0(s2)] + 3] ^ tds[4 * ibox[GET_B1(s3)] + 2] ^ tds[4 * ibox[GET_B2(s0)] + 1] ^ tds[4 * ibox[GET_B3(s1)] + 0];
t2 = rk[46] ^ tds[4 * ibox[GET_B0(s3)] + 3] ^ tds[4 * ibox[GET_B1(s0)] + 2] ^ tds[4 * ibox[GET_B2(s1)] + 1] ^ tds[4 * ibox[GET_B3(s2)] + 0];
t3 = rk[47] ^ tds[4 * ibox[GET_B0(s0)] + 3] ^ tds[4 * ibox[GET_B1(s1)] + 2] ^ tds[4 * ibox[GET_B2(s2)] + 1] ^ tds[4 * ibox[GET_B3(s3)] + 0];
s0 = rk[40] ^ tds[4 * ibox[GET_B0(t1)] + 3] ^ tds[4 * ibox[GET_B1(t2)] + 2] ^ tds[4 * ibox[GET_B2(t3)] + 1] ^ tds[4 * ibox[GET_B3(t0)] + 0];
s1 = rk[41] ^ tds[4 * ibox[GET_B0(t2)] + 3] ^ tds[4 * ibox[GET_B1(t3)] + 2] ^ tds[4 * ibox[GET_B2(t0)] + 1] ^ tds[4 * ibox[GET_B3(t1)] + 0];
s2 = rk[42] ^ tds[4 * ibox[GET_B0(t3)] + 3] ^ tds[4 * ibox[GET_B1(t0)] + 2] ^ tds[4 * ibox[GET_B2(t1)] + 1] ^ tds[4 * ibox[GET_B3(t2)] + 0];
s3 = rk[43] ^ tds[4 * ibox[GET_B0(t0)] + 3] ^ tds[4 * ibox[GET_B1(t1)] + 2] ^ tds[4 * ibox[GET_B2(t2)] + 1] ^ tds[4 * ibox[GET_B3(t3)] + 0];
t0 = rk[36] ^ tds[4 * ibox[GET_B0(s1)] + 3] ^ tds[4 * ibox[GET_B1(s2)] + 2] ^ tds[4 * ibox[GET_B2(s3)] + 1] ^ tds[4 * ibox[GET_B3(s0)] + 0];
t1 = rk[37] ^ tds[4 * ibox[GET_B0(s2)] + 3] ^ tds[4 * ibox[GET_B1(s3)] + 2] ^ tds[4 * ibox[GET_B2(s0)] + 1] ^ tds[4 * ibox[GET_B3(s1)] + 0];
t2 = rk[38] ^ tds[4 * ibox[GET_B0(s3)] + 3] ^ tds[4 * ibox[GET_B1(s0)] + 2] ^ tds[4 * ibox[GET_B2(s1)] + 1] ^ tds[4 * ibox[GET_B3(s2)] + 0];
t3 = rk[39] ^ tds[4 * ibox[GET_B0(s0)] + 3] ^ tds[4 * ibox[GET_B1(s1)] + 2] ^ tds[4 * ibox[GET_B2(s2)] + 1] ^ tds[4 * ibox[GET_B3(s3)] + 0];
s0 = rk[32] ^ tds[4 * ibox[GET_B0(t1)] + 3] ^ tds[4 * ibox[GET_B1(t2)] + 2] ^ tds[4 * ibox[GET_B2(t3)] + 1] ^ tds[4 * ibox[GET_B3(t0)] + 0];
s1 = rk[33] ^ tds[4 * ibox[GET_B0(t2)] + 3] ^ tds[4 * ibox[GET_B1(t3)] + 2] ^ tds[4 * ibox[GET_B2(t0)] + 1] ^ tds[4 * ibox[GET_B3(t1)] + 0];
s2 = rk[34] ^ tds[4 * ibox[GET_B0(t3)] + 3] ^ tds[4 * ibox[GET_B1(t0)] + 2] ^ tds[4 * ibox[GET_B2(t1)] + 1] ^ tds[4 * ibox[GET_B3(t2)] + 0];
s3 = rk[35] ^ tds[4 * ibox[GET_B0(t0)] + 3] ^ tds[4 * ibox[GET_B1(t1)] + 2] ^ tds[4 * ibox[GET_B2(t2)] + 1] ^ tds[4 * ibox[GET_B3(t3)] + 0];
t0 = rk[28] ^ tds[4 * ibox[GET_B0(s1)] + 3] ^ tds[4 * ibox[GET_B1(s2)] + 2] ^ tds[4 * ibox[GET_B2(s3)] + 1] ^ tds[4 * ibox[GET_B3(s0)] + 0];
t1 = rk[29] ^ tds[4 * ibox[GET_B0(s2)] + 3] ^ tds[4 * ibox[GET_B1(s3)] + 2] ^ tds[4 * ibox[GET_B2(s0)] + 1] ^ tds[4 * ibox[GET_B3(s1)] + 0];
t2 = rk[30] ^ tds[4 * ibox[GET_B0(s3)] + 3] ^ tds[4 * ibox[GET_B1(s0)] + 2] ^ tds[4 * ibox[GET_B2(s1)] + 1] ^ tds[4 * ibox[GET_B3(s2)] + 0];
t3 = rk[31] ^ tds[4 * ibox[GET_B0(s0)] + 3] ^ tds[4 * ibox[GET_B1(s1)] + 2] ^ tds[4 * ibox[GET_B2(s2)] + 1] ^ tds[4 * ibox[GET_B3(s3)] + 0];
s0 = rk[24] ^ tds[4 * ibox[GET_B0(t1)] + 3] ^ tds[4 * ibox[GET_B1(t2)] + 2] ^ tds[4 * ibox[GET_B2(t3)] + 1] ^ tds[4 * ibox[GET_B3(t0)] + 0];
s1 = rk[25] ^ tds[4 * ibox[GET_B0(t2)] + 3] ^ tds[4 * ibox[GET_B1(t3)] + 2] ^ tds[4 * ibox[GET_B2(t0)] + 1] ^ tds[4 * ibox[GET_B3(t1)] + 0];
s2 = rk[26] ^ tds[4 * ibox[GET_B0(t3)] + 3] ^ tds[4 * ibox[GET_B1(t0)] + 2] ^ tds[4 * ibox[GET_B2(t1)] + 1] ^ tds[4 * ibox[GET_B3(t2)] + 0];
s3 = rk[27] ^ tds[4 * ibox[GET_B0(t0)] + 3] ^ tds[4 * ibox[GET_B1(t1)] + 2] ^ tds[4 * ibox[GET_B2(t2)] + 1] ^ tds[4 * ibox[GET_B3(t3)] + 0];
t0 = rk[20] ^ tds[4 * ibox[GET_B0(s1)] + 3] ^ tds[4 * ibox[GET_B1(s2)] + 2] ^ tds[4 * ibox[GET_B2(s3)] + 1] ^ tds[4 * ibox[GET_B3(s0)] + 0];
t1 = rk[21] ^ tds[4 * ibox[GET_B0(s2)] + 3] ^ tds[4 * ibox[GET_B1(s3)] + 2] ^ tds[4 * ibox[GET_B2(s0)] + 1] ^ tds[4 * ibox[GET_B3(s1)] + 0];
t2 = rk[22] ^ tds[4 * ibox[GET_B0(s3)] + 3] ^ tds[4 * ibox[GET_B1(s0)] + 2] ^ tds[4 * ibox[GET_B2(s1)] + 1] ^ tds[4 * ibox[GET_B3(s2)] + 0];
t3 = rk[23] ^ tds[4 * ibox[GET_B0(s0)] + 3] ^ tds[4 * ibox[GET_B1(s1)] + 2] ^ tds[4 * ibox[GET_B2(s2)] + 1] ^ tds[4 * ibox[GET_B3(s3)] + 0];
s0 = rk[16] ^ tds[4 * ibox[GET_B0(t1)] + 3] ^ tds[4 * ibox[GET_B1(t2)] + 2] ^ tds[4 * ibox[GET_B2(t3)] + 1] ^ tds[4 * ibox[GET_B3(t0)] + 0];
s1 = rk[17] ^ tds[4 * ibox[GET_B0(t2)] + 3] ^ tds[4 * ibox[GET_B1(t3)] + 2] ^ tds[4 * ibox[GET_B2(t0)] + 1] ^ tds[4 * ibox[GET_B3(t1)] + 0];
s2 = rk[18] ^ tds[4 * ibox[GET_B0(t3)] + 3] ^ tds[4 * ibox[GET_B1(t0)] + 2] ^ tds[4 * ibox[GET_B2(t1)] + 1] ^ tds[4 * ibox[GET_B3(t2)] + 0];
s3 = rk[19] ^ tds[4 * ibox[GET_B0(t0)] + 3] ^ tds[4 * ibox[GET_B1(t1)] + 2] ^ tds[4 * ibox[GET_B2(t2)] + 1] ^ tds[4 * ibox[GET_B3(t3)] + 0];
t0 = rk[12] ^ tds[4 * ibox[GET_B0(s1)] + 3] ^ tds[4 * ibox[GET_B1(s2)] + 2] ^ tds[4 * ibox[GET_B2(s3)] + 1] ^ tds[4 * ibox[GET_B3(s0)] + 0];
t1 = rk[13] ^ tds[4 * ibox[GET_B0(s2)] + 3] ^ tds[4 * ibox[GET_B1(s3)] + 2] ^ tds[4 * ibox[GET_B2(s0)] + 1] ^ tds[4 * ibox[GET_B3(s1)] + 0];
t2 = rk[14] ^ tds[4 * ibox[GET_B0(s3)] + 3] ^ tds[4 * ibox[GET_B1(s0)] + 2] ^ tds[4 * ibox[GET_B2(s1)] + 1] ^ tds[4 * ibox[GET_B3(s2)] + 0];
t3 = rk[15] ^ tds[4 * ibox[GET_B0(s0)] + 3] ^ tds[4 * ibox[GET_B1(s1)] + 2] ^ tds[4 * ibox[GET_B2(s2)] + 1] ^ tds[4 * ibox[GET_B3(s3)] + 0];
s0 = rk[8 ] ^ tds[4 * ibox[GET_B0(t1)] + 3] ^ tds[4 * ibox[GET_B1(t2)] + 2] ^ tds[4 * ibox[GET_B2(t3)] + 1] ^ tds[4 * ibox[GET_B3(t0)] + 0];
s1 = rk[9 ] ^ tds[4 * ibox[GET_B0(t2)] + 3] ^ tds[4 * ibox[GET_B1(t3)] + 2] ^ tds[4 * ibox[GET_B2(t0)] + 1] ^ tds[4 * ibox[GET_B3(t1)] + 0];
s2 = rk[10] ^ tds[4 * ibox[GET_B0(t3)] + 3] ^ tds[4 * ibox[GET_B1(t0)] + 2] ^ tds[4 * ibox[GET_B2(t1)] + 1] ^ tds[4 * ibox[GET_B3(t2)] + 0];
s3 = rk[11] ^ tds[4 * ibox[GET_B0(t0)] + 3] ^ tds[4 * ibox[GET_B1(t1)] + 2] ^ tds[4 * ibox[GET_B2(t2)] + 1] ^ tds[4 * ibox[GET_B3(t3)] + 0];
t0 = rk[4 ] ^ tds[4 * ibox[GET_B0(s1)] + 3] ^ tds[4 * ibox[GET_B1(s2)] + 2] ^ tds[4 * ibox[GET_B2(s3)] + 1] ^ tds[4 * ibox[GET_B3(s0)] + 0];
t1 = rk[5 ] ^ tds[4 * ibox[GET_B0(s2)] + 3] ^ tds[4 * ibox[GET_B1(s3)] + 2] ^ tds[4 * ibox[GET_B2(s0)] + 1] ^ tds[4 * ibox[GET_B3(s1)] + 0];
t2 = rk[6 ] ^ tds[4 * ibox[GET_B0(s3)] + 3] ^ tds[4 * ibox[GET_B1(s0)] + 2] ^ tds[4 * ibox[GET_B2(s1)] + 1] ^ tds[4 * ibox[GET_B3(s2)] + 0];
t3 = rk[7 ] ^ tds[4 * ibox[GET_B0(s0)] + 3] ^ tds[4 * ibox[GET_B1(s1)] + 2] ^ tds[4 * ibox[GET_B2(s2)] + 1] ^ tds[4 * ibox[GET_B3(s3)] + 0];
buf[0 ] = GET_B3(rk[0]) ^ ibox[GET_B3(t0)];
buf[1 ] = GET_B2(rk[0]) ^ ibox[GET_B2(t3)];
buf[2 ] = GET_B1(rk[0]) ^ ibox[GET_B1(t2)];
buf[3 ] = GET_B0(rk[0]) ^ ibox[GET_B0(t1)];
buf[4 ] = GET_B3(rk[1]) ^ ibox[GET_B3(t1)];
buf[5 ] = GET_B2(rk[1]) ^ ibox[GET_B2(t0)];
buf[6 ] = GET_B1(rk[1]) ^ ibox[GET_B1(t3)];
buf[7 ] = GET_B0(rk[1]) ^ ibox[GET_B0(t2)];
buf[8 ] = GET_B3(rk[2]) ^ ibox[GET_B3(t2)];
buf[9 ] = GET_B2(rk[2]) ^ ibox[GET_B2(t1)];
buf[10] = GET_B1(rk[2]) ^ ibox[GET_B1(t0)];
buf[11] = GET_B0(rk[2]) ^ ibox[GET_B0(t3)];
buf[12] = GET_B3(rk[3]) ^ ibox[GET_B3(t3)];
buf[13] = GET_B2(rk[3]) ^ ibox[GET_B2(t2)];
buf[14] = GET_B1(rk[3]) ^ ibox[GET_B1(t1)];
buf[15] = GET_B0(rk[3]) ^ ibox[GET_B0(t0)];
}
/* **************************** */
s14aes_handle* s14aes_init() {
s14aes_handle* ctx = malloc(sizeof(s14aes_handle));
if (!ctx) goto fail;
aes_init_state(ctx);
return ctx;
fail:
return NULL;
}
void s14aes_close(s14aes_handle* ctx) {
free(ctx);
}
void s14aes_set_key(s14aes_handle* ctx, const uint8_t* key) {
aes_init_key(ctx, key);
}
void s14aes_decrypt(s14aes_handle* ctx, uint8_t* buf) {
aes_decrypt_block(ctx, buf);
}

View File

@ -0,0 +1,19 @@
#ifndef _G7221_DECODER_AES_H
#define _G7221_DECODER_AES_H
#include <stdint.h>
typedef struct s14aes_handle s14aes_handle;
/* init/close handle (AES-192 in ECB mode) */
s14aes_handle* s14aes_init();
void s14aes_close(s14aes_handle* ctx);
/* set new key (can be called multiple times) */
void s14aes_set_key(s14aes_handle* ctx, const uint8_t* key);
/* decrypt a single 0x10 block */
void s14aes_decrypt(s14aes_handle* ctx, uint8_t* buf);
#endif

View File

@ -3,6 +3,7 @@
#include <string.h> #include <string.h>
#include "g7221_decoder_lib.h" #include "g7221_decoder_lib.h"
#include "g7221_decoder_aes.h"
/* Decodes Siren14 from Namco's BNSF, a mono MLT/DCT-based codec for speech/sound (low bandwidth). /* Decodes Siren14 from Namco's BNSF, a mono MLT/DCT-based codec for speech/sound (low bandwidth).
@ -35,7 +36,7 @@
* - very minor change in bit unpacking (minor output diffs) * - very minor change in bit unpacking (minor output diffs)
* - modified DCT-IV optimizations, scaling and window functions (minor output diffs) * - modified DCT-IV optimizations, scaling and window functions (minor output diffs)
* - internally PCM16 bufs, but converts to float (sample/32768.0) afterwards if the platform needs it * - internally PCM16 bufs, but converts to float (sample/32768.0) afterwards if the platform needs it
* - less error control * - less error control (on error decoder is supposed to repeat last coefs)
* - can't decode Siren7, and given output diffs it's not actually ITU-compliant * - can't decode Siren7, and given output diffs it's not actually ITU-compliant
* - minor optimizations here and there but otherwise very similar * - minor optimizations here and there but otherwise very similar
* This decoder generally uses Polycom's terminology, and while some parts like the bitreader could be * This decoder generally uses Polycom's terminology, and while some parts like the bitreader could be
@ -93,13 +94,14 @@ static int imlt_window(int16_t* new_samples, int16_t* old_samples, int16_t* out_
old_ptr = old_samples + 0; old_ptr = old_samples + 0;
new_ptr = new_samples + 320; new_ptr = new_samples + 320;
for (i = 320; i > 0; --i) { for (i = 0; i < 320; i++) {
*old_ptr++ = *new_ptr++; old_ptr[i] = new_ptr[i];
} }
return 0; return 0;
} }
/* "dct4_x640_int" */
static int imlt_dct4(int16_t* mlt_coefs, int16_t* new_samples, int mag_shift) { static int imlt_dct4(int16_t* mlt_coefs, int16_t* new_samples, int mag_shift) {
int i, j, k, n; int i, j, k, n;
const uint8_t *set1_ptr; const uint8_t *set1_ptr;
@ -186,55 +188,55 @@ static int imlt_dct4(int16_t* mlt_coefs, int16_t* new_samples, int mag_shift) {
{ {
int cos_val, sin_val; int cos_val, sin_val;
const uint16_t *cos_ptr, *sin_ptr, *cos_ptr_lo, *sin_ptr_lo; const uint16_t *cos_ptr, *sin_ptr, *cos_ptr_lo, *sin_ptr_lo;
int16_t C_in_val_lo, C_in_val_hi, C_in_val_mlo, C_in_val_mhi; int16_t mlt_val_lo, mlt_val_hi, mlt_val_mlo, mlt_val_mhi;
int16_t *C_in_ptr, *C_in_ptr_lo, *C_in_ptr_hi, *C_in_ptr_mlo, *C_in_ptr_mhi; int16_t *mlt_ptr, *mlt_ptr_lo, *mlt_ptr_hi, *mlt_ptr_mlo, *mlt_ptr_mhi;
cos_ptr = &imlt_cos_tables[320+160]; /* cos_table_16 > 8 > 4 > 2 */ cos_ptr = &imlt_cos_tables[320+160]; /* cos_table_16 > 8 > 4 > 2 */
sin_ptr = &imlt_sin_tables[320+160]; /* sin_table_16 > 8 > 4 > 2 */ sin_ptr = &imlt_sin_tables[320+160]; /* sin_table_16 > 8 > 4 > 2 */
for (n = 160; n >= 20; n /= 2) { for (n = 160; n >= 20; n /= 2) {
C_in_ptr = mlt_coefs + 0; mlt_ptr = mlt_coefs + 0;
while (C_in_ptr < mlt_coefs + 640) { while (mlt_ptr < mlt_coefs + 640) {
for (j = *set1_ptr; j > 0; --j) { for (j = *set1_ptr; j > 0; --j) {
C_in_ptr_lo = C_in_ptr + 0; mlt_ptr_lo = mlt_ptr + 0;
C_in_ptr_hi = C_in_ptr + n; mlt_ptr_hi = mlt_ptr + n;
C_in_ptr_mlo = C_in_ptr + (n / 2); mlt_ptr_mlo = mlt_ptr + (n / 2);
C_in_ptr_mhi = C_in_ptr + (n / 2); mlt_ptr_mhi = mlt_ptr + (n / 2);
for (k = n / 4; k > 0; --k) { for (k = n / 4; k > 0; --k) {
C_in_val_lo = *C_in_ptr_lo; mlt_val_lo = *mlt_ptr_lo;
C_in_val_hi = *--C_in_ptr_hi; mlt_val_hi = *--mlt_ptr_hi;
C_in_val_mhi = *--C_in_ptr_mhi; mlt_val_mhi = *--mlt_ptr_mhi;
C_in_val_mlo = *C_in_ptr_mlo; mlt_val_mlo = *mlt_ptr_mlo;
*C_in_ptr_lo++ = C_in_val_lo + C_in_val_hi; *mlt_ptr_lo++ = mlt_val_lo + mlt_val_hi;
*C_in_ptr_mlo++ = C_in_val_lo - C_in_val_hi; *mlt_ptr_mlo++ = mlt_val_lo - mlt_val_hi;
*C_in_ptr_mhi = C_in_val_mlo + C_in_val_mhi; *mlt_ptr_mhi = mlt_val_mlo + mlt_val_mhi;
*C_in_ptr_hi = C_in_val_mhi - C_in_val_mlo; *mlt_ptr_hi = mlt_val_mhi - mlt_val_mlo;
} }
C_in_ptr += n; mlt_ptr += n;
} }
set1_ptr++; set1_ptr++;
for (j = *set1_ptr; j > 0; --j) { for (j = *set1_ptr; j > 0; --j) {
C_in_ptr_lo = C_in_ptr + 0; mlt_ptr_lo = mlt_ptr + 0;
C_in_ptr_hi = C_in_ptr + n; mlt_ptr_hi = mlt_ptr + n;
cos_ptr_lo = cos_ptr + 0; cos_ptr_lo = cos_ptr + 0;
sin_ptr_lo = sin_ptr + 0; sin_ptr_lo = sin_ptr + 0;
for (k = n / 4; k > 0; --k) { for (k = n / 4; k > 0; --k) {
cos_val = *cos_ptr_lo++; cos_val = *cos_ptr_lo++;
sin_val = *sin_ptr_lo++; sin_val = *sin_ptr_lo++;
C_in_val_lo = *C_in_ptr_lo; mlt_val_lo = *mlt_ptr_lo;
C_in_val_hi = *--C_in_ptr_hi; mlt_val_hi = *--mlt_ptr_hi;
*C_in_ptr_lo++ = (cos_val * C_in_val_lo + sin_val * C_in_val_hi + 32768) >> 16; *mlt_ptr_lo++ = (cos_val * mlt_val_lo + sin_val * mlt_val_hi + 32768) >> 16;
*C_in_ptr_hi = (sin_val * -C_in_val_lo + cos_val * C_in_val_hi + 32768) >> 16; *mlt_ptr_hi = (sin_val * -mlt_val_lo + cos_val * mlt_val_hi + 32768) >> 16;
cos_val = *cos_ptr_lo++; cos_val = *cos_ptr_lo++;
sin_val = *sin_ptr_lo++; sin_val = *sin_ptr_lo++;
C_in_val_lo = *C_in_ptr_lo; mlt_val_lo = *mlt_ptr_lo;
C_in_val_hi = *--C_in_ptr_hi; mlt_val_hi = *--mlt_ptr_hi;
*C_in_ptr_lo++ = (cos_val * C_in_val_lo + sin_val * C_in_val_hi + 32768) >> 16; *mlt_ptr_lo++ = (cos_val * mlt_val_lo + sin_val * mlt_val_hi + 32768) >> 16;
*C_in_ptr_hi = (sin_val * C_in_val_lo - cos_val * C_in_val_hi + 32768) >> 16; *mlt_ptr_hi = (sin_val * mlt_val_lo - cos_val * mlt_val_hi + 32768) >> 16;
} }
C_in_ptr += n; mlt_ptr += n;
} }
set1_ptr++; set1_ptr++;
} }
@ -408,7 +410,7 @@ static int imlt_dct4(int16_t* mlt_coefs, int16_t* new_samples, int mag_shift) {
new_ptr += 10; new_ptr += 10;
} }
/* below is some three way swapping tmp ptrs change between mlt<>new */ /* below is some three way swapping, tmp ptrs change between mlt<>new */
tmp0_ptr = mlt_coefs + 640; tmp0_ptr = mlt_coefs + 640;
tmp1_ptr = new_samples + 640; tmp1_ptr = new_samples + 640;
for (n = 20; n <= 160; n *= 2) { for (n = 20; n <= 160; n *= 2) {
@ -532,18 +534,18 @@ static int imlt_dct4(int16_t* mlt_coefs, int16_t* new_samples, int mag_shift) {
return 0; return 0;
} }
/* transform frequency domain MLT spectrum coefs to time domain PCM samples with reverse/inverse MLT */ /* "inverse_MLT" */
static int rmlt_coefs_to_samples(int mag_shift, int16_t* mlt_coefs, int16_t* old_samples, int16_t* out_samples /*, int p_samples_done*/) { static int rmlt_coefs_to_samples(int mag_shift, int16_t* mlt_coefs, int16_t* old_samples, int16_t* out_samples /*, int p_samples_done*/) {
int res; int res;
int16_t new_samples[640]; int16_t new_samples[640];
/* block transform coefs-to-samples using DCT-IV (inverse) */ /* block transform MLT spectrum coefs to time domain PCM samples using DCT-IV (inverse) */
res = imlt_dct4(mlt_coefs, new_samples, mag_shift); res = imlt_dct4(mlt_coefs, new_samples, mag_shift);
if (res) return res; if (res < 0) return res;
/* apply IMLT overlapped window filter function (640 samples) */ /* apply IMLT overlapped window filter function (640 samples) */
res = imlt_window(new_samples, old_samples, out_samples); res = imlt_window(new_samples, old_samples, out_samples);
if (res) return res; if (res < 0) return res;
//*p_samples_done = 640; /* in Namco's code but actually ignored */ //*p_samples_done = 640; /* in Namco's code but actually ignored */
@ -802,7 +804,7 @@ static inline void index_to_array(int index, int* array_cv, int category) {
} }
} }
static int decode_vector_quantized_mlt_indices(uint32_t* data_u32, int bitpos, int bit_count, uint32_t* p_random_value, int* decoder_region_standard_deviation, int* power_categories, int16_t* mlt_coefs) { static int decode_vector_quantized_mlt_indices(uint32_t* data_u32, int* p_bitpos, int bit_count, uint32_t* p_random_value, int* decoder_region_standard_deviation, int* power_categories, int16_t* mlt_coefs) {
int16_t standard_deviation; int16_t standard_deviation;
int array_cv[MAX_VECTOR_DIMENSION]; int array_cv[MAX_VECTOR_DIMENSION];
int i, v, region, category, index; int i, v, region, category, index;
@ -810,8 +812,8 @@ static int decode_vector_quantized_mlt_indices(uint32_t* data_u32, int bitpos, i
uint32_t* ptr_u32; uint32_t* ptr_u32;
/* bitreading setup */ /* bitreading setup */
ptr_u32 = &data_u32[(bitpos >> 5)]; ptr_u32 = &data_u32[(*p_bitpos >> 5)];
bitmask = 1 << (31 - (bitpos & 0x1F)); bitmask = 1 << (31 - (*p_bitpos & 0x1F));
cur_u32 = *ptr_u32; cur_u32 = *ptr_u32;
ptr_u32++; ptr_u32++;
@ -832,6 +834,7 @@ static int decode_vector_quantized_mlt_indices(uint32_t* data_u32, int bitpos, i
do { do {
int bit = (bitmask & cur_u32) != 0; int bit = (bitmask & cur_u32) != 0;
bitmask >>= 1; bitmask >>= 1;
(*p_bitpos)++;
if (bitmask == 0) { if (bitmask == 0) {
bitmask = 0x80000000; bitmask = 0x80000000;
cur_u32 = *ptr_u32; cur_u32 = *ptr_u32;
@ -872,6 +875,7 @@ static int decode_vector_quantized_mlt_indices(uint32_t* data_u32, int bitpos, i
negative = (bitmask & cur_u32) != 0; negative = (bitmask & cur_u32) != 0;
bitmask >>= 1; bitmask >>= 1;
(*p_bitpos)++;
if (bitmask == 0) { if (bitmask == 0) {
bitmask = 0x80000000; bitmask = 0x80000000;
cur_u32 = *ptr_u32; cur_u32 = *ptr_u32;
@ -1015,7 +1019,7 @@ static int unpack_frame(int bit_rate, const uint8_t* data, int frame_size, /*int
res = categorize( res = categorize(
8 * expected_frame_size - bitpos, 8 * expected_frame_size - bitpos,
absolute_region_power_index, power_categories, category_balances); absolute_region_power_index, power_categories, category_balances);
if (res) return res; if (res < 0) return res;
/* adjust power categories (rate_adjust_categories) */ /* adjust power categories (rate_adjust_categories) */
{ {
@ -1060,16 +1064,44 @@ static int unpack_frame(int bit_rate, const uint8_t* data, int frame_size, /*int
/* decode the quantized bits into MLT coefs */ /* decode the quantized bits into MLT coefs */
res = decode_vector_quantized_mlt_indices( res = decode_vector_quantized_mlt_indices(
data_u32, bitpos, 8 * expected_frame_size, data_u32, &bitpos, 8 * expected_frame_size,
p_random_value, p_random_value,
decoder_region_standard_deviation, power_categories, mlt_coefs); decoder_region_standard_deviation, power_categories, mlt_coefs);
if (res) return res; if (res < 0) return res;
/* test for errors (in refdec but not Namco's, useful to detect decryption) */
{
int bits_left = 8 * expected_frame_size - bitpos;
int i;
if (bits_left > 0) {
/* frame must be padded with 1s */
for (i = 0; i < bits_left; i++) {
int bit = (data_u32[bitpos >> 5] >> (31 - (bitpos & 0x1F))) & 1;
bitpos++;
if (bit == 0)
return -1;
}
}
else {
/* ? */
if (categorization_control < NUM_CATEGORIZATION_CONTROL_BITS - 1 && bits_left < 0)
return -2;
}
for (i = 0; i < NUMBER_OF_REGIONS; i++) {
if ((absolute_region_power_index[i] + ESF_ADJUSTMENT_TO_RMS_INDEX > 31) ||
(absolute_region_power_index[i] + ESF_ADJUSTMENT_TO_RMS_INDEX < -8))
return -4;
}
}
return 0; return 0;
} }
/***************************************************************************** /*****************************************************************************
* API * API
*****************************************************************************/ *****************************************************************************/
@ -1078,13 +1110,15 @@ struct g7221_handle {
/* control */ /* control */
int bit_rate; int bit_rate;
int frame_size; int frame_size;
/* AES setup/state */
s14aes_handle* aes;
/* state */ /* state */
int16_t mlt_coefs[MAX_DCT_LENGTH]; int16_t mlt_coefs[MAX_DCT_LENGTH];
int16_t old_samples[MAX_DCT_LENGTH >> 1]; int16_t old_samples[MAX_DCT_LENGTH >> 1];
uint32_t random_value; uint32_t random_value;
}; };
g7221_handle* g7221_init(int bytes_per_frame, int flags) { g7221_handle* g7221_init(int bytes_per_frame) {
g7221_handle* handle = NULL; g7221_handle* handle = NULL;
int bit_rate; int bit_rate;
@ -1093,9 +1127,6 @@ g7221_handle* g7221_init(int bytes_per_frame, int flags) {
if (bit_rate != 24000 && bit_rate != 32000 && bit_rate != 48000) if (bit_rate != 24000 && bit_rate != 32000 && bit_rate != 48000)
goto fail; goto fail;
//if (flags != 0)
// goto fail;
handle = calloc(1, sizeof(g7221_handle)); handle = calloc(1, sizeof(g7221_handle));
if (!handle) goto fail; if (!handle) goto fail;
@ -1111,41 +1142,38 @@ fail:
} }
void g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples) { int g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples) {
int res; int res;
int mag_shift; int mag_shift;
#if 0 /* first 0x10 bytes may be encrypted with AES. Original code also saves encrypted bytes,
/* first 0x10 bytes are encrypted with an unknown substitution key and a complex * then re-crypts after unpacking, presumably to guard against memdumps. */
* unXOR function. Original code also saves encrypted bytes, then re-crypts after if (handle->aes != NULL) {
* unpacking, presumably to guard against memdumps. */ s14aes_decrypt(handle->aes, data);
if (handle->flags & 0x02) {
decrypt_frame(data, key);
} }
#endif
/* Namco's decoder is designed so that out_samples can be used in place of mlt_coefs, /* Namco's decoder is designed so that out_samples can be set in place of mlt_coefs,
* so we could avoid one extra buffer, but for clarity we'll leave as is */ * so we could avoid one extra buffer, but for clarity we'll leave as is */
/* unpack data into MLT spectrum coefs */ /* unpack data into MLT spectrum coefs */
res = unpack_frame(handle->bit_rate, data, handle->frame_size, &mag_shift, handle->mlt_coefs, &handle->random_value); res = unpack_frame(handle->bit_rate, data, handle->frame_size, &mag_shift, handle->mlt_coefs, &handle->random_value);
if (res) goto fail; if (res < 0) goto fail;
/* convert coefs to samples using reverse (inverse) MLT */ /* convert coefs to samples using reverse (inverse) MLT */
res = rmlt_coefs_to_samples(mag_shift, handle->mlt_coefs, handle->old_samples, out_samples); res = rmlt_coefs_to_samples(mag_shift, handle->mlt_coefs, handle->old_samples, out_samples);
if (res) goto fail; if (res < 0) goto fail;
/* Namco also gets number of codes/samples done from unpack_frame/rmlt (ptr arg), /* Namco also sets number of codes/samples done from unpack_frame/rmlt (ptr arg),
* but they seem unused */ * but they seem unused */
//todo return values return 1;
return;
fail: fail:
return; //;printf("S14: fail %i\n", res);
return 0;
} }
#if 0 #if 0
void g7221_decode_empty(g7221_handle* handle, int16_t* out_samples) { int g7221_decode_empty(g7221_handle* handle, int16_t* out_samples) {
static const uint8_t empty_frame[0x3c] = { static const uint8_t empty_frame[0x3c] = {
0x1E,0x0B,0x89,0x40,0x02,0x4F,0x51,0x35, 0x10,0xA1,0xFE,0xDF,0x52,0x51,0x10,0x0B, 0x1E,0x0B,0x89,0x40,0x02,0x4F,0x51,0x35, 0x10,0xA1,0xFE,0xDF,0x52,0x51,0x10,0x0B,
0xF0,0x69,0x7B,0xAE,0x18,0x17,0x00,0x52, 0x07,0x74,0xF4,0x65,0xA2,0x58,0xD8,0x3F, 0xF0,0x69,0x7B,0xAE,0x18,0x17,0x00,0x52, 0x07,0x74,0xF4,0x65,0xA2,0x58,0xD8,0x3F,
@ -1155,8 +1183,8 @@ void g7221_decode_empty(g7221_handle* handle, int16_t* out_samples) {
int res; int res;
int mag_shift; int mag_shift;
/* This only seems to exist in older exes. Namco's samples don't seem to reach EOF, /* This only seems to exist in older exes. Namco's samples don't reach EOF, so this
* so this wouldn't need to be called. Doesn't seem to use encoder delay either. */ * wouldn't need to be called. Doesn't seem to use encoder delay either. */
res = unpack_frame(24000, empty_frame, 0x3c, &mag_shift, handle->mlt_coefs, &handle->random_value); res = unpack_frame(24000, empty_frame, 0x3c, &mag_shift, handle->mlt_coefs, &handle->random_value);
if (res) goto fail; if (res) goto fail;
@ -1165,9 +1193,9 @@ void g7221_decode_empty(g7221_handle* handle, int16_t* out_samples) {
res = rmlt_coefs_to_samples(mag_shift, handle->mlt_coefs, handle->old_samples, out_samples); res = rmlt_coefs_to_samples(mag_shift, handle->mlt_coefs, handle->old_samples, out_samples);
if (res) goto fail; if (res) goto fail;
return; return 1;
fail: fail:
return; return 0;
} }
#endif #endif
@ -1184,5 +1212,46 @@ void g7221_reset(g7221_handle* handle) {
} }
void g7221_free(g7221_handle* handle) { void g7221_free(g7221_handle* handle) {
if (!handle)
return;
s14aes_close(handle->aes);
free(handle); free(handle);
} }
int g7221_set_key(g7221_handle* handle, const uint8_t* key) {
const int key_size = 192 / 8; /* only 192 bit mode */
uint8_t temp_key[192 / 8];
const char* mod_key = "Ua#oK3P94vdxX,ft*k-mnjoO"; /* constant for all platform/games */
int i;
if (!handle)
goto fail;
/* disable, useful for testing? */
if (key == NULL) {
s14aes_close(handle->aes);
handle->aes = NULL;
return 1;
}
/* init AES state (tables) or reuse if already exists */
if (handle->aes == NULL) {
handle->aes = s14aes_init();
if (!handle->aes) goto fail;
}
/* Base key is XORed probably against memdumps, as plain key would be part of the final AES key. However
* roundkey is still in memdumps near AES state (~0x1310 from sbox table, that starts with 0x63,0x7c,0x77,0x7b...)
* so it isn't too effective. XORing was originally done inside aes_expand_key during S14/S22 init. */
for (i = 0; i < key_size; i++) {
temp_key[i] = key[i] ^ mod_key[i];
}
/* reset new key */
s14aes_set_key(handle->aes, temp_key);
return 1;
fail:
return 0;
}

View File

@ -1,8 +1,8 @@
/* /*
Interface to Namco G.722.1 decoder Interface to Namco G.722.1 decoder
*/ */
#ifndef G7221_H #ifndef _G7221_DECODER_LIB_H
#define G7221_H #define _G7221_DECODER_LIB_H
#include <stdint.h> #include <stdint.h>
@ -10,14 +10,14 @@
typedef struct g7221_handle g7221_handle; typedef struct g7221_handle g7221_handle;
/* return a handle for decoding on successful init, NULL on failure */ /* return a handle for decoding on successful init, NULL on failure */
g7221_handle* g7221_init(int bytes_per_frame, int flags); g7221_handle* g7221_init(int bytes_per_frame);
/* decode a frame, at code_words, into 16-bit PCM in sample_buffer */ /* decode a frame, at code_words, into 16-bit PCM in sample_buffer */
void g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples); int g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples);
#if 0 #if 0
/* decodes an empty frame after no more data is found (may be used to "drain" window samples */ /* decodes an empty frame after no more data is found (may be used to "drain" window samples */
void g7221_decode_empty(g7221_handle* handle, int16_t* out_samples); int g7221_decode_empty(g7221_handle* handle, int16_t* out_samples);
#endif #endif
/* reset the decoder to its initial state */ /* reset the decoder to its initial state */
@ -26,4 +26,7 @@ void g7221_reset(g7221_handle* handle);
/* free resources */ /* free resources */
void g7221_free(g7221_handle* handle); void g7221_free(g7221_handle* handle);
/* set new key (ignores key on failure) */
int g7221_set_key(g7221_handle* handle, const uint8_t* key);
#endif #endif

View File

@ -17,7 +17,7 @@
* for (i = 0; i < 640; i++) * for (i = 0; i < 640; i++)
* window[i] = floor(sin((PI/2.0) * (i + 0.5) / 640) * 32767.0) * window[i] = floor(sin((PI/2.0) * (i + 0.5) / 640) * 32767.0)
* while the original int refdec table uses an altered formula? (smaller values) */ * while the original int refdec table uses an altered formula? (smaller values) */
static const int16_t imlt_samples_window[MAX_DCT_LENGTH] = { static const int16_t imlt_samples_window[MAX_DCT_LENGTH] = { /* "Out_Window"? */
40, 120, 201, 281, 361, 442, 522, 603, 683, 763, 40, 120, 201, 281, 361, 442, 522, 603, 683, 763,
844, 924, 1005, 1085, 1165, 1246, 1326, 1406, 1487, 1567, 844, 924, 1005, 1085, 1165, 1246, 1326, 1406, 1487, 1567,
1647, 1728, 1808, 1888, 1969, 2049, 2129, 2209, 2290, 2370, 1647, 1728, 1808, 1888, 1969, 2049, 2129, 2209, 2290, 2370,
@ -204,7 +204,7 @@ static const uint16_t imlt_cos_tables[636] = {
}; };
/* see cos table info */ /* see cos table info */
static const uint16_t imlt_sin_tables[636] = { static const uint16_t imlt_sin_tables[636] = { /* "sin_table" */
/* imlt_sin_table_64[320] (640/2) */ /* imlt_sin_table_64[320] (640/2) */
80, 241, 402, 562, 723, 884, 1045, 1206, 80, 241, 402, 562, 723, 884, 1045, 1206,
1367, 1527, 1688, 1849, 2010, 2171, 2331, 2492, 1367, 1527, 1688, 1849, 2010, 2171, 2331, 2492,
@ -326,7 +326,7 @@ static const uint16_t imlt_sin_tables[636] = {
/* vs refdec: has region 0 (unused, all 0s) and regions>13 (repeats of region 13) so they were removed. /* vs refdec: has region 0 (unused, all 0s) and regions>13 (repeats of region 13) so they were removed.
* 2nd index only went to DIFF_REGION_POWER_LEVELS-1 and last was added (all 0s though so probably unused). */ * 2nd index only went to DIFF_REGION_POWER_LEVELS-1 and last was added (all 0s though so probably unused). */
static const int16_t differential_region_power_decoder_tree[NUMBER_OF_REGIONS][DIFF_REGION_POWER_LEVELS][2] = { static const int16_t differential_region_power_decoder_tree[NUMBER_OF_REGIONS][DIFF_REGION_POWER_LEVELS][2] = { /* "rms_table"? */
{{ 1, 2},{ 3, 4},{ 5, 6},{ 7, 8},{ 9, 10},{ 11,-12},{-11,-10},{ -8, -9},{ -7, -6},{-13, 12},{ -5, -4},{ 0, 13},{ -3,-14},{ -2, 14},{ -1, 15},{-15, 16},{-16, 17},{-17, 18},{ 19, 20},{ 21, 22},{-18,-19},{-20,-21},{-22,-23},{ 0, 0}}, {{ 1, 2},{ 3, 4},{ 5, 6},{ 7, 8},{ 9, 10},{ 11,-12},{-11,-10},{ -8, -9},{ -7, -6},{-13, 12},{ -5, -4},{ 0, 13},{ -3,-14},{ -2, 14},{ -1, 15},{-15, 16},{-16, 17},{-17, 18},{ 19, 20},{ 21, 22},{-18,-19},{-20,-21},{-22,-23},{ 0, 0}},
{{ 1, 2},{ 3, 4},{ 5, 6},{ 7, 8},{-10, -9},{ -8,-11},{ -7, -6},{ 9, -5},{ 10,-12},{ -4, 11},{-13, -3},{ 12, -2},{ 13,-14},{ -1, 14},{ 15,-15},{ 0, 16},{-16, 17},{-17, 18},{-18, 19},{ 20, 21},{ 22,-19},{-20,-21},{-22,-23},{ 0, 0}}, {{ 1, 2},{ 3, 4},{ 5, 6},{ 7, 8},{-10, -9},{ -8,-11},{ -7, -6},{ 9, -5},{ 10,-12},{ -4, 11},{-13, -3},{ 12, -2},{ 13,-14},{ -1, 14},{ 15,-15},{ 0, 16},{-16, 17},{-17, 18},{-18, 19},{ 20, 21},{ 22,-19},{-20,-21},{-22,-23},{ 0, 0}},
{{ 1, 2},{ 3, 4},{ 5, 6},{ 7, 8},{ 9, 10},{-12, 11},{-11,-13},{-10, -9},{ 12,-14},{ -8, -7},{-15, -6},{ 13, -5},{-16, -4},{ 14,-17},{ 15, -3},{ 16,-18},{ -2, 17},{ 18,-19},{ -1, 19},{-20, 20},{ 0, 21},{ 22,-21},{-22,-23},{ 0, 0}}, {{ 1, 2},{ 3, 4},{ 5, 6},{ 7, 8},{ 9, 10},{-12, 11},{-11,-13},{-10, -9},{ 12,-14},{ -8, -7},{-15, -6},{ 13, -5},{-16, -4},{ 14,-17},{ 15, -3},{ 16,-18},{ -2, 17},{ 18,-19},{ -1, 19},{-20, 20},{ 0, 21},{ 22,-21},{-22,-23},{ 0, 0}},
@ -343,7 +343,7 @@ static const int16_t differential_region_power_decoder_tree[NUMBER_OF_REGIONS][D
}; };
/* vs refdec: same table */ /* vs refdec: same table */
static const int16_t mlt_quant_centroid[NUM_CATEGORIES][NUM_BINS] = { static const int16_t mlt_quant_centroid[NUM_CATEGORIES][NUM_BINS] = { /* "mlt_q" */
{ 0, 1606, 3119, 4586, 6049, 7502, 8941,10406,11851,13292,14736,16146,17566,19351, 0, 0}, { 0, 1606, 3119, 4586, 6049, 7502, 8941,10406,11851,13292,14736,16146,17566,19351, 0, 0},
{ 0, 2229, 4341, 6401, 8471,10531,12583,14588,16673,18924, 0, 0, 0, 0, 0, 0}, { 0, 2229, 4341, 6401, 8471,10531,12583,14588,16673,18924, 0, 0, 0, 0, 0, 0},
{ 0, 3055, 5998, 8929,11806,14680,17680, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 3055, 5998, 8929,11806,14680,17680, 0, 0, 0, 0, 0, 0, 0, 0, 0},
@ -361,7 +361,7 @@ static const int16_t expected_bits_table[NUM_CATEGORIES] = {
/* vs refdec: Namco uses positive values *2 but I'm not sure what they are for (some index access) /* vs refdec: Namco uses positive values *2 but I'm not sure what they are for (some index access)
* so these are the refdec values */ * so these are the refdec values */
static const int16_t mlt_decoder_tree_category_0[180][2] = { static const int16_t mlt_decoder_tree_category_0[180][2] = { /* "reasion_huffman_table"? */
{ 1, 0},{ 2, 3},{ 4, 5},{ 6, 7},{ 8, 9},{ -1, -14},{ 10, 11},{ 12, 13}, { 1, 0},{ 2, 3},{ 4, 5},{ 6, 7},{ 8, 9},{ -1, -14},{ 10, 11},{ 12, 13},
{ 14, 15},{ 16, 17},{ 18, 19},{ -15, 20},{ 21, 22},{ 23, -28},{ 24, -2},{ 25, 26}, { 14, 15},{ 16, 17},{ 18, 19},{ -15, 20},{ 21, 22},{ 23, -28},{ 24, -2},{ 25, 26},
{ 27, 28},{ 29, 30},{ 31, 32},{ -29, 33},{ -16, 34},{ -3, 35},{ 36, 37},{ -42, 38}, { 27, 28},{ 29, 30},{ 31, 32},{ -29, 33},{ -16, 34},{ -3, 35},{ 36, 37},{ -42, 38},
@ -541,7 +541,7 @@ static const int16_t *table_of_decoder_tables[NUM_CATEGORIES-1] = {
/* vs refdec: same table */ /* vs refdec: same table */
static const int16_t region_standard_deviation_table[REGION_POWER_TABLE_SIZE] = { static const int16_t region_standard_deviation_table[REGION_POWER_TABLE_SIZE] = { /* "rnd_reg"? */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
@ -559,17 +559,17 @@ static const int16_t number_of_vectors[NUM_CATEGORIES] = {
10, 10, 10, 5, 5, 4, 4, 0, 10, 10, 10, 5, 5, 4, 4, 0,
}; };
/* vs refdec: same table but last index is 1 */ /* vs refdec: same table but last index is 1 */
static const int16_t vector_dimension[NUM_CATEGORIES] = { static const int16_t vector_dimension[NUM_CATEGORIES] = { /* "vd_inv"? */
2, 2, 2, 4, 4, 5, 5, 0, 2, 2, 2, 4, 4, 5, 5, 0,
}; };
/* vs refdec: pre-adds one instead of in runtime and last index is 1 */ /* vs refdec: pre-adds one instead of in runtime and last index is 1 */
static const int16_t max_bin_plus1[NUM_CATEGORIES] = { static const int16_t max_bin_plus1[NUM_CATEGORIES] = { /* "kmax_p1" */
14, 10, 7, 5, 4, 3, 2, 0, 14, 10, 7, 5, 4, 3, 2, 0,
}; };
/* vs refdec: pre-scaled x2 (cat3 subs -1 and cat5/7 -2 too) */ /* vs refdec: pre-scaled x2 (cat3 subs -1 and cat5/7 -2 too) */
static const uint16_t max_bin_plus_one_inverse_scaled[8] = { static const uint16_t max_bin_plus_one_inverse_scaled[8] = { /* "kmax_p1_inv" */
4682, 6554, 9363, 13108, 16384, 21846, 32768, 0, 4682, 6554, 9363, 13108, 16384, 21846, 32768, 0,
}; };

View File

@ -252,6 +252,10 @@
RelativePath=".\meta\bgw_streamfile.h" RelativePath=".\meta\bgw_streamfile.h"
> >
</File> </File>
<File
RelativePath=".\meta\bnsf_keys.h"
>
</File>
<File <File
RelativePath=".\meta\cri_utf.h" RelativePath=".\meta\cri_utf.h"
> >
@ -1894,6 +1898,10 @@
RelativePath=".\coding\ea_mt_decoder_utk.h" RelativePath=".\coding\ea_mt_decoder_utk.h"
> >
</File> </File>
<File
RelativePath=".\coding\g7221_decoder_aes.h"
>
</File>
<File <File
RelativePath=".\coding\g7221_decoder_lib.h" RelativePath=".\coding\g7221_decoder_lib.h"
> >
@ -2010,6 +2018,10 @@
RelativePath=".\coding\g7221_decoder.c" RelativePath=".\coding\g7221_decoder.c"
> >
</File> </File>
<File
RelativePath=".\coding\g7221_decoder_aes.c"
>
</File>
<File <File
RelativePath=".\coding\g7221_decoder_lib.c" RelativePath=".\coding\g7221_decoder_lib.c"
> >

View File

@ -105,6 +105,7 @@
<ClInclude Include="meta\awc_xma_streamfile.h" /> <ClInclude Include="meta\awc_xma_streamfile.h" />
<ClInclude Include="meta\bar_streamfile.h" /> <ClInclude Include="meta\bar_streamfile.h" />
<ClInclude Include="meta\bgw_streamfile.h" /> <ClInclude Include="meta\bgw_streamfile.h" />
<ClInclude Include="meta\bnsf_keys.h" />
<ClInclude Include="meta\cri_utf.h" /> <ClInclude Include="meta\cri_utf.h" />
<ClInclude Include="meta\deblock_streamfile.h" /> <ClInclude Include="meta\deblock_streamfile.h" />
<ClInclude Include="meta\ea_eaac_streamfile.h" /> <ClInclude Include="meta\ea_eaac_streamfile.h" />
@ -138,6 +139,7 @@
<ClInclude Include="coding\acm_decoder_libacm.h" /> <ClInclude Include="coding\acm_decoder_libacm.h" />
<ClInclude Include="coding\coding.h" /> <ClInclude Include="coding\coding.h" />
<ClInclude Include="coding\ea_mt_decoder_utk.h" /> <ClInclude Include="coding\ea_mt_decoder_utk.h" />
<ClInclude Include="coding\g7221_decoder_aes.h" />
<ClInclude Include="coding\g7221_decoder_lib.h" /> <ClInclude Include="coding\g7221_decoder_lib.h" />
<ClInclude Include="coding\g7221_decoder_lib_data.h" /> <ClInclude Include="coding\g7221_decoder_lib_data.h" />
<ClInclude Include="coding\fsb_vorbis_data.h" /> <ClInclude Include="coding\fsb_vorbis_data.h" />
@ -559,6 +561,7 @@
<ClCompile Include="coding\g719_decoder.c" /> <ClCompile Include="coding\g719_decoder.c" />
<ClCompile Include="coding\g721_decoder.c" /> <ClCompile Include="coding\g721_decoder.c" />
<ClCompile Include="coding\g7221_decoder.c" /> <ClCompile Include="coding\g7221_decoder.c" />
<ClCompile Include="coding\g7221_decoder_aes.c" />
<ClCompile Include="coding\g7221_decoder_lib.c" /> <ClCompile Include="coding\g7221_decoder_lib.c" />
<ClCompile Include="coding\hca_decoder.c" /> <ClCompile Include="coding\hca_decoder.c" />
<ClCompile Include="coding\ima_decoder.c" /> <ClCompile Include="coding\ima_decoder.c" />

View File

@ -86,6 +86,9 @@
<ClInclude Include="meta\bgw_streamfile.h"> <ClInclude Include="meta\bgw_streamfile.h">
<Filter>meta\Header Files</Filter> <Filter>meta\Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="meta\bnsf_keys.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\cri_utf.h"> <ClInclude Include="meta\cri_utf.h">
<Filter>meta\Header Files</Filter> <Filter>meta\Header Files</Filter>
</ClInclude> </ClInclude>
@ -185,7 +188,7 @@
<ClInclude Include="coding\ea_mt_decoder_utk.h"> <ClInclude Include="coding\ea_mt_decoder_utk.h">
<Filter>coding\Header Files</Filter> <Filter>coding\Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="coding\g7221_decoder_lib.h"> <ClInclude Include="coding\g7221_decoder_aes.h">
<Filter>coding\Header Files</Filter> <Filter>coding\Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="coding\g7221_decoder_lib_data.h"> <ClInclude Include="coding\g7221_decoder_lib_data.h">
@ -1192,6 +1195,9 @@
<ClCompile Include="coding\g7221_decoder.c"> <ClCompile Include="coding\g7221_decoder.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="coding\g7221_decoder_aes.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\g7221_decoder_lib.c"> <ClCompile Include="coding\g7221_decoder_lib.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>

View File

@ -1,8 +1,12 @@
#include "meta.h" #include "meta.h"
#include "../coding/coding.h" #include "../coding/coding.h"
#include "../util.h" #include "../util.h"
#include "bnsf_keys.h"
/* BNSF - Namco Bandai's Bandai Namco Sound Format/File [Tales of Graces (Wii), Tales of Berseria (PS4)] */
static void find_bnsf_key(g7221_codec_data *data, off_t start, STREAMFILE *sf, uint8_t *best_key);
/* BNSF - Bandai Namco Sound Format/File [Tales of Graces (Wii), Tales of Berseria (PS4)] */
VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) { VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM * vgmstream = NULL;
off_t start_offset = 0, first_offset = 0x0C; off_t start_offset = 0, first_offset = 0x0C;
@ -19,11 +23,10 @@ VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
if (read_32bitBE(0,streamFile) != 0x424E5346) /* "BNSF" */ if (read_32bitBE(0,streamFile) != 0x424E5346) /* "BNSF" */
goto fail; goto fail;
bnsf_size = read_32bitBE(0x04,streamFile);
codec = read_32bitBE(0x08,streamFile); codec = read_32bitBE(0x08,streamFile);
/* check file size (siren22 uses full size) */ if (bnsf_size + (codec == 0x49533232 ? 0x00 : 0x08) != get_streamfile_size(streamFile)) /* IS22 uses full size */
bnsf_size = read_32bitBE(0x04,streamFile);
if (bnsf_size + (codec == 0x49533232 ? 0x00 : 0x08) != get_streamfile_size(streamFile))
goto fail; goto fail;
if (!find_chunk_be(streamFile, 0x73666d74,first_offset,0, &sfmt_chunk,NULL)) /* "sfmt" */ if (!find_chunk_be(streamFile, 0x73666d74,first_offset,0, &sfmt_chunk,NULL)) /* "sfmt" */
@ -40,15 +43,14 @@ VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
channel_count = read_16bitBE(sfmt_chunk+0x02,streamFile); channel_count = read_16bitBE(sfmt_chunk+0x02,streamFile);
sample_rate = read_32bitBE(sfmt_chunk+0x04,streamFile); sample_rate = read_32bitBE(sfmt_chunk+0x04,streamFile);
num_samples = read_32bitBE(sfmt_chunk+0x08,streamFile); num_samples = read_32bitBE(sfmt_chunk+0x08,streamFile);
loop_adjust = read_32bitBE(sfmt_chunk+0x0c,streamFile); /* 0 if no looping */ loop_adjust = read_32bitBE(sfmt_chunk+0x0c,streamFile); /* 0 when no loop */
block_size = read_16bitBE(sfmt_chunk+0x10,streamFile); block_size = read_16bitBE(sfmt_chunk+0x10,streamFile);
block_samples = read_16bitBE(sfmt_chunk+0x12,streamFile); block_samples = read_16bitBE(sfmt_chunk+0x12,streamFile);
//max_samples = sdat_size / block_size * block_samples /* num_samples is smaller */ //max_samples = sdat_size / block_size * block_samples;
start_offset = sdat_chunk; start_offset = sdat_chunk;
/* shouldn't happen, plus decoder can't handle it */ if (loop_adjust >= block_samples) /* decoder can't handle this */
if (loop_adjust >= block_samples)
goto fail; goto fail;
@ -65,10 +67,6 @@ VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
vgmstream->layout_type = layout_interleave; vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = block_size / channel_count; vgmstream->interleave_block_size = block_size / channel_count;
/* Late IS14 set flag 0x02 = encrypted [Tales of Zestiria (PS3/PC) voices, The Idolm@ster 2 (PS3) voices] */
if (flags != 0)
goto fail;
switch (codec) { switch (codec) {
#ifdef VGM_USE_G7221 #ifdef VGM_USE_G7221
case 0x49533134: /* "IS14" (interleaved Siren14) */ case 0x49533134: /* "IS14" (interleaved Siren14) */
@ -76,10 +74,29 @@ VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
vgmstream->codec_data = init_g7221(vgmstream->channels, vgmstream->interleave_block_size); vgmstream->codec_data = init_g7221(vgmstream->channels, vgmstream->interleave_block_size);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
/* get decryption key in .bnsfkey file or list, for later games' voices
* [The Idolm@ster 2 (PS3/X360), Tales of Zestiria (PS3/PC)] */
if (flags != 0) { /* only known value is 0x02 though */
size_t keysize;
uint8_t key[24] = {0}; /* keystring 0-padded to 192-bit */
keysize = read_key_file(key, sizeof(key), streamFile);
if (keysize <= 0 || keysize > sizeof(key)) {
find_bnsf_key(vgmstream->codec_data, start_offset, streamFile, key);
}
set_key_g7221(vgmstream->codec_data, key);
}
break; break;
#endif #endif
#ifdef VGM_USE_G719 #ifdef VGM_USE_G719
case 0x49533232: /* "IS22" (interleaved Siren22) */ case 0x49533232: /* "IS22" (interleaved Siren22) */
/* same encryption as IS14 but not seen */
if (flags != 0)
goto fail;
vgmstream->coding_type = coding_G719; vgmstream->coding_type = coding_G719;
vgmstream->codec_data = init_g719(vgmstream->channels, vgmstream->interleave_block_size); vgmstream->codec_data = init_g719(vgmstream->channels, vgmstream->interleave_block_size);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
@ -99,3 +116,41 @@ fail:
close_vgmstream(vgmstream); close_vgmstream(vgmstream);
return NULL; return NULL;
} }
static void find_bnsf_key(g7221_codec_data* data, off_t start, STREAMFILE* sf, uint8_t* best_key) {
const size_t keys_length = sizeof(s14key_list) / sizeof(bnsfkey_info);
int score, best_score = -1;
int i;
uint8_t tmpkey[24];
for (i = 0; i < keys_length; i++) {
const char* key = s14key_list[i].key;
int keylen = strlen(key);
if (keylen > sizeof(tmpkey))
continue;
memcpy(tmpkey, key, keylen);
memset(tmpkey + keylen, 0, sizeof(tmpkey) - keylen);
//;VGM_LOG("BNSF: test key=%.24s\n", tmpkey);
set_key_g7221(data, tmpkey);
score = test_key_g7221(data, start, sf);
if (score < 0) continue;
if (best_score <= 0 || (score < best_score && score > 0)) {
best_score = score;
memcpy(best_key, key, keylen);
memset(best_key + keylen, 0, sizeof(tmpkey) - keylen);
}
if (best_score == 1) {
break;
}
}
VGM_ASSERT(best_score > 0, "BNSF: best key=%.24s (score=%i)\n", best_key, best_score);
VGM_ASSERT(best_score < 0, "BNSF: key not found\n"); /* defaults to all 0s */
}

16
src/meta/bnsf_keys.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _BNSF_KEYS_H_
#define _BNSF_KEYS_H_
typedef struct {
const char* key;
} bnsfkey_info;
/* Known keys, extracted from games' exe */
static const bnsfkey_info s14key_list[] = {
/* THE iDOLM@STER 2 (PS3/X360) */
{"haruka17imas"},
};
#endif/*_BNSF_KEYS_H_*/

View File

@ -695,7 +695,7 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
#ifdef VGM_USE_G7221 #ifdef VGM_USE_G7221
if (vgmstream->coding_type == coding_G7221C) { if (vgmstream->coding_type == coding_G7221C) {
reset_g7221(vgmstream); reset_g7221(vgmstream->codec_data);
} }
#endif #endif
@ -879,7 +879,7 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
#ifdef VGM_USE_G7221 #ifdef VGM_USE_G7221
if (vgmstream->coding_type == coding_G7221C) { if (vgmstream->coding_type == coding_G7221C) {
free_g7221(vgmstream); free_g7221(vgmstream->codec_data);
vgmstream->codec_data = NULL; vgmstream->codec_data = NULL;
} }
#endif #endif