Java异常之:AES加密兼容Linux

解决 AES 双向加密技术在 Linux 和 Windows 平台上的差异化。

一、描述

之前有一篇文章中介绍过 AES 的双向加密的实现,此为链接,然后某一天就出异常了。

问题很蛋疼,Windows 系统上开发的项目,利用 AES 双向加密技术,在 Java 代码内对手机号进行加密解密操作。

一切正常,但是项目移到 Linux 系统上,解密就出如下异常:</p>

1
2
3
4
5
6
7
8
javax.crypto.BadPaddingException:&nbsp;Given&nbsp;final&nbsp;block&nbsp;not&nbsp;properly&nbsp;padded
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;javax.crypto.Cipher.doFinal(DashoA13*..)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;chb.test.crypto.AESUtil.crypt(AESUtil.java:386)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;chb.test.crypto.AESUtil.AesDecrypt(AESUtil.java:254)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;chb.test.crypto.AESUtil.main(AESUtil.java:40)

定位很精准,就是我的 AESUtil 这个工具类里面的如下代码有问题:

1
2
3
4
5
//1.构造密钥生成器,指定为AES算法,不区分大小写
KeyGenerator&nbsp;keygen=&nbsp;KeyGenerator.getInstance("AES");
//2.根据ecnodeRules规则初始化密钥生成器
//生成一个128位的随机源,根据传入的字节数组
keygen.init(128,&nbsp;new&nbsp;SecureRandom(encodeRules.getBytes()));

上面生成 key 的时候出问题了。

二、解决

那就将随机源手动指定就好,即手动生成一个key,

如下为代码改造,完美解决。

1
2
3
4
5
6
7
//1.构造密钥生成器,指定为AES算法,不区分大小写
KeyGenerator&nbsp;keygen=&nbsp;KeyGenerator.getInstance("AES");
//2.根据ecnodeRules规则初始化密钥生成器
//防止linux下&nbsp;随机生成key
SecureRandom&nbsp;secureRandom&nbsp;=&nbsp;SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(encodeRules.getBytes());
keygen.init(128,&nbsp;secureRandom);


三、原理

其实原理也很蛋疼,网上解决办法大同小异,理由也都是千篇一律:

1
2
SecureRandom&nbsp;实现完全随操作系统本身的內部状态,除非调用方在调用&nbsp;getInstance&nbsp;方法之后又调用了&nbsp;setSeed&nbsp;方法;
该实现在&nbsp;windows&nbsp;上每次生成的&nbsp;key&nbsp;都相同,但是在&nbsp;solaris&nbsp;或部分&nbsp;linux&nbsp;系统上则不同。

简单理解就是在 new SecureRandom() 的时候,两种操作系统上生成的随机数不相同罢了,why,追了下源码。

其实默认情况下,我们需要的 prng(random number algorithm),

在 Windows 环境下,默认是:SHA1PRNG,而 Linux 环境下,则默认是:NativePRNG。

bugCollection-AES.png

再换句话说,Linux 默认使用 NativePRNG, 则它会去本地寻找熵(/ dev /urandom),产生的随机数(直接影响我们加密解密时需要的key)每次都是不一样的,故解密必然会失败了。

所以最直接的方式就是直接指定 prng,使用SHA1PRNG,即用下述方法来建立 SecureRandom,

1
2
SecureRandom&nbsp;secureRandom&nbsp;=&nbsp;SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(encodeRules.getBytes());

源码地址:MyGitHub




------ 本文结束 感谢阅读 ------
0%