Home > Blockchain >  How shuffle and then unshuffle a bytearray, given a key as seed
How shuffle and then unshuffle a bytearray, given a key as seed

Time:10-18

I am trying to create an encryption system, and for that I will be taking a bytearray, and I intend to use a

random.Random(seed).shuffle(bytearray)

function to encrypt the information.

I'm having trouble reversing this process for the deencryption, i tried something like (didnt work) :

random.Random(1/seed).shuffle(encryptedbytearray)

Is there anyway to do this?

CodePudding user response:

You need to use the same seed to shuffle indexes so that you can backtrack the original positions. (enumerate will allow you to avoid sorting that mapping)

import random

def encrypt(decrypted,seed=4):
    encrypted = decrypted.copy()
    random.Random(seed).shuffle(encrypted)
    return encrypted

def decrypt(encrypted,seed=4):
    decrypted = encrypted.copy()
    indexes   = list(range(len(encrypted)))
    random.Random(seed).shuffle(indexes)
    for e,d in enumerate(indexes):
        decrypted[d] = encrypted[e]
    return decrypted

Sample run (using list of characters but it will work for bytearrays or any other type of lists):

clearText = list('ABCDE')

encryptedText = encrypt(clearText)
print(encryptedText)
['D', 'E', 'A', 'C', 'B']

decryptedText = decrypt(encryptedText)
print(decryptedText)
['A', 'B', 'C', 'D', 'E']

If you want the functions to work "in place" directly on the array (instead of returning a value), you can writ them like this:

def encrypt(decrypted,seed=4):
    random.Random(seed).shuffle(encrypted)

def decrypt(encrypted,seed=4):
    before   = encrypted.copy()
    indexes  = list(range(len(encrypted)))
    random.Random(seed).shuffle(indexes)
    for e,d in enumerate(indexes):
        encrypted[d] = before[e]

CodePudding user response:

Shuffle a sorted range, so that we can match the shuffled indicies to the unshuffled indicies.

x = list(range(len(s)))
random.Random(seed).shuffle(x)

For a seed of 12345, this produces [14, 15, 12, 3, 24, 16, 7, 22, 10, 2, 19, 4, 20, 17, 1, 21, 5, 25, 18, 8, 6, 11, 9, 0, 23, 13]. This indicates that the value in the 0th index in the shuffled list is actually in the 14th index of the unshuffled list, the 1st index is actually the 15th unshuffled, etc.

Then match each shuffled index to the shuffled value, and then sort (based on the index) back into their unshuffled positions.

unshuffled = bytearray(c for i, c in sorted(zip(x,s)))
print(unshuffled)

Full example:

import random
# Setup
s = bytearray(b"abcdefghijklmnopqrstuvxwyz")
seed = 12345
random.Random(seed).shuffle(s)

# shuffle a sorted range, so that we can match the shuffled indicies to the unshuffled indicies
x = list(range(len(s)))
random.Random(seed).shuffle(x)

# match each shuffled index to the shuffled value, and then sort (based on the index) back into their unshuffled positions
unshuffled = bytearray(c for i, c in sorted(zip(x,s)))
print(unshuffled)

The process detailed above should work for any shuffled sequence (eg. lists), not just bytearrays.

Here is a more detailed explanation of this process on crypto.se with a lot more math involved.

  • Related