如何将字节字符串转换为元组列表?

How to convert a byte string into a list of tuples?

我正在使用 pycryptodome 模块及其 AES 功能来加密一些数据。但是,我需要为以后可以检索的 AEScipher 生成一个密钥。该项目以图像的形式存储所有私有数据(包括密钥)。基本上我们使用像素数组并使用 PIL 创建图像并使用 getdata() 函数检索 pixel_list。

创建图像:-

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

请注意,pixels 是一个 整数元组列表列表 [[(...), (...)], [(...), (...)], ...],这是携带键的对象 从图像中获取密钥:-

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

现在我无法直接存储 AES key,假设我使用 Random.get_random_bytes(AES.key_size) 从 Crypto 模块生成它。

如何生成加密安全密钥,同时使用 pixels 中的其中一个密钥检索它,就像在整数元组中一样?

编辑:-

具体来说,像素对象是一个整数元组列表列表,每个元组包含3个整数,每个整数的范围是0到255。像素对象的第0个索引可能看起来像这样- [(69, 147, 245), (120, 212, 198), ...] 我指的 key_list 对象实际上是 list(im.getdata())。这是一个整数元组列表,每个元组包含 3 个整数,每个整数的范围从 0 到 255。这看起来像这样- [(69, 147, 245), (120, 212, 198)....] 因此,key_list 的第 0 个索引将是 (69, 147, 245)

我需要存储与这些值相同的 AES 密钥。理想情况下,我希望将 AES 密钥存储为 0 到 255 之间的 3 个整数的元组。所以是的,我需要将 AES 密钥转换为元组,然后将其存储在 pixels.

还有一个关键细节,元组包含 3 个整数,因为它们分别代表创建图像的 RGB 值。我相信元组也可以用 4 个整数来表示 RGBA 值。这样就解决了 3 的倍数问题。

但是还有一个问题。 pixels中的每个元组实际上都是通过[i for i in itertools.product(range(256), repeat=3)]生成的。为了生成一个包含 4 个整数而不是 3 个整数的元组,我必须将 repeat=3 更改为 repeat=4,这将引发 MemoryError。

这是一个函数,可用于将字节字符串中的值划分为指定大小的元组。字节字符串首先作为整数列表打印出来,然后是与之对应的元组列表。请注意示例中最终元组除以 3 时的最后两个值是如何用零填充的,因为字节字符串长度 (16) 不是它的倍数。将它分成大小为 4 的元组时不会发生这种情况(因此没有附加填充值)。

另请注意,下面的 grouper() 函数与 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)

输出:

[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)]

既然您想用这些数据制作图像,您可能仍需要进一步格式化该数据,具体取决于图像每行中的像素数。

您可以像这样将元组列表转换回字节字符串:

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

输出:

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

但是,如果没有添加填充值(就像使用 4 元组的情况一样),这只会与原始字节字符串相同。