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

Rust解密Web Crypto AES-GCM加密字符串时遇密钥长度断言错误

问题根源与解决方案

核心错误原因

你遇到的断言错误本质是密钥长度与AES算法变体不匹配:

  • JS端:32位十六进制字符串转换后是16字节密钥,对应AES-128,但你调用importKey时错误指定了AES-GCM 256位(需要32字节密钥)。Web Crypto API可能做了隐式兼容,但实际生效的是AES-128-GCM。
  • Rust端:你使用了Aes256Gcm(要求32字节密钥),但传入的是16字节密钥,导致GenericArray长度断言失败(预期32,实际16)。

分步修正方案

1. 统一JS端密钥与算法匹配

根据实际需求二选一:

  • 使用AES-256-GCM:
    替换密钥为64位十六进制字符串(对应32字节密钥),保持importKey的length: 256参数:

    const keyHex = "替换为64位十六进制字符串"; // 对应32字节密钥
    const keyBytes = new Uint8Array(Buffer.from(keyHex, 'hex'));
    const cryptoKey = await crypto.subtle.importKey(
      'raw',
      keyBytes,
      { name: 'AES-GCM', length: 256 },
      true,
      ['encrypt', 'decrypt']
    );
    
  • 继续使用现有16字节密钥:
    修改importKey的算法参数为AES-GCM 128位,匹配16字节密钥:

    const keyHex = "你的32位十六进制字符串"; // 对应16字节密钥
    const keyBytes = new Uint8Array(Buffer.from(keyHex, 'hex'));
    const cryptoKey = await crypto.subtle.importKey(
      'raw',
      keyBytes,
      { name: 'AES-GCM', length: 128 }, // 修正为128位
      true,
      ['encrypt', 'decrypt']
    );
    

2. 修正Rust端的AES算法变体

对应JS端的选择调整:

  • 对应AES-256-GCM:
    确保密钥为32字节,继续使用Aes256Gcm:

    use aes_gcm::{Aes256Gcm, KeyInit, Nonce, Tag};
    use generic_array::GenericArray;
    
    // 解析64位十六进制字符串得到32字节密钥
    let key_bytes = hex::decode("你的64位十六进制密钥").unwrap();
    let key = GenericArray::from_slice(&key_bytes);
    let cipher = Aes256Gcm::new(key);
    
    // 解密:确保nonce(默认12字节)、密文、tag(16字节)与JS端完全一致
    let nonce = Nonce::from_slice(&nonce_bytes);
    let tag = Tag::from_slice(&tag_bytes);
    let plaintext = cipher.decrypt(nonce, (&ciphertext, tag)).unwrap();
    
  • 对应AES-128-GCM:
    改用Aes128Gcm适配16字节密钥:

    use aes_gcm::{Aes128Gcm, KeyInit, Nonce, Tag};
    use generic_array::GenericArray;
    
    // 解析32位十六进制字符串得到16字节密钥
    let key_bytes = hex::decode("你的32位十六进制密钥").unwrap();
    let key = GenericArray::from_slice(&key_bytes);
    let cipher = Aes128Gcm::new(key);
    
    // 解密逻辑同上,注意nonce和tag长度匹配JS端默认值
    let nonce = Nonce::from_slice(&nonce_bytes);
    let tag = Tag::from_slice(&tag_bytes);
    let plaintext = cipher.decrypt(nonce, (&ciphertext, tag)).unwrap();
    

额外注意事项

  • Web Crypto API的AES-GCM默认生成16字节认证标签,Rust端必须传入完整的16字节tag,不能截断或长度错误。
  • Nonce推荐使用12字节(Web Crypto默认),确保JS加密和Rust解密使用完全相同的nonce值。
  • 密文与tag的拆分要正确:JS端加密返回的ArrayBuffer通常是密文 + tag(最后16字节为tag),拆分时需按此规则处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 23:10:54