【发布时间】:2022-06-10 17:48:04
【问题描述】:
我有一个相当简单的挑战,至少一开始看起来是这样。我选择了 python 来做这个。
我有多个 PDF 文件,我必须检测其数字签名(如果存在或根本不存在)并从中获取一些详细信息(如果存在)。例如,在我的 PDF 文件中,在签名上,总是有签名人的电子邮件地址。没有电子邮件的签名将是例外情况。
我的设想是,我应该能够找到文档中的所有签名对象并将它们放入数组或列表中,然后检查它们的详细信息。这可能吗?如何找到它们?
我在网上能找到的所有内容都与验证签名或签署 PDF 文件有关,虽然这很重要,但我不需要。
编辑
我现在已经设法在我的 PDF 文件中找到签名并获取其内容。但是,我现在确实在努力解码内容。
当前查找签名的解决方案只是暂时的,因为我必须使用签名对象的索引来定位它。不同的 PDF 文档的签名索引会有不同的索引。但是类型是“Sig”,因此可以实现某种循环来检查对象类型,如果它是“Sig”,那么您已经找到了一个签名对象。稍后我将使用最终脚本编辑我的帖子。
签名内容类型为pdfreader.types.native.HexString。我相信如果我设法解码字符串,我将能够获得我正在寻找的数据。我一直在尝试将其更改为字节,然后从字节解码为 utf-8 或 ascii,但如果是 UTF-8,我会收到错误 'utf-8' codec can't decode byte 0x82 in position 1: invalid start byte,如果是 ascii,我会收到错误 'ascii' codec can't decode byte 0x82 in position 1: ordinal not in range(128)
任何解决方法将不胜感激。
解决方案
正如我在 cmets 中指出的那样,正如我开始怀疑的那样,签名的“内容”不会包含我需要的任何属性。我注意到,当输出签名时,我在控制台中的输出不完整(可能是因为我在 Visual Studio 中使用了调试控制台)并且数字签名有更多属性。我发现,对于我的签名,电子邮件位于“名称”属性下。现在唯一的挑战是找出我的 PDF 文件中有多少对象。为此,我使用了字符串操作。我发现最后一个预告片有一个带有对象数量的“大小”属性。我没有设法在 PDFTrailer 对象中找到它,因此是字符串操作。如果有其他方法,很高兴分享。请原谅最后在对象循环中的try-catch,更好的是在读取对象之前检查对象是否存在并且它有一个类型。不要复制它并制定适当的解决方案。
from pdfreader import PDFDocument
filename = r"<filepath.pdf>"
fd = open(filename, "rb")
doc = PDFDocument(fd)
pdf_content = str(fd.read())
nr_of_obj = 0
nr_of_signatures = 0
signature_names = [] #in my case - emails
s_trailer = 'trailer'
s_startxref = 'startxref'
# +/- 2 at the end for new line character before and after the trailer
#Finding where last trailer of the document starts and ends
last_trailer_start = pdf_content.rfind(s_trailer)+len(s_trailer)+2
last_trailer_end = pdf_content.rfind(s_startxref)-2
#Putting the trailer together
trailer = ""
for i in range(last_trailer_start, last_trailer_end):
trailer += pdf_content[i]
#Split the trailer attributes. Locate and read Size
trailer = trailer.split('/')
for attribute in trailer:
if attribute.find('Size') >= 0:
nr_of_obj = int(attribute.replace('Size','').strip())
break
#Use the size to loop through objects. All the objects will not exist and not all will have Types. Hence try-catch.
for i in range(1, nr_of_obj):
try:
raw_obj = doc.locate_object(i,0)
obj = doc.build(raw_obj)
if obj.Type == 'Sig':
nr_of_signatures +=1
signature_names.append(obj.Name)
except:
continue
print(nr_of_signatures)
print(signature_names)
【问题讨论】:
-
“在 PDF 文件的签名上,总是有签名人的电子邮件地址。” - 不,不是这样。
-
@mkl 对不起,我的意思是在我的情况下总是有一封电子邮件
-
没有样本(如果它的变量格式)这对我来说不容易猜到,但是可以使用命令行工具来解压pdf格式,这样如果签名部分可以扩展,那么电子邮件的文本部分将更容易看到。我会尝试 Qpdf 及其文本编辑变体,看看是否适合您qpdf.readthedocs.io/en/stable/qdf.html
-
"签名内容类型是
pdfreader.types.native.HexString。我相信如果我能够解码字符串,我就能得到我正在寻找的数据。我'一直在尝试将其更改为字节,然后从字节解码为 utf-8 或 ascii..." - 内容不是 text 字符串,它是 包含 PKCS#7/CMS 签名容器的二进制字符串。
标签: python pdf digital-signature