PDF加密

原创
2019/08/07 15:07
阅读数 308

pdf加密实现

在工作中碰到需求是给pdf记性权限加密,区分打开,编辑、打印的权限,并且设置密码,经过调研有两种实现方式,但是这两种方式均不能很好的兼容市面上大多数pdf软件,并且限制了打印功能以后,几乎很少有软件能显式的要求输入打印密码,表现均为打印按钮被置灰,无法打印,只有在输入ownerPassword(文件所有者权限)以后,才能够打印,可以说是很傻了,当实在有这种打印需要输入密码界面的需求,请带着你的刀去和产品重新讨论需求

Adobe Acrobat DC

该软件是市面上比较规范的pdf工具,该软件详细pdf权限控制界面如图所示:

Adobe Acrobat DC权限界面

从图中可以看出:
这款工具有两个密码,分别为,用户权限密码(打开pdf需要)和所有者权限密码(编辑等其他所有权限),经测试,所有者权限密码可以进行查看,例如chrome等其他工具打开时均有输入密码的界面

N多个权限
1:允许打印



2:允许更改


以上总共这么多权限,下面就开始我们的实现


通过pdfbox实现

pdfbox加密实现方式非常简单,当然这个类的功能不止加密,还有很多实现,具体参考官方demo和api https://pdfbox.apache.org/docs/2.0.13/javadocs/

pom依赖

<!-- pdfbox 目前最新版本是2.0.16 -->
<dependency>
	<groupId>org.apache.pdfbox</groupId>
	<artifactId>pdfbox</artifactId>
	<version>2.0.16</version>
</dependency>
<!--  -->
<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId>bcprov-jdk15on</artifactId>
	<version>1.57</version>
</dependency>

PDFEncryptUtils.java

/**
 * <p>对pdf进行权限控制</p>
 * @author Calvin
 * @date 2019/07/17
 * @since v1.0
 */
public class PDFEncryptUtils {

	/**
	 * 加密
	 * @param fileName  文件名
	 * @param fileAuth 文件权限
	 * @throws Exception
	 */
	public static void encrypt(String fileName, FileAuth fileAuth) throws Exception {
		File file = new File(fileName);
		PDDocument document = PDDocument.load(file);
		AccessPermission permissions = new AccessPermission();
		//此处简单进行实现,具体还有很多个权限,此处只实现最常用的,打开,编辑,打印
		//权限中默认都可以操作
		permissions.setCanExtractContent(fileAuth.getOpen() != 1);
		permissions.setCanModify(fileAuth.getEdit() != 1);
		permissions.setCanPrint(fileAuth.getPrint() != 1);
		StandardProtectionPolicy policy = new StandardProtectionPolicy(fileAuth.getOwnerPassword(),
		        fileAuth.getUserPassword(), permissions);
		SecurityHandler handler = new StandardSecurityHandler(policy);
		handler.prepareDocumentForEncryption(document);
		PDEncryption encryption = new PDEncryption();
		encryption.setSecurityHandler(handler);
		document.setEncryptionDictionary(encryption);
		//保存原路径
		document.save(file.getPath());
	}
}

FileAuth.java

/**
 * <p> 用户权限</p>
 *
 * @author Calvin
 * @date 2019/07/15
 * @since v1.0
 */
public class FileAuth {


	/**
	 * 是否可以打开
	 */
	private int open;

	/**
	 * 是否可以编辑
	 */
	private int edit;

	/**
	 * 是否可以打印
	 */
	private int print;

	/**
	 * 所有者权限密码
	 */
	private String ownerPassword;

	/**
	 * 用户权限密码
	 */
	private String userPassword;

	public int getOpen() {
	    return open;
	}

	public void setOpen(int open) {
	    this.open = open;
	}

	public int getEdit() {
	    return edit;
	}

	public void setEdit(int edit) {
	    this.edit = edit;
	}

	public int getPrint() {
	    return print;
	}

	public void setPrint(int print) {
	    this.print = print;
	}

	public String getOwnerPassword() {
	    return ownerPassword;
	}

	public void setOwnerPassword(String ownerPassword) {
	    this.ownerPassword = ownerPassword;
	}

	public String getUserPassword() {
	    return userPassword;
	}

	public void setUserPassword(String userPassword) {
	    this.userPassword = userPassword;
	}
}

利用itext-pdf给pdf加密

<dependency>
	<groupId>com.itextpdf</groupId>
	<artifactId>itextpdf</artifactId>
	<version>5.5.11</version>
	<!-- 最新版本是7.1.7-->
</dependency>
<!-- 这里贴一下
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>barcodes</artifactId>
    <version>7.1.7</version>
    <type>pom</type>
</dependency>

-->

PDFEncryptUtils.java

/**
 * 给pdf设置权限
 * @param pdfStamper pdf文件
 * @param fileAuth 文件权限密码
 * @throws IOException 文件异常
 * @throws DocumentException
 */
public static void encrypt(PdfStamper pdfStamper, FileAuth fileAuth) throws DocumentException, IOException {
        pdfStamper.setEncryption(null, null, PdfWriter.ALLOW_COPY, true);
        pdfStamper.setEncryption(null, null, PdfWriter.ALLOW_DEGRADED_PRINTING, true);
        pdfStamper.setEncryption(null, null, PdfWriter.ALLOW_FILL_IN, true);
        pdfStamper.setEncryption(null, null, PdfWriter.ALLOW_MODIFY_ANNOTATIONS, true);
        pdfStamper.setEncryption(null, null, PdfWriter.ALLOW_MODIFY_CONTENTS, true);
        pdfStamper.setEncryption(null, null, PdfWriter.ALLOW_PRINTING, true);
        byte[] userpassword = fileAuth.getUserPassword().getBytes();
        byte[] owenerpassword = fileAuth.getOwnerPassword().getBytes();
           if(fileAuth.getOpen() == 1){
               pdfStamper.setEncryption(userpassword, userpassword, PdfWriter.ALLOW_SCREENREADERS, false);
           }
           if(fileAuth.getEdit() == 1){
               pdfStamper.setEncryption(userpassword, owenerpassword, PdfWriter.ALLOW_PRINTING, false);
               pdfStamper.setEncryption(userpassword, owenerpassword, PdfWriter.ALLOW_DEGRADED_PRINTING,
                       false);
           }
           if(fileAuth.getPrint() == 1){
               pdfStamper.setEncryption(userpassword, owenerpassword, PdfWriter.ALLOW_MODIFY_ANNOTATIONS,
                       false);
               pdfStamper.setEncryption(userpassword, owenerpassword, PdfWriter.ALLOW_MODIFY_CONTENTS, false);
               pdfStamper.setEncryption(userpassword, owenerpassword, PdfWriter.ALLOW_FILL_IN, false);
           }
           pdfStamper.close();
    }

Client调用

public static void main(String[] args) throws IOException, DocumentException, NoSuchFieldException, IllegalAccessException {
        PdfReader reader = new PdfReader("D:\\4028832b6c4af5e2016c4af694310044.pdf");
        java.lang.reflect.Field f = reader.getClass().getDeclaredField("encrypted");
        f.setAccessible(true);
        f.set(reader, false);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("D:\\test1.pdf"));
        FileAuth fileAuth = new FileAuth();
        fileAuth.setEdit(1);
        fileAuth.setOpen(1);
        fileAuth.setPrint(1);
        fileAuth.setUserPassword("123456");
        fileAuth.setOwnerPassword("654321");
        encrypt(stamper, fileAuth);
    }

缺点

1:这两种做法并不能兼容市面上所有的软件,并且由一些pdf密码破解工具,即可进行解密操作,安全的密码,还是建议使用证书 2:如果限制了打印的权限,那么除非主动去获取pdf的owner权限,不然打印的按钮都是disabled,无法进行打印,并且没有输入打印密码的地方

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部