• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Advanced Data Encryption

Level 31
Joined
Jul 10, 2007
Messages
6,306
This tutorial uses http://www.hiveworkshop.com/forums/submissions-414/system-bigint-188973/.

This tutorial will cover advanced data encryption techniques that will make a code nearly impossible to crack while minimizing added data. This requires knowledge of http://www.hiveworkshop.com/forums/...s-280/data-encryption-save-load-codes-188790/ and http://www.hiveworkshop.com/forums/...ials-280/data-encryption-using-cipher-188801/.

The previous tutorial covered name based encryption using a cipher. There is a better way that doesn't involve any random encryption keys, thus minimizing the code. This method takes the same idea of a hash, but it converts it into base 8 and adds 1 to each digit.

192821551->1337434457->2448545568

From here, store the digits into a collection specific to the player as before
{2,4,4,8,5,4,5,5,6,8}

The above key can be used for shuffling the code up bit by bit. Starting from the left most binary digit, shuffle through by swapping the current digit with the a digit at an offset where the offset is the current digit in the base.

Code:
WHILE still shuffling
    RESET curDigit to left most digit
    SET swapper to left most digit on player collection (this case 2)
    WHILE curDIgit not pointer
        IF swapper is back at the pointer, reset it to left most digit
        SET secondSwapper to curDigit-swapper
        WHILE secondSwapper < 0 add numSize+1 to it
        SWAP swapper and secondSwapper digits
        SET curDigit to previous digit
        SET swapper to previous digit (this case 4)
    END WHILE
END WHILE

Essentially, given 123456 (normally binary, but showing in radix so it can easily be seen), a shuffle using the current key would do-

{2,4,4,8,5,4,5,5,6,8}
123456

Code:
digit = 1
swapper = 2
second swapper = 3
swap 1,3
321456

digit = 2
swapper = 4
second swapper = 6
swap 2,6
361452

digit = 1
swapper = 4
second swapper = 3
swap 1,3
163452

digit = 4
swapper = 8
second swapper = 2
swap 4,2
163254

digit = 5
swapper = 5
second swapper = 2
swapp 2,5
163524

digit = 4
swapper = 4
second swapper = 5
swap 4,5
163425

123456->163425

N number of shuffles can be performed. Obviously binary numbers shuffle much more nicely as they have a much higher amount of digits. The bigger the number, the more different it is per shuffle.

Because these shuffles are based on the player name, a code will not work unless it is used by the player that originally typed it.

Keep in mind that shuffles will require a 1 be added in front of the number to protect against shuffling 0s in front.

When using checksums-
123456
1+2+3+4+5+6=21->21*10+2->212+1=213
123456213

Shuffling (especially in binary) will mess up the code even more, making it near impossible to modify.

Using this technique and a checksum method that Dr_Super_Good suggested, I ended up with this output in base 36 (notice I only modified one of the values by 1 each time!)

Code:
Original Code: 13D
Code after checksum: 5FLQl
Code after scramble: C461C

Original Code: 13F
Code after checksum: 5FVQX
Code after scramble: F8L2Z

Original Code: 13E
Code after checksum: 5FQQQ
Code after scramble: GB98Q

As can be seen, the code does change quite a bit after the checksum
Code:
5FLQl
5FVQX
5FQQQ

But it changes drastically with scrambling
Code:
C461C
F8L2Z
GB98Q

And notice that in most cases, adding 1 bit to the value (required to employ scrambling) will not increase the length of the code.

Another test case
Code:
13D (1417) (original)
YUAV6XZ (75842836199) (checksum + encoder id)
1XNRU30N (151635456455) (scrambled)

13E (1418) (original)
YV67KAA (75895481458) (checksum + encoder id)
39GX3C2U  (255706575078) (scrambled)

13F (1419) (original)
YW31XML (75950646141) (checksum + encoder id)
2J4FY2K0 (198355841136) (scrambled)

Comparisons

Actual Values
Code:
1417
1418 (dif of 1)
1419 (dif of 1)

After checksum and encoder id
Code:
75842836199
75895481458 (notice bigger) (dif of 52645259)
75950646141 (notice bigger) (dif of 55164683) (dif of 2519424)

After scramble
Code:
151635456455
255706575078 (dif of 104071118623)
198355841136 (dif of -57350733942) (dif of -161421852565)

To unshuffle a number, the shuffles must be looped through first to determine which numbers were swapped last, then the thing is done completely in reverse. If shuffling a large perhaps 200 digit binary number 32-64 times, the player's will have no chance of ever cracking the code. Yes, they can still use code gen, but shuffling protects a code without adding anything to the size. It also makes each code unique to each player.

If wanting to really generate a unique shuffle key, then don't use string hash but rather convert the player name into a very large integer: http://www.asciitable.com/

Given only certain characters can be used in a player name, the numbers will be smaller.

Convert the very large number to base 8 and add 1 to each digit.
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
This tutorial will cover advanced data encryption techniques that will make a code nearly impossible to crack while minimizing added data.

A far simpler approach is to just generate a checksum via abusing the stringhash of stored values converet to strings in some custom itterative calculation. As no players and few programmers know how the string hash native computes its value, you will generate a code that is equally unbreakable even if you leave the encoded values stored in human friendly form (like level number showing in decimal).

Do remember that no mater how encrypted or whatever a code is, the safety comes down to how many code permitations are invalid (eg failed checksum or nonsense values). It is technically possible that a person can guess a totally valid code through trial and error but using 8 bits for a checksum and having all loaded values valid, you would have a 1 in 256 chance of getting a working code. Ofcourse adding restrictions on value domain and more bits to the checksum can very easilly bring the chance of guessing a working code to the impracticle level and thus pointless to do.

The advantage of mapping data to fixed bit width however is good for minimizing code length.

The encryption and the method I described above are still easilly broken via hacking the save script itself. A more obscure code generation system is needed to discourage that.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Well, the problem with having the checksum only in one place is that the checksum can be easily modified. I've cracked many a code in a few minutes because the code's were static sizes and the checksums were always at the right side of the digit. When I increased a value by an amount, I increased the checksum by an amount. However, I couldn't crack a code in a couple of minutes if it were shuffled as the bits representing the checksum would be all over the place and modifying one character would potentially modify 7 different values. Also, the shuffling only costs 1 bit, a bit I'd gladly pay ^_^. In most cases, that won't increase the code size at all.

Furthermore, 1 value change could potentially change the way the entire code looked. Random encryption keys seem cool because the code changes with each save, but this accomplishes the same thing with 1 bit. Furthermore, you can't center in on the values within the code as they are shuffled (1 bit change in a value may change the 5th char while 3 bit changes might change chars 2, 4, and 6). These seemingly random changes will make the code pretty impossible to crack unless you know that it was shuffled and how many shuffles were performed ;P.

Also, I believe StringHash will hash any string the same way in any map ;|. It always seems to output the same values for the strings (if it were like regular hashing, this entire theory would fail as the hash values might be different from game to game, meaning the thing couldn't be unshuffled).

The only other problem is protecting against cnping into an unauthorized map... hmm

They'd have to know all of the current object ids and what not as well as have identical arrays, but /sad face.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
When I increased a value by an amount, I increased the checksum by an amount.

Too bad this does not help with the checksum method I described as it cascades down values (changing 1 value changes the checksum massivly). Only unsafe checksums are prone to that ease of cracking (eg one which sums all the values in the code). In the case of save/load a checksum is more than a damage prevension system, it is meant to be hard to compute.

Also, I believe StringHash will hash any string the same way in any map ;|. It always seems to output the same values for the strings (if it were like regular hashing, this entire theory would fail as the hash values might be different from game to game, meaning the thing couldn't be unshuffled).
The same string will hash to the same value inbetween game sessions. String hashes are case insensitive so "END" and "end" hash to the same number (great for name security). The idea is for each value to turn the checksum into a string and hash it and add it to the old checksum. This means a small change will make a huge alteration to the checksum. Ofcourse you wrap it to the desired size via a modula opperation.

This is what my save/load system I made in a few hours used. I do admit that some form of scrambeling would probably be better than non scrambeling but to me the output code seemed immume to easy modification which was prety good for something I made in a few hours (so I could understand save/load systems better).

Ofcourse if you used a better checksum generation process, it becomes even harder to crack as ultimatly you want the relationship between code values and checksum to be completly random (Yes it is reversable, but there is no coleration between values and the produced checksum).
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
I suppose, but scrambling does cost almost nothing ^_^.

Your stuff with the checksums is actually pretty cool, maybe you should make a secure checksum tutorial?

I'm actually going to be writing this method as its own sort of system. In the center I'll have a buffer than merges the integers together (final write converts the entire thing to binary). Then you can perform encryptions on the buffer and finally read the buffer. This means people can use any form of protection that they want.
 
Top