PDF加密、解密内幕(二) - PDF文件口令加密内幕

                                      PDF加密、解密内幕(二)
                                                - PDF文件口令加密内幕

几个重要概念

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

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

User Password 用户口令。

Owner password 权限口令。

1 PDF文件的加密流程

上一篇文章大致介绍了关于ACROBATPDF加密操作和加密后生成的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规范。这上面的加密字典条目中除了条目OU之外其它的都可以直接生成。那么接下来我们就来看这两个条目,全局加密密钥,和对象加密密钥的生成过程。

如果你去看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 RC4AES对数据进行加密算法:

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

2.将对象号和产生号作2进制整数对待,将原始的N字节长的密匙扩展到n+5字节,即将对象号的低3个字节和产生号的低2个字节依次接在前面N字节长的加密K密钥上, 顺序为低字节靠前。(如果密钥的长度为40那么n5,如果V的值大于1 n的值就为Length除以8。)

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

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

如果是用到AES算法,用到CBC模式。

                                                                              图 3

3 回答云木的问题

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

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

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

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

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

本文总结

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

       当然,错误是在所难免的,如果你对文章有什么意见,或者有什么知道,或者你认为怎样会更好,那么我非常希望你能给我来信或者给我评论和留言。

       非常感谢!

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值