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

Node.js加密的AES-GCM文件无法在Deno中解密的问题求助

问题根源分析

导致Node.js加密的文件在Deno中解密失败、两端加密结果不一致的核心原因,是两者在AES-128-GCM的实现细节处理上存在差异,主要集中在以下几点:

  • 密钥导入/编码不一致:Node.js的crypto模块直接支持Buffer/字符串密钥,而Deno遵循Web Crypto API,需要明确指定密钥格式(如raw)和编码,若导入时格式不匹配,实际使用的密钥会不同。
  • GCM标签长度与分离逻辑不匹配:Node.js默认生成16字节(128位)的认证标签,且需手动获取并与密文拼接;Deno解密时必须正确分离密文和标签,若标签长度或拼接顺序不一致,会直接触发解密失败。
  • IV的传递/解析错误:GCM推荐使用12字节IV,若两端对IV的编码(如Base64/Hex)或传递方式(如文件中存储位置)不同,会导致解密时IV不匹配。
  • 附加认证数据(AAD)未同步:如果加密时使用了AAD,两端必须完全同步AAD的内容、编码和长度,否则会触发认证失败。
排查与修正步骤

针对以上问题,可按以下步骤排查并修正代码:

1. 统一密钥处理逻辑

确保两端使用相同长度(AES-128对应16字节)和编码的密钥:

  • Node.js侧:直接用Buffer导入密钥
    const key = Buffer.from('your-16-byte-secret', 'utf8'); // 必须16字节
    
  • Deno侧:按Web Crypto API规范导入原始格式密钥
    const keyBuffer = new TextEncoder().encode('your-16-byte-secret');
    const cryptoKey = await crypto.subtle.importKey(
      'raw',
      keyBuffer,
      { name: 'AES-GCM' },
      false,
      ['decrypt']
    );
    

2. 统一加密输出格式

Node.js加密时需按「IV(12字节) + 密文 + 标签(16字节)」的顺序存储,Deno解密时按同样规则分离:

  • Node.js加密代码(修正后)
    const fs = require('fs');
    const crypto = require('crypto');
    
    const encryptFile = (inputPath, outputPath, key) => {
      const iv = crypto.randomBytes(12); // GCM标准12字节IV
      const cipher = crypto.createCipheriv('aes-128-gcm', key, iv);
      
      // 若使用AAD,需与Deno保持一致
      // const aad = Buffer.from('fixed-aad-content', 'utf8');
      // cipher.setAAD(aad);
    
      const inputStream = fs.createReadStream(inputPath);
      const outputStream = fs.createWriteStream(outputPath);
    
      // 先写入IV
      outputStream.write(iv);
      // 写入密文
      inputStream.pipe(cipher).pipe(outputStream);
      // 写入认证标签
      inputStream.on('end', () => {
        outputStream.write(cipher.getAuthTag());
        outputStream.end();
      });
    };
    
    const key = Buffer.from('your-16-byte-secret', 'utf8');
    encryptFile('input.txt', 'encrypted.bin', key);
    
  • Deno解密代码(对应格式)
    const decryptFile = async (inputPath, outputPath, keyStr) => {
      const encryptedData = await Deno.readFile(inputPath);
      
      // 分离IV、密文、标签
      const iv = encryptedData.slice(0, 12);
      const ciphertext = encryptedData.slice(12, encryptedData.length - 16);
      const authTag = encryptedData.slice(encryptedData.length - 16);
    
      // 导入密钥
      const keyBuffer = new TextEncoder().encode(keyStr);
      const cryptoKey = await crypto.subtle.importKey(
        'raw',
        keyBuffer,
        { name: 'AES-GCM' },
        false,
        ['decrypt']
      );
    
      // 解密(同步AAD和标签长度)
      const decryptedBuffer = await crypto.subtle.decrypt(
        {
          name: 'AES-GCM',
          iv: iv,
          // additionalData: new TextEncoder().encode('fixed-aad-content'), // 与Node.js一致
          tagLength: 128 // 对应16字节标签
        },
        cryptoKey,
        new Uint8Array([...ciphertext, ...authTag])
      );
    
      await Deno.writeFile(outputPath, new Uint8Array(decryptedBuffer));
    };
    
    await decryptFile('encrypted.bin', 'decrypted.txt', 'your-16-byte-secret');
    

3. 验证IV与标签长度

  • 确保IV始终为12字节(GCM最优长度,避免兼容性问题)
  • 若手动设置了标签长度(如Node.js中cipher.setAuthTagLength(12)),Deno解密时需在选项中指定tagLength: 96(12字节对应96位)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 03:00:58