文档库 最新最全的文档下载
当前位置:文档库 › PDF加密

PDF加密

PDF加密
PDF加密

0 几个关键词的说明

PDF加密有两个口令即:Owner(to set the pdf document Permission or change the permission) Password和User Password,在本文中翻译为主(权限)口令和用户口令,我觉得权限口令更好,因此就称作权限口令。

文件加密后会生成一个新的对象,encryption dictionaries Object,本文中以加密字典对象来说明。

其中加密字典对象中的项称为加密字典对象项。

另外文中能以中文来说明的尽量以中文来说明,如果一些关键的英文词没有很好的中文对应词我们还是保留原来的英文说法。

1 几个常见的PDF安全问题

最近经常有人问到几个问题,是关于PDF加解密的,如果你对PDF规范比较熟悉,那么有可能会觉得这这几个问题很简单甚至有些傻。但几乎每个人都会有这么一个阶段,总是从无知到有知,再到无知,…,一个个轮回。

在文章的最开始我把问题给提出来,然后作一个简单的回答,如果觉得这有助于你对PDF加解密的认识,那我会非常开心的。

如果你需要对PDF加密解密有更深入地了解和学习,那么可以继续关注系列文章。当然这些文章的大部分内容你都可以从PDF规范里面找到,在这里,我只是以我个人的理解帮助大家可以更快地理解和应用。

2问:PDF有那些加密算法?

PDF文件采用的加密算法目前在用的有两种,RC4和AES。

PDF的早期版本是通过RC4加密算法对内容进行加密的,加密的长度为(40-128位)而从PDF1.6起,引入了AES加密算法(128位),对应的阅读器有ACROBAT7.0 。因此说PDF中的加密算法是固定的,没有其他第三种加密算法。关于RC4和AES,你可以到相关网站找到答案,见参考资料。

2问:为什么我的PDF已经设置了权限设置,并且屏蔽了打印,但是为什么别人可以很容易地破解?

答::打个不恰当的比方,这只是“防君子而非小人”。但是很多人都对PDF 的权限设置产生误解。认为作了权限设置就已经对文件内容进行了加密而一定要输入口令,其实不然,典型的例子有:。GMAIL这样做确实是一个非常大的BUG,这是明显违反PDF规范的,在这一点上GMAIL做的太不严谨,幸好它能及时作修正。

PDF中的权限设置只是一串字符而已,用这些字符的某些位来表示PDF是否允许某个操作或者禁止某个操作,而只有权限口令没有打开口令的情况下文件虽然是加密了,但是可以通过加密字典对象和PDF生成加密密钥的规则来得到加密密钥(下一篇文章会详细解释),从而对文件内容进行解密,如果你解密后把它另存为一个新的文件,那么就可以修改或去除这个字符串和相关的信息,那么PDF文件权限就不受限制了。

如果是要确保文件内容加密,那只有设置打开口令。

2问:为什么我设置了打开口令,还被别人破解?

答:如果你设置了打开口令,那么这个时候文件内容是加密的。要打开这类文件是必须要得到加密口令的,这个时候如果还被破解的话,那很有可能是因为你设置的打开口令太过于简单,长度比较小的缘故,这样的情况是可以通过穷举来破解的,当然也可以使用口令字典来破解。

那是通过怎样来破解的呢?

PDF文件加密的时候,你输入一个打开口令,比如说是123456, 其实不是直接由你输入的口令作为PDF加密内容的密钥的,还需要有一个转换过程才得到加密密钥。

而怎么才能判断你输入的口令是否正确呢?

那是因为在加密PDF文件的时候会在PDF文件中放入一个由打开口令运算得到的HASH序列,当你输入口令的时候就需要对你输入的口令作一系列的运算而得到另一个HASH序列,如果两个HASH序列一致,那么就可以根据这个HASH序列和你输入的口令生成解密密钥开始解密,否则提示口令错误。这在我的上一篇文章《PDF加密仿真》中可以得到答案。

2问:什么是ACROBAT中自定义的Security Handler?

答:PDF允许自定义Security handler,如果大家访问过PDF电子书网站,那一定会明白这是怎么一回事。一般的PDF电子书网站都会要求你下载一个

PLUGIN(acrobat 或adobe pdf reader的插件),在这个PLUGIN里就会用到自定义的Security Handler。

那这些新的PDF Security Handler是否使用了新的加密方法呢?当然不是,对PDF内容的加密还是使用RC4或AES,只是加密密钥的生成方法不同。

如果大家对这个感兴趣,我也将给大家作一个比较全面的介绍。

2 一个PDF文件加密

2.1 用ACROBAT7.0英文版给PDF文件口令加密的过

程:

1)打开PDF文件。

2)选择菜单:File->Document Properties。

3)选择Security选项卡。

4)在 Security Method一栏中选择Password Security,点change Settings…

按钮,如下图:

5)出现下面加密项设置对话框:

6)首先选择兼容性,共有acrobat3.0, acrobat5.0,acrobat6.0和acrobat7.0,

默认为acrobat5.0,即被实现PDF1.4规范的软件支持。(本文我们就以此为例)7)分别设置打开口令和权限口令,注意两个口令不能一样,我们在这个例子里

面将分别输入111111和222222,当然你在实际应用中必须使用复杂的口令。

8)设置你准备给该PDF文档读者授予的操作权限。

9)按OK按钮后确认打开口令和权限口令,按OK。

10)文档被加密。

2.2 加密后PDF文件发生了什么变化?

如果想知道PDF加密后发生了什么变化,那么最好的方法是找一个PDF文件,然后对它进行加密,保存后再用Ultra Edit打开,这样所有的变化都会一目了然。

将我文章最后的PDF文件下载,如果你有ACROBAT的话,那么按照我上面的流程作一加密,加密保存后我们会发现文件发生了变化。

通过观察你会看到PDF文件尾部(trailer)发生了变化,加密前我们看到文件尾为:

trailer

<< /Size 16

/Root 1 0 R

/Info 2 0 R

/ID [<14147840093798E8EDC491FC1B2F19A7><14147840093798E8EDC491FC1B2F19A7>]

>>

加密后文件尾变为:

trailer

<

/Prev 10226

/Root 6 0 R

/Encrypt 5 0 R

/Info 3 0 R

/ID[<14147840093798E8EDC491FC1B2F19A7><3F95D9F08175974E8A55871FCBB2F983>]>>

明显地,红色部分是加密后增加的,说明加密字典对象的对象号为5.

我们可以很容易找到以下的加密字典对象:

5 0 obj

<

/Filter/Standard

/O(_憘颖祳>S8+E v櫁-zE {\r脮<滲?

/P -3392

/R 3

/U(v旐厺 a 踜鎒h聨 )

/V 2>>

endobj

其实这些加密字典对象项都是通过我们图形界面输入项生成的,那么这些项都表达什么意思呢?

下面的内容我们可以从PDF规范1.6中找到:

/Length 密钥的长度

/Filter 生成密钥的方法,就是前面说的security handler

/O 是由用户口令和权限口令得到的,用来生成密钥和验证输入的权限口令

/P 访问权限的标志

/R 标准加密的(standard security handler)的版本

/U由用户口令生成,用来验证输入的用户口令或权限口令,是否要提醒用户输入密码

/V 可选,用来指明加密的算法。

当然加密字典还可能包含有其它项,但是这里我不打算介绍每项可能的值和对应的意思,因为这不是PDF规范的中文翻译,而是希望通过一系列的文章让读者能对PDF规范有个更好更快速地了解。

接下来我们结合实际的例子来说明各个加密字典对象项表达的意思。

/Length 128

%密钥的长度为128位

/Filter/Standard

%内建的标准加密引擎standard security handler,对应的操作是口令加密的第4步,即选择Password Security

/O(_憘颖祳>S8+E v櫁-zE {\r脮<滲?

%由用户口令,权限口令,和文档ID生成的

/P -3392

%权限标志见PDF规范

/R 3

%加密版本3,如果V为2或3, 那么就属于“版本3或更高”的范畴,在下一篇文章中我们要用到这个概念

/U(v旐厺 a 踜鎒h聨 )

%由用户口令得到,用来验证用户口令

/V 2

%允许加密长度超过40位,在上述这个例子里例子里密钥为128位

3 实现PDF加密需要回答的三个问题

加密字典对象是通过我们对加密的方式的选择和输入的口令生成的,那每项的内容对PDF文件的加密和解密都是有关系的,接下来我们最关心的问题是如何来实现对一个PDF文件的加密?这个问题可以分解为四个小的问题:

1.文件的内容是如何被加密的?

2.加密密钥是如何生成的?

3.上面的加密字典中的每一项是如何生成的?

4.加密字典和加密密钥的关系?

接下来的文章我将告诉你所有的这几个问题的答案。当然如果你要真正地写一个实现PDF口令加密的程序,那么还得参考PDF规范1.6。但是你觉得阅读起来有困惑的地方,那么我想下篇文章对你来说也会有帮助的,也会详细地告诉你如何通过编程来实现PDF文件的口令加密。

0 几个重要概念

全局加密密钥,简称为全局密钥,该全局密钥由加密字典对象和你输入的口令生成,用来生成对象加密密钥。

对象加密密钥,简称为对象密钥,是用来实际加密PDF文件内容的密钥,不同于上篇PDF加密仿真里的全部的对象共用一个密钥不同,PDF文件中每个对象的加密密钥都不一样。

User Password 用户口令。

Owner password 权限口令。

adobe pdf reference 1.7格式规范下载地址:如果想要解析pdf文档的话请先看这篇格式规范文章!将文档格式解析出来之后才能利用pdf的加密流程进行破解!

1 PDF文件的加密流程

上一篇文章大致介绍了关于ACROBAT对PDF加密操作和加密后生成的PDF文件中的加密字典对象。同时我们提出了下面的四个问题:

1.文件的内容是如何被加密的?

2.加密密钥是如何生成的?

3.加密字典中的每一项是如何生成的?

4.加密字典和加密密钥的关系?

第一个问题是我们的最终目的,本文要最终要解决的就是这个问题。而第2,3,4个问题作为第1个问题的分解,在下文中有个清晰地解答。

下面是一个PDF文件加密的大致过程:

1.选择PDF兼容版本和输入用户口令,权限口令。

2.根据输入生成加密字典对象。

3.由输入和加密字典对象生成全局密钥。

4.由全局密钥生成对象加密密钥。

5.用对象加密密钥加密对象内容。

2 PDF加密解密流程详解

加密字典对象一般有下面的条目:

/Length密钥的长度

/Filter 生成密钥的方法,就是前面说的security handler

/O 是由用户口令和权限口令得到的,用来生成密钥和验证输入的权限口令

/P 访问权限的标志

/R标准加密的(standard security handler)的版本

/U由用户口令生成,用来验证输入的用户口令或权限口令,是否要提醒用户输入密码

/V 可选,用来指明加密的算法。

一般来说这上面的条目是必须的,其它条目具体见PDF规范。这上面的加密字典条目中除了条目O和U之外其它的都可以直接生成。那么接下来我们就来看这两个条目,全局加密密钥,和对象加密密钥的生成过程。

如果你去看PDF规范,在有的步骤会有点迷茫的,相信下面的详细介绍对大家会有所帮助,如果你要实现自己的加密程序,也将给你一个指引。

2.1 生成加密字典和加密密钥

2.1.1 生成条目O

算法3.3:

1.补充或截取权限口令字符串为32个字节。如果输入的口令大于32个字节,

那么只保留前32个字节,如果少于32个字节,那么就按下面的字符串补上所缺少的字节数:

<0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41,

0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,

0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,

0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a>

如果没有权限(主)口令,那么就用用户口令替代。

2.初始化MD5函数并将步骤1产生的结果输入MD5函数。

3.(版本3或更高)连续做50次:此后输出作为输入新的MD5哈希函数中。

4.利用这个HASH数列的前面n位创建RC4密钥,对于版本2来说,n始终为

5, 但对于版本3或更高版本来说,取决于加密字典中Length的值,为

length/8。

5.按照算法3.2中的第一步由用户口令得到32字节字符串。

6.将第5步中产生的32位字节字符串用第4步中产生的密钥用RC4算法加密。

7.(版本3或更高)做19次:用前一次的输出作为下一次的输入进行编码;密

钥是由第1步产生的原始密钥的单个字节和循环数和进行XOR(异或)运算得到的。

char Test[32] = 第1步生成的32字符串。

char temKey = Test[32];

unsigned int keyLength = length/8;

for (i = 1; i <=19; i++)

{

for (j = 0; j < keyLength; ++j)

{

tmpKey[j] = fileKey[j] ^ i;

}

rc4InitKey(tmpKey, keyLength, fState);

fx = fy = 0;

for (j = 0; j < 32; ++j)

{

test[j] = rc4EncryptByte(fState, &fx, &fy, test[j]);

}

8.这32字节字符串即为加密字典对象条目O的值。

图1

2.1.2 得到全局加密密钥

算法2:

1.补充或截取口令字符串为32个字节。如果输入的口令大于32个字节,那么只保留前32个字节,如果少于32个字节,那么就按下面的字符串补上所缺少的字节数:

<0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41,

0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,

0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,

0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a>

如果用户口令为空,那么就意味着没有用户口令,用这32个字节完全填充。2.初始化MD5函数并将步骤1产生的结果输入MD5函数。

3.将加密字典O条目输入MD5中。(算法3.3描述O值的产生)。

4.将P条目作为无符号的4字节整数然后将该4字节输入MD5函数。

5.将该PDF文档的ID标识数组的第一个元素(即该PDF文档中trailer字典中ID条目的第一个字符串)输入到函数MD5中。(关于PDF文档ID的介绍见文章“PDF文档ID”)

6. (版本3或更高)如果该文档的metadata不加密,将4字节的0xFFFFFFFF 输入哈希函数MD5中。

7.结束散列。

8.(版本3或更高)将前面MD5产生的HASH序列的前n位,也就是加密字典中的Length/8位字串,输入到新的MD5哈希函数中,此后输出作为输入连续再做49次。

9.加密密钥就是这个HASH数列的前面n位,对于版本2来说,n始终为5,对于版本3或更高版本来说,就取决于加密字典中Length的值,n=length/8。这个算法,是根据用户口令字符串,产生全局加密密钥。

图2

2.1.3 生成条目U

算法4版本2:

1 按照算法2的方法,基于用户口令字符串生成加密密钥。

2 用上面步骤产生的加密密钥加密按照算法2步骤1生成的32位串。

3 步骤2的输出即为加密字典对象中条目U的值。

算法5版本3:

1按照算法2的方法,基于用户口令字符串生成加密密钥。

2 初始化MD5 HASH函数并将按照算法2步骤1生成的32位字符串输入该函数。

3 将文件ID数组中的第一个32位ID字串传入MD5函数。

4 用第1步产生的密钥通过RC4算法来加密由步骤3输出的16位字符串。9.做19次:用前一次的输出作为下一次的输入进行解码;密钥是由第1步产

生的原始密钥的单个字节和循环数和进行XOR(异或)运算得到的。

char Test[32] = 第1步生成的32字符串。

char temKey = Test[32];

unsigned int keyLength = length/8;

for (i = 1; i <=19; i++)

{

for (j = 0; j < keyLength; ++j)

{

tmpKey[j] = fileKey[j] ^ i;

}

rc4InitKey(tmpKey, keyLength, fState);

fx = fy = 0;

for (j = 0; j < 32; ++j)

{

test[j] = rc4EncryptByte(fState, &fx, &fy, test[j]);

}

2.2 生成对象加密密钥并将对象加密

算法3.1用RC4和AES对数据进行加密算法:

1.获得字符串对象或流对象的对象号(object number)和产生号(generation numer),如果字符串对象是一个直接对象,则利用其包含该对象的标识符。

2.将对象号和产生号作2进制整数对待,将原始的N字节长的密匙扩展到n+5字节,即将对象号的低3个字节和产生号的低2个字节依次接在前面N字节长

的加密K密钥上,顺序为低字节靠前。(如果密钥的长度为40那么n为5,如果V的值大于1,n的值就为Length除以8。)

3.初始化MD5哈希函数,然后将步骤2产生的字符串输入到MD5中。

4.用前(n+5)个字节,如果N+5>16那么截取前面的16个字节,将这个产生的hash结果作为RC4和AES对称加密算法的密匙来对该字符串或流对象进行加密。如果是用到AES算法,用到CBC模式。

图3

3 回答云木的问题

云木的问题是这样,只有设置了权限口令的的PDF文件,是否可以直接从PDF文件中取出某个对象的流?

他想这样的PDF文件应该是不加密的,因为PDF文件的内容是可以看到的,只是设置了一个用来表示权限的串。这是我上篇文章《PDF文件加密仿真》中说的,而且还说了可以有办法去掉这个串或者修改这个串,不过我也有在文章中用红色字体说明PDF文件中内容实际上是加密了的,只是加密密钥可以从加密字典中直接计算出来。

那么这个密钥如何如何计算得到呢?我想由算法3.2和算法3.1就得出答案了。因为没有打开口令,那么直接由上面的32字节加密口令常量串填充,然后根据其它文件中的相关内容得到全局密钥。进而生成对象加密密钥。

4 是否可以直接修改权限设置串

有的人说可以直接修改加密字典中的条目P得到更大的权限,其实不然,因为按照加密算法2,全局加密密钥其中有个输入就是P, 如果P修改了,也不能正确得到加密密钥。你也可以实际试验一下,用Ultra Edit打开,修改P条目,然后再用PDF reader打开,就会提示你输入口令,因为根据该PDF文件本身是无法得到加密密钥了。

5 本文总结

本文详细地对PDF文件的口令加密做了一个说明,相信你可以利用它来对PDF文件进行口令加密了,当然在一些细节方面你需要查询一下PDF规范。整篇文章采用多种方式来表达,目的只有一个,就是让整个内容显得非常明白容易理解。在两个比较难懂的地方我用了伪码,我想这也会对你的理解有所帮助。

1 一般的口令验证

我想很多人在学习某个技术或者其它之前总会想想如果换作自己来设计会

怎么办,比如说PDF文件的解密,我就会想,文件内容是经过加密的,那么必须要有一个密钥才能解密文件的内容。而这一定和要求输入的口令是有关。那么这之间有什么关系呢?

当然有很多种可能,在很久以前,一些系统竟然在后台用明文保存用户口令和口令,这样用户在登录系统的时候就直接比较用户名密码是否一致,当然这些用户名和密码全部掌握在管理员的手中;到我们比较注重系统安全的时候,用口令通过HASH函数生成HASH序列保存在数据库里,这样就比较安全,因为HASH 函数是单向的,没有输入的口令的话只有用暴力破解的方法了。如果你的口令设置的比较简单也是很容易被破解的。因此现在一些对安全性比较高的网站都会要求你不要将口令设置的过于简单。

那么解密PDF的时候口令是如何来验证的呢?

是不是由我们的口令生成的HASH序列保存在PDF文件里,然后在打开的时候由你输入的口令再生成一个HASH序列,两者比对,同则由你输入的口令会同PDF文件中的其它内容生成密钥,然后解密?这只是我们的设想,那么PDF 文件解密是不是真的这样做的呢?

图1 假想的PDF解密

下面我们来寻找问题的答案。

2 PDF文件口令验证

在上几篇文章中我们也知道了PDF有两组口令,一为Owner Password, 另外一组称为User Password,因为Owner Password是用来控制权限的,在文章中我们把它称为权限口令;而User Password是用来打开文件的,称为打开口令。

如果一个文件同时设置了打开口令和权限口令,那么在打开PDF文件的时候只要输入任何一个口令就可以打开该加密的PDF文件了。

而当我们输入口令的时候,一般处理PDF的软件会先判断是否权限口令,如果是,那么开放所有的操作权限,用户就可以没有任何限制地使用该PDF文件;

如果不是权限口令,那么会判断输入的口令是否为打开口令,如果验证成功,那么PDF文件就解密,就可以看到文件的内容,但是此时文件的其它操作是受限制的。

算法3.6和算法3.7分别描述了对用户口令和权限口令的验证。如果你尚未读过前一篇文章,那么如果你感兴趣的话可以去看一看,然后再回过来看本文。

2.1算法

3.6 验证用户口令

1利用用户提供的口令执行算法3.4(R2)或算法3.5(R3或更高)。

2 如果步骤1的输出和PDF文件中加密字典中的U值一致(R2),或者前16位一

致(R3或更高),因为版本3或更高的情况后十六位是任意补足的。那么该输入的用户口令正确,并且可以按照算法3.1对文件内容进行解密。

2.2 算法3.7 验证主口令

1.根据算法3.3的1到4步,由提供的口令串计算得到一个密钥。

2.(仅版本2)用步骤1得到的密钥解密加密字典中的O条目值。

((版本3或更高)做20次:用前一次的输出作为下一次的输入进行解密;密钥是由第1步产生的原始密钥的单个字节依次和循环数和进行XOR(异或)运算得到的(循环数从19到0)。

下面为该过程的伪码:

Test[32] = 加密字典对象中条目O的32位字符串值;

temKey = Test[32];

keyLength = length/8;

for (i = 19; i >= 0; --i)

{

for (j = 0; j < keyLength; ++j)

{

tmpKey[j] = fileKey[j] ^ i;

相关文档