如何将CryptoJS DES加密逻辑等价实现为Java代码?
等价于CryptoJS DES加密的Java实现
CryptoJS的DES.encrypt默认采用加盐的PBKDF2密钥派生+CBC模式+PKCS7填充,每次生成随机Salt和IV,因此加密结果不同但解密后一致。你的原Java工具类使用ECB模式且无加盐逻辑,无法与JS端互通,以下是完全等价的实现:
import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import java.security.SecureRandom; import java.util.Base64; public class CryptoJSDESUtil { // CryptoJS默认固定参数 private static final String PREFIX = "Salted__"; private static final int SALT_SIZE = 8; private static final int IV_SIZE = 8; // DES块大小为8字节 private static final int ITERATION_COUNT = 1000; private static final int KEY_SIZE = 64; // PBKDF2派生密钥长度,DES取前8字节 private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding"; private static final String KEY_DERIVATION_ALGORITHM = "PBKDF2WithHmacSHA1"; /** * 等价于CryptoJS.DES.encrypt(plainText, password) */ public static String encrypt(String plainText, String password) throws Exception { // 生成随机Salt byte[] salt = new byte[SALT_SIZE]; new SecureRandom().nextBytes(salt); // 生成随机IV byte[] iv = new byte[IV_SIZE]; new SecureRandom().nextBytes(iv); // 从密码和Salt派生密钥 SecretKey secretKey = deriveKey(password, salt); // 初始化CBC模式加密器 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); // 加密明文 byte[] cipherBytes = cipher.doFinal(plainText.getBytes("UTF-8")); // 组装CryptoJS标准格式:Salted__前缀 + Salt + IV + 密文 byte[] resultBytes = new byte[PREFIX.getBytes().length + SALT_SIZE + IV_SIZE + cipherBytes.length]; System.arraycopy(PREFIX.getBytes(), 0, resultBytes, 0, PREFIX.getBytes().length); System.arraycopy(salt, 0, resultBytes, PREFIX.getBytes().length, SALT_SIZE); System.arraycopy(iv, 0, resultBytes, PREFIX.getBytes().length + SALT_SIZE, IV_SIZE); System.arraycopy(cipherBytes, 0, resultBytes, PREFIX.getBytes().length + SALT_SIZE + IV_SIZE, cipherBytes.length); // Base64编码返回 return Base64.getEncoder().encodeToString(resultBytes); } /** * 等价于CryptoJS.DES.decrypt(cipherText, password).toString(CryptoJS.enc.Utf8) */ public static String decrypt(String cipherText, String password) throws Exception { // 解码Base64得到原始字节数据 byte[] resultBytes = Base64.getDecoder().decode(cipherText); // 验证CryptoJS专属前缀 byte[] prefixBytes = PREFIX.getBytes(); for (int i = 0; i < prefixBytes.length; i++) { if (resultBytes[i] != prefixBytes[i]) { throw new IllegalArgumentException("无效的CryptoJS加密格式"); } } // 提取Salt、IV和密文内容 byte[] salt = new byte[SALT_SIZE]; System.arraycopy(resultBytes, prefixBytes.length, salt, 0, SALT_SIZE); byte[] iv = new byte[IV_SIZE]; System.arraycopy(resultBytes, prefixBytes.length + SALT_SIZE, iv, 0, IV_SIZE); byte[] cipherBytes = new byte[resultBytes.length - prefixBytes.length - SALT_SIZE - IV_SIZE]; System.arraycopy(resultBytes, prefixBytes.length + SALT_SIZE + IV_SIZE, cipherBytes, 0, cipherBytes.length); // 派生解密密钥 SecretKey secretKey = deriveKey(password, salt); // 初始化CBC模式解密器 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); // 解密并转为UTF-8明文 return new String(cipher.doFinal(cipherBytes), "UTF-8"); } /** * 用PBKDF2算法从密码和Salt派生密钥,完全匹配CryptoJS默认逻辑 */ private static SecretKey deriveKey(String password, byte[] salt) throws Exception { PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, KEY_SIZE); SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_DERIVATION_ALGORITHM); // DES仅使用派生密钥的前8字节 byte[] keyBytes = factory.generateSecret(spec).getEncoded(); return new SecretKeySpec(keyBytes, 0, 8, "DES"); } }
使用示例
public class TestDES { public static void main(String[] args) throws Exception { String plainText = "123456"; String password = "12345678"; // 加密(每次执行结果不同) String cipherText = CryptoJSDESUtil.encrypt(plainText, password); System.out.println("加密结果:" + cipherText); // 解密(得到原始明文) String decryptedText = CryptoJSDESUtil.decrypt(cipherText, password); System.out.println("解密结果:" + decryptedText); } }
关键匹配逻辑说明
- CryptoJS默认用PBKDF2算法,迭代次数1000,密钥长度64位,随机生成8字节Salt
- 加密模式为CBC,随机生成8字节IV(DES块大小)
- 输出格式为
Salted__前缀 + Salt + IV + 密文,再进行Base64编码 - 解密时反向解析格式,提取Salt和IV后派生密钥解密
内容的提问来源于stack exchange,提问作者Fate
相关产品推荐
相关产品推荐

