0

I'm using the pycryptodome module and its AES functionality to encrypt some data. However I need to generate a key for the AEScipher that I can later retrieve. The project stores all private data (including keys) in the form of an image. Basically we use an array of pixels and create the image using PIL and retrieve the pixel_list using the getdata() function.

To create the image:-

array = numpy.array(pixels, dtype = numpy.uint8)
new_image = Image.fromarray(array)
new_image.save('user_key.png')

Note that pixels is a list of list of tuples of integers [[(...), (...)], [(...), (...)], ...] and this is the object that carries keys To get keys from the image:-

im = Image.open(image_path)
return list(im.getdata())

Now I'm not able to directly store the AES key, assuming I generate it with Random.get_random_bytes(AES.key_size) from the Crypto module.

How can I generate a cryptographically secure key but also retrieve it by using one of the keys in pixels, as in a tuple of integers?

Edit:-

To elaborate, the pixels object is a list of list of tuples of integers, each tuple contains 3 integers and each integer can range from 0 to 255. The 0th index of the pixels object may look like this- [(69, 147, 245), (120, 212, 198), ...] The key_list object I'm referring to is actually list(im.getdata()). This is a list of tuples of integers, each tuple contains 3 integers and each integer can range from 0 to 255. This looks like this- [(69, 147, 245), (120, 212, 198)....] Hence, the 0th index of key_list will be (69, 147, 245)

I need to store the AES key on par with these values. I'd ideally like to store the AES key as a tuple of 3 integers ranging from 0 to 255. So yes, I need to convert the AES key into a tuple and then store it in pixels.

One more key detail, the tuples contain 3 integers because they represent the RGB values respectively to create the image. I believe the tuple can be made with 4 integers as well to represent RGBA values. So that will solve the multiple of 3 problem.

But there's another problem. Each tuple in pixels is actually generated through [i for i in itertools.product(range(256), repeat=3)]. In order to generate a tuple of 4 integers instead of 3 I'll have to change repeat=3 to repeat=4, this will raise MemoryError.

4

1 回答 1

2

Here's a function that can be used to divide the values in a byte string up into tuples of a specified size. The byte string is first printed out as list of integers, followed by the list of tuples corresponding to that. Note how in the example the last two values of the final tuple when it's divided by 3 have been filled-in with zero since the byte string length (16) isn't a multiple of that. That doesn't happen when dividing it up into tuples of size 4 (so no fill-values were appended).

Also note that the grouper() function below is a slightly different implementation of the recipe by the same name in the itertools documentation.

from itertools import zip_longest

def grouper(n, iterable, fillvalue=None):
    "s -> (s0, s1...sn-1), (sn, sn+1...s2n-1), (s2n, s2n+1...s3n-1), ..."
    return zip_longest(*[iter(iterable)]*n, fillvalue=fillvalue)

aes_key = b'\x80in\xbe\x06b\x8f\x8fZ}l-\xb4j\xb5\x1f'

ints = list(aes_key)
print(ints)

tuples = list(grouper(3, aes_key, fillvalue=0))
print(tuples)

tuples = list(grouper(4, aes_key, fillvalue=0))
print(tuples)

Output:

[128, 105, 110, 190, 6, 98, 143, 143, 90, 125, 108, 45, 180, 106, 181, 31]
[(128, 105, 110), (190, 6, 98), (143, 143, 90), (125, 108, 45), (180, 106, 181), (31, 0, 0)]
[(128, 105, 110, 190), (6, 98, 143, 143), (90, 125, 108, 45), (180, 106, 181, 31)]

Since it appears you want to make an image out of this data, you likely will still need to format that data further depending on what the number of pixels there are in each row of the image.

You can convert a list of tuples back into a byte string like this:

# To convert a list of tuples back into a byte string.
from itertools import chain
print(bytes(chain.from_iterable(tuples)))

Output:

b'\x80in\xbe\x06b\x8f\x8fZ}l-\xb4j\xb5\x1f'

However this will only be the same as the original byte string if no fill values were added (as was the case using 4-tuples).

于 2019-12-12T10:10:50.463 回答