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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 16:24:19