CryptoJS与Java/Scala AES加密结果不一致的问题及适配咨询
CryptoJS与Java/Scala AES加密结果不一致的问题及适配咨询
我来帮你梳理下问题的核心原因,以及对应的解决方案:
一、CryptoJS.AES.encrypt()的默认设置
CryptoJS的AES加密默认遵循OpenSSL的标准规范,和你当前Java/Scala实现的逻辑差异很大,具体默认参数如下:
- 密钥派生方式:默认采用OpenSSL的EVP_BytesToKey算法,不是直接对传入的
secret做哈希。它会生成一个随机8字节的盐,以secret为密码,通过MD5哈希(默认迭代1次)来生成AES密钥(256位对应32字节)和IV(16字节)。 - 加密模式:默认使用CBC模式
- 填充方式:默认是PKCS7填充(和Java中的
PKCS5Padding在AES场景下完全等价,因为AES的块大小是16字节,两者的填充规则一致) - 输出格式:默认生成OpenSSL兼容的Base64字符串,结构为:
Salted__(固定8字节标识) + 8字节随机盐 + 加密后的密文,而非你代码中直接拼接的IV+密文。
二、修改Java/Scala代码匹配CryptoJS的加密格式
要让你的Java/Scala实现和CryptoJS兼容,需要实现EVP_BytesToKey算法来生成密钥和IV,并按照OpenSSL的格式拼接最终内容。以下是修改后的Scala代码:
import javax.crypto.{Cipher, SecretKeySpec} import javax.crypto.spec.IvParameterSpec import java.security.MessageDigest import java.util.Base64 def encryptWithCryptoJSFormat(data: String, secret: String): String = { // 生成CryptoJS默认的8字节随机盐 val salt = new Array[Byte](8) new java.security.SecureRandom().nextBytes(salt) // 实现OpenSSL EVP_BytesToKey算法,生成AES-256密钥和IV val passwordBytes = secret.getBytes("UTF-8") var keyAndIv = Array[Byte]() var lastHash = Array[Byte]() // 需生成32字节密钥 + 16字节IV,总计48字节 while (keyAndIv.length < 48) { val digest = MessageDigest.getInstance("MD5") if (lastHash.nonEmpty) digest.update(lastHash) digest.update(passwordBytes) digest.update(salt) lastHash = digest.digest() keyAndIv = keyAndIv ++ lastHash } val keyBytes = keyAndIv.take(32) // 提取AES-256密钥 val ivBytes = keyAndIv.slice(32, 48) // 提取IV // 初始化CBC模式加密器,PKCS5Padding等价于CryptoJS的PKCS7填充 val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") val keySpec = new SecretKeySpec(keyBytes, "AES") val ivSpec = new IvParameterSpec(ivBytes) cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec) // 执行加密 val encryptedBytes = cipher.doFinal(data.getBytes("UTF-8")) // 按照OpenSSL格式拼接内容:Salted__标识 + 盐 + 密文 val saltedPrefix = "Salted__".getBytes("UTF-8") val combined = saltedPrefix ++ salt ++ encryptedBytes // Base64编码输出,和CryptoJS默认输出格式一致 Base64.getEncoder.encodeToString(combined) }
代码修改说明:
- 生成了8字节随机盐,和CryptoJS的默认盐长度匹配
- 用EVP_BytesToKey算法生成密钥和IV,替代了你原来直接SHA256哈希
secret的逻辑 - 最终拼接的内容遵循OpenSSL标准格式,这样服务端就能和CryptoJS的加密结果一样被正常解密了
备注:内容来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

