Bootstrap

SpringBoot(八)使用AES库对字符串进行加密解密

博客的文章详情页面传递参数是使用AES加密过得,如下图所示:

1.jpg

这个AES加密是通用的加密方式,使用同一套算法,前端和后端都可以对加密之后的字符串进行加密解密操作。

目前线上正在使用的是前端javascript进行加密操作,将加密之后的字符串再传递到后端,PHP再进行解密操作。

现在我们将后端换成了SpringBoot,就需要使用java来实现后端解密操作。

一:javascript使用AES加密解密

需要引入加密文件库

https://s3.pstatp.com/cdn/expire-1-M/crypto-js/3.1.9/crypto-js.min.js

加密解密方法如下所示:

/**
 * @name:crypto-js 加密
 * @author: camellia
 * @email: [email protected]
 * @date: 2021-01-22
 */
export function encryptCode(param)
{
    var text = JSON.stringify(param);
    var key = CryptoJS.enc.Latin1.parse(‘1234567890789456’); //为了避免补位,直接用16位的秘钥
    var iv = CryptoJS.enc.Latin1.parse(‘1234567890789456’); //16位初始向量
    var encrypted = CryptoJS.AES.encrypt(text, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.ZeroPadding
    }).toString();
    return encrypted;
}
/**
 * @name:crypto-js 解密
 * @author: camellia
 * @email: [email protected]
 * @date: 2021-01-22
 */
export function decryptCode(param)
{
    var key = CryptoJS.enc.Latin1.parse(‘1234567890789456’); //为了避免补位,直接用16位的秘钥
    var iv = CryptoJS.enc.Latin1.parse(‘1234567890789456’); //16位初始向量
    const decrypt = CryptoJS.AES.decrypt(param, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.ZeroPadding
    }).toString(CryptoJS.enc.Utf8);
    return decrypt;
}

通过观察上方代码,我们可以发现,我使用的是AES-128算法加密,加解密模式为CBC,ZeroPadding是填充方法。

我的key和iv都是标准的16位,理论上来说,这个填充模式直接选择NoPadding就可以了,因为我不需要补位。

二:java使用AES加密解密

protected String key = "1234567890789456";
 protected String iv = "1234567890789456";
 /**
  * @Description AES算法加密明文
  * @param data 明文
  * @param key 密钥,长度16
  * @param iv 偏移量,长度16
  * @return 密文
  */
 public String encryptAES(String data,String key,String iv) throws Exception
 {
     try
     {
         //            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
         //            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
         //            Cipher cipher = Cipher.getInstance("AES/CBC/ZeroPadding"); java中没有实现这个方法
         // 声明加密算法 / 加密方式  / 填充方式
         Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
         int blockSize = cipher.getBlockSize();
         byte[] dataBytes = data.getBytes();
         int plaintextLength = dataBytes.length;
 
         if (plaintextLength % blockSize != 0)
         {
             plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
         }
 
         byte[] plaintext = new byte[plaintextLength];
         System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
 
         SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
         IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());  // CBC模式,需要一个向量iv,可增加加密算法的强度
 
         cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
         byte[] encrypted = cipher.doFinal(plaintext);
 
         return encode(encrypted).trim(); // BASE64做转码。
 
     }
     catch (Exception e)
     {
         e.printStackTrace();
         return null;
     }
 }
 
 /**
  * @Description AES算法解密密文
  * @param data 密文
  * @param key 密钥,长度16
  * @param iv 偏移量,长度16
  * @return 明文
  */
 public String decryptAES(String data,String key,String iv) throws Exception
 {
     try
     {
         byte[] encrypted1 = decode(data);//先用base64解密
         Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
         SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
         IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
 
         cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
 
         byte[] original = cipher.doFinal(encrypted1);
         String originalString = new String(original,"UTF-8");
         return originalString.trim();
     }
     catch (Exception e)
     {
         e.printStackTrace();
         return null;
     }
 }
 
 /**
  * 编码
  * @param byteArray
  * @return
  */
 public String encode(byte[] byteArray)
 {
     return new String(new Base64().encode(byteArray));
 }
 
 /**
  * 解码
  * @param base64EncodedString
  * @return
  */
 public byte[] decode(String base64EncodedString)
 {
     return new Base64().decode(base64EncodedString);
 }

这里注意一下,我使用的是java11,他是没有实现ZeroPadding这个填充方式的,但是,由于我的key和iv都是16位,不需要补位,因此我这里直接使用NoPadding即可。如果我的上述条件您不满足,可能您就需要换一个填充方式了。

三:AES加密简单介绍

AES加密又分成AES-128、AES-196、AES-256,其中128、196、256是针对加解密密钥长度的要求,即128位(16字节),196位(24字节),256位(32字节);

关于加解密模式和填充方式

针对待加解密明文、密文,长度有严格要求,即必须为16字节的整数倍(所以针对不同长度的数据,需要对齐,不够16位的需要填充数据,由此产生了不同的填充方式)。整个加解密的过程是对所有分割成16个字节长度的数据块进行循环加解密,最后合并起来形成最终结果集(加解密过程的不同产生了不同的加解密模式)。

常见加密模式:

2.jpg

常见填充方式:

3.jpg

以上大概就是java中AES加密和解密的使用。

有好的建议,请在下方输入你的评论。

;