ToaHartor / GI-cutscenes

A command line program playing with the cutscenes files (USM) from Genshin Impact.
GNU General Public License v3.0
659 stars 73 forks source link

Saving decrypted HCA #71

Open wh665o opened 1 year ago

wh665o commented 1 year ago

Hi I was trying to output the unconverted decrypted HCA. I see there is a part in HCA.cs about saving decrypted HCA to the disk but I've had no luck getting this segment to work.

ToaHartor commented 1 year ago

So if I understood well, you want to only decrypt the HCA file without converting it into a wav file right ? For the method, the Mask() function does the decryption on a data block, then the block checksum has to be made since the block content changed. Of course the decrypted header has to be written before the data. To know if it's decrypted, you can see the header fields (fmt, comp written in raw if you open the file in a HEX viewer/editor.) If I recall correctly, the Decrypt() function you might have seen has some missing parts, and I don't think it actually writes the decrypted header to the file as well.

wh665o commented 1 year ago

Yes, I was wanting to only decrypt the HCA file without converting it into a wav file. What I had tried was this:

//FileStream filePointer = File.OpenRead(_filename);
string decryptedFile = Path.Combine(outputDir, _filename[..^4] + "_decrypted.hca");

byte[] content = new byte[_hcaHeader.blockSize * _hcaHeader.blockCount];
byte[] buf = new byte[_hcaHeader.blockSize];
if (_hcaHeader.ciphType != 0)
{
    for (uint i = 0, offset = 0; i < _hcaHeader.blockCount; i++, offset += _hcaHeader.blockSize)
    {
        Array.Copy(_data, offset, buf, 0, _hcaHeader.blockSize);
        //filePointer.Seek(offset, SeekOrigin.Begin);
        //filePointer.Read(buf, 0, _hcaHeader.blockSize);
        Mask(ref buf, _hcaHeader.blockSize);
        //DecodeBlock(ref buf);
        BitConverter.GetBytes(Tools.Bswap(CheckSum(buf, _hcaHeader.blockSize - 2))).CopyTo(buf, _hcaHeader.blockSize - 2);
        Array.Copy(buf, 0, content, offset, _hcaHeader.blockSize);
    }
}

File.WriteAllBytes(decryptedFile, this._header.Concat(content).ToArray());
Console.WriteLine("File written : " + decryptedFile);
return Task.CompletedTask;

And although the header does get decrypted, the audio is still not playable. Any ideas what I'm missing/have done wrong?

ToaHartor commented 1 year ago

Sorry, I'm replying a bit late, but with which player are you trying to play the file ?

wh665o commented 1 year ago

I'm using foobar2000 and can play unencrypted HCA files from other games and also some encrypted ones included in vgmstream.