现在电子签章主要针对pdf文件,所以如果要验签,那么必须要熟悉pdf文件结构。Pdf文件知识点较多,仅pdf标准文档就已经到第7版了,最后一个版本就有800+页,学习起来难度相对较大,但如果仅仅是为了验签,那么看完本文即可满足主要需求,然后根据需要有目的去标准中查询相关知识点。
需要注意的是:本文的文档结构是我自己总结的,与标准中说法不一致。从验签的角度来理解是可以的,但是做pdf文件相关的编程,请参考pdf标准。
1、pdf文件结构
Pdf文档基本上是由文件头、文件体、交叉引用表、trailer等。如下图:
文件体是由一系列的x 0 obj。。。endobj数据组成简介对象组成。简介对象并不一定是按对象号大小顺序排列的。如果出现相同编号的简介对象,以后出现的简介对象为准。
Trailer中定义了交叉表的起始位置。
交叉引用表是pdf文件中重要的部分。它保存了所有简介对象在pdf文件中的物理偏移地址以及简介对象是否可用。交叉引用表可能有多个。
通常,交叉引用表具有以下形式:
交叉引用表通常以xref开始,其中0 4表示对象号以0开始的连续4个对象,其中对象号0和3表示的对象不存在或不可用。对象号1和2表示的对象正常使用中。以下是实际pdf中的一个交叉引用表:
那么一个pdf文件中的交叉引用表是在什么地方呢?通常文件尾部以startxref开头的部分定义了交叉表位置,比如包含上述交叉引用表的pdf文件尾部:
那么交叉引用表的起始位置就是303961,十六进制表示的位置是0x4a359,正好和上述截图位置相符(xref的起始位置)。
2、pdf文件的增量更新
增量更新提供了一种更新pdf文件而又无需完全重写的方法。更改将附加到文件尾部,保留原始内容:
增量更新的次数没有限制。所以一个pdf文件中可能会存在多个交叉引用表。判断是否又多个交叉引用表的简单方法就是查找是否有多个”%%EOF”
3、Pdf文件签章验签
增量更新方法为pdf签章提供了方便。具体pdf签章参考pdfref-7规范的8.7章节(大概是第725页)。简单的说,pdf签章信息一定存在一个简介对象中,这个对象既包含/content,它包含了签章结构体的十六进制字符串,也包含/byteRange,它定义了这个签章信息针对的pdf文件的那些内容(物理位置)。同样的多个签章一定会多个类似的简介对象。所以pdf签章验签就是找到这些简介对象,然后对这个简介对象中的签章结构体按照国标要求进行验签即可。
pdf简介对象列举:https://github.com/paulsoncheng/PDFSpy
或github中搜索mupdf。