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

如何将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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:35:01