PDF文件加密仿真

PDF文件加密仿真

前言:

通过上一篇文章的阅读,想必大家对基本的PDF文件的格式有所了解。其实对PDF具体格式的学习,不光可以帮助我们理解这种格式本身,同时你也会受到它的启发定义一种自己的文件格式,比如说一种简单的类似PDF格式,来满足你对某些项目的需求。

本文就是先仿照PDF(也有借鉴XML加密方式)自定义一种非常简单的文件格式来说明PDF文件的加密方式和过程。

几个基本概念

我们学习和讨论PDF文件的加密原理和过程不需要讨论具体的加密算法实现本身,因为所有流行的加密算法早就有所实现,我们需要做的就是直接加以利用。何况介绍和讨论加密算法篇幅巨大,也不应该包含在这短文之中。但是我想下面的几个概念大家都应该明白:

   (下面所有内容包括图例都不是严格的定义,基本上是我本人的理解,如果要知道确切的定义请自己查询相关网站。)

 

 

 

 

 

1.1 对称加密方法

       对称加密方法指的是加密和解密使用同一密钥的方法。PDF文件内容的加密采用RC4AES的方法。(关于RC4算法和AES算法请自己搜索相关网站)

 

 

 

 

 

例如下面是对称加密的两种简单实现:

 1

1.2 非对称加密方法

       非对称加密有一对密钥(KEY1, KEY2),加解密需要用不同的密钥,加密的密钥用KEY1,那么解密的密钥就用KEY2;如果加密的密钥用KEY2,那么解密的密钥就用KEY1。但是一般的使用上来说,这一对密钥中一个称为公钥,作为公开密钥,另外一个称为私有密钥,用来解密。

   

 2

1.3 散列(hash)

   流行的算法有MD5SHA1,就是不同的任何两组内容通过一组运算得到的结果也不同,我们称为hash数,或者可以叫做数字指纹。

   比如我们常常将系统的登录口令通过MD5运算后存放在口令表里,登录的时候就将用户输入的口令通过MD5运算后和口令表中的相关项对比,如相同就通过认证,否则口令错误。

 3

2 PDF文件加密的仿真

在讨论真正的PDF文件加密之前先设计一个自己的文件格式,文件格式只包含文本,主要是让大家明白加解密的过程而简化一些次要的属性。 下文中把这种格式的文件称为ZONYPDF,我们把这种称为ZONYPDF的文件格式比作PDF文件格式。

同时假定有一个ZONYPDF reader是作为ZONYPDF文件阅读器来对应于adobePDF reader

要模拟PDF的加密及解密,这个格式的文件必须满足下面的条件:

²        必须能够判断一个文件是否被加密。

²        输入一个口令以后必须能验证其正确与否。

²        输入的口令能够产生加密文件内容的KEY,从而解密整个文件。

 

 

 

 

 

2.1 定义自己的一个文件格式

文件头%ZONYPDF-1.0;文件体包含在bodyendbody之间,文件体包含三个属性,一是文本的长度/length,二是文件的打开密钥/userpassword,包含在(和)之间,三是文本本身/content, 也包含在()之间。下面是按照我们的定义的一个最简单的未加密的ZONYPDF文件。

 

 

 

 

 

ZONYPDF-1.0

Body

/length 11

/userpassword ()

/content (Hello world)

endbody

%%EOF

 

 

 

 

 

2.2 将一个自定义的文件加密

我们规定加密的时候只加密数据而不加密其他的符号(事实上PDF也是这么做的)。对于文本的加密采用称为XC1XC1是为了说明而虚构的一种对称加密算法)的对称加密算法,通过XC1加密的文本的长度和明文的长度一样。

然后加密完文件内容就将加密口令password进行MD5运算后放入/userpassword后的括号内。

用户加密的密钥为123, 加密后就有下面的文件

 

 

 

 

 

ZONYPDF-1.0

Body

/length 11

/userpassword (#¥%&…)

/content (#¥%&^=+-!@)

endbody

%%EOF

 

 

 

 

 

    当然PDF文件的加密不是直接把用户输入的口令作为加密PDF文件内容的KEY的,而是要通过一定的变换与运算的, 关于如何运算得到这个加密的KEY会在下一次详细说明。同时保存在口令字典里的口令hash也不仅仅是一次MD5运算,会有更多的迭代运算。

 

 

 

 

 

2.3 将加密的文件解密

   首先我们的ZONYPDF reader看到/userpassword后面的长度不为0,就要求用户输入口令,输入口令password1,然后ZONYPDF reader做一次MD5运算然后和/userpassword后的括号里的内容去比对,如果一样那么就说明是正确的口令,则对内容进行解密然后显示。在本例中如果password1123那么就通过验证并顺利解密。

 

 

 

 

 

2.4 将文件加上权限控制

   那么PDF格式中的权限控制是如何实现的呢?

   ZONYPDF reader加上一个打印的功能,那么相应地,给ZONYPDF格式中的body部分加上一个打印允许口令/permpassowrd

   如果打印允许口令/permpassowrd为空则没有打印限制,如果不为空则有打印限制,在打印前需验证口令。口令的生成和打开口令的生成方法一样,由输入口令通过MD5运算放入/permpassword 后的括号内。

  

   那么上面的例子文件就变成。

ZONYPDF-1.0

Body

/length 11

/userpassword ()

/permpassword ()

/content (Hello world)

endbody

%%EOF

 

 

 

 

 

设置打印权限以后为:

ZONYPDF-1.0

Body

/length 11

/userpassword ()

/permpassword (%+◎#!…)

/content (Hello world)

endbody

%%EOF

可以看到通过权限设置文件的内容是没有经过加密的,如果是本文中的ZONYPDF

格式的话,直接把/permpassword后的内容直接除去就失去了对打印的控制了。而且如果另外一个人也开发了一个ZONYPDF文件阅览器ZONYPDF reader1, 如果它在打开的时候完全忽略权限控制这一属性,那么对它来说任何的限制都是没有用的,因为内容本身是没有加密的。

对于PDF的权限设置其实也是类似的,设置打开口令时才对文件的内容进行加密,而只进行PDF权限设置是相对比较容易去除的,虽然不像我们前面定义的ZONYPDF直接去处/permpassword即可,因为正如上一篇文章所述,PDF有交叉表引用表,如果你删除了一个条目那么就会对交叉引用表中的地址产生影响,从而导致PDF文件结构被破坏并不可用。这也是网上的一些PDF破解程序只能去掉权限控制口令而不能去掉打开口令的缘故。

  对于权限控制这一块,ADOBE公司的相关的文档里也清楚地说明了,如果第三方的PDF阅读器是完全遵循PDF规范的,那么应该判断PDF文件的权限控制这个属性。当然如果第三方的阅读器不尊重所有的PDF规范,那么它是完全可以忽略掉这个权限控制而直接打开的。

因此说PDF的权限设置严格意义上来说是不安全的。

注意:其实加了权限的PDF文件,内容也是加密的,只不过它的加密密钥可以通过文件本身包含的加密字典对象计算得到。因此对一般用户来说它是不加密的。但是你要编程实现从其中抽取内容,那么必须计算得到密钥然后解密以后得到对应的流。

 

 

 

2.5 ZONYPDF文件加密和解密的图例:

 

 

 

 

 

加密:

 4

 

 

 

 

 

 

 

 

 

 

解密:

 5

总结

        通过对一个最小规模的自定义文件加密过程的分析,可以明白PDF文件加密大体过程,之所以给出这个自定义文件格式的加密过程,为的是让大家明白其实所有文件格式的加密方式都是有相通之处的,那就是用对称加密来加密文件内容,用hash数来保存加密文件内容的key.

       如果你只要明白PDF文件的大体流程,那么这则短文对你的理解应该就可可以了,如果你需要了解PDF文件加密过程的细节, 比如说你要具体实现自己对PDF的加密或者是解密,那么希望你能去看PDF Reference1.6

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用iTextPDF对MultipartFile文件进行加密,你可以按照以下步骤进行操作: 1. 首先,确保你的项目中已经添加了iTextPDF的相关依赖。你可以在项目的pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13.2</version> </dependency> ``` 2. 在你的加密方法中,使用iTextPDF的相关API来实现文件加密。下面是一个简单的示例代码: ```java import com.itextpdf.text.Document; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfStamper; import com.itextpdf.text.pdf.PdfWriter; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; public class PDFEncryptionUtil { public static void encryptPdf(InputStream inputPdfStream, OutputStream encryptedPdfStream, String userPassword, String ownerPassword) throws Exception { PdfReader reader = new PdfReader(inputPdfStream); ByteArrayOutputStream baos = new ByteArrayOutputStream(); PdfStamper stamper = new PdfStamper(reader, baos); stamper.setEncryption(userPassword.getBytes(), ownerPassword.getBytes(), PdfWriter.ALLOW_PRINTING, PdfWriter.ENCRYPTION_AES_128); stamper.close(); reader.close(); encryptedPdfStream.write(baos.toByteArray()); } } ``` 3. 在你的控制器或服务类中,接收MultipartFile参数,并调用PDFEncryptionUtil.encryptPdf方法进行文件加密,如下所示: ```java import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; import java.io.ByteArrayOutputStream; import java.io.OutputStream; @RestController public class FileController { @PostMapping("/encrypt") public void encryptFile(@RequestParam("file") MultipartFile file) { try { InputStream inputStream = file.getInputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); PDFEncryptionUtil.encryptPdf(inputStream, outputStream, "userPassword", "ownerPassword"); // 处理加密后的文件,例如保存到本地或者返回给前端 } catch (Exception e) { e.printStackTrace(); } } } ``` 在上述代码中,`encryptPdf`方法接收一个输入流`inputPdfStream`,一个输出流`encryptedPdfStream`,以及用户密码和所有者密码。该方法使用iTextPDF的`PdfStamper`类将输入的PDF文件加密,并将加密后的内容写入到输出流中。 请注意,这只是一个简单的示例,你可以根据自己的需求进行修改和扩展。 希望对你有所帮助!如果还有其他问题,请继续提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值