AES工具类加解密,在windows环境下可以正常加解密(之前部署到linux服务器上也没有出现问题),但是在mac环境下解密时出现以下问题
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:989)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:845)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
整个工具类代码如下
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class AESUtils {
public static String encryptStr(String content, String password) {
return ParseHexUtils.parseByte2HexStr(encrypt(content,password));
}
public static byte[] encrypt(String content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
/*SecureRandom random=SecureRandom.getInstance("SHA1PRNG");
random.setSeed(password.getBytes());
kgen.init(128, random);*/
kgen.init(128, new SecureRandom(password.getBytes()));// 利用用户密码作为随机数初始化出
SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥,如果此密钥不支持编码,则返回
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化为加密模式的密码器
byte[] result = cipher.doFinal(byteContent);// 加密
return result;
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
public static String decryptStr(String content, String password){
try {
return new String(decrypt(ParseHexUtils.parseHexStr2Byte(content),password),"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
public static byte[] decrypt(byte[] content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
/*SecureRandom random=SecureRandom.getInstance("SHA1PRNG");
random.setSeed(password.getBytes());
kgen.init(128, random);*/
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化为解密模式的密码器
byte[] result = cipher.doFinal(content);
return result; // 明文
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
}
}
最后的解决办法就是把上述代码中加密解密方法中的多行注释的部分放开,再把下方的kegen.init(...)这行注释掉即可
原因:
简单看了一下源码SecureRandom的源码,没有得到很好的结论,个人觉得大概是环境的问题,没有调用setSeed()方法的时候,直接new SecureRandom(...)调用了它的默认方式生成秘钥,而调用了setSeed()方法,指定了它的秘钥生成方式
注:在此过程中,曾尝试修改jdk中jre目录下的java.security文件中属性且没有恢复默认,具体路径为
/Users/.../Documents/jdk1.8.0_201.jdk/Contents/Home/jre/lib/security/java.security
修改了文件中
securerandom.source=file:/dev/random属性为securerandom.source=file:/dev/./urandom