当前位置: 代码迷 >> 综合 >> Hutool 封装JDK的对称加密AES算法使用
  详细解决方案

Hutool 封装JDK的对称加密AES算法使用

热度:72   发布时间:2024-02-19 14:23:59.0

Hutool

        Hutool 是一个小而全的Java工具类库,提供了很多常用的工具类。官网:https://www.hutool.cn/docs/#/

AES封装

       遇到一个场景,透出了业务的订单号,该订单号是由年月日+自增ID拼成,如20200916000066。用户查询订单详情时,本应该根据登录用户的id和订单号去数据库中查询,但是因为历史原因(直接用订单号查询了!)以及一些其他的因素,暂时没能这么做。这样就会有数据泄漏问题,因为很容易构造出一个正确的且数据库内存在的这种订单号,但是这个订单可能不属于登录的用户,这就有可能用户A可以查到B用户的订单数据,甚至把你系统内的全部数据取出来,造成严重的数据泄露。

       因为系统设计缺陷导致不能用用户ID和订单号查询,设计一种临时方案【只是临时方案,应该从根本上解决设计缺陷】:考虑对透出去的订单号采用对称加密方式解决数据泄漏问题。我们把数据库表中的的订单号通过对称加密(比如AES),把加密后的订单号给到用户前端。请求订单详情的接口入参中的订单号改为加密后的订单号,经过解密后得到数据库中的订单号用于查询即可。

       Hutool 中的对称加密是对JDK中自带实现的封装,使用方便简洁,对称加密-SymmetricCrypto。

示例:

maven 依赖:

    <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.4.2</version></dependency>

官网示例代码: 

    public static void main(String[] args) {String content = "test中文";// 随机生成密钥byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded();// 构建AES aes = SecureUtil.aes(key);// 加密byte[] encrypt = aes.encrypt(content);// 解密byte[] decrypt = aes.decrypt(encrypt);// 加密为16进制表示String encryptHex = aes.encryptHex(content);// 解密为字符串String decryptStr = aes.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8);}

       上面是随机生成的密钥,我们可以指定密钥,只要满足AES的密钥长度规则即可,比如128 bits 的密钥key,构造出对应的byte数组即可,如下就是一个符合要求的AES密钥(16 * 8 = 128, 一个 byte 等于 8 bit):

public final static byte[] aes_key = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};

注意:

       1、QPS 敏感的接口需要关注加密、解密过程对接口执行总时长的影响。本地测试偶尔出现 AES aes = SecureUtil.aes(aes_key);这一步骤耗时较多的情况,加密、解密耗时反而很快。这个需要留意一下对生产环境接口QPS等的影响。

       2、对称加密,加密和解密用的是同一个密钥。上述代码中,如果对使用密钥A加密后的密文使用密钥B解密,会抛出异常:

public class AESTest {public final static byte[] aes_key = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};public static void main(String[] args) {String content = "test中文";// 随机生成密钥byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded();// 构建AES aes = SecureUtil.aes(key);AES aes1 = SecureUtil.aes(aes_key);// 加密为16进制表示String encryptHex = aes.encryptHex(content);// 解密为字符串String decryptStr = aes1.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8);}
}

异常信息:


Exception in thread "main" cn.hutool.crypto.CryptoException: BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.at cn.hutool.crypto.symmetric.SymmetricCrypto.decrypt(SymmetricCrypto.java:388)at cn.hutool.crypto.symmetric.SymmetricCrypto.decrypt(SymmetricCrypto.java:424)at cn.hutool.crypto.symmetric.SymmetricCrypto.decryptStr(SymmetricCrypto.java:435)at hutool.AESTest.main(AESTest.java:33)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.at com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)at javax.crypto.Cipher.doFinal(Cipher.java:2168)at cn.hutool.crypto.symmetric.SymmetricCrypto.decrypt(SymmetricCrypto.java:386)... 3 moreProcess finished with exit code 1