如何从 PNG 图像中获取像素数据以进行 gpg 签名?

How to get pixel data from a PNG image for the purpose of gpg signing it?

我想对 PNG 图像中的像素数据进行 gpg 签名。后来,我希望能够 gpg --verify 找到像素数据上的签名,以了解图像的作者,并且自签名后它没有改变。

动机

我正在开发一个系统,该系统允许日后验证和归因于 PNG 图像的完整性(参见不可否认性)。我在 Python 工作。理想情况下,我希望附加信息不会妨碍任何用户照常阅读图像。

图像中重要的是什么?在我的应用程序中,只有像素数据很重要。我需要将这些数据转化为 gpg --sign 接受的形式,这相当于序列化一个 Python 对象。未来验证未被篡改的图像的签名的能力依赖于序列化(pickle.dumps、cPickle.dumps)产生相同的输出,比如从现在起 5 年。

为什么不使用 gpg --sign 对文件进行签名?将像素数据的签名粘贴回同一图像的元数据中可保持签名 1. 附加和 2. 有效。图片到哪里,签名就到哪里(除了任何可能会删除它的过分热心的软件)。

下面的例子是 运行 in ipython.

为 PNG 图片签名。

# The PNG image to sign.
f = 'image.png'

# Read pixel data from a PNG image.
from pillow import Image
serialized = Image.open(f).tobytes(encoder_name='raw')

open('serialized.txt').write(pixel_data)

# Sign the data with gpg using the default private key.
!gpg --sign --detach --armor --output sig.asc serialized.txt
# <enter gpg passphrase as required>

# Write the signature to the PNG image's metadata using Image Magick.
import subprocess
subprocess.call(['mogrify', '-set', 'gpgsig', open('sig.asc').read()])

# Verify it got added using Image Magick.
!identify -verbose image.png

很久以后,尝试验证签名

# Many, many moons go by, and you find a PNG image in the wild.
# It looks familiar, but its provenance and integrity are unknown.
# But lo! it includes a gpg signature in its metadata.
# You want to verify the signature (which may have been signed
# by yourself or anybody else whose gpg public key you have
# access to) to ensure the image is unchanged.

# Read the pixel data, same as before.
from pillow import Image
serialized = Image.open(f).tobytes(encoder_name='raw')

open('serialized.txt').write(serialized)

# Get the included signature.  This may be done
# programmatically, but for the sake of simplicity,
# just use Image Magick.
!identify -verbose image.png

# Save the signature to sig.txt.

# Attempt to verify the detached signature
!gpg --verify sig.txt serialized.txt

我想我会在内存中使用 pycrypto 对其进行哈希签名并签名。序列化是不必要的额外步骤。

编辑:这是之前的Q/A:

Signing and verifying data using pycrypto (RSA)

阅读下面的评论后编辑两个:

我相信 PIL tostring() 函数只是将像素数据转储到一个字符串中,例如它是预序列化的。所以如果你真的想使用外部程序,也许你可以简单地将这个字符串输出到一个文件。