You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用openpgpjs加密PDF后Chrome无法加载,如何调出密码弹窗?

加密PDF后Chrome无法识别并弹出密码输入框的问题

我正在开发一款应用,支持选择本地PDF文件并使用openpgpjs加密。目前能成功完成加密,但在Chrome中打开加密后的文件时,会弹出“无法加载PDF文档”的错误提示。不过手动解密该文件后,原始PDF可以正常显示。

选择文件并赋值给uint8Array的代码:

//file picker listener uint8Array 
document.getElementById("file_picker").onchange = function (event) {
    var file = event.target.files[0];
    console.log(file);
    var reader = new FileReader();
    reader.readAsArrayBuffer(file);

    reader.addEventListener('load', (loadEvent) => {
        console.log("array data")
        var buffer = loadEvent.target.result;
        uint8Array = new Uint8Array(buffer);
        console.log(uint8Array);
    })
}

加密并下载加密文件的代码:

//encrypt click listener
document
    .getElementById("encrypt")
    .addEventListener("click", function (e) {

        if (uint8Array != undefined) {

            (async () => {
                const message = await openpgp.createMessage({ binary: uint8Array });
                const encrypted = await openpgp.encrypt({
                    message, // input as Message object
                    passwords: ['password'], // multiple passwords possible
                    format: 'binary' // don't ASCII armor (for Uint8Array output)
                });
                console.log(encrypted); // Uint8Array

                downloadBlob(encrypted, 'data.pdf', 'application/pdf');

            })();

        }

    });

function downloadBlob(data, fileName, mimeType) {
    var blob, url;
    blob = new Blob([data], {
        type: mimeType
    });
    url = window.URL.createObjectURL(blob);
    downloadURL(url, fileName);
    setTimeout(function () {
        return window.URL.revokeObjectURL(url);
    }, 1000);
}

function downloadURL(data, fileName) {
    var a;
    a = document.createElement('a');
    a.href = data;
    a.download = fileName;
    document.body.appendChild(a);
    a.style = 'display: none';
    a.click();
    a.remove();
}

现在PDF能正常下载,但打开时会出现上述错误。是否需要设置某些参数来触发Chrome弹出密码输入弹窗?

更新

我尝试改用CryptoJS的AES加密,依然遇到相同问题。

期望效果

打开加密PDF时,能弹出如下密码输入弹窗:
密码输入弹窗


问题原因与解决方案

你现在的核心问题是:用openpgpjs或CryptoJS做的是「整个PDF文件的加密」,而Chrome的PDF阅读器只识别PDF标准内置的加密格式,这是两种完全不同的加密逻辑。

解决思路

要让Chrome弹出原生的PDF密码输入框,必须遵循PDF规范的内置加密机制,而非直接加密整个文件二进制流。具体来说:

  1. 不能用通用加密库直接加密PDF的Uint8Array,需要操作PDF内部的加密字典(Encrypt字典),添加符合标准的密码保护。
  2. 推荐使用专门处理PDF的库实现,比如pdf-lib,它支持给PDF添加标准的用户/所有者密码,加密后的文件能被Chrome原生阅读器识别并触发密码弹窗。

用pdf-lib实现的示例代码

// 先通过CDN或npm引入pdf-lib
import { PDFDocument } from 'pdf-lib';

// 修改文件选择后的处理逻辑
document.getElementById("file_picker").onchange = async function (event) {
    const file = event.target.files[0];
    const pdfBytes = await file.arrayBuffer();
    
    // 加载原始PDF
    const pdfDoc = await PDFDocument.load(pdfBytes);
    
    // 设置用户密码(打开时需输入)和所有者密码(用于权限控制)
    const userPassword = 'your-user-password';
    const ownerPassword = 'your-owner-password';
    pdfDoc.setUserPassword(userPassword);
    pdfDoc.setOwnerPassword(ownerPassword);
    
    // 导出加密后的PDF字节流
    const encryptedPdfBytes = await pdfDoc.save();
    
    // 下载文件
    downloadBlob(encryptedPdfBytes, 'protected.pdf', 'application/pdf');
};

// 保留原有的下载函数
function downloadBlob(data, fileName, mimeType) {
    var blob, url;
    blob = new Blob([data], {
        type: mimeType
    });
    url = window.URL.createObjectURL(blob);
    downloadURL(url, fileName);
    setTimeout(function () {
        return window.URL.revokeObjectURL(url);
    }, 1000);
}

function downloadURL(data, fileName) {
    var a;
    a = document.createElement('a');
    a.href = data;
    a.download = fileName;
    document.body.appendChild(a);
    a.style = 'display: none';
    a.click();
    a.remove();
}

为什么原方式不行?

openpgpjs和CryptoJS是对整个文件进行加密,加密后的文件本质上已经不是合法的PDF格式,只是一个加密后的二进制数据块。Chrome的PDF阅读器无法识别这种非标准格式,因此会提示“无法加载PDF文档”;而手动解密后恢复了原始PDF结构,所以能正常打开。只有按照PDF规范添加的内置加密,才能被阅读器识别并触发原生密码输入弹窗。

内容的提问来源于stack exchange,提问作者KonTash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 23:03:24