I make no claim to this info, nor do I understand it, nor do I take responsibility for its use. As linked, I got this from a reddit post about the company and copy/pasted it into Obsidian so I'd have it. The code blocks are as close to the original as I cared to fiddle with. This is all greek to me but there are Python scripts linked, which may help you generate a key that works to register EV. Good luck!
Note: I had to split this into multiple posts cause it was not wanting to post the entire thing in one reply.
Ambrosia and Registration (Site)
Now that Ambrosia is gone, new registrations are no longer possible, and due to their expiring codes, using legitimate license keys has become difficult. We may hope to see a few of their games revived in the future but at present, only the original releases are available. Perhaps this case study on Ambrosia's registration algorithms will be useful to some.
The Old System
In their earliest days, ASW didn't require registration, but they eventually began locking core features away behind codes. All of their classic titles use the original algorithm by Andrew Welch.
Given a licensee name, number of copies, and game name, the code generator runs through two loops. The first loop iterates over each letter of the capitalized licensee name, adding the ASCII representation of that letter with the number of copies and then rotating the resulting bits. The second loop repeats that operation, only using the game's name instead of the license holder's name.
Beginning with Mars Rising, later games added a step to these loops: XOR the current code with the common hex string $DEADBEEF. However, the rest of the algorithm remained essentially unchanged.
The resulting 32 bits are converted into a text registration code by adding the ASCII offset of $41 to each hex digit. This maps the 32-bit string into 8 characters, but due to the limit of a hex digit to only encode 16 values, codes only contain letters from the first 16 of the alphabet.
The following chart shows an example using a well-known hacked code for Slithereens.
Iteration 1 ('A' in ANONYMOUS)
Name: Anonymous Code = $0 + $41
Number: 100 (hex: $64) -> << 6 ... -> Code = $FD53 FFA0
Game: Slithereens + $64
^ $DEAD BEEF
>> 1
Add $41 to each digit: Registration
-> $41 + $F = $50 = P -> Reverse string -> ------------
$41 + $D = $4E = N | AKPPDFNP |
... ------------
Here is a Python implementation of the v1 system: aswreg_v1.py
Once you have the bit-string module installed via sudo pip install bitstring
, you can test the output yourself with python aswreg_v1.py "Anonymous" 100 "Slithereens"
.
The New System
As Ambrosia's Matt Slot explains, the old system continued to allow a lot of piracy, so in the early 2000's they decided to switch to a more challenging registration system. This new method was based on polynomial hashing and included a timestamp so that codes could be expired and renewed. Ambrosia now had better control over code distribution, but they assumed their renewal server would never be shut down...
They also took more aggressive steps to reduce key sharing. The registration app checks against a list of blacklisted codes, and if found to be using one, the number of licenses is internally perturbed so that subsequent calculations fail. To combat tampering, your own information can get locally blacklisted in a similar manner if too many failed attempts occur, at least until the license file is deleted. Furthermore, the app attempts to verify the system time via a remote time server to minimize registration by changing the computer's clock.
You can disable the internet connection, set the clock back, and enter codes. There's also a renewal bot for EV: Nova. But let us look at the algorithm more closely.
64-bit Codes
The first noticeable difference is that registration codes in v2 are now 12 digits, containing both letters and numbers. This is due to a move from a 32-bit internal code to a 64-bit one. Rather than add an ASCII offset to hex digits, every letter or number in a new registration code has a direct mapping to a chunk of 5 bits. Using 5 bits per digit supports up to 32 values, or almost all letters of the alphabet and digits up to 9 (O, I, 0, and 1 were excluded given their visual similarities).
The resulting 64 bits (really only 60 because the upper 4 are unused: 12 digits * 5 bits each = 60) are a combination of two other hashes XOR'd together. This is a notable change from v1 because it only used the registration code to verify against the hashing algorithm. Only the licensee name, number of copies, and game name were really used. In v2, the registration code is itself a hash which contains important information like a code's timestamp.
Two Hashes
To extract such information from the registration code, we must reverse the XOR operation and split out the two hashes which were combined. Fortunately, XOR is reversible, and we can compute one of the hashes. The first hash, which I'll call the userkey, is actually quite similar to v1's algorithm. It loops through the licensee name, adding the ASCII value, number of copies, and shifting bits. This is repeated with the game name. An important change is including multiplication by a factor based on the string size.
The second hash, which I'll call the basekey, is the secret sauce of v2; it's what you pay Ambrosia to generate when registering a product. It is not computed by the registration app, but there are several properties by which it must be validated.
The chart below visualizes the relationships among the various hashes, using the well-known "Barbara Kloeppel" code for EV: Nova.