pythonencryptionsteganography

Is it possible to encrypt integers?


So my program is a Stenography program, it inserts an image into another image, and I'm trying to encrypt the data before inserting it into the cover image. However, most encryption modules expect strings and I'm trying to pass integers.

I've tried converting to string then encrypting, but the encryption is full of special characters and letters so converting back to integer for insertion is impossible.

Anyone know if I can somehow encrypt an integer? It doesn't have to be very secure.

I'm trying to add the encryption in here:

for i in range(0,3):
    #verify we have reached the end of our hidden file
    if count >= len(Stringbits):
        #convert the bits to their rgb value and appened them
        for rgbValue in pixelList:
            pixelnumbers1 = int(''.join(str(b) for b in rgbValue), 2)
            #print pixelnumbers1
            rgb_Array.append(pixelnumbers1)
        pixels[x, y] = (rgb_Array[0], rgb_Array[1], rgb_Array[2])
        print "Completed"
        return imageObject.save(output)

I've been trying to encrypt pixelnumbers1 then add it in. But pixels[x, y] requires an integer.

Below is the rest of the code in-case:

def write(mainimage, secret, output):
    #string contains the header, data and length in binary
    Stringbits = dcimage.createString(secret)
    imageObject = Image.open(mainimage).convert('RGB')
    imageWidth, imageHeight = imageObject.size
    pixels = imageObject.load()
    rgbDecimal_Array = []
    rgb_Array = []
    count = 0

    #loop through each pixel
    for x in range (imageWidth):
        for y in range (imageHeight):
            r,g,b = pixels[x,y]
            #convert each pixel into an 8 bit representation
            redPixel = list(bin(r)[2:].zfill(8))
            greenPixel = list(bin(g)[2:].zfill(8))
            bluePixel = list(bin(b)[2:].zfill(8))
            pixelList = [redPixel, greenPixel, bluePixel]

            #for each of rgb
            for i in range(0,3):
                #verify we have reached the end of our hidden file
                if count >= len(Stringbits):
                    #convert the bits to their rgb value and appened them
                    for rgbValue in pixelList:
                        pixelnumbers1 = int(''.join(str(b) for b in rgbValue), 2)
                        #print pixelnumbers1
                        rgb_Array.append(pixelnumbers1)
                    pixels[x, y] = (rgb_Array[0], rgb_Array[1], rgb_Array[2])
                    print "Completed"
                    return imageObject.save(output)

                #If we haven't rached the end of the file, store a bit
                else:
                    pixelList[i][7] = Stringbits[count]
                    count+=1
            pixels[x, y] = dcimage.getPixel(pixelList)

Solution

  • You have a fundamental misunderstanding of how computers see any type of data.

    You read the bytestream of a file, which looks like a string to you, but each character is actually a byte, a value from 0 to 255. It just happens that some of them are represented by conventional string characters. Try print(bytes(range(256)) to see them all. Most standard encryption functions take a byte array in and spit a byte array out. It just happens that you get more of the bytes that don't have a "simple" representation. But they are not any less bytes than what you initially fed in.

    Your dcimage.py has the following:

    #get the file data in binary
    fileData = bytearray(open(secret, 'rb').read())#opens the binary file in read or write mode
    for bits in fileData:
        binDataString += bin(bits)[2:].zfill(8)#convert the file data to binary
    

    There is nothing that stops you from doing this

    fileData = open(secret, 'rb').read() # a bytes object by default
    encryptedData = myEncryptionFuction(fileData) # also a bytes object
    for bits in encryptedData:
        # ...
    

    VERY IMPORTANT: You add a null byte at the end of your message so your extracting sequence knows when to stop. If you compress, or encrypt, a string (or byte array), it is likely a null byte will be part of that stream, which will break your extraction sequence. In that case you want to use a header that tells your program ahead of time how many bits to extract.


    By the way, bytes are already in an integer form.

    >>> some_byte = b'G'
    >>> some_byte[0]
    71
    

    You're better of using bitwise operations for steganography. You take bytes and instead of using bitwise operations between them and your pixels, you turn both to binary strings, slice and stitch them and then turn them back to integers.

    def bytes_to_bits(stream):
        for byte in stream:
            for shift in range(7, -1, -1):
                yield (byte >> shift) & 0x01
    
    secret_bits = tuple(bytes_to_bits(encoded_data))
    
    # simplified for one colour plane
    for x in range(image_height):
        for y in range(image_width):
            # (pixel AND 254) OR bit - the first part zeroes out the lsb
            pixels[x,y] = (pixels[x,y] & 0xfe) | secret_bits[count]
            count += 1
    
    # -------------------------------------
    
    # to extract the bit from a stego pixel
    bit = pixel & 0x01