Experimental fast ADX encryption cracker by furrybob at 1:43 PM EDT on May 29, 2017
I was recently asked by @bnmm about guessing keys for encrypted ADX files. Sadly, I knew nothing about ADX encryption at the time. Yesterday I remembered bnmm's comment, and decided to have a go at it, and here's the result.
Link Usage: VGAudioTools.exe CrackAdx <path to files>
Unlike GuessAdx, this operates on a folder of encrypted ADX files, with the goal of finding keys as quickly as possible, usually within 1-3 seconds.
Once a valid key is found, it will be used to decrypt, decode, and reencode all the ADX files in the folder, and the re-encoded file will be compared to the original. The closer to the original the re-encoded file is, the more likely the found key is correct.
I only implemented type 8 encryption cracking. I'll probably add type 9 soon.
@bnmm I haven't looked at that Japanese ADX cracker yet. I might take a look now that I've made one myself.
Instead of reimplementing some stuff in a separate program, I used my library, VGAudio, for reading, decoding, and encoding the audio. Just a note in case anyone wonders why the .exe is so large.
Whoops. I hadn't pushed the commits. Here's the code.
I take advantage of the fact that the scale of the first non-empty frame in the file is usually 1 or 2, so I try those first. Combined with the fact that the key's shared between dozens of files, you're pretty much guaranteed to find the key within couple seconds. They're practically giving away the seed value, and from there, the search space is small enough that brute forcing is no problem at all.
Neat stuff, we could also crosscheck old keys with it (though I tried God Hand and seemed it couldn't decide which key was best from 3).
What makes interesting the japanese decoder though, is that it supports (I believe -- I just checked the code) the original key format expected by the encoder/decoder. Ie.- seed/mult/add isn't really a key, but the result of deriving the original 16b key (let's call it keyphrase for a moment).
Type 8 and 9 derive seed/mult/add differently, but interestingly keyphrases seem shared between ADX and HCA (also 16b).
I think I could add this key format (for science) once I check the validity. It would be nice to key cracker would find these original keyphrases too. Maybe they can be re-derived from seed/mult/add too?
I researched type 9 encryption today, and I'm wondering what in the world the developers were thinking when they "improved" the encryption. It's no better than it was before, and quickly crackable. There are still only 0x2000^3, or 2^39, possible keys. The upper 3 bits of each part of the LCG values have no effect on the encryption.
@bnnm The official encoder uses what they call a "keycode" for the encryption key. This can be anything from 0 to u64_max.
Amusingly, those 2^64 possible keycodes only contain 2^39 unique keys for the purpose of ADX encryption. That means that about only 3/100,000,000 of the possible keyspace is used. To be fair, the upper ~21 bits of the keycode have no effect on the LCG values, which would result in 1/16 of the keyspace being unique.
Anyway, the conversion between the formats looks like this. Is that what's in the Japanese decoder? I still haven't looked at it.
Unfortunately, I haven't found any readily available type-9-encrypted ADX files except for some Sonic Runners SFX. The keycode for Sonic Runners is 19910623, or seed:0x0000 mult:0x1fbd inc:0x18b1
I think it's a lookup table of primes. guessadx uses this too but does a Sieve of Eratosthenes at runtime (see the readme for some discussion of that), and probably uses 3x as many as it needs to since this table only has the 0x400 first from 0x4000.
Those files for Gunhound aren't encrypted. I've pushed code that cracks type 9 ADX files. I realized today that the search space is 8x smaller than I thought, so cracking type 9 might be faster than cracking type 8 ATM.
Does anybody have any software that creates type-8 encrypted ADX files? The old adxencd only does version 3 ADX, and CriAtomEncoder only does type 9 encryption. There's some "adxfed.dll" for ADX encoding and decoding, but searching for it gets no results.
Edit: I spoke too soon. Found something by searching for adxtools
So Type 8 encryption is pretty much worthless now.
Using a stock i7-6700K to crack type 8 encryption using one file:
Worst case time when the first frame is not empty: ~450ms. Worst case time when the first frame is empty: ~5000ms. This is the time it takes to check every single possible (I'm pretty sure) key.
Average time when the first frame is not empty: ~10-100ms depending on the first frame's scale. Average time when the first frame is empty: ~10-400ms depending on the first frame's scale.
I reverse engineered the type 8 encryption from that ADXTools thing I downloaded. The seed, multiplier, and increment all have to come from a set of 1024 primes. That information allowed the search time to get so low, and I wouldn't be surprised if there are still ways to bring that time even lower.
Does or will this also allow getting the key for encrypted HCA files? I was trying the exe from the first post on a folder of HCA files from a mobile game and it was just counting to 4095 without any other visible effect. Thanks again!
could you decode this one sir? (HCA) just want to rip some BGM and AUDIO from this game.. title:fate grand order (Android) sample : https://my.pcloud.com/publink/show?code=XZJh6GZLJodIog2eqS1zfnXxAuyP0MvprMX
@furrybob - doing AHX stuff I noticed some AHX in the wild (Amagami) also have keyword encryption (type 08 in the header).
The algo seems a lot simpler, but enough to throw off decoders. It justs encrypts a few bits (6?) near the MPEG side info every new frame.
You wouldn't happen to know how this works? It's mostly used for voices but would be easy add to vgmstream (for science) once we know the algorithm. I think you have access to ahxencd.exe but I can upload samples and stuff.
Okay, here's how the encryption works. For the setup, you take your keystring and run the same process on it as you do with ADX to get 3 prime numbers. Assign these primes to the indexes 1, 2, and 3, and assign the number 0 to index 0.
For example, with the keystring "test": 0 - 0 1 - 0x5ced 2 - 0x4efb 3 - 0x5381
Now take the bitstream you want to encode, up to 18-bits, and read the first 2 bits. These bits correspond to the index of the number you'll use, as described above. We'll call this the key.
Take the next 2 bits from the bitstream, and take the two low bits from the key (i.e. bits 1 and 0). Xor these 2 values together, and put the resulting 2 bits in the output bitstream.
Again, take the next 2 bits from the bitstream, and now take bits 3 and 2 from the key. Xor them together and output the result.
Continue until you've encrypted all the bits you want to.
Awesome, thanks a lot! Worked like a charm. In Amagami the key is shared with ADX too ("mituba").
For AHX, the bitstream/index seems to start 103b into each frame (presumably some Layer II field), and somehow always uses index 2. AHX "for DC" encrypt the full 16b, while normal AHX 6b only (size of whatever field?).
Not exactly a mass-demanded feature, but I love little fun things like this.