Search code examples
pythonencryptionxor

Image encryption IndexError: list index out of range


I am using a double strength XOR encryption to encrypt a bytearray of an image and than rewrite the array into the image file. When I use small numbers for the encryption keys this works great and the file is unreadable until it's run through the code with the same keys, decrypting it. However, I want to use 256-bit keys for protection and anytime I generate these keys and attempt the XOR my function exception runs and I get an index overflow error like this- IndexError: list index out of range

I assume the encrypted bytes are too big for the image file, any way I can fix this?

#Encryption/decryption keys
key1 = random.randrange(1, 115792089237316195423570985008687907852837564279074904382605163141518161494336)
key2 = random.randrange(1, 115792089237316195423570985008687907852837564279074904382605163141518161494336)
#In the extraordinarily rare case that both keys are equal regenerate key2
while(key1 == key2):
    key2 = random.randrange(1, 115792089237316195423570985008687907852837564279074904382605163141518161494336)

def secureImg(name):
    try:
        #Path to image
        path = name+".jpg"    
        #Open file to read
        file = open(path, "rb")          
        #Storing image data
        image = file.read()
        file.close()       
        #Converting image into byte array to perform encryption on numeric data
        image = bytearray(image)     
        #Performing XOR operation on each value of bytearray
        for index, values in enumerate(image):
            image[index] = (values ^ key1) ^ key2     
        #Opening file to write
        file = open(path, "wb")          
        #Writing encrypted data in image
        file.write(image)
        file.close()            
    except Exception:
        print("Img error caught: ", Exception.__name__)

Solution

  • Main issues:

    1. Xor is not aligned on chunks. single byte from image is being xored with a potentially very long number - the result is unlikely to be one byte.
    2. Xor is a commutative operation. There is no reason to use two keys - it is the same as using one, key1 ^ key2.
    3. Images tend to have a lot of predictable bytes in the header, which makes possible to reconstruct the key

    Smaller items: use context managers (with ...), don't blanket try-catch, etc.

    So, ignoring all conceptual issues it'd be something like:

    from itertools import repeat
    import os
    
    KEY_SIZE = 1024
    
    key = os.urandom(KEY_SIZE)
    
    
    def bogus_encrypt(name):
        path = name+".jpg"
        with open(path, 'rb') as fh:
            # generally, bad idea; better limit to reasonable increments, few Kb to Mb
            raw_data = fh.read()
    
        encrypted_data = b''.join(a^b for a, b in zip(raw_data, repeat(key)))
    
        with open(path, 'wb') as fh:
            fh.write(encrypted_data)