From ec0043bf6b816c817ee786458f314f2808fd5846 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 13 Oct 2018 19:50:42 +0200 Subject: [PATCH] Improve HCA key testing --- ext_includes/clHCA.h | 7 +++- ext_libs/clHCA.c | 77 +++++++++++++++++++++++++--------------- src/coding/hca_decoder.c | 9 +++-- 3 files changed, 61 insertions(+), 32 deletions(-) diff --git a/ext_includes/clHCA.h b/ext_includes/clHCA.h index 071e3a2b..df2b71a8 100644 --- a/ext_includes/clHCA.h +++ b/ext_includes/clHCA.h @@ -27,7 +27,7 @@ void clHCA_delete(clHCA *); * the header length with clHCA_isOurFile, then read data and call this. * May be called multiple times to reset decoder state. * Returns 0 on success, <0 on failure. */ -int clHCA_DecodeHeader(clHCA *, void *data, unsigned int size); +int clHCA_DecodeHeader(clHCA *, const void *data, unsigned int size); typedef struct clHCA_stInfo { unsigned int version; @@ -61,6 +61,7 @@ int clHCA_getInfo(clHCA *, clHCA_stInfo *out); /* Decodes a single frame, from data after headerSize. Should be called after * clHCA_DecodeHeader and size must be at least blockSize long. + * Data may be modified if encrypted. * Returns 0 on success, <0 on failure. */ int clHCA_DecodeBlock(clHCA *, void *data, unsigned int size); @@ -81,6 +82,10 @@ void clHCA_SetKey(clHCA *, unsigned long long keycode); * and select the key with scores closer to 1. */ int clHCA_TestBlock(clHCA *hca, void *data, unsigned int size); +/* Resets the internal decode state, used when restarting to decode the file from the beginning. + * Without it there are minor differences, mainly useful when testing a new key. */ +void clHCA_DecodeReset(clHCA * hca); + #ifdef __cplusplus } #endif diff --git a/ext_libs/clHCA.c b/ext_libs/clHCA.c index 03c8afad..d2d330ec 100644 --- a/ext_libs/clHCA.c +++ b/ext_libs/clHCA.c @@ -293,10 +293,10 @@ void clHCA_ReadSamples16(clHCA *hca, signed short *samples) { for (k = 0; k < hca->channels; k++) { f = hca->channel[k].wave[i][j]; //f = f * hca->rva_volume; /* rare, won't apply for now */ - if (f > 1) { - f = 1; - } else if (f < -1) { - f = -1; + if (f > 1.0f) { + f = 1.0f; + } else if (f < -1.0f) { + f = -1.0f; } s = (signed int) (f * scale); if ((unsigned) (s + 0x8000) & 0xFFFF0000) @@ -575,7 +575,7 @@ static unsigned int header_ceil2(unsigned int a, unsigned int b) { return (b > 0) ? (a / b + ((a % b) ? 1 : 0)) : 0; } -int clHCA_DecodeHeader(clHCA *hca, void *data, unsigned int size) { +int clHCA_DecodeHeader(clHCA *hca, const void *data, unsigned int size) { clData br; int res; @@ -929,43 +929,62 @@ int clHCA_TestBlock(clHCA *hca, void *data, unsigned int size) { unsigned int ch, sf, s; int status; int clips = 0, blanks = 0; - float fsample; - signed int psample; - /* return if decode fails (happens sometimes with wrong keys) */ + + /* first blocks can be empty/silent, check all bytes but sync/crc */ + { + int i; + int is_empty = 1; + const unsigned char *buf = data; + + for (i = 2; i < size - 0x02; i++) { + if (buf[i] != 0) { + is_empty = 0; + break; + } + } + + if (is_empty) { + return 0; + } + } + + /* return if decode fails (happens often with wrong keys due to bad bitstream values) */ status = clHCA_DecodeBlock(hca, data, size); if (status < 0) return -1; - /* check decode results */ + /* check decode results as bad keys may still get here */ for (ch = 0; ch < hca->channels; ch++) { for (sf = 0; sf < HCA_SUBFRAMES_PER_FRAME; sf++) { for (s = 0; s < HCA_SAMPLES_PER_SUBFRAME; s++) { - fsample = hca->channel[ch].wave[sf][s]; - psample = (signed int) (fsample * scale); - if (fsample > 1.0f || fsample < -1.0f) + float fsample = hca->channel[ch].wave[sf][s]; + + if (fsample > 1.0f || fsample < -1.0f) { //improve? clips++; - else if (psample == 0 || psample == -1) - blanks++; + } + else { + signed int psample = (signed int) (fsample * scale); + if (psample == 0 || psample == -1) + blanks++; + } } } } /* the more clips the less likely block was correctly decrypted */ - if (clips > 0) + if (clips == 1) + clips++; + if (clips > 1) return clips; /* if block is silent result is not useful */ if (blanks == hca->channels * HCA_SUBFRAMES_PER_FRAME * HCA_SAMPLES_PER_SUBFRAME) return 0; - /* block may be correct (but wrong keys can get this too) */ + /* block may be correct (but wrong keys can get this too and should test more blocks) */ return 1; } - -#if 0 -// it'd seem like resetting IMDCT (others get overwritten) would matter when restarting the -// stream from 0, but doesn't seem any different, maybe because the first frame acts as setup/empty void clHCA_DecodeReset(clHCA * hca) { unsigned int i; @@ -975,18 +994,18 @@ void clHCA_DecodeReset(clHCA * hca) { for (i = 0; i < hca->channels; i++) { stChannel *ch = &hca->channel[i]; - memset(ch->intensity, 0, sizeof(ch->intensity[0]) * HCA_SUBFRAMES_PER_FRAME); - memset(ch->scalefactors, 0, sizeof(ch->scalefactors[0]) * HCA_SAMPLES_PER_SUBFRAME); - memset(ch->resolution, 0, sizeof(ch->resolution[0]) * HCA_SAMPLES_PER_SUBFRAME); - memset(ch->gain, 0, sizeof(ch->gain[0]) * HCA_SAMPLES_PER_SUBFRAME); - memset(ch->spectra, 0, sizeof(ch->spectra[0]) * HCA_SAMPLES_PER_SUBFRAME); - memset(ch->temp, 0, sizeof(ch->temp[0]) * HCA_SAMPLES_PER_SUBFRAME); - memset(ch->dct, 0, sizeof(ch->dct[0]) * HCA_SAMPLES_PER_SUBFRAME); + /* most values get overwritten during decode */ + //memset(ch->intensity, 0, sizeof(ch->intensity[0]) * HCA_SUBFRAMES_PER_FRAME); + //memset(ch->scalefactors, 0, sizeof(ch->scalefactors[0]) * HCA_SAMPLES_PER_SUBFRAME); + //memset(ch->resolution, 0, sizeof(ch->resolution[0]) * HCA_SAMPLES_PER_SUBFRAME); + //memset(ch->gain, 0, sizeof(ch->gain[0]) * HCA_SAMPLES_PER_SUBFRAME); + //memset(ch->spectra, 0, sizeof(ch->spectra[0]) * HCA_SAMPLES_PER_SUBFRAME); + //memset(ch->temp, 0, sizeof(ch->temp[0]) * HCA_SAMPLES_PER_SUBFRAME); + //memset(ch->dct, 0, sizeof(ch->dct[0]) * HCA_SAMPLES_PER_SUBFRAME); memset(ch->imdct_previous, 0, sizeof(ch->imdct_previous[0]) * HCA_SAMPLES_PER_SUBFRAME); - memset(ch->wave, 0, sizeof(ch->wave[0][0]) * HCA_SUBFRAMES_PER_FRAME * HCA_SUBFRAMES_PER_FRAME); + //memset(ch->wave, 0, sizeof(ch->wave[0][0]) * HCA_SUBFRAMES_PER_FRAME * HCA_SUBFRAMES_PER_FRAME); } } -#endif //-------------------------------------------------- // Decode diff --git a/src/coding/hca_decoder.c b/src/coding/hca_decoder.c index 61c824fb..ab88ff33 100644 --- a/src/coding/hca_decoder.c +++ b/src/coding/hca_decoder.c @@ -123,6 +123,7 @@ void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do) { void reset_hca(hca_codec_data * data) { if (!data) return; + clHCA_DecodeReset(data->handle); data->current_block = 0; data->samples_filled = 0; data->samples_consumed = 0; @@ -152,15 +153,18 @@ void free_hca(hca_codec_data * data) { #define HCA_KEY_MAX_BLANK_FRAMES 15 /* ignored up to N blank frames (not uncommon to have ~10, if more something is off) */ #define HCA_KEY_MAX_TEST_FRAMES 10 /* 5~15 should be enough, but mostly silent or badly mastered files may need more */ -#define HCA_KEY_MAX_ACCEPTABLE_SCORE 300 /* unlikely to work correctly, 10~30 may be ok */ +#define HCA_KEY_MAX_ACCEPTABLE_SCORE 150 /* more is unlikely to work correctly, 10~30 isn't uncommon */ /* Test a number of frames if key decrypts correctly. - * Returns score: <0: error/wrong, 0: unknown/silent file, >0: good (the closest to 1 the better) */ + * Returns score: <0: error/wrong, 0: unknown/silent file, >0: good (the closest to 1 the better). */ int test_hca_key(hca_codec_data * data, unsigned long long keycode) { size_t test_frame = 0, current_frame = 0, blank_frames = 0; int total_score = 0; const unsigned int blockSize = data->info.blockSize; + /* Due to the potentially large number of keys this must be tuned for speed. + * Buffered IO seems fast enough (not very different reading a large block once vs frame by frame). + * clHCA_TestBlock could be optimized a bit more. */ clHCA_SetKey(data->handle, keycode); @@ -204,5 +208,6 @@ int test_hca_key(hca_codec_data * data, unsigned long long keycode) { total_score = 1; } + clHCA_DecodeReset(data->handle); return total_score; }