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
相关产品推荐
相关产品推荐

