> 文档中心 > Java加密算法—对称加密(DES、AES)

Java加密算法—对称加密(DES、AES)

目录

  • 1、概述
  • 2、加密模式
    • 2.1 ECB
    • 2.2 CBC
  • 3、填充模式
  • 4、对称加密、解密实现

1、概述

对称加密就是采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,也称为单密钥加密。

比如:凯撒加密就可以认为是一种对称加密,将偏移量看作密钥,加密和解密都用的是相同的偏移量(密钥)

  • 常见加密算法:

    • DES : Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美 国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。
    • AES : Advanced Encryption Standard, 高级加密标准 .在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
  • 特点:

    • 加密速度快, 可以加密大文件。
    • 密文可逆, 一旦密钥文件泄漏, 就会导致数据暴露。
    • 加密后编码表找不到对应字符, 出现乱码,一般结合Base64使用。

2、加密模式

2.1 ECB

ECB : Electronic codebook, 电子密码本. 需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密。
在这里插入图片描述

  • 优点 : 可以并行处理加密数据,速度快。
  • 缺点 : 同样的原文生成同样的密文, 不能很好的保护数据。

2.2 CBC

CBC : Cipher-block chaining, 密码块链接. 每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块。
在这里插入图片描述

优点 : 同样的原文生成的密文不一样。
缺点 : 串行处理数据,速度较慢。

3、填充模式

当需要按块处理的数据, 数据长度不符合块处理需求时, 按照一定的方法填充满块长的规则,分为NoPaddingPKCS5Padding

NoPadding:

  • 不填充。
  • 在DES加密算法下, 要求原文长度必须是8byte的整数倍。
  • 在AES加密算法下, 要求原文长度必须是16byte的整数倍。

PKCS5Padding:

  • 数据块的大小为8位, 不够就补足

注意:

  • 默认情况下, 加密模式和填充模式为 : ECB/PKCS5Padding
  • 如果使用CBC模式, 在初始化Cipher对象时, 需要增加参数, 初始化向量IV : IvParameterSpec iv = new IvParameterSpec(key.getBytes());

加密模式和填充模式创建模式:

AES/CBC/NoPadding (128)AES/CBC/PKCS5Padding (128)AES/ECB/NoPadding (128)AES/ECB/PKCS5Padding (128)DES/CBC/NoPadding (56)DES/CBC/PKCS5Padding (56)DES/ECB/NoPadding (56)DES/ECB/PKCS5Padding (56)

4、对称加密、解密实现

将对称加密的DES和AES进行封装处理,达到一套代码实现两种加密方式,结合了加密模式和填充模式的应用,代码可以直进行使用。。

代码实现:

public class SymmetryTest {    private final static String DES = "DES";    private final static String AES = "AES";    /**     * 设置为CBC加密模式,默认情况下ECB比CBC更高效     */    private final static String CBC = "/CBC/PKCS5Padding";    public static void main(String[] args) { // 对称加密 密文 String input = "key=85CD019515D14B91AD942787532314FF&startTime=1629431243245&endTime=1660967243244"; // DES加密算法,key的大小必须是8个字节 String desKey = "12345678"; // AES加密算法,key的大小必须是16个字节 String aesKey = "1234567812345678";String encryptDes = encryptBySymmetry(input, desKey, SymmetryTest.DES, true); System.out.println("DES加密:" + encryptDes); String des = decryptBySymmetry(encryptDes, desKey, SymmetryTest.DES, true); System.out.println("DES解密:" + des); System.out.println("\n==============================================\n"); String encryptAes = encryptBySymmetry(input, aesKey, SymmetryTest.AES); System.out.println("AES加密:" + encryptAes); String aes = decryptBySymmetry(encryptAes, aesKey, SymmetryTest.AES); System.out.println("AES解密:" + aes);    }    /**     * 对称加密     *     * @param input     : 密文     * @param key: 密钥     * @param algorithm : 类型:DES、AES     * @return     */    public static String encryptBySymmetry(String input, String key, String algorithm) { return encryptBySymmetry(input, key, algorithm, false);    }    /**     * 对称解密     *     * @param input     : 密文     * @param key: 密钥     * @param algorithm : 类型:DES、AES     * @return     */    public static String decryptBySymmetry(String input, String key, String algorithm) { return decryptBySymmetry(input, key, algorithm, false);    }    /**     * 对称加密数据     *     * @param input     : 原文     * @param key: 密钥     * @param algorithm : 类型:DES、AES     * @param cbc: CBC加密模式:同样的原文生成的密文不一样,串行进行,加密使用CBC解密也需要CBC     * @return : 密文     * @throws Exception     */    public static String encryptBySymmetry(String input, String key, String algorithm, Boolean cbc) { try {     // 根据加密类型判断key字节数     checkAlgorithmAndKey(key, algorithm);     // CBC模式     String transformation = cbc ? algorithm + CBC : algorithm;     // 获取加密对象     Cipher cipher = Cipher.getInstance(transformation);     // 创建加密规则     // 第一个参数key的字节     // 第二个参数表示加密算法     SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);     // ENCRYPT_MODE:加密模式     // DECRYPT_MODE: 解密模式     // 初始化加密模式和算法     // 默认采用ECB加密:同样的原文生成同样的密文,并行进行     // CBC加密:同样的原文生成的密文不一样,串行进行     if (cbc) {  // 使用CBC模式  IvParameterSpec iv = new IvParameterSpec(key.getBytes());  cipher.init(Cipher.ENCRYPT_MODE, sks, iv);     } else {  cipher.init(Cipher.ENCRYPT_MODE, sks);     }     // 加密     byte[] bytes = cipher.doFinal(input.getBytes());     // 输出加密后的数据     return Base64.encode(bytes); } catch (Exception e) {     e.printStackTrace();     throw new RuntimeException("加密失败!"); }    }    /**     * 对称解密     *     * @param input     : 密文     * @param key: 密钥     * @param algorithm : 类型:DES、AES     * @param cbc: CBC加密模式:同样的原文生成的密文不一样,串行进行,加密使用CBC解密也需要CBC     * @throws Exception     * @return: 原文     */    public static String decryptBySymmetry(String input, String key, String algorithm, Boolean cbc) { try {     // 根据加密类型判断key字节数     checkAlgorithmAndKey(key, algorithm);     // CBC模式     String transformation = cbc ? algorithm + CBC : algorithm;     // 1,获取Cipher对象     Cipher cipher = Cipher.getInstance(transformation);     // 指定密钥规则     SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);     // 默认采用ECB加密:同样的原文生成同样的密文     // CBC加密:同样的原文生成的密文不一样     if (cbc) {  // 使用CBC模式  IvParameterSpec iv = new IvParameterSpec(key.getBytes());  cipher.init(Cipher.DECRYPT_MODE, sks, iv);     } else {  cipher.init(Cipher.DECRYPT_MODE, sks);     }     // 3. 解密,上面使用的base64编码,下面直接用密文     byte[] bytes = cipher.doFinal(Base64.decode(input));     //  因为是明文,所以直接返回     return new String(bytes); } catch (Exception e) {     e.printStackTrace();     throw new RuntimeException("解密失败!"); }    }    private static void checkAlgorithmAndKey(String key, String algorithm) { // 根据加密类型判断key字节数 int length = key.getBytes().length; boolean typeEnable = false; if (DES.equals(algorithm)) {     typeEnable = length == 8; } else if (AES.equals(algorithm)) {     typeEnable = length == 16; } else {     throw new RuntimeException("加密类型不存在"); } if (!typeEnable) {     throw new RuntimeException("加密Key错误"); }    }}

效果:

在这里插入图片描述