AES解密

本文介绍了一个AES算法工具类,该工具类使用CBC模式和PKCS7填充方式实现数据的加密和解密。提供了两种方法来获取Cipher实例,并通过示例展示了如何使用这些方法进行AES解密。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.util.Base64;

/**
 * AES算法工具类
 */
public class AESUtil {

    private final static Logger logger = LoggerFactory.getLogger(AESUtil.class);

    /**
     * 密码算法
     */
    private final static String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding";
    /**
     * Key算法
     */
    private final static String KEY_ALGORITHM = "AES";

    /**
     * 密码
     */
    private static ThreadLocal<Cipher> cipherThreadLocal = new ThreadLocal<>();
    private static ThreadLocal<Cipher> cipherBCThreadLocal = new ThreadLocal<>();

//    static {
//        Security.addProvider(new BouncyCastleProvider());
//        try {
//            cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
//            logger.error("AESUtil produce cipher error.", e);
//            cipher = null;
//        }
//    }

    public static Cipher getCipher() {
        Security.addProvider(new BouncyCastleProvider());
        try {
            if (cipherThreadLocal.get() == null) {
                Cipher c = Cipher.getInstance(CIPHER_ALGORITHM);
                cipherThreadLocal.set(c);
            }
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            logger.error("AESUtil produce cipher error.", e);
            cipherThreadLocal = null;
        }
        return cipherThreadLocal.get();
    }

    /**
     * AES解密
     *
     * @param encryptedData 加密数据
     * @param encodeKey Base64编码的Key
     * @param encodeIv  Base64编码的偏移量
     * @return  解密后的数据
     */
    public static String decrypt(String encryptedData, String encodeKey, String encodeIv) {
        Cipher cipher = getCipher();
        if (cipher == null) {
            return null;
        }
        byte[] decodeData = decodeData(encryptedData);
        SecretKeySpec secretKey = decodeKey(encodeKey);
        IvParameterSpec ivParameter = decodeIv(encodeIv);

        try {
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameter);
            return new String(cipher.doFinal(decodeData));
        } catch (InvalidKeyException
                | InvalidAlgorithmParameterException
                | IllegalBlockSizeException
                | BadPaddingException e) {
            logger.error("AESUtil decrypt data error. openId:{}, e:{}", e);
            return null;
        }
    }


    public static Cipher getCipherBC() {
        Security.addProvider(new BouncyCastleProvider());
        try {
            if (cipherBCThreadLocal.get() == null) {
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
                cipherBCThreadLocal.set(cipher);
            }
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | NoSuchProviderException e) {
            logger.error("AESUtil produce cipher error.", e);
            cipherBCThreadLocal = null;
        }
        return cipherBCThreadLocal.get();
    }

    /**
     * AES解密
     *
     * @param encryptedData 加密数据
     * @param encodeKey Base64编码的Key
     * @param encodeIv  Base64编码的偏移量
     * @return  解密后的数据
     */
    public static String decryptBC(String encryptedData, String encodeKey, String encodeIv) {
        Cipher cipher = getCipherBC();
        if (cipher == null) {
            return null;
        }
        byte[] decodeData = decodeData(encryptedData);
        SecretKeySpec secretKey = decodeKey(encodeKey);
        IvParameterSpec ivParameter = decodeIv(encodeIv);

        try {
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameter);
            return new String(cipher.doFinal(decodeData));
        } catch (InvalidKeyException
                | InvalidAlgorithmParameterException
                | IllegalBlockSizeException
                | BadPaddingException e) {
            logger.error("AESUtil decrypt data error. openId:{}, e:{}", e);
            return null;
        }
    }

    /**
     * 解码数据
     *
     * @param encodeData  编码数据
     * @return  数据
     */
    private static byte[] decodeData(String encodeData) {
        return Base64.getDecoder().decode(encodeData);
    }

    /**
     * 解码Key
     *
     * @param encodeKey  编码Key
     * @return  Key
     */
    private static SecretKeySpec decodeKey(String encodeKey) {
        byte[] decodeKey = Base64.getDecoder().decode(encodeKey);
        return new SecretKeySpec(decodeKey, KEY_ALGORITHM);
    }

    /**
     * 解码偏移量
     *
     * @param encodeIv  编码偏移量
     * @return  偏移量
     */
    private static IvParameterSpec decodeIv(String encodeIv) {
        byte[] decodeIv = Base64.getDecoder().decode(encodeIv);
        return new IvParameterSpec(decodeIv);
    }
}
### 实现AES解密 在Java中实现AES解密涉及多个方面,包括设置正确的算法参数、处理密钥以及确保输入输出流的安全性。 #### 设置环境与导入必要的库 要执行AES解密操作,需先引入`javax.crypto.Cipher`类以及其他辅助工具类。此外,还需准备用于测试的数据,比如密文和密钥等。 ```java import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.IvParameterSpec; import java.util.Base64; ``` #### 准备解密所需的材料 按照给定条件,这里采用固定的密钥和初始化向量(IV),这些通常不应直接写入源码内,在真实场景下应通过更安全的方法获取[^2]。 ```java // 定义密钥和IV String key = "o91GjT9BsPn8iAuLwBRliA=="; // Base64 encoded secret key string byte[] decodedKey = Base64.getDecoder().decode(key); SecretKeySpec skeySpec = new SecretKeySpec(decodedKey, "AES"); // 使用Base64编码的字符串作为IV String ivStr = "..."; // 这里省略具体值,假设已知 byte[] ivBytes = Base64.getDecoder().decode(ivStr); IvParameterSpec ivspec = new IvParameterSpec(ivBytes); // 加载待解密的内容 String encryptedText = "your_encrypted_string_here"; byte[] encData = Base64.getDecoder().decode(encryptedText.getBytes()); ``` #### 创建并配置Cipher对象 指定具体的加密/解密模式(如AES/CBC/PKCS5Padding),这有助于提高程序的可移植性和一致性。 ```java // 初始化cipher实例为解密模式 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivspec); ``` #### 执行解密动作 调用`doFinal()`方法完成最终的解密工作,并将得到的结果转换回原始形式以便查看或进一步处理。 ```java try { byte[] decryptedData = cipher.doFinal(encData); String originalText = new String(decryptedData, "UTF-8"); // 确保使用相同字符集 System.out.println(originalText); // 输出解密后的明文 } catch (Exception e) { e.printStackTrace(); } ``` #### 常见问题及解决方案 - **错误的填充方式**:如果遇到类似于“Bad padding exception”的报错,则可能是由于使用的填充机制不匹配所引起的;此时应当确认两端都采用了相同的填充策略。 - **非法密钥长度**:部分JVM版本可能存在对不同大小密钥的支持差异,可通过安装不受限强度政策文件来支持更大的密钥尺寸。 - **乱码现象**:当看到不可识别的文字时,很可能是因为字符编码设定不当造成的,务必保持前后端一致性的字符编码标准。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值