Node.js AES-256-GCM加密时出现Invalid key length错误求助
解决Node.js AES-256-GCM加密的"Invalid key length"错误
我来帮你搞定这个问题——这个错误的根源非常明确:AES-256-GCM要求密钥必须是32字节(256位)长度,但你的代码里直接把短字符串'd6F3Efeq'当作密钥使用,它的UTF-8字节数只有8,远达不到AES-256的要求,所以crypto模块抛出了密钥长度无效的错误。
除此之外,你的代码还有几个需要修正的安全问题和笔误,我一步步给你拆解解决:
1. 正确生成符合要求的AES密钥
不能直接用明文密码当作AES密钥,应该用**密钥派生函数(KDF)**从密码中生成固定长度的密钥。Node.js的crypto模块提供了scrypt(推荐)或pbkdf2函数来做这件事,它们会通过加盐处理,生成符合长度要求的安全密钥。
2. 不要硬编码IV(初始化向量)
GCM模式下,IV应该是随机生成的(推荐12字节长度,这是GCM的最优长度),硬编码固定IV会严重降低加密的安全性——相同的明文+密钥+固定IV会生成相同的密文,泄露敏感信息。
3. 修正代码中的笔误
你的代码里返回了content:encrypted,但实际加密后的变量名是crypted,这会导致未定义变量的错误。
修正后的完整代码
module.exports = function(crypto) { const algorithm = 'aes-256-gcm'; const password = 'd6F3Efeq'; // 你的原始密码(生产环境别硬编码,用环境变量!) this.testFunc = async function(text) { // 生成随机盐值(解密时需要用同一个盐,所以要保存下来) const salt = crypto.randomBytes(16); // 从密码派生32字节的AES-256密钥 const key = await new Promise((resolve, reject) => { crypto.scrypt(password, salt, 32, (err, derivedKey) => { if (err) reject(err); resolve(derivedKey); }); }); // 生成随机12字节IV(GCM模式推荐长度) const iv = crypto.randomBytes(12); const cipher = crypto.createCipheriv(algorithm, key, iv); let crypted = cipher.update(text, 'utf8', 'hex'); crypted += cipher.final('hex'); const tag = cipher.getAuthTag(); // 返回所有解密需要的参数:密文、标签、IV、盐值 return { content: crypted, tag: tag.toString('hex'), iv: iv.toString('hex'), salt: salt.toString('hex') }; }; // 配套的解密函数,方便测试和使用 this.decryptFunc = async function(encryptedData) { // 用相同的盐值派生密钥 const key = await new Promise((resolve, reject) => { crypto.scrypt(password, Buffer.from(encryptedData.salt, 'hex'), 32, (err, derivedKey) => { if (err) reject(err); resolve(derivedKey); }); }); // 初始化解密器,传入密钥、IV,并设置验证标签 const decipher = crypto.createDecipheriv(algorithm, key, Buffer.from(encryptedData.iv, 'hex')); decipher.setAuthTag(Buffer.from(encryptedData.tag, 'hex')); let decrypted = decipher.update(encryptedData.content, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; }; };
关键说明
- 密钥派生:
scrypt函数通过加盐将短密码转换为32字节的安全密钥,同时增加了暴力破解的难度。 - 随机IV:每次加密生成新的IV,确保相同明文加密后结果不同,符合加密的语义安全性。
- GCM标签:
getAuthTag()获取的标签用于解密时验证密文是否被篡改,这是GCM模式提供的完整性校验功能。 - 生产环境注意:绝对不要把密码硬编码在代码里,应该用环境变量(比如
process.env.ENCRYPTION_PASSWORD)或者专业的密钥管理服务存储密码。
内容的提问来源于stack exchange,提问作者Pranab V V
相关产品推荐
相关产品推荐

