使用browserpgp(OpenPGP.js)前端加密ZIP文件无法被Kleopatra解密问题
问题背景
- 需求:纯浏览器端(不依赖Node.js环境)使用OpenPGP.js实现ZIP文件加密,所有逻辑在客户端完成
- 故障现象:加密纯文本文件流程正常,但加密二进制ZIP文件时,按照官方二进制处理指南编写的代码生成的密文为二进制格式,但无法通过桌面端OpenPGP工具Kleopatra正常解密
- 原实现代码如下:
function openpgp_encryptZIPFile(){ var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); var img = zip.folder("images"); zip.generateAsync({type:"blob"}) .then(function(content) { console.log('contents: ' + content); encryptedZipFile = OpenPGPEncryptDataZipFile(content); }); } async function OpenPGPEncryptDataZipFile(zipBlob) { // 加密公钥1 const key1 = `somekey1`; // 加密公钥2 const key2 = `somekey2`; const publicKeysArmored = [key1, key2]; // 解析公钥 const publicKeys = await Promise.all(publicKeysArmored.map(armoredKey => openpgp.readKey({ armoredKey }))); var binaryData = new Uint8Array(zipBlob); // 构造加密消息 const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ binary: binaryData }), encryptionKeys: publicKeys, //signingKeys: privateKey // 可选签名私钥 format: 'binary' }); console.log('encrypted: ' + encrypted); var encryptedBlob = new Blob([encrypted],{type: 'text/plain'}); //var encryptedBlob = new Blob([encrypted], {type: "octet/stream"}); saveAs(encryptedBlob, 'test.zip.enc' ); }
故障原因
代码存在两个直接导致密文损坏无法解密的核心错误:
- Blob转二进制数组逻辑错误:直接调用
new Uint8Array(zipBlob)无法正确读取Blob中的二进制内容。Blob是浏览器封装的文件对象,并非ArrayBuffer类型,直接转换得到的是结构错误、内容无效的二进制数组,基于错误明文生成的密文自然无法解密。 - 密文保存时被编码破坏:生成密文Blob时错误使用
text/plain作为MIME类型,浏览器在保存text/plain类型文件时会自动执行UTF-8编码转换、换行符适配等文本处理操作,直接破坏二进制格式的OpenPGP密文结构。
修复方案
针对上述问题修改代码即可,修复后代码如下:
function openpgp_encryptZIPFile(){ const zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); zip.folder("images"); zip.generateAsync({type:"blob"}) .then(async function(content) { await OpenPGPEncryptDataZipFile(content); }); } async function OpenPGPEncryptDataZipFile(zipBlob) { const key1 = `somekey1`; // 替换为实际公钥 const key2 = `somekey2`; // 替换为实际公钥 const publicKeysArmored = [key1, key2]; const publicKeys = await Promise.all(publicKeysArmored.map(armoredKey => openpgp.readKey({ armoredKey }))); // 正确读取Blob为Uint8Array const arrayBuffer = await zipBlob.arrayBuffer(); const binaryData = new Uint8Array(arrayBuffer); const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ binary: binaryData }), encryptionKeys: publicKeys, format: 'binary' }); // 使用正确的二进制MIME类型,避免文本编码破坏密文 const encryptedBlob = new Blob([encrypted], {type: "application/octet-stream"}); saveAs(encryptedBlob, 'test.zip.enc' ); }
修复后生成的test.zip.enc文件可直接被Kleopatra等标准OpenPGP工具正常解密。
内容的提问来源于stack exchange,提问作者Paul Butler
相关产品推荐
相关产品推荐

