Skip to content

Commit

Permalink
Updated HCA decryption (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
hozuki committed Oct 17, 2018
1 parent d8c8a3e commit 0b8ad79
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 40 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ A quick example, from [hca2wav](src/apps/hca2wav/hca2wav.cpp):

int main() {
cgss::CHcaDecoderConfig decoderConfig;
// Currently only signed 16-bit is available.
decoderConfig.decodeFunc = cgss::CDefaultWaveGenerator::Decode16BitS;
decoderConfig.waveHeaderEnabled = TRUE;
decoderConfig.cipherConfig.keyParts.key1 = 0x12345678;
Expand Down
27 changes: 19 additions & 8 deletions src/apps/hca2wav/hca2wav.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ using namespace std;

void PrintHelp();

uint32_t hex_alpha_to_uint(const char *a);
template<typename T>
T hex_alpha_to_integer(const char *a);

int main(int argc, const char *argv[]) {
int argc0;
Expand Down Expand Up @@ -47,8 +48,12 @@ int main(int argc, const char *argv[]) {
pKey2 = g_CgssKey2;

if (argc0 >= 5) {
pKey1 = hex_alpha_to_uint(argv0[3]);
pKey2 = hex_alpha_to_uint(argv0[4]);
pKey1 = hex_alpha_to_integer<uint32_t>(argv0[3]);
pKey2 = hex_alpha_to_integer<uint32_t>(argv0[4]);
}

if (argc0 >= 6) {
decoderConfig.cipherConfig.keyModifier = hex_alpha_to_integer<uint16_t>(argv0[5]);
}

// Go!
Expand All @@ -60,8 +65,10 @@ int main(int argc, const char *argv[]) {
uint32_t read = 1;
static const uint32_t bufferSize = 1024;
uint8_t buffer[bufferSize];

while (read > 0) {
read = hcaDecoder.Read(buffer, bufferSize, 0, bufferSize);

if (read > 0) {
fileOut.Write(buffer, bufferSize, 0, read);
}
Expand Down Expand Up @@ -92,16 +99,18 @@ void PrintHelp() {
k2 = g_CgssKey2;
cout << "hca2wav: Utility for decoding HCA to wave audio\n\n"
<< "Usage:\n"
<< " hca2wav <in file> <out file> [<decode key 1 = " << hex << k1 << "> <decode key 2 = " << hex << k2 << ">]\n"
<< " hca2wav <in file> <out file> [<decode key 1 = " << hex << k1 << "> <decode key 2 = " << hex << k2 << ">] [<keymod>]\n"
<< "Example:\n"
<< " hca2wav C:\\input.hca C:\\output.wav 12345678 90abcdef"
<< " hca2wav C:\\input.hca C:\\output.wav 12345678 90abcdef a1b2"
<< endl;
}

uint32_t hex_alpha_to_uint(const char *a) {
uint32_t val = 0;
template<typename T>
T hex_alpha_to_integer(const char *a) {
T val = 0;
auto i = 0;
while (a && *a && i < (sizeof(uint32_t) / sizeof(uint8_t) * 2)) {

while (a && *a && i < (sizeof(T) / sizeof(uint8_t) * 2)) {
if ('0' <= *a && *a <= '9') {
val = (val << 4u) + (*a - '0');
} else if ('a' <= *a && *a <= 'f') {
Expand All @@ -111,8 +120,10 @@ uint32_t hex_alpha_to_uint(const char *a) {
} else {
break;
}

++i;
++a;
}

return val;
}
2 changes: 2 additions & 0 deletions src/lib/cdata/HCA_CIPHER_CONFIG.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ typedef struct _HCA_CIPHER_CONFIG {

CGSS_HCA_CIPHER_TYPE cipherType;

uint16_t keyModifier;

} HCA_CIPHER_CONFIG;

#pragma pack(pop)
42 changes: 29 additions & 13 deletions src/lib/ichinose/CAcbFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ CAcbFile::CAcbFile(cgss::IStream *stream, const char *fileName)
: MyClass(stream, 0, fileName) {
}

const uint32_t CAcbFile::KEY_MODIFIER_ENABLED_VERSION = 0x01300000;

CAcbFile::CAcbFile(IStream *stream, uint64_t streamOffset, const char *fileName)
: MyBase(stream, streamOffset) {
_internalAwb = nullptr;
Expand All @@ -43,6 +45,8 @@ CAcbFile::~CAcbFile() {
void CAcbFile::Initialize() {
MyBase::Initialize();

GetFieldValueAsNumber(this, 0, "Version", &_formatVersion);

InitializeAcbTables();
InitializeCueNameToWaveformTable();
InitializeAwbArchives();
Expand All @@ -57,9 +61,12 @@ void CAcbFile::InitializeAcbTables() {

_cues.reserve(cueCount);

uint64_t refItemOffset = 0;
uint32_t refItemSize = 0, refCorrection = 0;
CBinaryReader reader(GetStream());
uint64_t
refItemOffset = 0;
uint32_t
refItemSize = 0, refCorrection = 0;
CBinaryReader
reader(GetStream());

for (uint32_t i = 0; i < cueCount; ++i) {
ACB_CUE_RECORD cue = {0};
Expand Down Expand Up @@ -93,7 +100,7 @@ void CAcbFile::InitializeAcbTables() {
cue.waveformIndex = reader.PeekUInt16BE(refItemOffset + refCorrection);

uint8_t
isStreaming;
isStreaming;
auto hasIsStreaming = GetFieldValueAsNumber(waveformTable, cue.waveformIndex, "Streaming", &isStreaming);

if (hasIsStreaming) {
Expand All @@ -116,7 +123,7 @@ void CAcbFile::InitializeAcbTables() {
}

uint8_t
encodeType;
encodeType;
if (GetFieldValueAsNumber(waveformTable, cue.waveformIndex, "EncodeType", &encodeType)) {
cue.encodeType = encodeType;
}
Expand Down Expand Up @@ -162,12 +169,14 @@ void CAcbFile::InitializeCueNameToWaveformTable() {
}

void CAcbFile::InitializeAwbArchives() {
uint32_t internalAwbSize;
uint32_t
internalAwbSize;
if (GetFieldSize(0, "AwbFile", &internalAwbSize) && internalAwbSize > 0) {
_internalAwb = GetInternalAwb();
}

uint32_t externalAwbSize;
uint32_t
externalAwbSize;
if (GetFieldSize(0, "StreamAwbAfs2Header", &externalAwbSize) && externalAwbSize > 0) {
_externalAwb = GetExternalAwb();
}
Expand All @@ -192,13 +201,15 @@ CUtfTable *CAcbFile::GetTable(const char *tableName) {
}

CUtfTable *CAcbFile::ResolveTable(const char *tableName) {
uint64_t tableOffset;
uint64_t
tableOffset;

if (!GetFieldOffset(0, tableName, &tableOffset)) {
return nullptr;
}

uint32_t tableSize;
uint32_t
tableSize;

if (!GetFieldSize(0, tableName, &tableSize)) {
return nullptr;
Expand All @@ -210,7 +221,8 @@ CUtfTable *CAcbFile::ResolveTable(const char *tableName) {
}

CAfs2Archive *CAcbFile::GetInternalAwb() {
uint64_t internalAwbOffset;
uint64_t
internalAwbOffset;

if (!GetFieldOffset(0, "AwbFile", &internalAwbOffset)) {
return nullptr;
Expand All @@ -231,7 +243,7 @@ const std::vector<std::string> &CAcbFile::GetFileNames() const {
}

IStream *CAcbFile::OpenDataStream(const char *fileName) {
IStream *result = nullptr;
IStream * result = nullptr;

for (auto &cue : _cues) {
if (strcmp(cue.cueName, fileName) == 0) {
Expand All @@ -248,7 +260,7 @@ IStream *CAcbFile::OpenDataStream(uint32_t cueId) {

sprintf(tempFileName, "cue #%u", cueId);

IStream *result = nullptr;
IStream * result = nullptr;

for (auto &cue : _cues) {
if (cue.cueId == cueId) {
Expand All @@ -265,7 +277,7 @@ IStream *CAcbFile::GetDataStreamFromCueInfo(const ACB_CUE_RECORD &cue, const cha
return nullptr;
}

IStream *result;
IStream * result;

if (cue.isStreaming) {
auto externalAwb = _externalAwb;
Expand Down Expand Up @@ -316,6 +328,10 @@ std::string CAcbFile::GetSymbolicFileNameFromCueId(uint32_t cueId) {
return std::string(buffer);
}

uint32_t CAcbFile::GetFormatVersion() const {
return _formatVersion;
}

static std::string GetExtensionForEncodeType(uint8_t encodeType) {
auto type = static_cast<CGSS_ACB_WAVEFORM_ENCODE_TYPE>(encodeType);

Expand Down
6 changes: 6 additions & 0 deletions src/lib/ichinose/CAcbFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ CGSS_NS_BEGIN

void Initialize() override;

uint32_t GetFormatVersion() const;

static const uint32_t KEY_MODIFIER_ENABLED_VERSION;

private:

void InitializeAcbTables();
Expand Down Expand Up @@ -66,6 +70,8 @@ CGSS_NS_BEGIN
std::map<std::string, CUtfTable *> _tables;
std::map<std::string, uint16_t> _cueNameToWaveform;

uint32_t _formatVersion;

const char *_fileName;

};
Expand Down
7 changes: 6 additions & 1 deletion src/lib/ichinose/CAfs2Archive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ void CAfs2Archive::Initialize() {
}

auto byteAlignment = reader.PeekUInt32LE(offset + 12);
_byteAlignment = byteAlignment;
_byteAlignment = byteAlignment & 0xffff;
_hcaKeyModifier = static_cast<uint16_t>(byteAlignment >> 16);

auto version = reader.PeekUInt32LE(offset + 4);
_version = version;
Expand Down Expand Up @@ -113,3 +114,7 @@ uint32_t CAfs2Archive::GetVersion() const {
uint32_t CAfs2Archive::GetByteAlignment() const {
return _byteAlignment;
}

uint16_t CAfs2Archive::GetHcaKeyModifier() const {
return _hcaKeyModifier;
}
3 changes: 3 additions & 0 deletions src/lib/ichinose/CAfs2Archive.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ CGSS_NS_BEGIN

uint32_t GetVersion() const;

uint16_t GetHcaKeyModifier() const;

private:

void Initialize();
Expand All @@ -38,6 +40,7 @@ CGSS_NS_BEGIN
std::map<uint32_t, AFS2_FILE_RECORD> _files;

uint32_t _byteAlignment;
uint16_t _hcaKeyModifier;
uint32_t _version;

};
Expand Down
10 changes: 5 additions & 5 deletions src/lib/kawashima/hca/CDefaultWaveGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ CGSS_NS_BEGIN

public:

static uint32_t Decode8BitU(float data, uint8_t *buffer, const uint32_t cursor);
static uint32_t Decode8BitU(float data, uint8_t *buffer, uint32_t cursor);

static uint32_t Decode16BitS(float data, uint8_t *buffer, const uint32_t cursor);
static uint32_t Decode16BitS(float data, uint8_t *buffer, uint32_t cursor);

static uint32_t Decode24BitS(float data, uint8_t *buffer, const uint32_t cursor);
static uint32_t Decode24BitS(float data, uint8_t *buffer, uint32_t cursor);

static uint32_t Decode32BitS(float data, uint8_t *buffer, const uint32_t cursor);
static uint32_t Decode32BitS(float data, uint8_t *buffer, uint32_t cursor);

static uint32_t DecodeFloat(float data, uint8_t *buffer, const uint32_t cursor);
static uint32_t DecodeFloat(float data, uint8_t *buffer, uint32_t cursor);

PURE_STATIC(CDefaultWaveGenerator);

Expand Down
53 changes: 46 additions & 7 deletions src/lib/kawashima/hca/CHcaCipherConfig.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,63 @@
#include "CHcaCipherConfig.h"

static void TransformKey(uint32_t key1, uint32_t key2, uint16_t mod, uint32_t *pk1, uint32_t *pk2) {
auto key = (uint64_t)key1 << 32 | key2;
auto k2 = ((uint64_t)mod << 16 | (uint16_t)(~mod + 2));

auto newKey = key * k2;

if (pk1) {
*pk1 = (uint32_t)(newKey >> 32);
}

if (pk2) {
*pk2 = (uint32_t)(newKey & 0xffffffff);
}
}

CGSS_NS_BEGIN

CHcaCipherConfig::CHcaCipherConfig() {
CHcaCipherConfig::CHcaCipherConfig()
: MyBase() {
memset(this, 0, sizeof(CHcaCipherConfig));
}

CHcaCipherConfig::CHcaCipherConfig(HcaCipherType cipherType) {
CHcaCipherConfig::CHcaCipherConfig(HcaCipherType cipherType)
: MyClass() {
keyParts.key1 = keyParts.key2 = 0;
if (cipherType == HcaCipherType::WithKey) {
cipherType = HcaCipherType::NoCipher;
}
this->cipherType = static_cast<CGSS_HCA_CIPHER_TYPE>(cipherType);
}

CHcaCipherConfig::CHcaCipherConfig(uint32_t key1, uint32_t key2) {
CHcaCipherConfig::CHcaCipherConfig(uint32_t key1, uint32_t key2)
: MyClass() {
Initialize(key1, key2);
}

CHcaCipherConfig::CHcaCipherConfig(uint64_t key)
: MyClass((uint32_t)(key >> 32), (uint32_t)(key & 0xffffffff)) {
}

CHcaCipherConfig::CHcaCipherConfig(uint32_t key1, uint32_t key2, uint16_t keyModifier)
: MyClass() {
if ((key1 == 0 && key2 == 0) || keyModifier == 0) {
Initialize(key1, key2);
} else {
uint32_t newKey1, newKey2;

TransformKey(key1, key2, keyModifier, &newKey1, &newKey2);

Initialize(newKey1, newKey2);
}
}

CHcaCipherConfig::CHcaCipherConfig(uint64_t key, uint16_t keyModifier)
: MyClass((uint32_t)(key >> 32), (uint32_t)(key & 0xffffffff), keyModifier) {
}

void CHcaCipherConfig::Initialize(uint32_t key1, uint32_t key2) {
if (key1 == 0 && key2 == 0) {
cipherType = static_cast<CGSS_HCA_CIPHER_TYPE>(HcaCipherType::NoCipher);
} else {
Expand All @@ -24,8 +67,4 @@ CGSS_NS_BEGIN
keyParts.key2 = key2;
}

CHcaCipherConfig::CHcaCipherConfig(uint64_t key)
: CHcaCipherConfig((uint32_t)(key >> 32), (uint32_t)(key & 0xffffffff)) {
}

CGSS_NS_END
Loading

0 comments on commit 0b8ad79

Please sign in to comment.