如何实现Java/Kotlin加密、Node.js解密?AES/CBC算法适配求助
解决AES/CBC跨Kotlin-Java和Node.js的加密解密互通问题
我帮你排查了代码里的几个关键差异点,这些就是导致两边无法互通的核心原因,调整后就能正常工作了:
核心问题分析
- 密文编码格式不统一:Kotlin端加密后把字节数组转成了Base64字符串,但Node.js端生成的是Hex编码的密文,解密时也用Hex解析,两边格式完全不匹配。
- 编码一致性隐患:虽然你的密码长度刚好符合AES-128要求,但要确保字符串转字节数组时,两端都使用UTF-8编码,避免不同平台默认编码差异(比如某些环境默认用ISO-8859-1)导致的密钥/IV不一致。
修改后的Kotlin代码
这里保持加密后输出Base64,同时明确指定UTF-8编码,避免默认编码问题:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val text = "Hello everybody !" val password = "1234567812345678" val encrypted = encrypt(text, password) Log.i("MainActivity", "encrypted = $encrypted") val decrypted = decrypt(encrypted, password) Log.i("MainActivity", "decrypted = $decrypted") } private fun encrypt(text: String, password: String): String { val keyBytes = password.toByteArray(Charsets.UTF_8) val ivBytes = password.toByteArray(Charsets.UTF_8) val keySpec = SecretKeySpec(keyBytes, "AES") val ivSpec = IvParameterSpec(ivBytes) val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec) val results = cipher.doFinal(text.toByteArray(Charsets.UTF_8)) return Base64.encodeToString(results, Base64.NO_WRAP) } private fun decrypt(text: String, password: String): String { val keyBytes = password.toByteArray(Charsets.UTF_8) val ivBytes = password.toByteArray(Charsets.UTF_8) val keySpec = SecretKeySpec(keyBytes, "AES") val ivSpec = IvParameterSpec(ivBytes) val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec) val decodedBytes = Base64.decode(text, Base64.NO_WRAP) return String(cipher.doFinal(decodedBytes), Charsets.UTF_8) }
修改后的Node.js代码
这里调整为和Kotlin端一致的Base64编码,同时明确使用UTF-8,确保两端规则对齐:
const crypto = require('crypto'); const text = "Hello everybody !"; const password = Buffer.from("1234567812345678", 'utf8'); console.log("Password = " + password.toString('utf8')); const encrypted = encrypt(text, password); console.log("Encrypted = " + encrypted); const decrypted = decrypt(encrypted, password); console.log("Decrypted = " + decrypted); function encrypt(data, password) { const cipher = crypto.createCipheriv('aes-128-cbc', password, password); let crypted = cipher.update(data, 'utf8', 'base64'); crypted += cipher.final('base64'); return crypted; } function decrypt(data, password) { const decipher = crypto.createDecipheriv('aes-128-cbc', password, password); let dec = decipher.update(data, 'base64', 'utf8'); dec += decipher.final('utf8'); return dec; }
额外生产环境注意事项
- IV的安全性:你现在直接用密码作为IV,这在生产环境是不安全的!IV应该是随机生成的,每次加密都用不同的IV,然后把IV和密文一起传输(比如IV放在密文前面,或者用JSON打包)。比如Kotlin端随机生成IV,转成Base64后和密文拼接,Node.js端拆分IV和密文再解密。
- 密钥的生成:如果密码不是固定长度的16/24/32字节,建议用KDF(比如PBKDF2)从密码生成符合AES要求的密钥,避免密钥长度不匹配导致的兼容性问题。
内容的提问来源于stack exchange,提问作者Liam
相关产品推荐
相关产品推荐

