欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Java工具类】对称加密之整合AES、DES算法加解密工具类

程序员文章站 2022-03-12 21:39:28
...
  • 对称加密算法只是为了区分非对称加密算法。特点就是加密是加密解密使用相同的**,而非对称加密加密和解密时使用的**不一样
    • 对称加密的**交换时可以使用非对称加密,这有效保护**的安全。
    • 非对称加密加密和解***不同,安全性高,但加解密的速度很慢,不适合对大数据加密。而对称加密加密速度快,因此混合使用最好。

常用的对称加密算法有:AES和DES.

  • DES:比较老的算法,一共有三个参数入口(原文,**,加密模式)。而3DES只是DES的一种模式,是以DES为基础更安全的变形,对数据进行了三次加密,也是被指定为AES的过渡算法。
  • AES:高级加密标准,新一代标准,加密速度更快,安全性更高(优先选择)
import org.junit.Test;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

public class SymmetricEncryptionUtil {
    private static final String AES = "AES";
    private static final String DES = "DES";
    /**
     * AES**
     */
    private static final String AES_KEY = "FFC22E80F61AB7295C02493856B4C520";

    /**
     * AES模式
     */
    private static final String AES_MODE = "AES/ECB/PKCS5Padding";


    /**
     * DES**: 加解密用到的秘钥-getBytes().length即字节的长度必须大于等于8,否则报异常java.security.InvalidKeyException: Wrong key size
     */
    private static final String DES_KEY = "*%#@()^&";
    /**
     * DES模式
     * "AES/ECB/PKCS5Padding"在加密和解密时必须相同,可以直接写”AES”,这样就是使用默认模式分别的意思为:AES是加密算法,ECB是工作模式,PKCS5Padding是填充方式。
     */
    private static final String DES_MODE = "DES/ECB/PKCS5Padding";


    /**
     * 使用AES对字符串加密
     *
     * @param str utf8编码的字符串
     * @param key **(16字节)
     * @return 加密结果
     * @throws Exception
     */
    public static String aesEncrypt(String str, String key) throws Exception {
        if (str == null || key == null) {
            return null;
        }

        //AES/ECB/PKCS5Padding在加密和解密时必须相同
        Cipher cipher = Cipher.getInstance(AES_MODE);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES));
        byte[] bytes = cipher.doFinal(str.getBytes(StandardCharsets.UTF_8));

        //使用base64编码
        return Base64.getEncoder().encodeToString(bytes);
    }

    /**
     * 使用AES对数据解密
     *
     * @param base64Encoder base64编码后的字符串
     * @param key           **(16字节)
     * @return 解密结果
     * @throws Exception
     */
    public static String aesDecrypt(String base64Encoder, String key) throws Exception {
        if (base64Encoder == null || key == null) {
            return null;
        }

        SecureRandom random = new SecureRandom();
        Cipher cipher = Cipher.getInstance(AES_MODE);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES), random);

        //使用base64解码
        byte[] base64DecoderByte = Base64.getDecoder().decode(base64Encoder);
        return new String(cipher.doFinal(base64DecoderByte), StandardCharsets.UTF_8);
    }


    /**
     * 使用DES对字符串加密
     *
     * @param str utf8编码的字符串
     * @param key **(56位,7字节)
     * @return 加密结果
     * @throws Exception
     */
    public static String desEncrypt(String str, String key) throws Exception {
        if (str == null || key == null) {
            return null;
        }

        SecureRandom random = new SecureRandom();
        Cipher cipher = Cipher.getInstance(DES_MODE);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), DES), random);
        byte[] bytes = cipher.doFinal(str.getBytes(StandardCharsets.UTF_8));

        //使用base64编码
        return Base64.getEncoder().encodeToString(bytes);
    }

    /**
     * 使用DES对数据解密
     *
     * @param base64Encoder base64编码后的字符串
     * @param key           **(16字节)
     * @return 解密结果
     * @throws Exception
     */
    public static String desDecrypt(String base64Encoder, String key) throws Exception {
        if (base64Encoder == null || key == null) {
            return null;
        }
        Cipher cipher = Cipher.getInstance(DES_MODE);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), DES));
        //使用base64解码
        byte[] base64DecoderByte = Base64.getDecoder().decode(base64Encoder);

        return new String(cipher.doFinal(base64DecoderByte), StandardCharsets.UTF_8);
    }


    /**
     * 测试AES算法
     *
     * @throws Exception
     */
    @Test
    public void main1() throws Exception {
        String str = "你好,张三!";
        System.out.println("原文:" + str);
        System.out.println("**:" + AES_KEY);

        String aesEncrypt = aesEncrypt(str, AES_KEY);
        System.out.println("加密后:" + aesEncrypt);

        String aesDecrypt = aesDecrypt(aesEncrypt, AES_KEY);
        System.out.println("解密后:" + aesDecrypt);
    }


    /**
     * 测试DES算法
     *
     * @throws Exception
     */
    @Test
    public void main2() throws Exception {
        String str = "你好,张三!";
        System.out.println("原文:" + str);
        System.out.println("**:" + DES_KEY);

        String aesEncrypt = desEncrypt(str, DES_KEY);
        System.out.println("加密后:" + aesEncrypt);

        String aesDecrypt = desDecrypt(aesEncrypt, DES_KEY);
        System.out.println("解密后:" + aesDecrypt);
    }
}

执行结果

```java
//main1
原文:你好,张三!
**:FFC22E80F61AB7295C02493856B4C520
加密后:Vlm7AY5VxhiOc5QSZe5Szga2oN2+AMpMDyHU9tYktFw=
解密后:你好,张三!

//main2
原文:你好,张三!
**:*%#@()^&
加密后:STDcjuovhcYOwV/tFmrvPH25wWw6o48M
解密后:你好,张三!

AES算法的所有参数都是字节码的(包括**)。因此字符串字符需要转换成字节码后进行加密

  • 参数:”AES/ECB/PKCS5Padding”加密和解密时必须相同,可以直接写”AES”,这样就是使用默认模式。分别的意思为:AES是加密算法,ECB是工作模式,PKCS5Padding是填充方式

AES是分组加密算法,也称块加密。每一组16字节。这样明文就会分成多块。当有一块不足16字节时就会进行填充。一共有四种工作模式:

  • ECB 电子密码本模式:相同的明文块产生相同的密文块,容易并行运算,但也可能对明文进行攻击。
  • CBC 加密分组链接模式:一块明文加密后和上一块密文进行链接,不利于并行,但安全性比ECB好,是SSL,IPSec的标准。
  • CFB 加密反馈模式:将上一次密文与**运算,再加密。隐藏明文模式,不利于并行,误差传递。
  • OFB 输出反馈模式:将上一次处理过的**与**运算,再加密。隐藏明文模式,不利于并行,有可能明文攻击,误差传递。

PKCS5Padding的填充方式是差多少字节就填数字多少;刚好每一不足16字节时,那么就会加一组填充为16.还有其他填充模式【Nopadding,ISO10126Padding】(不影响算法,加密解密时一致就行)。