前言

1:我们在java-8中使用AES加解密用PKCS5Padding填充(默认支持),但是换成PKCS7Padding填充就会报错,原因是jdk-8中没有支持PKCS7Padding的填充。

com.utils.MsfAESUtilTest
============PKCS5Padding===========
java.security.NoSuchAlgorithmException: Cannot find any provider supporting AES/CBC/PKCS7Padding
	at javax.crypto.Cipher.getInstance(Cipher.java:543)

Process finished with exit code 0

2:现在一般的应用都会使用256位加密key,但是这个在java中有些版本是不支持的,执行加解密会报错。

java.security.InvalidKeyException: Illegal key size or default parameters

解决方式

一、AES PKCS7Padding填充加解密支持的二种方式

1:在jdk安装目录下添加bouncycastle包支持

到该网站下载jar支持包添加到jdk目录jdk_path/jre/lib/ext bcprov-jdk18on-171.jar)https://www.bouncycastle.org/latest_releases.html#google_vignette

修改/%JAVA_HOME%/jdk/jre/lib/security/java.security这个文件

security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=sun.security.ec.SunEC
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
#security.provider.7=com.sun.security.sasl.Provider   #注释这一行
security.provider.7=org.bouncycastle.jce.provider.BouncyCastleProvider #添加这一行
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC

2:在AES代码中使用bouncycastle包支持

/**
pom.xml添加依赖
<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcprov-jdk18on</artifactId>
  <version>1.71</version>
</dependency>
 */
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public static String encryptByCBC256(String data, String secretKey, String iv) throws Exception {
  ...
  // 在加密方法中添加这一句
  Security.addProvider(new BouncyCastleProvider());
  ...
}

示例

package com.utils;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;


public class MsfAESUtilTest {

    private static final String KEY_ALGORITHM = "AES";
    public static final String SECRET_KEY = "88888888888888888888888888888888";
    public static final String IV = "xxxxxxxxxxxxxx";
    private static final String CBC_CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final String CBC_CIPHER_ALGORITHM_256 = "AES/CBC/PKCS7Padding";
    private static final String CHARSET_NAME = "utf-8";

    public static void main(String[] args) {
        try {

            System.out.println("============PKCS5Padding===========");
            String encrypted = encryptByP5("caodegao", SECRET_KEY, IV);
            System.out.println("encrypted : " + encrypted);
            String result = decryptByP5(encrypted, SECRET_KEY, IV);
            System.out.println("result : " + result);

            System.out.println("============PKCS7Padding===========");

            encrypted = encryptByP7("caodegao", SECRET_KEY, IV);
            System.out.println("encrypted : " + encrypted);
            result = decryptByP7(encrypted, SECRET_KEY, IV);
            System.out.println("result : " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static String encryptByP5(String data, String secretKey, String iv) throws Exception {
        if (org.apache.commons.lang3.StringUtils.isBlank(data)) {
            return data;
        }
        if (org.apache.commons.lang3.StringUtils.isBlank(iv)) {
            throw new IllegalArgumentException("decrypt iv isBlank");
        }
        byte[] raw = secretKey.getBytes(CHARSET_NAME);
        SecretKeySpec sKeySpec = new SecretKeySpec(raw, KEY_ALGORITHM);
        //算法/模式/补码方式
        Cipher cipher = Cipher.getInstance(CBC_CIPHER_ALGORITHM);
        //使用CBC模式,需要一个向量iv,可增加加密算法的强度
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
        cipher.init(Cipher.ENCRYPT_MODE, sKeySpec, ivParameterSpec);
        byte[] encrypted = cipher.doFinal(data.getBytes());

        return Base64.encodeBase64String(encrypted);

    }

    public static String encryptByP7(String data, String secretKey, String iv) throws Exception {
        if (org.apache.commons.lang3.StringUtils.isBlank(data)) {
            return data;
        }
        if (org.apache.commons.lang3.StringUtils.isBlank(iv)) {
            throw new IllegalArgumentException("decrypt iv isBlank");
        }
        byte[] raw = secretKey.getBytes(CHARSET_NAME);
        SecretKeySpec keySpec = new SecretKeySpec(raw, "AES");
        Security.addProvider(new BouncyCastleProvider());

        Cipher cipher = Cipher.getInstance(CBC_CIPHER_ALGORITHM_256, "BC");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv.getBytes()));
        byte[] encrypted = cipher.doFinal(data.getBytes());
        return Base64.encodeBase64String(encrypted);

    }

    public static String decryptByP5(String data, String secretKey, String iv) throws Exception {
        if (org.apache.commons.lang3.StringUtils.isBlank(data)) {
            return data;
        }
        if (StringUtils.isBlank(iv)) {
            throw new IllegalArgumentException("decrypt iv isBlank");
        }
        byte[] raw = secretKey.getBytes(CHARSET_NAME);
        SecretKeySpec sKeySpec = new SecretKeySpec(raw, KEY_ALGORITHM);
        Cipher cipher = Cipher.getInstance(CBC_CIPHER_ALGORITHM);
        //使用CBC模式,需要一个向量iv,可增加加密算法的强度
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
        cipher.init(Cipher.DECRYPT_MODE, sKeySpec, ivParameterSpec);
        byte[] original = cipher.doFinal(Base64.decodeBase64(data));
        return new String(original, CHARSET_NAME);
    }

    public static String decryptByP7(String data, String secretKey, String iv) throws Exception {
        if (org.apache.commons.lang3.StringUtils.isBlank(data)) {
            return data;
        }
        if (StringUtils.isBlank(iv)) {
            throw new IllegalArgumentException("decrypt iv isBlank");
        }
        byte[] raw = secretKey.getBytes(CHARSET_NAME);
        SecretKeySpec keySpec = new SecretKeySpec(raw, KEY_ALGORITHM);
        Security.addProvider(new BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance(CBC_CIPHER_ALGORITHM_256, "BC");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv.getBytes()));
        byte[] original = cipher.doFinal(Base64.decodeBase64(data));

        return new String(original, CHARSET_NAME);
    }

}
运行结果,发现没啥两样

============PKCS5Padding===========
encrypted : 5yy52rtdRArbCRdA7R0CwQ==
result : caodegao
============PKCS7Padding===========
encrypted : 5yy52rtdRArbCRdA7R0CwQ==
result : caodegao

Process finished with exit code 0

二、解决jdk支持256长度key的两种方式

1:在jdk安装目录下替换加解密jdk支持

到Oracle下载https://www.oracle.com/java/technologies/javase-jce8-downloads.html 加密支持包
解压之后得到local_policy.jar & US_export_policy.jar两个jar包,把这两个jar包放到 /%JAVA_HOME%/jdk/lib/security 目录下
jdk

注意:jre\lib\security\policy,在某些版本这个文件夹下能看见两个文件夹,分别是“limited”和“unlimited”,两个文件夹下面的内容都是“local_policy.jar和US_export_policy.jar”这两个东西,我们要用的是“unlimited”下的jar

2:升级高版本的jdk(以1.8.x版本为例),但具体的版本我也没有安装过那么多,目前是1.8.151版本不行,换到1.8.202版本后可以。