AES-256解密报错:wrong final block length问题修复咨询
修复AES-256-CBC解密时的"wrong final block length"错误
问题场景
向数据库插入100个密码经AES-256加密的用户后,解密时触发错误:Error decrypting passwords error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length
原加密代码
const secretKey = crypto.randomBytes(32); const secretIV = crypto.randomBytes(16); const insertEncryptAESUsers = async() => { try { const client = await pool.connect(); await client.query(`TRUNCATE users_aes RESTART IDENTITY`); const insertUserQuery = 'INSERT INTO users_aes (username, password) VALUES ($1, $2)'; for (let i = 0; i < 100; i++) { const username = faker.internet.userName(); const password = faker.internet.password(); const cipher = crypto.createCipheriv('aes-256-cbc', secretKey, secretIV); let encryptedPassword = cipher.update(password, 'utf8', 'binary'); encryptedPassword += cipher.final('binary'); encryptedPassword = Buffer.from(encryptedPassword, 'binary').toString('base64'); await client.query(insertUserQuery, [username, encryptedPassword]); } console.log('Users AES table filled successfully'); } catch (err) { console.error('Error filling users AES table', err.message); } }
原解密代码
const getUsersDecryptPasswordAES = async data => { try { const client = await pool.connect(); const selectUsersQuery = 'SELECT username, password FROM users_aes'; const queryResult = await client.query(selectUsersQuery); const passwords = queryResult.rows.map(row => row.password); for (let i = 0; i < passwords.length; i++) { const encryptedPassword = passwords[i]; const decipher = crypto.createDecipheriv('aes-256-cbc', secretKey, Buffer.from(secretIV, 'base64')); let decryptedPassword = decipher.update(Buffer.from(encryptedPassword, 'base64'), 'binary', 'utf8'); decryptedPassword += decipher.final('utf8'); console.log(`User ${queryResult.rows[i].username} has password: ${decryptedPassword}`); } console.log('Password decryption successful'); } catch (err) { console.error('Error decrypting passwords', err.message); } }
错误原因
- IV处理错误:加密时
secretIV是crypto.randomBytes(16)生成的原始二进制Buffer,解密时却错误地用Buffer.from(secretIV, 'base64')尝试解码,导致IV数据完全错误,解密流程无法匹配加密时的块对齐规则。 - update参数格式错误:解密时不需要将base64解码后的Buffer转成
binary格式传递,直接传入Buffer即可,格式不匹配会导致解密数据截断或损坏。
修复后的解密代码
const getUsersDecryptPasswordAES = async data => { try { const client = await pool.connect(); const selectUsersQuery = 'SELECT username, password FROM users_aes'; const queryResult = await client.query(selectUsersQuery); for (let i = 0; i < queryResult.rows.length; i++) { const { username, password: encryptedPassword } = queryResult.rows[i]; // 直接使用原始secretIV,无需base64解码 const decipher = crypto.createDecipheriv('aes-256-cbc', secretKey, secretIV); // 直接传入base64解码后的Buffer,不需要转binary let decryptedPassword = decipher.update(Buffer.from(encryptedPassword, 'base64'), 'utf8'); decryptedPassword += decipher.final('utf8'); console.log(`User ${username} has password: ${decryptedPassword}`); } console.log('Password decryption successful'); } catch (err) { console.error('Error decrypting passwords', err.message); } }
额外注意事项
secretKey和secretIV必须持久化存储(比如写入配置文件或环境变量),不能每次服务重启都重新生成,否则之前加密的所有数据都无法解密。- 加密时的输出格式可以简化:直接使用
cipher.update和cipher.final的base64输出,无需先转binary再转base64,优化后的加密代码片段如下:// 加密部分简化 const cipher = crypto.createCipheriv('aes-256-cbc', secretKey, secretIV); let encryptedPassword = cipher.update(password, 'utf8', 'base64'); encryptedPassword += cipher.final('base64');
内容的提问来源于stack exchange,提问作者John Smith
相关产品推荐
相关产品推荐

