kabili207 / zora-sharp

A decoder for the password system used in the Legend of Zelda Oracle of Ages and Oracle of Seasons games.
GNU Lesser General Public License v3.0
48 stars 22 forks source link

Cipher generation used for encoding secrets is wrong #2

Closed kabili207 closed 9 years ago

kabili207 commented 10 years ago

The XOR logic for cipher generation as described by 39ster only works for about 25% of game IDs. I suspect there is a simpler formula used that I am currently overlooking.

M1CR0H4CK3R commented 10 years ago

I didn't think all Game IDs were valid.

Edit by kabili: Publishing someone's personal contact info probably isn't a good idea.

Sorry. Did you at least get it down somewhere? I would have emailed it to you if I knew your email address. :/

kabili207 commented 10 years ago

Valid games IDs range from 1 to 32767. In 39ster's attempt at deciphering the code, which I've linked above (post #4), he identified the following formula for calculating the cipher byte: ID bit 0 XOR ID bit 8 = Cipher start byte bit 0 ID bit 1 XOR ID bit 9 = Cipher start byte bit 1 ID bit 2 XOR ID bit 10 = Cipher start byte bit 2

Unfortunately, this only works for a very limited subset of game IDs. For example, all odd Game IDs will fail to generate a matching cipher.

twrightsman commented 10 years ago

On the second page of 39ster's post he decodes someone's game ID that is odd, so how is the cipher formula wrong for all odd game ID's?

kabili207 commented 10 years ago

Decoding the secrets will work for any valid code. The first three bits, the cipher key, is all that's needed. You don't need the XOR formula, or even the game ID, to decode the secret. The game ID plays no part in the actual decoding process, it's just part of the message.

The problem is trying to encode the secrets. The formula above does not work when trying to create the cipher key. The cipher key is only 3 bits, whereas the game ID is 15 bits. For a single game ID there are a huge number of XOR formulas that will create a working cipher key. But not all of those formulas will work for other games IDs. 39ster was lucky enough to find a formula that worked for his original test cases.

twrightsman commented 10 years ago

Thanks for the explanation, I'll see what I can do to work out a formula. One thing that I don't understand is what decimal value the {space} stands for. There are 65 characters on the input screen including the space. I've never seen a code with a space; so is the space just not considered a character? If so, it must be only there to fill in for the lack of lowercase 'l', which may be confused with the number 1.

kabili207 commented 10 years ago

The space is indeed not considered a character. It's only used for alignment purposes.

There are some notes in doc folder of the source code that I've gathered from the gamefaqs posts and my own findings, if you think it would be helpful.

kabili207 commented 10 years ago

I've noticed a pattern with the memory secrets (first three bits are the RAW values, everything else is decoded). The second bit in the cipher always seems to be 1 for Ages, and 0 for Seasons. There's also a noticeable pattern in the checksum at the end (assuming you decode it). I get the impression that the cipher byte also plays a role in determining what kind of secret is being used.

twrightsman commented 10 years ago

If the cipher byte plays a role in determining secret type, that would imply each secret type can only start with a few types of characters and seasons and ages have different characters that can start the code. I'll keep working on the checksum, I've been playing my linked ages game trying to get a new set of all 8 secrets, I'll post those to my git repo.

kabili207 commented 10 years ago

It's possible that a value indicating the secret type is used in an AND, OR, or XOR operation against the Game ID, rather than being used directly. Or perhaps the Game IDs I used for my memory secrets just happened to generate ciphers with the same pattern by coincidence.

We also still have to identify what the unknown value at the beginning of the secrets are used for.

kabili207 commented 10 years ago

On another note, bit two in the first byte may not be the RingOrGame bit as 39ster originally thought. Someone sent me some test data that causes this bit to be the inverse of the expected value (0 instead of 1 for game secrets).

Hero: Link ID: 20839 Child: Garen Behavior: BouncyE Friend: Dimitri

twrightsman commented 10 years ago

I am thinking the manual way of discovering the checksum and cipher byte generation algorithms is becoming tedious. I have restarted school again and time is limited, I'll see if I can write a script to test multiple variations of algorithms automatically with a given data set.

So my next goal before the script would be to collect data (all secrets) from the Internet to get a large enough and varied enough sample set. I don't want to use Paulygon's program since it might not be 100% accurate.

kabili207 commented 10 years ago

I've been in a similar situation since I started working on this. The vast majority of what I've worked on has been done over my vacation time from work.

I'll see about gathering up my secrets and sending them your way.

kabili207 commented 10 years ago

I just noticed the following text on Paulygon's website: "the password engine for both games is nearly identical, which simplified things quite a bit."

I'm very curious what's different about the two algorithms.

twrightsman commented 10 years ago

What would be cool is if the former dev team would be willing/allowed to discuss the password system, if only it was easy to contact developers from behind the corporate barrier.

twrightsman commented 9 years ago

Created a google form in order to collect secrets from various forums:

https://docs.google.com/forms/d/1HsF1bFkzCEEPn6QDyQ82FG1O2Qkip2QvILrCkbi9G1k/viewform

Let me know what you think and I'll start posting it around to get responses.

kabili207 commented 9 years ago

That looks good to me, though you'll want to add the Hero's Secret as well. Do we want to add the other half of the memory secrets? Paulygon's program never generated them, but they would still be useful to know how to encode/decode them.

Also, can you provide a link to the responses spreadsheet?

twrightsman commented 9 years ago

https://docs.google.com/spreadsheets/d/1nql5s9nSazISf4UUls8hL3r9S1pmNFGuIVJ7jAgnVQY Can you verify you can copy/paste the spreadsheet? Also, the hero secrets are in the form now. And yes, I would like to collect all the secrets in order to have varied data in order to help crack the code completely.

kabili207 commented 9 years ago

I can copy text from it, but I can't edit it. That's not really an issue as far as I'm concerned. I only care about reading the data. We'll want to change the Hero's Secrets to read "from" instead of "to" since they can be entered in either game.

twrightsman commented 9 years ago

Alright, form should be good now.

LunarCookies commented 9 years ago

Cipher key generation for game and ring secrets works as follows:

id = (MSB) XXXXXXX YYYYYYYY (LSB)

ZZZZZghi = XXXXXXXX + YYYYYYYY

key = ihg

Basically you add the two bytes that conform the id, then pick the three LSB of that sum result byte and reverse their order, that's the key.

For memory secrets the key generation is a bit more convoluted.

kabili207 commented 9 years ago

I'm working on rewriting the logic that encodes and decodes the secrets. I'll update the key generation and validation once I'm finished with my cleanup.

LunarCookies commented 9 years ago

Cipher key generation for memory secrets:

id = (MSB) XXXXXXXX YYYYYYYY (LSB)
memoryID = (MSB) WWWt (LSB)

gm = 0x01 //For AGES NEW
gm = 0x02 //For AGES LINKED
gm = 0x03 //For SEASONS NEW
gm = 0x00 //For SEASONS LINKED

ZZZZZghi = XXXXXXX + YYYYYYYY + 00000tgm

key = ihg

This generation is almost the same, you only have to add a third byte to the sum. This byte depends on the memoryID, the game and the mode.

kabili207 commented 9 years ago

Your cipher logic seems to work as far as I can tell. I'd consider this issue resolved.