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

如何实现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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:44:10