一、描述
之前有一篇文章中介绍过 AES 的双向加密的实现,此为链接,然后某一天就出异常了。
问题很蛋疼,Windows 系统上开发的项目,利用 AES 双向加密技术,在 Java 代码内对手机号进行加密解密操作。
一切正常,但是项目移到 Linux 系统上,解密就出如下异常:</p>
1 | javax.crypto.BadPaddingException: Given final block not properly padded |
定位很精准,就是我的 AESUtil 这个工具类里面的如下代码有问题:
1 | //1.构造密钥生成器,指定为AES算法,不区分大小写 |
上面生成 key 的时候出问题了。
二、解决
那就将随机源手动指定就好,即手动生成一个key,
如下为代码改造,完美解决。
1 | //1.构造密钥生成器,指定为AES算法,不区分大小写 |
三、原理
其实原理也很蛋疼,网上解决办法大同小异,理由也都是千篇一律:
1 | SecureRandom 实现完全随操作系统本身的內部状态,除非调用方在调用 getInstance 方法之后又调用了 setSeed 方法; |
简单理解就是在 new SecureRandom() 的时候,两种操作系统上生成的随机数不相同罢了,why,追了下源码。
其实默认情况下,我们需要的 prng(random number algorithm),
在 Windows 环境下,默认是:SHA1PRNG,而 Linux 环境下,则默认是:NativePRNG。
再换句话说,Linux 默认使用 NativePRNG, 则它会去本地寻找熵(/ dev /urandom),产生的随机数(直接影响我们加密解密时需要的key)每次都是不一样的,故解密必然会失败了。
所以最直接的方式就是直接指定 prng,使用SHA1PRNG,即用下述方法来建立 SecureRandom,
1 | SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); |
源码地址:MyGitHub