从加密图像创建jpg/png

3
我希望能够转换/显示一个AES256非对称加密的图像,即使它看起来像垃圾。我在SO上读过许多关于删除头信息然后重新附加头信息的建议,这样即使图像看起来怪异,它仍然可以显示出来。
这样做的目的是为了查看是否可能对使用已知公钥加密的图像数据集执行图像分类。如果我有一张猫的图片并且使用完全相同的密钥进行加密,则结果通常会是可重现的,并且会产生某种方式等价于原始图像的图像。
抱歉没有提供代码,我不想通过自己的想法影响讨论,以便从您这些可爱的人那里获得正确的批评 - 我会说我不是加密专家,因此在此寻求建议。

1
只是一些笔记。"非对称"加密不适用,因为非对称加密仅适用于少量数据(因此使用对称加密如AES)。其次:在CBC模式下运行加密(例如AES)并使用随机初始化向量将提供一个“随机”的输出,并且每次运行加密时会有所不同,因此没有“可重复性”。 - Michael Fehr
第三点:您可以搜索“ECB Penguin”,并找到“差劲”加密的示例 - 这些示例在AES ECB模式下运行,并剥离BMP图像的头部,例如(免责声明,它是用德语、Java语言编写的,我是作者)http://javacrypto.bplaced.net/g01-ecb-pinguin/。 - Michael Fehr
嗨,Michael,谢谢你的帮助 - 我想测试的是是否可以在进行端到端加密的同时仍然允许对恶意内容进行分类。我已经阅读了各种科学论文,似乎如果你知道密钥,那么你可以使用相同的方法加密每个图像。 - Mrk Fldig
这就是加密数据的“问题”,如果它们是恶意的,你无法根据加密内容进行分类。只有知道秘钥(这就是为什么它被称为秘密...)的人才能够进行加密和解密。 - Michael Fehr
很抱歉,您错了。我不想解密它,我想显示加密版本,并且希望以同样的方式加密其他图像。因此,似乎需要IV和公钥来执行“相同”的加密。然而,我的问题是如何以加密形式显示加密图像? - Mrk Fldig
2个回答

5

有许多选项,但我建议按照以下指南进行:

  • 加密图像数据,而不是图像文件。
    如果图像是100x100x3字节,则加密30000字节(例如不加密img.jpg文件)。
    (缺点是元数据不保存为加密图像的一部分)。
  • 使用无损图像文件格式存储加密图像(例如PNG文件格式,而不是JPEG格式)。
    有损格式(如JPEG)将无法恢复。
  • 将加密图像的分辨率设置为输入图像的相同分辨率。
    这样您就不需要存储图像头 - 分辨率已保存。
    您可能需要添加填充,以使字节数为32的倍数。

希望你懂Python...

以下是演示编码和解码过程的Python代码示例:

import cv2
import numpy as np
from Crypto.Cipher import AES

# https://stackoverflow.com/questions/61240967/image-encryption-using-aes-in-python
key = b'Sixteen byte key'
iv = b'0000000000000000'

# Read image to NumPy array - array shape is (300, 451, 3)
img = cv2.imread('chelsea.png')

# Pad zero rows in case number of bytes is not a multiple of 16 (just an example - there are many options for padding)
if img.size % 16 > 0:
    row = img.shape[0]
    pad = 16 - (row % 16)  # Number of rows to pad (4 rows)
    img = np.pad(img, ((0, pad), (0, 0), (0, 0)))  # Pad rows at the bottom  - new shape is (304, 451, 3) - 411312 bytes.
    img[-1, -1, 0] = pad  # Store the pad value in the last element

img_bytes = img.tobytes()  # Convert NumPy array to sequence of bytes (411312 bytes)
enc_img_bytes = AES.new(key, AES.MODE_CBC, iv).encrypt(img_bytes)  # Encrypt the array of bytes.

# Convert the encrypted buffer to NumPy array and reshape to the shape of the padded image (304, 451, 3)
enc_img = np.frombuffer(enc_img_bytes, np.uint8).reshape(img.shape)

# Save the image - Save in PNG format because PNG is lossless (JPEG format is not going to work).
cv2.imwrite('enctypted_chelsea.png', enc_img)



# Decrypt:
################################################################################
key = b'Sixteen byte key'
iv = b'0000000000000000'

enc_img = cv2.imread('enctypted_chelsea.png')

dec_img_bytes = AES.new(key, AES.MODE_CBC, iv).decrypt(enc_img.tobytes())

dec_img = np.frombuffer(dec_img_bytes, np.uint8).reshape(enc_img.shape)  # The shape of the encrypted and decrypted image is the same (304, 451, 3)

pad = int(dec_img[-1, -1, 0])  # Get the stored padding value

dec_img = dec_img[0:-pad, :, :].copy()  # Remove the padding rows, new shape is (300, 451, 3)

# Show the decoded image
cv2.imshow('dec_img', dec_img)
cv2.waitKey()
cv2.destroyAllWindows()

加密图像:
输入图像描述这里

解密图像:
输入图像描述这里


识别加密图像的思路:

  • 计算加密图像的哈希值,并将其与原始图像、密钥和IV一起存储在数据库中。
  • 当您有加密图像时,计算哈希值,并在数据库中搜索。

1
我想提出一点建议:使用像AES这样的块密码在CBC模式下需要16字节的倍数 - 这是AES块大小。为了识别任何文件 - 为什么我们不应该计算整个文件的哈希值(仅获取图像数据将需要针对每种图像格式(例如JPG,BMP,PNG,TIFF ...)编写自己的函数? - Michael Fehr
做得好,Rotem,非常感谢,标记为正确。 - Mrk Fldig
我们使用Python来处理所有的机器学习相关工作,所以没有问题。现在我们正准备测试你的代码,如果能够成功运行,那将是一件非常特别的事情。 - Mrk Fldig

3
我将使用一个答案,虽然它不是一个答案,因为我想展示两张图片来进行演示。
这两张图片都来自我的博客文章http://javacrypto.bplaced.net/g01-ecb-pinguin/(德语)。
第一张图片展示了使用AES在ECB模式下加密后的Tuc企鹅:

Tuc penguin after AES ECB encryption

表单仍然存在,你可以“想象”出显示的动物是什么。
第二张图片使用AES CBC模式加密,输出看起来像垃圾:

Tuc penguin after AES CBC encryption

结论:如果图片使用类似于CBC、CTR或GCM的模式进行加密,即使您知道使用的模式、密钥和初始化向量,您也将始终得到类似于第二幅图片的结果。
很抱歉,视觉比较无法奏效。
回答您在评论中的问题“如何以加密形式显示加密图像”:您无法显示它们,因为通常情况下,图片有一个标题也会被加密,所以这些信息将丢失。这两张“加密”的图片是通过在加密之前剥离头部,然后加密图片数据,最后再添加头部创建的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接