基于PDF文档结构的数字隐写
前言
前面看了PDF隐写,研究了一下是怎么回事,自己想实现一下,然后在网上也没看到有相应脚本,就花时间写了一下,也趁此做下记录。
PDF文档结构
PDF文件结构由四部分元素构成:文件头 文件体 交叉引用表 文件尾
文件头。指明了该文件所遵从的PDF规范的版本号,它出现在PDF文件的第一行。
文件体。PDF文件的主要部分﹐由一系列间接对象组成。这些间接对象描述了文档的各个组成部分﹐如字体、页面、实例图形等。各个间接对象间的层次关系构成了PDF的文档结构(即逻辑结构),其是一个树形结构,由目录(Catalog)、页树( page tree)、大纲树( outline tree)、线索树(Article thread)和名字树(Named Destination)组成。
交叉引用表。为了能对间接对象进行随机存取而设立的一个间接对象的地址索引表,包含了间接对象的偏移地址、产生号和是否在使用等信息。其对应着一个或者多个交叉引用节。
文件尾。说明了根对象(Catalog)的对象号和交叉引用表的偏移地址,另外还保存了PDF文件的加密等安全信息。
随便拿一个pdf文档,丢到010里面运行pdf模板就可以得到上述那样一个结果
而解析是应用程序从PDF文件的尾段开始访问的,其过程为:首先从文件尾所声明的交叉引用表的地址,找到交叉引用表;然后根据交叉引用表所提供的间接对象地址索引表,随机访问文件体中的间接对象。
算法原理
首先看下交叉引用节的格式
每个交叉引用节都以关键字“xref”开头,其后是若干个对象号在一个连续范围内的间接对象,每个间接对象都有相应的一行来指示该对象在文件中的位置等信息,每行大约有20个字节长,格式如下: nnnnnnnnnn ggggg n eol
,其中 nnnnnnnnnn
是地址偏移值,是一个10个数字的编号;ggggg
是由5个数字组成的生成编号;n表示该对象正在使用,若为f则表示已被删除并已闲置的对象;eol
是由2个字符组成的行末标识符,其是空白字符,不会显示输出。该标识符有两种组合方式:一个空格符和一个换行符,即\n
;或者是一个回车符和一个换行符,即\r\n
。
基于交叉引用表行末标识符的不唯一性,可将行末标识符作为水印嵌入点。首先将所有交叉引用表的行末标识符修改成统一的形式(\r\n
或者\r\n
),然后将水印信息编码成二进制数据流,根据水印二进制数据流逐个修改交叉引用表中的行末标识符(例如\r\n
代表水印数据“1”,\r\n
代表水印数据“0”),最终实现水印信息的嵌入。为了增强算法的安全性,在水印信息嵌入前,先对水印信息进行加密﹑编码等预处理。同时,为了提高算法的鲁棒性,可以采用循环嵌入的方法,向文档中重复嵌入水印信息。对图1的交叉引用表嵌入二进制比特流100110后,结果如图2所示(图中的行末标识符不会显示输出)。
实现程序(python)
写的有点烂。。
隐写程序
# -*- coding:utf-8 -*-#基于PDF文档结构的数字水印算法实现#author:xiangzikou#time 2022.12.06 11.37import redef str_2_bin(str):"""字符串转换为二进制"""return ' '.join([bin(ord(c)).replace('0b', '0') for c in str])if __name__ == '__main__':#隐写的内容secretmsg = 'yinxie_by_sjx's = str_2_bin(secretmsg).split(' ')#print(s)s = ''.join(s)#print(s)#隐写的pdf文件filename = '基于PDF文档结构的数字水印算法_钟征燕.pdf'#打开想隐写的pdf文档with open(filename,'rb') as f:with open('xiangzikou_'+filename,'wb') as f1:#读取比特流a = f.read()#print(a)#查找交叉引用表,把之前内容全部写入f1b = re.findall(b'([\s\S]*)xref[\s\S]*trailer',a)f1.write(b[0])#从交叉引用表内隐写b = re.findall(b'xref[\s\S]*trailer', a)c = b[0].split(b'\r\n')#判断隐写容量是否足够len1 = len(c)#len1 = 44len2 = len(s)#print(len1)#167#print(len2)#42assert len1-2 >= len2s = s+ '0'* (len1-len2-2)#print(s)#隐写c = [i.decode('utf-8') for i in c]#print(c)c[0] = c[0]+"\r\n"for i in range(1,len(s)+1):if s[i-1]=='0':c[i] = c[i] + "\r\n"else:c[i] = c[i] + "\n"#print(c)d = ''.join(c)e = bytes(d,'utf-8')#print(e)f1.write(e)#交叉表后面内容b = re.findall(b'xref[\s\S]*trailer([\s\S]*)', a)#print(b)f1.write(b[0])#re = re.findall(b'[f|n]\r\n',a)#print(re)f1.close()f.close()print("隐写内容:{}".format(secretmsg))print("隐写完成")
水印提取程序
# -*- coding:utf-8 -*-#基于PDF文档结构的数字水印算法实现#author:xiangzikou#time 2022.12.06 11.37import redef str_2_bin(str):"""字符串转换为二进制"""return ' '.join([bin(ord(c)).replace('0b', '') for c in str])if __name__ == '__main__':secretmsg = ''filename = 'xiangzikou_基于PDF文档结构的数字水印算法_钟征燕.pdf'#打开想隐写的pdf文档with open(filename,'rb') as f:#读取比特流a = f.read()#读取交叉引用表#b = re.findall(b'endobj\nxref[\s\S]*trailer', a)#c = re.findall(b'[f|n][0-9]{8}',b[0])b = re.findall(b'xref[\s\S]*trailer', a)#print(b)b = re.findall(b'\r?\n', b[0])b = b[2:]#print(b)c = [i.decode('utf-8') for i in b]for i in range(len(c)):if c[i]=='\r\n':c[i] = '0'else:c[i] = '1'#print(len(b))#将读取的二进制转化为字符串c = ''.join(c)#print(c)bb = re.findall(r'.{8}', c)str1 = ""for b in bb:str1 += chr(int(b, 2))print("隐写内容为:{}".format(str1))f.close()
ps:经过测试,发现程序有BUG,对于具有多个交叉引用表的pdf文档来说隐写有错误,其实就是re正则匹配的原因,匹配交叉引用表正则表达式改下机型,但是由于懒也就不修改了,有时间再说。。
也可参考个人博客查看此文章
基于PDF文档结构的数字隐写相关推荐
- 快速无损原样提取PDF文档中的图片
网上已经有很多提取PDF文档图片的工具了,但是这些工具要么就是非常庞大,要么就是速度很慢,要么就是导出的图片失真,我对这些工具均不满意,因此为PDF补丁丁开发了快速.无损地提取PDF文档图片的功能. ...
- pdf文档补丁,pdf编辑,去除pdf文件限制
哈喽,大家好!我是指北君. 在我们的日常生活中,PDF文档是我们除了Office外经常需要接触的文件格式.很多时候,我们都需要能对PDF文档进行一些处理,比如编辑文字.拆分/合并文档.生成书签.提取图 ...
- app canvas渲染后图片黑色_H5 基于 canvas 实现电子签名并生成PDF文档
(给前端大全加星标,提升前端技能) 转自:coyota666 https://juejin.cn/post/6901273585428463624 前言 电子签名通俗来说就是通过技术手段实现在电子文档 ...
- 破解打开证书加密的PDF文档-数字证书(电子书私钥)下载和导入教程
数字证书(电子书私钥)的导入方法-如何破解打开证书加密的PDF文档 请回复下载本证书,相关教程见压缩包内使用说明:文件解压密码:www.8cmd.com *** Hidden to visitors ...
- HTML5文档结构主体结构 语义结构,html5组织文档结构.pdf
html5组织文档结构 1 / 10 html5 组织文档结构 文档部分,即 body 部分,包含了访问者可以看到的内容.传统的 HTML 文档通常通过 div 元素来组织文档结构,再配 上适当的样式 ...
- 使用poi写入doc文档中文档打不开_基于NodeJS和浏览器的PDF文档引擎——PDFKit
介绍 PDFKit是一个用于Node和浏览器的PDF文档生成库,可以轻松创建复杂的多页面可打印文档.API包含可链接性,包括低级功能以及更高级功能的抽象.PDFKit API设计简单,因此生成复杂文档 ...
- 【Java】基于Pdfbox解析PDF文档中指定位置的文字和图片
1.1 PDFBOX介绍 Apache PDFBox是一个开源Java库,支持PDF文档的开发和转换. 我们可以使用PDFBox开发可以创建,转换和操作PDF文档的Java程序.PDFBox的主要功能 ...
- H5基于canvas实现电子签名并生成PDF文档
关注公众号 前端开发博客,回复"加群" 加入我们一起学习,天天进步 作者:coyota666 链接:https://juejin.cn/post/69012735854284636 ...
- 通过css类/选择器选取元素 文档结构和遍历 元素树的文档
通过css类选取元素 html所有的元素拥有class属性,该属性会对元素进行分组,标识为某一组. js中使用className属性来保存HTML的class的属性值 var NodeList = d ...
最新文章
- 初步了解mac下C源码的编译过程
- mysql能安装的版本下载失败_mysql 安装失败 每次都安装失败 每个版本都失败
- Linux:常用命令大全
- LeetCode 1147. 段式回文(贪心)
- RedHat Enterprise AS4安装步骤
- 数据表的查看 mysql
- python中的opencv读取数字_opencv+python 机读卡识别之试错(一)模板匹配的数字识别...
- 阿里云虚拟主机的使用,附幸运券领取
- c语言文件操作——复制文件
- 证明LDU分解的唯一性
- visio 生成mysql脚本_Visio2010建立ER图并直接导出为SQL语句
- 中兴ZXV10 B860AV1.1 全TTL操作完美破解
- 10年软件测试行业经验教你如何写简历【绝对靠谱】
- PAT考前准备篇:目标满分
- “互联网+”环境下高职毕业生求职风险应对策略
- 原型图都可以用什么软件做?分享这9款给你
- outlook邮箱邮件大小限制_outlook 附件大小限制
- Python计算空间二面角
- 为网页承载页面添加更多功能
- (笔记)数据结构--抽象数据类型的定义